Fix that toHierarchy couldn't be found. Updated docs and test.

This commit is contained in:
Bram 2024-12-02 17:44:38 +01:00
commit 048c10a6ab
11 changed files with 70 additions and 47 deletions

View file

@ -4699,21 +4699,21 @@ export interface 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 |
| nodes | No | <code>let</code> | Yes | <code>Array<TreeNode></code> | <code>[]</code> | Provide a nested array of nodes to render |
| nodesFlat | No | <code>let</code> | No | <code>Array<TreeNode & {pid?: any}></code> | <code>[]</code> | Provide a flat 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 = flattenedNodes .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 = flattenedNodes .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; } } }</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> | No | <code>Array<TreeNode></code> | <code>[]</code> | Provide a nested 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 |
| toHierarchy | No | <code>function</code> | No | <code>(flatArray: TreeNode[] & { pid?: any }[]) => TreeNode[]</code> | <code>() => { return th(flatArray); }</code> | Create a nested array from a flat array |
| expandNodes | No | <code>function</code> | No | <code>(filterId?: (node: TreeNode) => boolean) => void</code> | <code>() => { expandedIds = flattenedNodes .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 = flattenedNodes .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; } } }</code> | Programmatically show a node by `id`.<br />The matching node will be expanded, selected, and focused |
### Slots

View file

@ -17777,18 +17777,6 @@
"isFunctionDeclaration": false,
"isRequired": false,
"constant": false,
"reactive": true
},
{
"name": "nodesFlat",
"kind": "let",
"description": "Provide a flat array of nodes to render",
"type": "Array<TreeNode & {pid?: any}>",
"value": "[]",
"isFunction": false,
"isFunctionDeclaration": false,
"isRequired": false,
"constant": false,
"reactive": false
},
{
@ -17887,6 +17875,18 @@
"constant": false,
"reactive": false
},
{
"name": "toHierarchy",
"kind": "function",
"description": "Create a nested array from a flat array",
"type": "(flatArray: TreeNode[] & { pid?: any }[]) => TreeNode[]",
"value": "() => {\n return th(flatArray);\n}",
"isFunction": true,
"isFunctionDeclaration": true,
"isRequired": false,
"constant": false,
"reactive": false
},
{
"name": "expandNodes",
"kind": "function",

View file

@ -58,14 +58,6 @@ To render a node with an icon, define an `icon` property with a Carbon Svelte ic
<FileSource src="/framed/TreeView/TreeViewIcons" />
## Flat data structure
Provide a flat data structure through the `nodesFlat` property. Child object needs to have a `pid` property
to reference its parent. Optionally the key for the parent can be provided.
When no parent id is available the object is assumed to be at the root of the tree.
<FileSource src="/framed/TreeView/TreeViewFlatArray" />
## Initial expanded nodes
Expanded nodes can be set using `expandedIds`.
@ -116,3 +108,13 @@ Use the `TreeView.showNode` method to show a specific node.
If a matching node is found, it will be expanded, selected, and focused.
<FileSource src="/framed/TreeView/TreeViewShowNode" />
## Flat data structure
Use the `toHierarchy` method to provide a flat data structure to the `nodes` property.
This method will transform a flat array of objects into the hierarchical array as expected by `nodes`.
The child objects in the flat array need to have a `pid` property to reference its parent.
When `pid` is not provided the object is assumed to be at the root of the tree.
<FileSource src="/framed/TreeView/TreeViewFlatArray" />

View file

@ -89,6 +89,14 @@
expandedIds = [];
}
/**
* Create a nested array from a flat array
* @type {(flatArray: TreeNode[] & { pid?: any }[]) => TreeNode[]}
*/
export function toHierarchy(flatArray) {
return th(flatArray);
}
/**
* Programmatically expand a subset of nodes.
* Expands all nodes if no argument is provided
@ -147,6 +155,7 @@
import { createEventDispatcher, setContext, onMount, tick } from "svelte";
import { writable } from "svelte/store";
import TreeViewNodeList from "./TreeViewNodeList.svelte";
import { toHierarchy as th } from "./treeview";
const dispatch = createEventDispatcher();
const labelId = `label-${Math.random().toString(36)}`;

View file

@ -25,8 +25,6 @@ export function toHierarchy(flatArray) {
});
// Remove the empty nodes props that make TreeView render a twistie.
// Maybe this should actually be taken care of in TreeView itself? It makes
// no sense i think that an empty nodes property render a twistie.
function removeEmptyNodes(element) {
element.forEach((elmt) => {
if (elmt.nodes?.length === 0) delete elmt.nodes;

View file

@ -127,6 +127,7 @@ export { Tooltip, TooltipFooter } from "./Tooltip";
export { TooltipDefinition } from "./TooltipDefinition";
export { TooltipIcon } from "./TooltipIcon";
export { TreeView } from "./TreeView";
export { toHierarchy } from "./TreeView/treeview";
export { Truncate } from "./Truncate";
export { default as truncate } from "./Truncate/truncate";
export {

View file

@ -1,7 +1,9 @@
<script lang="ts">
import type { ComponentProps } from "svelte";
import { Button, TreeView } from "carbon-components-svelte";
import type { TreeNodeId } from "carbon-components-svelte/TreeView/TreeView.svelte";
import type {
TreeNode,
TreeNodeId,
} from "carbon-components-svelte/TreeView/TreeView.svelte";
import Analytics from "carbon-icons-svelte/lib/Analytics.svelte";
import WatsonMachineLearning from "carbon-icons-svelte/lib/WatsonMachineLearning.svelte";
import Blockchain from "carbon-icons-svelte/lib/Blockchain.svelte";
@ -13,7 +15,7 @@
let selectedIds: TreeNodeId[] = [];
let expandedIds: TreeNodeId[] = [1];
let nodesFlat: ComponentProps<TreeView>["nodesFlat"] = [
let nodesFlat: TreeNode[] & { pid?: any }[] = [
{ id: 0, text: "AI / Machine learning", icon: WatsonMachineLearning },
{ id: 1, text: "Analytics", icon: Analytics },
{ id: 2, text: "IBM Analytics Engine", pid: 1, icon: Analytics },
@ -60,7 +62,7 @@
bind:this={treeview}
size="compact"
labelText="Cloud Products"
{nodesFlat}
nodes={treeview?.toHierarchy(nodesFlat)}
bind:activeId
bind:selectedIds
bind:expandedIds

View file

@ -20,12 +20,6 @@ type $Props = {
*/
nodes?: Array<TreeNode>;
/**
* Provide a flat array of nodes to render
* @default []
*/
nodesFlat?: Array<TreeNode & { pid?: any }>;
/**
* Set the current active node id
* Only one node can be active
@ -100,6 +94,11 @@ export default class TreeView extends SvelteComponentTyped<
*/
collapseAll: () => void;
/**
* Create a nested array from a flat array
*/
toHierarchy: (flatArray: TreeNode[] & { pid?: any }[]) => TreeNode[];
/**
* Programmatically expand a subset of nodes.
* Expands all nodes if no argument is provided

2
types/TreeView/index.d.ts vendored Normal file
View file

@ -0,0 +1,2 @@
export { default as TreeView } from "./TreeView.svelte";
export { toHierarchy } from "./treeview";

9
types/TreeView/treeview.d.ts vendored Normal file
View file

@ -0,0 +1,9 @@
import { type TreeNode } from "carbon-components-svelte/TreeView/TreeView.svelte";
/**
* Create a nested array from a flat array
*/
export function toHierarchy(
flatArray: TreeNode[] & { pid?: any }[],
): TreeNode[];
export default toHierarchy;

1
types/index.d.ts vendored
View file

@ -143,6 +143,7 @@ export { default as TooltipFooter } from "./Tooltip/TooltipFooter.svelte";
export { default as TooltipDefinition } from "./TooltipDefinition/TooltipDefinition.svelte";
export { default as TooltipIcon } from "./TooltipIcon/TooltipIcon.svelte";
export { default as TreeView } from "./TreeView/TreeView.svelte";
export { default as toHierarchy } from "./TreeView/treeview";
export { default as Truncate } from "./Truncate/Truncate.svelte";
export { default as truncate } from "./Truncate/truncate";
export { default as Header } from "./UIShell/Header.svelte";