Skip to content

Commit

Permalink
RecursiveList (carbon-design-system#717)
Browse files Browse the repository at this point in the history
* feat(recursive-list): add RecursiveList

* feat(recursive-list): rename items prop to children

* docs(recursive-list): add full examples

* test(recursive-list): add types test

* refactor(recursive-list): remove superfluous nested prop

* docs(recursive-list): update docs

* fix(recursive-list): remove nested prop from type test

* fix(recursive-list): explicitly type restProps
  • Loading branch information
metonym authored Jul 5, 2021
1 parent 870c2c2 commit ae27bed
Show file tree
Hide file tree
Showing 17 changed files with 334 additions and 6 deletions.
30 changes: 29 additions & 1 deletion COMPONENT_INDEX.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Component Index

> 168 components exported from [email protected].
> 169 components exported from [email protected].
## Components

Expand Down Expand Up @@ -107,6 +107,7 @@
- [`RadioButtonGroup`](#radiobuttongroup)
- [`RadioButtonSkeleton`](#radiobuttonskeleton)
- [`RadioTile`](#radiotile)
- [`RecursiveList`](#recursivelist)
- [`Row`](#row)
- [`Search`](#search)
- [`SearchSkeleton`](#searchskeleton)
Expand Down Expand Up @@ -3031,6 +3032,33 @@ None.
| mouseenter | forwarded | -- |
| mouseleave | forwarded | -- |

## `RecursiveList`

### Types

```ts
export interface RecursiveListNode {
text?: string;
href?: string;
html?: string;
}
```

### Props

| Prop name | Kind | Reactive | Type | Default value | Description |
| :-------- | :--------------- | :------- | :-------------------------------------------------------------------------- | ------------------------ | ---------------------------------- |
| children | <code>let</code> | No | <code>Array<RecursiveListNode & { children?: RecursiveListNode[]; }></code> | <code>[]</code> | Specify the children to render |
| type | <code>let</code> | No | <code>"unordered" &#124; "ordered" &#124; "ordered-native"</code> | <code>"unordered"</code> | Specify the type of list to render |

### Slots

None.

### Events

None.

## `Row`

### Props
Expand Down
38 changes: 37 additions & 1 deletion docs/src/COMPONENT_API.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"total": 168,
"total": 169,
"components": [
{
"moduleName": "Accordion",
Expand Down Expand Up @@ -7865,6 +7865,42 @@
"typedefs": [],
"rest_props": { "type": "Element", "name": "label" }
},
{
"moduleName": "RecursiveList",
"filePath": "src/RecursiveList/RecursiveList.svelte",
"props": [
{
"name": "children",
"kind": "let",
"description": "Specify the children to render",
"type": "Array<RecursiveListNode & { children?: RecursiveListNode[]; }>",
"value": "[]",
"isFunction": false,
"constant": false,
"reactive": false
},
{
"name": "type",
"kind": "let",
"description": "Specify the type of list to render",
"type": "\"unordered\" | \"ordered\" | \"ordered-native\"",
"value": "\"unordered\"",
"isFunction": false,
"constant": false,
"reactive": false
}
],
"slots": [],
"events": [],
"typedefs": [
{
"type": "{ text?: string; href?: string; html?: string; }",
"name": "RecursiveListNode",
"ts": "interface RecursiveListNode { text?: string; href?: string; html?: string; }"
}
],
"rest_props": { "type": "Element", "name": "ul | ol" }
},
{
"moduleName": "Row",
"filePath": "src/Grid/Row.svelte",
Expand Down
2 changes: 1 addition & 1 deletion docs/src/pages/_layout.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
import Footer from "../components/Footer.svelte";
const deprecated = ["ToggleSmall", "Icon"];
const new_components = ["ProgressBar"];
const new_components = ["ProgressBar", "RecursiveList"];
let isOpen = false;
let isSideNavOpen = true;
Expand Down
8 changes: 7 additions & 1 deletion docs/src/pages/components/OrderedList.svx
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,16 @@ components: ["OrderedList", "ListItem"]
---

<script>
import { OrderedList, ListItem, Link } from "carbon-components-svelte";
import { InlineNotification, OrderedList, ListItem, Link } from "carbon-components-svelte";
import Preview from "../../components/Preview.svelte";
</script>

<InlineNotification svx-ignore title="Tip:" kind="info" hideCloseButton>
<div class="body-short-01">
To render data formatted as a tree structure, use the <Link href="/components/RecursiveList#ordered">RecursiveList</Link> component.
</div>
</InlineNotification>

### Default

<OrderedList>
Expand Down
34 changes: 34 additions & 0 deletions docs/src/pages/components/RecursiveList.svx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<script>
import { InlineNotification, RecursiveList } from "carbon-components-svelte";
import Preview from "../../components/Preview.svelte";
</script>

This component uses the [svelte:self API](https://svelte.dev/docs#svelte_self) to render the [UnorderedList](/components/UnorderedList) and [OrderedList](/components/OrderedList) components with data formatted as a tree structure. This is especially useful when the depth of the tree is unknown.

A child node can render text (`text`), a link (`href`), HTML content (`html`), and other `children`.

<InlineNotification svx-ignore title="Warning:" kind="warning" hideCloseButton>
<div class="body-short-01">
HTML content provided via the <code>html</code> prop is not sanitized.
</div>
</InlineNotification>

### Unordered

The `children` prop accepts an array of child nodes.

By default, the list type is unordered.

<FileSource src="/framed/RecursiveList/RecursiveList" />

### Ordered

Set `type` to `"ordered"` to use the ordered list variant.

<FileSource src="/framed/RecursiveList/RecursiveListOrdered" />

### Ordered (native styles)

Set `type` to `"ordered-native"` to use the native styles for an ordered list.

<FileSource src="/framed/RecursiveList/RecursiveListOrderedNative" />
8 changes: 7 additions & 1 deletion docs/src/pages/components/UnorderedList.svx
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,16 @@ components: ["UnorderedList", "ListItem"]
---

<script>
import { UnorderedList, ListItem, Link } from "carbon-components-svelte";
import { InlineNotification, UnorderedList, ListItem, Link } from "carbon-components-svelte";
import Preview from "../../components/Preview.svelte";
</script>

<InlineNotification svx-ignore title="Tip:" kind="info" hideCloseButton>
<div class="body-short-01">
To render data formatted as a tree structure, use the <Link href="/components/RecursiveList#unordered">RecursiveList</Link> component.
</div>
</InlineNotification>

### Default

<UnorderedList>
Expand Down
32 changes: 32 additions & 0 deletions docs/src/pages/framed/RecursiveList/RecursiveList.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<script>
import { RecursiveList } from "carbon-components-svelte";
const children = [
{
text: "Item 1",
children: [
{
text: "Item 1a",
children: [{ html: "<h5>HTML content</h5>" }],
},
],
},
{
text: "Item 2",
children: [
{
href: "https://svelte.dev/",
},
{
href: "https://svelte.dev/",
text: "Link with custom text",
},
],
},
{
text: "Item 3",
},
];
</script>

<RecursiveList children="{children}" />
32 changes: 32 additions & 0 deletions docs/src/pages/framed/RecursiveList/RecursiveListOrdered.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<script>
import { RecursiveList } from "carbon-components-svelte";
const children = [
{
text: "Item 1",
children: [
{
text: "Item 1a",
children: [{ html: "<h5>HTML content</h5>" }],
},
],
},
{
text: "Item 2",
children: [
{
href: "https://svelte.dev/",
},
{
href: "https://svelte.dev/",
text: "Link with custom text",
},
],
},
{
text: "Item 3",
},
];
</script>

<RecursiveList type="ordered" children="{children}" />
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<script>
import { RecursiveList } from "carbon-components-svelte";
const children = [
{
text: "Item 1",
children: [
{
text: "Item 1a",
children: [{ html: "<h5>HTML content</h5>" }],
},
],
},
{
text: "Item 2",
children: [
{
href: "https://svelte.dev/",
},
{
href: "https://svelte.dev/",
text: "Link with custom text",
},
],
},
{
text: "Item 3",
},
];
</script>

<RecursiveList type="ordered-native" children="{children}" />
38 changes: 38 additions & 0 deletions src/RecursiveList/RecursiveList.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<script>
/**
* @typedef {{ text?: string; href?: string; html?: string; }} RecursiveListNode
* @restProps {ul | ol}
*/
/**
* Specify the children to render
* @type {Array<RecursiveListNode & { children?: RecursiveListNode[]; }>}
*/
export let children = [];
/**
* Specify the type of list to render
* @type {"unordered" | "ordered" | "ordered-native"}
*/
export let type = "unordered";
import UnorderedList from "../UnorderedList/UnorderedList.svelte";
import OrderedList from "../OrderedList/OrderedList.svelte";
import RecursiveListItem from "./RecursiveListItem.svelte";
</script>

<svelte:component
this="{type === 'unordered' ? UnorderedList : OrderedList}"
native="{type === 'ordered-native'}"
{...$$restProps}
>
{#each children as child}
{#if Array.isArray(child.children)}
<RecursiveListItem {...child}>
<svelte:self {...child} type="{type}" nested />
</RecursiveListItem>
{:else}
<RecursiveListItem {...child} />
{/if}
{/each}
</svelte:component>
19 changes: 19 additions & 0 deletions src/RecursiveList/RecursiveListItem.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<script>
/** Specify the text to render*/
export let text = "";
/** Specify a link href */
export let href = "";
/** Specify HTML to render using `@html` */
export let html = "";
import ListItem from "../ListItem/ListItem.svelte";
</script>

<ListItem>
{#if text && !href}{text}{/if}
{#if href}<a class:bx--link="{true}" href="{href}">{text || href}</a>{/if}
{#if !text && html}{@html html}{/if}
<slot />
</ListItem>
1 change: 1 addition & 0 deletions src/RecursiveList/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default as RecursiveList } from "./RecursiveList.svelte";
1 change: 1 addition & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ export {
} from "./ProgressIndicator";
export { RadioButton, RadioButtonSkeleton } from "./RadioButton";
export { RadioButtonGroup } from "./RadioButtonGroup";
export { RecursiveList } from "./RecursiveList";
export { Search, SearchSkeleton } from "./Search";
export { Select, SelectSkeleton, SelectItem, SelectItemGroup } from "./Select";
export { SkeletonPlaceholder } from "./SkeletonPlaceholder";
Expand Down
2 changes: 1 addition & 1 deletion tests/ProgressBar.test.svelte
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<script>
<script lang="ts">
import { ProgressBar } from "../types";
</script>

Expand Down
32 changes: 32 additions & 0 deletions tests/RecursiveList.test.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<script lang="ts">
import { RecursiveList } from "../types";
const children = [
{
text: "Item 1",
children: [
{
text: "Item 1a",
children: [{ html: "<h5>HTML content</h5>" }],
},
],
},
{
text: "Item 2",
children: [
{
href: "https://svelte.dev/",
},
{
href: "https://svelte.dev/",
text: "Link with custom text",
},
],
},
{
text: "Item 3",
},
];
</script>

<RecursiveList type="ordered" children="{children}" />
Loading

0 comments on commit ae27bed

Please sign in to comment.