feat(treeview)!: rename children prop to nodes for Svelte 5 compatibility

This commit is contained in:
Eric Liu 2024-10-20 14:28:52 -07:00
commit 82905ac696
6 changed files with 56 additions and 56 deletions

View file

@ -4690,26 +4690,26 @@ export interface TreeNode {
text: any; text: any;
icon?: typeof import("svelte").SvelteComponent<any>; icon?: typeof import("svelte").SvelteComponent<any>;
disabled?: boolean; disabled?: boolean;
children?: TreeNode[]; nodes?: TreeNode[];
} }
``` ```
### Props ### Props
| Prop name | Required | Kind | Reactive | Type | Default value | Description | | Prop name | Required | Kind | Reactive | Type | Default value | Description |
| :------------ | :------- | :-------------------- | :------- | ------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------- | | :------------ | :------- | :-------------------- | :------- | ------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------- |
| expandedIds | No | <code>let</code> | Yes | <code>ReadonlyArray<TreeNodeId></code> | <code>[]</code> | Set the node ids to be expanded | | expandedIds | No | <code>let</code> | Yes | <code>ReadonlyArray<TreeNodeId></code> | <code>[]</code> | Set the node ids to be expanded |
| selectedIds | No | <code>let</code> | Yes | <code>ReadonlyArray<TreeNodeId></code> | <code>[]</code> | Set the node ids to be selected | | selectedIds | No | <code>let</code> | Yes | <code>ReadonlyArray<TreeNodeId></code> | <code>[]</code> | Set the node ids to be selected |
| activeId | No | <code>let</code> | Yes | <code>TreeNodeId</code> | <code>""</code> | Set the current active node id<br />Only one node can be active | | activeId | No | <code>let</code> | Yes | <code>TreeNodeId</code> | <code>""</code> | Set the current active node id<br />Only one node can be active |
| children | No | <code>let</code> | No | <code>Array<TreeNode></code> | <code>[]</code> | Provide an array of children nodes to render | | nodes | No | <code>let</code> | Yes | <code>Array<TreeNode></code> | <code>[]</code> | Provide an array of nodes to render |
| size | No | <code>let</code> | No | <code>"default" &#124; "compact"</code> | <code>"default"</code> | Specify the TreeView size | | size | No | <code>let</code> | No | <code>"default" &#124; "compact"</code> | <code>"default"</code> | Specify the TreeView size |
| labelText | No | <code>let</code> | No | <code>string</code> | <code>""</code> | Specify the label text | | labelText | No | <code>let</code> | No | <code>string</code> | <code>""</code> | Specify the label text |
| hideLabel | No | <code>let</code> | No | <code>boolean</code> | <code>false</code> | Set to `true` to visually hide the label text | | hideLabel | No | <code>let</code> | No | <code>boolean</code> | <code>false</code> | Set to `true` to visually hide the label text |
| expandAll | No | <code>function</code> | No | <code>() => void</code> | <code>() => { expandedIds = [...nodeIds]; }</code> | Programmatically expand all nodes | | expandAll | No | <code>function</code> | No | <code>() => void</code> | <code>() => { expandedIds = [...nodeIds]; }</code> | Programmatically expand all nodes |
| collapseAll | No | <code>function</code> | No | <code>() => void</code> | <code>() => { expandedIds = []; }</code> | Programmatically collapse all nodes | | collapseAll | No | <code>function</code> | No | <code>() => void</code> | <code>() => { expandedIds = []; }</code> | Programmatically collapse all nodes |
| expandNodes | No | <code>function</code> | No | <code>(filterId?: (node: TreeNode) => boolean) => void</code> | <code>() => { expandedIds = nodes .filter( (node) => filterNode(node) &#124;&#124; node.children?.some((child) => filterNode(child) && child.children) ) .map((node) => node.id); }</code> | Programmatically expand a subset of nodes.<br />Expands all nodes if no argument is provided | | expandNodes | No | <code>function</code> | No | <code>(filterId?: (node: TreeNode) => boolean) => void</code> | <code>() => { expandedIds = nodes .filter( (node) => filterNode(node) &#124;&#124; node.nodes?.some((child) => filterNode(child) && child.nodes) ) .map((node) => node.id); }</code> | Programmatically expand a subset of nodes.<br />Expands all nodes if no argument is provided |
| collapseNodes | No | <code>function</code> | No | <code>(filterId?: (node: TreeNode) => boolean) => void</code> | <code>() => { expandedIds = nodes .filter((node) => expandedIds.includes(node.id) && !filterNode(node)) .map((node) => node.id); }</code> | Programmatically collapse a subset of nodes.<br />Collapses all nodes if no argument is provided | | collapseNodes | No | <code>function</code> | No | <code>(filterId?: (node: TreeNode) => boolean) => void</code> | <code>() => { expandedIds = nodes .filter((node) => expandedIds.includes(node.id) && !filterNode(node)) .map((node) => node.id); }</code> | Programmatically collapse a subset of nodes.<br />Collapses all nodes if no argument is provided |
| showNode | No | <code>function</code> | No | <code>(id: TreeNodeId) => void</code> | <code>() => { for (const child of children) { const nodes = findNodeById(child, id); if (nodes) { const ids = nodes.map((node) => node.id); const nodeIds = new Set(ids); expandNodes((node) => nodeIds.has(node.id)); const lastId = ids[ids.length - 1]; activeId = lastId; selectedIds = [lastId]; tick().then(() => { ref?.querySelector(\`[id="${lastId}"]\`)?.focus(); }); // Break out of the loop if the node is found. break; } } }</code> | Programmatically show a node by `id`.<br />The matching node will be expanded, selected, and focused | | showNode | No | <code>function</code> | No | <code>(id: TreeNodeId) => void</code> | <code>() => { for (const child of nodes) { const nodes = findNodeById(child, id); if (nodes) { const ids = nodes.map((node) => node.id); const nodeIds = new Set(ids); expandNodes((node) => nodeIds.has(node.id)); const lastId = ids[ids.length - 1]; activeId = lastId; selectedIds = [lastId]; tick().then(() => { ref?.querySelector(\`[id="${lastId}"]\`)?.focus(); }); // Break out of the loop if the node is found. break; } } }</code> | Programmatically show a node by `id`.<br />The matching node will be expanded, selected, and focused |
### Slots ### Slots

View file

@ -14710,16 +14710,16 @@
"filePath": "src/TreeView/TreeView.svelte", "filePath": "src/TreeView/TreeView.svelte",
"props": [ "props": [
{ {
"name": "children", "name": "nodes",
"kind": "let", "kind": "let",
"description": "Provide an array of children nodes to render", "description": "Provide an array of nodes to render",
"type": "Array<TreeNode>", "type": "Array<TreeNode>",
"value": "[]", "value": "[]",
"isFunction": false, "isFunction": false,
"isFunctionDeclaration": false, "isFunctionDeclaration": false,
"isRequired": false, "isRequired": false,
"constant": false, "constant": false,
"reactive": false "reactive": true
}, },
{ {
"name": "activeId", "name": "activeId",
@ -14822,7 +14822,7 @@
"kind": "function", "kind": "function",
"description": "Programmatically expand a subset of nodes.\nExpands all nodes if no argument is provided", "description": "Programmatically expand a subset of nodes.\nExpands all nodes if no argument is provided",
"type": "(filterId?: (node: TreeNode) => boolean) => void", "type": "(filterId?: (node: TreeNode) => boolean) => void",
"value": "() => { expandedIds = nodes .filter( (node) => filterNode(node) || node.children?.some((child) => filterNode(child) && child.children) ) .map((node) => node.id); }", "value": "() => { expandedIds = nodes .filter( (node) => filterNode(node) || node.nodes?.some((child) => filterNode(child) && child.nodes) ) .map((node) => node.id); }",
"isFunction": true, "isFunction": true,
"isFunctionDeclaration": true, "isFunctionDeclaration": true,
"isRequired": false, "isRequired": false,
@ -14846,7 +14846,7 @@
"kind": "function", "kind": "function",
"description": "Programmatically show a node by `id`.\nThe matching node will be expanded, selected, and focused", "description": "Programmatically show a node by `id`.\nThe matching node will be expanded, selected, and focused",
"type": "(id: TreeNodeId) => void", "type": "(id: TreeNodeId) => void",
"value": "() => { for (const child of children) { const nodes = findNodeById(child, id); if (nodes) { const ids = nodes.map((node) => node.id); const nodeIds = new Set(ids); expandNodes((node) => nodeIds.has(node.id)); const lastId = ids[ids.length - 1]; activeId = lastId; selectedIds = [lastId]; tick().then(() => { ref?.querySelector(`[id=\"${lastId}\"]`)?.focus(); }); // Break out of the loop if the node is found. break; } } }", "value": "() => { for (const child of nodes) { const nodes = findNodeById(child, id); if (nodes) { const ids = nodes.map((node) => node.id); const nodeIds = new Set(ids); expandNodes((node) => nodeIds.has(node.id)); const lastId = ids[ids.length - 1]; activeId = lastId; selectedIds = [lastId]; tick().then(() => { ref?.querySelector(`[id=\"${lastId}\"]`)?.focus(); }); // Break out of the loop if the node is found. break; } } }",
"isFunction": true, "isFunction": true,
"isFunctionDeclaration": true, "isFunctionDeclaration": true,
"isRequired": false, "isRequired": false,
@ -14894,9 +14894,9 @@
"ts": "type TreeNodeId = string | number" "ts": "type TreeNodeId = string | number"
}, },
{ {
"type": "{ id: TreeNodeId; text: any; icon?: typeof import(\"svelte\").SvelteComponent<any>; disabled?: boolean; children?: TreeNode[]; }", "type": "{ id: TreeNodeId; text: any; icon?: typeof import(\"svelte\").SvelteComponent<any>; disabled?: boolean; nodes?: TreeNode[]; }",
"name": "TreeNode", "name": "TreeNode",
"ts": "interface TreeNode { id: TreeNodeId; text: any; icon?: typeof import(\"svelte\").SvelteComponent<any>; disabled?: boolean; children?: TreeNode[]; }" "ts": "interface TreeNode { id: TreeNodeId; text: any; icon?: typeof import(\"svelte\").SvelteComponent<any>; disabled?: boolean; nodes?: TreeNode[]; }"
} }
], ],
"generics": null, "generics": null,

View file

@ -9,11 +9,11 @@
function findNodeById(node, id) { function findNodeById(node, id) {
if (node === null) return null; if (node === null) return null;
if (node.id === id) return [node]; if (node.id === id) return [node];
if (!Array.isArray(node.children)) { if (!Array.isArray(node.nodes)) {
return null; return null;
} }
for (const child of node.children) { for (const child of node.nodes) {
const nodes = findNodeById(child, id); const nodes = findNodeById(child, id);
if (Array.isArray(nodes)) { if (Array.isArray(nodes)) {
@ -29,7 +29,7 @@
<script> <script>
/** /**
* @typedef {string | number} TreeNodeId * @typedef {string | number} TreeNodeId
* @typedef {{ id: TreeNodeId; text: any; icon?: typeof import("svelte").SvelteComponent<any>; disabled?: boolean; children?: TreeNode[]; }} TreeNode * @typedef {{ id: TreeNodeId; text: any; icon?: typeof import("svelte").SvelteComponent<any>; disabled?: boolean; nodes?: TreeNode[]; }} TreeNode
* @slot {{ node: { id: TreeNodeId; text: string; expanded: boolean, leaf: boolean; disabled: boolean; selected: boolean; } }} * @slot {{ node: { id: TreeNodeId; text: string; expanded: boolean, leaf: boolean; disabled: boolean; selected: boolean; } }}
* @event {TreeNode & { expanded: boolean; leaf: boolean; }} select * @event {TreeNode & { expanded: boolean; leaf: boolean; }} select
* @event {TreeNode & { expanded: boolean; leaf: boolean; }} toggle * @event {TreeNode & { expanded: boolean; leaf: boolean; }} toggle
@ -37,10 +37,10 @@
*/ */
/** /**
* Provide an array of children nodes to render * Provide an array of nodes to render
* @type {Array<TreeNode>} * @type {Array<TreeNode>}
*/ */
export let children = []; export let nodes = [];
/** /**
* Set the current active node id * Set the current active node id
@ -99,7 +99,7 @@
.filter( .filter(
(node) => (node) =>
filterNode(node) || filterNode(node) ||
node.children?.some((child) => filterNode(child) && child.children) node.nodes?.some((child) => filterNode(child) && child.nodes)
) )
.map((node) => node.id); .map((node) => node.id);
} }
@ -121,7 +121,7 @@
* @type {(id: TreeNodeId) => void} * @type {(id: TreeNodeId) => void}
*/ */
export function showNode(id) { export function showNode(id) {
for (const child of children) { for (const child of nodes) {
const nodes = findNodeById(child, id); const nodes = findNodeById(child, id);
if (nodes) { if (nodes) {
@ -207,23 +207,23 @@
}); });
/** /**
* @param {Array<TreeNode & { children?: TreeNode[] }>} children * @param {Array<TreeNode & { nodes?: TreeNode[] }>} nodes
*/ */
function traverse(children) { function traverse(nodes) {
let nodes = []; let _nodes = [];
children.forEach((node) => { nodes.forEach((node) => {
nodes.push(node); _nodes.push(node);
if (Array.isArray(node.children)) { if (Array.isArray(node.nodes)) {
nodes = [...nodes, ...traverse(node.children)]; _nodes = [...nodes, ...traverse(node.nodes)];
} }
}); });
return nodes; return _nodes;
} }
$: nodes = traverse(children); $: nodes = traverse(nodes);
$: nodeIds = nodes.map((node) => node.id); $: nodeIds = nodes.map((node) => node.id);
$: activeNodeId.set(activeId); $: activeNodeId.set(activeId);
$: selectedNodeIds.set(selectedIds); $: selectedNodeIds.set(selectedIds);
@ -261,7 +261,7 @@
on:keydown on:keydown
on:keydown|stopPropagation="{handleKeyDown}" on:keydown|stopPropagation="{handleKeyDown}"
> >
<TreeViewNodeList root children="{children}" let:node> <TreeViewNodeList root nodes="{nodes}" let:node>
<slot node="{node}"> <slot node="{node}">
{node.text} {node.text}
</slot> </slot>

View file

@ -5,8 +5,8 @@
* @slot {{ node: { id: TreeNodeId; text: string; expanded: boolean, leaf: boolean; disabled: boolean; selected: boolean; } }} * @slot {{ node: { id: TreeNodeId; text: string; expanded: boolean, leaf: boolean; disabled: boolean; selected: boolean; } }}
*/ */
/** @type {Array<TreeNode & { children?: TreeNode[] }>} */ /** @type {Array<TreeNode & { nodes?: TreeNode[] }>} */
export let children = []; export let nodes = [];
export let root = false; export let root = false;
/** @type {string | number} */ /** @type {string | number} */
@ -55,7 +55,7 @@
prevActiveId = $activeNodeId; prevActiveId = $activeNodeId;
}); });
$: parent = Array.isArray(children); $: parent = Array.isArray(nodes);
$: node = { id, text, expanded, leaf: !parent }; $: node = { id, text, expanded, leaf: !parent };
$: if (refLabel) { $: if (refLabel) {
refLabel.style.marginLeft = `-${offset()}rem`; refLabel.style.marginLeft = `-${offset()}rem`;
@ -65,8 +65,8 @@
</script> </script>
{#if root} {#if root}
{#each children as child (child.id)} {#each nodes as child (child.id)}
{#if Array.isArray(child.children)} {#if Array.isArray(child.nodes)}
<svelte:self {...child} let:node> <svelte:self {...child} let:node>
<slot node="{node}" /> <slot node="{node}" />
</svelte:self> </svelte:self>
@ -162,8 +162,8 @@
</div> </div>
{#if expanded} {#if expanded}
<ul role="group" class:bx--tree-node__children="{true}"> <ul role="group" class:bx--tree-node__children="{true}">
{#each children as child (child.id)} {#each nodes as child (child.id)}
{#if Array.isArray(child.children)} {#if Array.isArray(child.nodes)}
<svelte:self {...child} let:node> <svelte:self {...child} let:node>
<slot node="{node}" /> <slot node="{node}" />
</svelte:self> </svelte:self>

View file

@ -8,16 +8,16 @@
let activeId: TreeNodeId = ""; let activeId: TreeNodeId = "";
let selectedIds: TreeNodeId[] = []; let selectedIds: TreeNodeId[] = [];
let expandedIds: TreeNodeId[] = [1]; let expandedIds: TreeNodeId[] = [1];
let children: ComponentProps<TreeView>["children"] = [ let nodes: ComponentProps<TreeView>["nodes"] = [
{ id: 0, text: "AI / Machine learning", icon: Analytics }, { id: 0, text: "AI / Machine learning", icon: Analytics },
{ {
id: 1, id: 1,
text: 0, text: 0,
children: [ nodes: [
{ {
id: 2, id: 2,
text: "IBM Analytics Engine", text: "IBM Analytics Engine",
children: [ nodes: [
{ id: 3, text: "Apache Spark" }, { id: 3, text: "Apache Spark" },
{ id: 4, text: "Hadoop" }, { id: 4, text: "Hadoop" },
], ],
@ -29,12 +29,12 @@
{ {
id: 7, id: 7,
text: "Blockchain", text: "Blockchain",
children: [{ id: 8, text: "IBM Blockchain Platform" }], nodes: [{ id: 8, text: "IBM Blockchain Platform" }],
}, },
{ {
id: 9, id: 9,
text: "Databases", text: "Databases",
children: [ nodes: [
{ id: 10, text: "IBM Cloud Databases for Elasticsearch" }, { id: 10, text: "IBM Cloud Databases for Elasticsearch" },
{ id: 11, text: "IBM Cloud Databases for Enterprise DB" }, { id: 11, text: "IBM Cloud Databases for Enterprise DB" },
{ id: 12, text: "IBM Cloud Databases for MongoDB" }, { id: 12, text: "IBM Cloud Databases for MongoDB" },
@ -45,7 +45,7 @@
id: 14, id: 14,
text: "Integration", text: "Integration",
disabled: true, disabled: true,
children: [{ id: 15, text: "IBM API Connect", disabled: true }], nodes: [{ id: 15, text: "IBM API Connect", disabled: true }],
}, },
]; ];
@ -66,7 +66,7 @@
bind:this="{treeview}" bind:this="{treeview}"
size="compact" size="compact"
labelText="Cloud Products" labelText="Cloud Products"
children="{children}" {nodes}
bind:activeId bind:activeId
bind:selectedIds bind:selectedIds
bind:expandedIds bind:expandedIds

View file

@ -8,17 +8,17 @@ export interface TreeNode {
text: any; text: any;
icon?: typeof import("svelte").SvelteComponent<any>; icon?: typeof import("svelte").SvelteComponent<any>;
disabled?: boolean; disabled?: boolean;
children?: TreeNode[]; nodes?: TreeNode[];
} }
type $RestProps = SvelteHTMLElements["ul"]; type $RestProps = SvelteHTMLElements["ul"];
type $Props = { type $Props = {
/** /**
* Provide an array of children nodes to render * Provide an array of nodes to render
* @default [] * @default []
*/ */
children?: Array<TreeNode>; nodes?: Array<TreeNode>;
/** /**
* Set the current active node id * Set the current active node id