diff --git a/COMPONENT_INDEX.md b/COMPONENT_INDEX.md index ed8d98b0..45bce5e2 100644 --- a/COMPONENT_INDEX.md +++ b/COMPONENT_INDEX.md @@ -171,6 +171,7 @@ - [`TooltipDefinition`](#tooltipdefinition) - [`TooltipFooter`](#tooltipfooter) - [`TooltipIcon`](#tooltipicon) +- [`TreeView`](#treeview) - [`Truncate`](#truncate) - [`UnorderedList`](#unorderedlist) @@ -4649,6 +4650,47 @@ None. | mouseleave | forwarded | -- | | focus | forwarded | -- | +## `TreeView` + +### Types + +```ts +export type TreeNodeId = string | number; + +export interface TreeNode { + id: TreeNodeId; + text: string; + disabled?: boolean; +} +``` + +### Props + +| Prop name | Kind | Reactive | Type | Default value | Description | +| :---------- | :--------------- | :------- | :------------------------------------------------ | ---------------------- | --------------------------------------------------------------- | +| selectedIds | let | Yes | TreeNodeIds | [] | Set the node ids to be selected | +| activeId | let | Yes | TreeNodeId | "" | Set the current active node id
Only one node can be active | +| children | let | No | TreeNode & { children?: TreeNode[] } | [] | Provide an array of children nodes to render | +| multiselect | let | No | boolean | false | Set to `true` to allow multiple selected nodes | +| size | let | No | "default" | "compact" | "default" | Specify the TreeView size | +| labelText | let | No | string | "" | Specify the label text | +| hideLabel | let | No | boolean | false | Set to `true` to visually hide the label text | + +### Slots + +| Slot name | Default | Props | Fallback | +| :-------- | :------ | :---- | :----------------------- | +| labelText | No | -- | {labelText} | + +### Events + +| Event name | Type | Detail | +| :--------- | :--------- | :------------------------------------------------------------ | +| select | dispatched | TreeNode & { expanded: boolean; leaf: boolean; } | +| toggle | dispatched | TreeNode & { expanded: boolean; leaf: boolean; } | +| focus | dispatched | TreeNode & { expanded: boolean; leaf: boolean; } | +| keydown | forwarded | -- | + ## `Truncate` ### Props diff --git a/css/all.scss b/css/all.scss index 6679fa7a..ecbbd37f 100644 --- a/css/all.scss +++ b/css/all.scss @@ -76,5 +76,8 @@ $css--plex: true; @import "carbon-components/scss/globals/scss/_css--body"; @import "carbon-components/scss/globals/grid/grid"; +// Import experimental TreeView styles not included in global styles +@import "carbon-components/src/components/treeview/treeview"; + // Import all component styles @import "carbon-components/scss/globals/scss/styles"; diff --git a/css/g10.scss b/css/g10.scss index e97cdb84..e77b2144 100644 --- a/css/g10.scss +++ b/css/g10.scss @@ -27,6 +27,9 @@ $carbon--theme: $carbon--theme--g10; @import "carbon-components/scss/globals/scss/_css--body"; @import "carbon-components/scss/globals/grid/grid"; +// Import experimental TreeView styles not included in global styles +@import "carbon-components/src/components/treeview/treeview"; + // Import all component styles @import "carbon-components/scss/globals/scss/styles"; diff --git a/css/g100.scss b/css/g100.scss index 6828061d..b30327a8 100644 --- a/css/g100.scss +++ b/css/g100.scss @@ -27,5 +27,8 @@ $carbon--theme: $carbon--theme--g100; @import "carbon-components/scss/globals/scss/_css--body"; @import "carbon-components/scss/globals/grid/grid"; +// Import experimental TreeView styles not included in global styles +@import "carbon-components/src/components/treeview/treeview"; + // Import all component styles @import "carbon-components/scss/globals/scss/styles"; \ No newline at end of file diff --git a/css/g80.scss b/css/g80.scss index 9f5475c9..c0df672a 100644 --- a/css/g80.scss +++ b/css/g80.scss @@ -27,6 +27,9 @@ $carbon--theme: $carbon--theme--g80; @import "carbon-components/scss/globals/scss/_css--body"; @import "carbon-components/scss/globals/grid/grid"; +// Import experimental TreeView styles not included in global styles +@import "carbon-components/src/components/treeview/treeview"; + // Import all component styles @import "carbon-components/scss/globals/scss/styles"; diff --git a/css/g90.scss b/css/g90.scss index abf54fa0..d219f985 100644 --- a/css/g90.scss +++ b/css/g90.scss @@ -27,5 +27,8 @@ $carbon--theme: $carbon--theme--g90; @import "carbon-components/scss/globals/scss/_css--body"; @import "carbon-components/scss/globals/grid/grid"; +// Import experimental TreeView styles not included in global styles +@import "carbon-components/src/components/treeview/treeview"; + // Import all component styles @import "carbon-components/scss/globals/scss/styles"; \ No newline at end of file diff --git a/css/white.scss b/css/white.scss index 9b4bd827..409b423f 100644 --- a/css/white.scss +++ b/css/white.scss @@ -27,5 +27,8 @@ $carbon--theme: $carbon--theme--white; @import "carbon-components/scss/globals/scss/_css--body"; @import "carbon-components/scss/globals/grid/grid"; +// Import experimental TreeView styles not included in global styles +@import "carbon-components/src/components/treeview/treeview"; + // Import all component styles @import "carbon-components/scss/globals/scss/styles"; \ No newline at end of file diff --git a/docs/src/App.svelte b/docs/src/App.svelte index 50709afa..95e62f70 100644 --- a/docs/src/App.svelte +++ b/docs/src/App.svelte @@ -84,6 +84,8 @@ @import "carbon-components/scss/globals/scss/_css--body"; @import "carbon-components/scss/globals/grid/grid"; + @import "carbon-components/src/components/treeview/treeview"; + // Import all component styles @import "carbon-components/scss/globals/scss/styles"; diff --git a/docs/src/COMPONENT_API.json b/docs/src/COMPONENT_API.json index 675d727a..9b9d82a6 100644 --- a/docs/src/COMPONENT_API.json +++ b/docs/src/COMPONENT_API.json @@ -11834,6 +11834,121 @@ "typedefs": [], "rest_props": { "type": "Element", "name": "button" } }, + { + "moduleName": "TreeView", + "filePath": "src/TreeView/TreeView.svelte", + "props": [ + { + "name": "children", + "kind": "let", + "description": "Provide an array of children nodes to render", + "type": "TreeNode & { children?: TreeNode[] }", + "value": "[]", + "isFunction": false, + "constant": false, + "reactive": false + }, + { + "name": "activeId", + "kind": "let", + "description": "Set the current active node id\nOnly one node can be active", + "type": "TreeNodeId", + "value": "\"\"", + "isFunction": false, + "constant": false, + "reactive": true + }, + { + "name": "multiselect", + "kind": "let", + "description": "Set to `true` to allow multiple selected nodes", + "type": "boolean", + "value": "false", + "isFunction": false, + "constant": false, + "reactive": false + }, + { + "name": "selectedIds", + "kind": "let", + "description": "Set the node ids to be selected", + "type": "TreeNodeIds", + "value": "[]", + "isFunction": false, + "constant": false, + "reactive": true + }, + { + "name": "size", + "kind": "let", + "description": "Specify the TreeView size", + "type": "\"default\" | \"compact\"", + "value": "\"default\"", + "isFunction": false, + "constant": false, + "reactive": false + }, + { + "name": "labelText", + "kind": "let", + "description": "Specify the label text", + "type": "string", + "value": "\"\"", + "isFunction": false, + "constant": false, + "reactive": false + }, + { + "name": "hideLabel", + "kind": "let", + "description": "Set to `true` to visually hide the label text", + "type": "boolean", + "value": "false", + "isFunction": false, + "constant": false, + "reactive": false + } + ], + "slots": [ + { + "name": "labelText", + "default": false, + "fallback": "{labelText}", + "slot_props": "{}" + } + ], + "events": [ + { + "type": "dispatched", + "name": "select", + "detail": "TreeNode & { expanded: boolean; leaf: boolean; }" + }, + { + "type": "dispatched", + "name": "toggle", + "detail": "TreeNode & { expanded: boolean; leaf: boolean; }" + }, + { + "type": "dispatched", + "name": "focus", + "detail": "TreeNode & { expanded: boolean; leaf: boolean; }" + }, + { "type": "forwarded", "name": "keydown", "element": "ul" } + ], + "typedefs": [ + { + "type": "string | number", + "name": "TreeNodeId", + "ts": "type TreeNodeId = string | number" + }, + { + "type": "{ id: TreeNodeId; text: string; disabled?: boolean; }", + "name": "TreeNode", + "ts": "interface TreeNode { id: TreeNodeId; text: string; disabled?: boolean; }" + } + ], + "rest_props": { "type": "Element", "name": "ul" } + }, { "moduleName": "Truncate", "filePath": "src/Truncate/Truncate.svelte", diff --git a/docs/src/pages/_layout.svelte b/docs/src/pages/_layout.svelte index 1fa85bb0..ddb35bb1 100644 --- a/docs/src/pages/_layout.svelte +++ b/docs/src/pages/_layout.svelte @@ -20,7 +20,7 @@ import Footer from "../components/Footer.svelte"; const deprecated = ["ToggleSmall", "Icon"]; - const new_components = ["ProgressBar", "RecursiveList"]; + const new_components = ["ProgressBar", "RecursiveList", "TreeView"]]; let isOpen = false; let isSideNavOpen = true; diff --git a/docs/src/pages/components/TreeView.svx b/docs/src/pages/components/TreeView.svx new file mode 100644 index 00000000..14b06a87 --- /dev/null +++ b/docs/src/pages/components/TreeView.svx @@ -0,0 +1,18 @@ + + +Note: every node MUST have an id. + +### Default + + + +### Compact size + + + +### With icons + + \ No newline at end of file diff --git a/src/TreeView/TreeView.svelte b/src/TreeView/TreeView.svelte new file mode 100644 index 00000000..1f47bf29 --- /dev/null +++ b/src/TreeView/TreeView.svelte @@ -0,0 +1,120 @@ + + +{#if !hideLabel} + + +{/if} + +
    + +
diff --git a/src/TreeView/TreeViewNode.svelte b/src/TreeView/TreeViewNode.svelte new file mode 100644 index 00000000..f8b7f303 --- /dev/null +++ b/src/TreeView/TreeViewNode.svelte @@ -0,0 +1,112 @@ + + + + +
  • +
    + + {text} +
    +
  • diff --git a/src/TreeView/TreeViewNodeList.svelte b/src/TreeView/TreeViewNodeList.svelte new file mode 100644 index 00000000..52c62b83 --- /dev/null +++ b/src/TreeView/TreeViewNodeList.svelte @@ -0,0 +1,150 @@ + + +{#if root} + {#each children as child (child.id)} + {#if Array.isArray(child.children)} + + {:else} + + {/if} + {/each} +{:else} +
  • +
    + + + + + + {text} + +
    + {#if expanded} +
      + {#each children as child (child.id)} + {#if Array.isArray(child.children)} + + {:else} + + {/if} + {/each} +
    + {/if} +
  • +{/if} diff --git a/src/TreeView/index.js b/src/TreeView/index.js new file mode 100644 index 00000000..59f96be0 --- /dev/null +++ b/src/TreeView/index.js @@ -0,0 +1 @@ +export { default as TreeView } from "./TreeView.svelte"; diff --git a/src/index.js b/src/index.js index 14924283..5dc44324 100644 --- a/src/index.js +++ b/src/index.js @@ -126,6 +126,7 @@ export { ToggleSmall, ToggleSmallSkeleton } from "./ToggleSmall"; export { Tooltip, TooltipFooter } from "./Tooltip"; export { TooltipDefinition } from "./TooltipDefinition"; export { TooltipIcon } from "./TooltipIcon"; +export { TreeView } from "./TreeView"; export { Truncate } from "./Truncate"; export { Header, diff --git a/types/TreeView/TreeView.d.ts b/types/TreeView/TreeView.d.ts new file mode 100644 index 00000000..3179712e --- /dev/null +++ b/types/TreeView/TreeView.d.ts @@ -0,0 +1,67 @@ +/// +import { SvelteComponentTyped } from "svelte"; + +export type TreeNodeId = string | number; + +export interface TreeNode { + id: TreeNodeId; + text: string; + disabled?: boolean; +} + +export interface TreeViewProps + extends svelte.JSX.HTMLAttributes { + /** + * Provide an array of children nodes to render + * @default [] + */ + children?: TreeNode & { children?: TreeNode[] }; + + /** + * Set the current active node id + * Only one node can be active + * @default "" + */ + activeId?: TreeNodeId; + + /** + * Set to `true` to allow multiple selected nodes + * @default false + */ + multiselect?: boolean; + + /** + * Set the node ids to be selected + * @default [] + */ + selectedIds?: TreeNodeIds; + + /** + * Specify the TreeView size + * @default "default" + */ + size?: "default" | "compact"; + + /** + * Specify the label text + * @default "" + */ + labelText?: string; + + /** + * Set to `true` to visually hide the label text + * @default false + */ + hideLabel?: boolean; +} + +export default class TreeView extends SvelteComponentTyped< + TreeViewProps, + { + select: CustomEvent; + toggle: CustomEvent; + focus: CustomEvent; + keydown: WindowEventMap["keydown"]; + }, + { labelText: {} } +> {} diff --git a/types/index.d.ts b/types/index.d.ts index 9123950f..02714fef 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -144,6 +144,7 @@ export { default as Tooltip } from "./Tooltip/Tooltip"; export { default as TooltipFooter } from "./Tooltip/TooltipFooter"; export { default as TooltipDefinition } from "./TooltipDefinition/TooltipDefinition"; export { default as TooltipIcon } from "./TooltipIcon/TooltipIcon"; +export { default as TreeView } from "./TreeView/TreeView"; export { default as Truncate } from "./Truncate/Truncate"; export { default as Header } from "./UIShell/GlobalHeader/Header"; export { default as HeaderAction } from "./UIShell/GlobalHeader/HeaderAction";