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;
icon?: typeof import("svelte").SvelteComponent<any>;
disabled?: boolean;
children?: TreeNode[];
nodes?: TreeNode[];
}
```
### Props
| 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 |
| 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 |
| children | No | <code>let</code> | No | <code>Array<TreeNode></code> | <code>[]</code> | Provide an array of children nodes to render |
| 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 |
| 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 |
| 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 |
| 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 |
| 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 |
| 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 |
| 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 |
| 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 |
| 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 |
| 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 |
| 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

View file

@ -14710,16 +14710,16 @@
"filePath": "src/TreeView/TreeView.svelte",
"props": [
{
"name": "children",
"name": "nodes",
"kind": "let",
"description": "Provide an array of children nodes to render",
"description": "Provide an array of nodes to render",
"type": "Array<TreeNode>",
"value": "[]",
"isFunction": false,
"isFunctionDeclaration": false,
"isRequired": false,
"constant": false,
"reactive": false
"reactive": true
},
{
"name": "activeId",
@ -14822,7 +14822,7 @@
"kind": "function",
"description": "Programmatically expand a subset of nodes.\nExpands all nodes if no argument is provided",
"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,
"isFunctionDeclaration": true,
"isRequired": false,
@ -14846,7 +14846,7 @@
"kind": "function",
"description": "Programmatically show a node by `id`.\nThe matching node will be expanded, selected, and focused",
"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,
"isFunctionDeclaration": true,
"isRequired": false,
@ -14894,9 +14894,9 @@
"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",
"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,

View file

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

View file

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

View file

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

View file

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