diff --git a/docs/pages/components/tree-item.md b/docs/pages/components/tree-item.md index cb50f69bd9..b17cacbdae 100644 --- a/docs/pages/components/tree-item.md +++ b/docs/pages/components/tree-item.md @@ -166,3 +166,66 @@ const App = () => ( ); ``` + +### Lazy Loading + +Use the `lazy` attribute on a tree item to indicate that the content is not yet present and will be loaded later. When the user tries to expand the node, the `loading` state is set to `true` and the `sl-lazy-load` event will be emitted to allow you to load data asynchronously. The item will remain in a loading state until its content is changed. + +If you want to disable this behavior after the first load, simply remove the `lazy` attribute and, on the next expand, the existing content will be shown instead. + +```html:preview + + Available Trees + + + +``` + +```jsx:react +import SlTree from '@shoelace-style/shoelace/dist/react/tree'; +import SlTreeItem from '@shoelace-style/shoelace/dist/react/tree-item'; + +const App = () => { + const [childItems, setChildItems] = useState([]); + const [lazy, setLazy] = useState(true); + + const handleLazyLoad = () => { + // Simulate asynchronous loading + setTimeout(() => { + setChildItems(['Birch', 'Cedar', 'Maple', 'Pine']); + + // Disable lazy mode once the content has been loaded + setLazy(false); + }, 1000); + }; + + return ( + + + Available Trees + {childItems.map(item => ( + {item} + ))} + + + ); +}; +``` diff --git a/docs/pages/components/tree.md b/docs/pages/components/tree.md index 65816b8b81..8bddde8133 100644 --- a/docs/pages/components/tree.md +++ b/docs/pages/components/tree.md @@ -235,69 +235,6 @@ const App = () => ( {% endraw %} -### Lazy Loading - -Use the `lazy` attribute on a tree item to indicate that the content is not yet present and will be loaded later. When the user tries to expand the node, the `loading` state is set to `true` and the `sl-lazy-load` event will be emitted to allow you to load data asynchronously. The item will remain in a loading state until its content is changed. - -If you want to disable this behavior after the first load, simply remove the `lazy` attribute and, on the next expand, the existing content will be shown instead. - -```html:preview - - Available Trees - - - -``` - -```jsx:react -import SlTree from '@shoelace-style/shoelace/dist/react/tree'; -import SlTreeItem from '@shoelace-style/shoelace/dist/react/tree-item'; - -const App = () => { - const [childItems, setChildItems] = useState([]); - const [lazy, setLazy] = useState(true); - - const handleLazyLoad = () => { - // Simulate asynchronous loading - setTimeout(() => { - setChildItems(['Birch', 'Cedar', 'Maple', 'Pine']); - - // Disable lazy mode once the content has been loaded - setLazy(false); - }, 1000); - }; - - return ( - - - Available Trees - {childItems.map(item => ( - {item} - ))} - - - ); -}; -``` - ### Customizing the Expand and Collapse Icons Use the `expand-icon` and `collapse-icon` slots to change the expand and collapse icons, respectively. To disable the animation, override the `rotate` property on the `expand-button` part as shown below. diff --git a/src/components/tree-item/tree-item.component.ts b/src/components/tree-item/tree-item.component.ts index 8b1cbffb31..417f372ce5 100644 --- a/src/components/tree-item/tree-item.component.ts +++ b/src/components/tree-item/tree-item.component.ts @@ -170,6 +170,9 @@ export default class SlTreeItem extends ShoelaceElement { this.setAttribute('aria-busy', this.loading ? 'true' : 'false'); if (!this.loading) { + this.getChildrenItems().forEach(item => { + item.selected = this.selected; + }); this.animateExpand(); } } diff --git a/src/components/tree-item/tree-item.test.ts b/src/components/tree-item/tree-item.test.ts index 023eb1f288..29e154c348 100644 --- a/src/components/tree-item/tree-item.test.ts +++ b/src/components/tree-item/tree-item.test.ts @@ -177,4 +177,25 @@ describe('', () => { expect(lazyChangeSpy).to.have.been.calledTwice; }); }); + + it('should update children select state after loading', async () => { + // Arrange + const lazyLoadSpy = sinon.spy(); + + parentItem.addEventListener('sl-lazy-load', lazyLoadSpy); + parentItem.selected = true; + parentItem.lazy = true; + + // Act + parentItem.expanded = true; + await waitUntil(() => lazyLoadSpy.calledOnce); + parentItem.loading = false; + await parentItem.updateComplete; + + // Assert + expect(parentItem.childElementCount).to.be.greaterThan(0); + parentItem.getChildrenItems().forEach(child => { + expect(child.selected).to.be.true; + }); + }); });