@rokkit/core 1.0.0-next.22 → 1.0.0-next.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rokkit/core",
3
- "version": "1.0.0-next.22",
3
+ "version": "1.0.0-next.24",
4
4
  "description": "Core components, actions and stores for svelte apps.",
5
5
  "author": "Jerry Thomas <me@jerrythomas.name>",
6
6
  "license": "MIT",
@@ -16,18 +16,19 @@
16
16
  "devDependencies": {
17
17
  "@jerrythomas/eslint-config-svelte": "^1.0.2",
18
18
  "@jerrythomas/prettier-config": "^1.0.0",
19
- "@sveltejs/vite-plugin-svelte": "^2.1.1",
19
+ "@sveltejs/vite-plugin-svelte": "^2.2.0",
20
20
  "@testing-library/svelte": "^3.2.2",
21
- "@vitest/coverage-istanbul": "^0.28.5",
22
- "@vitest/ui": "~0.12.10",
23
- "eslint": "^7.32.0",
24
- "jsdom": "^19.0.0",
25
- "svelte": "^3.58.0",
26
- "typescript": "^4.9.5",
21
+ "@vitest/coverage-c8": "^0.31.0",
22
+ "@vitest/coverage-istanbul": "^0.31.0",
23
+ "@vitest/ui": "~0.31.0",
24
+ "eslint": "^8.40.0",
25
+ "jsdom": "^22.0.0",
26
+ "svelte": "^3.59.1",
27
+ "typescript": "^5.0.4",
27
28
  "validators": "latest",
28
- "vite": "^4.3.4",
29
- "vitest": "~0.19.1",
30
- "shared-config": "1.0.0"
29
+ "vite": "^4.3.5",
30
+ "vitest": "~0.31.0",
31
+ "shared-config": "1.0.0-next.23"
31
32
  },
32
33
  "files": [
33
34
  "src/**/*.js",
@@ -47,7 +48,7 @@
47
48
  }
48
49
  },
49
50
  "dependencies": {
50
- "ramda": "^0.28.0"
51
+ "ramda": "^0.29.0"
51
52
  },
52
53
  "scripts": {
53
54
  "lint": "prettier --check --plugin-search-dir=. . && eslint .",
@@ -1,7 +1,7 @@
1
1
  <script>
2
2
  import { createEventDispatcher } from 'svelte'
3
3
  import { defaultFields } from './constants'
4
- import { Text, Summary } from './items'
4
+ import { Item, Summary } from './items'
5
5
  import List from './List.svelte'
6
6
  import { navigator } from './actions/navigator'
7
7
 
@@ -16,7 +16,7 @@
16
16
  let cursor = []
17
17
 
18
18
  $: fields = { ...defaultFields, ...fields }
19
- $: using = { default: Text, ...using }
19
+ $: using = { default: Item, ...using }
20
20
 
21
21
  function handle(event) {
22
22
  // console.log(event.type, event.detail)
@@ -63,7 +63,7 @@
63
63
  class:is-selected={item === value}
64
64
  data-path={index}
65
65
  >
66
- <Summary {fields} {using} bind:content={item} />
66
+ <Summary {fields} {using} bind:value={item} />
67
67
  {#if hasItems && item[fields.isOpen]}
68
68
  <List
69
69
  bind:items={item[fields.children]}
@@ -1,6 +1,6 @@
1
1
  <script>
2
2
  import { defaultFields } from './constants'
3
- import { Text } from './items'
3
+ import { Item } from './items'
4
4
 
5
5
  export let items = []
6
6
  export let separator = '/'
@@ -8,7 +8,7 @@
8
8
  export let using
9
9
 
10
10
  $: fields = { ...defaultFields, ...(fields ?? {}) }
11
- $: using = { default: Text, ...(using ?? {}) }
11
+ $: using = { default: Item, ...(using ?? {}) }
12
12
  </script>
13
13
 
14
14
  <crumbs class="flex">
@@ -27,7 +27,7 @@
27
27
  </span>
28
28
  {/if}
29
29
  <crumb class:is-selected={index == items.length - 1}>
30
- <svelte:component this={component} content={item} {fields} />
30
+ <svelte:component this={component} value={item} {fields} />
31
31
  </crumb>
32
32
  {/if}
33
33
  {/each}
@@ -4,7 +4,7 @@
4
4
  import { defaultFields, defaultStateIcons } from './constants.js'
5
5
 
6
6
  import Icon from './Icon.svelte'
7
- import Text from './items/Text.svelte'
7
+ import Item from './items/Item.svelte'
8
8
  import List from './List.svelte'
9
9
  import Slider from './Slider.svelte'
10
10
 
@@ -14,13 +14,13 @@
14
14
  export { className as class }
15
15
  export let items = []
16
16
  export let fields = defaultFields
17
- export let using = { default: Text }
17
+ export let using = { default: Item }
18
18
  export let value = null
19
- export let title
20
- export let icon
19
+ export let title = null
20
+ export let icon = null
21
21
  export let small = false
22
22
 
23
- $: using = { default: Text, ...using }
23
+ $: using = { default: Item, ...using }
24
24
  $: fields = { ...defaultFields, ...fields }
25
25
 
26
26
  let offsetTop = 0
@@ -46,7 +46,7 @@
46
46
  >
47
47
  <button
48
48
  on:click|stopPropagation={() => (open = !open)}
49
- class="flex"
49
+ class="flex items-center"
50
50
  bind:clientHeight={offsetTop}
51
51
  tabindex="-1"
52
52
  >
@@ -54,7 +54,7 @@
54
54
  <Icon name={icon} />
55
55
  {/if}
56
56
  {#if !small && title}
57
- <p>{title}</p>
57
+ <p class="flex w-full">{title}</p>
58
58
  {/if}
59
59
  {#if open}
60
60
  <icon class={icons.opened} />
@@ -2,14 +2,14 @@
2
2
  import { defaultFields } from './constants.js'
3
3
  import List from './List.svelte'
4
4
  import Slider from './Slider.svelte'
5
- import { Text } from './items'
5
+ import { Item } from './items'
6
6
 
7
7
  export let data
8
8
  export let value = null
9
9
  export let fields = defaultFields
10
- export let using = { default: Text }
10
+ export let using = { default: Item }
11
11
 
12
- $: using = { default: Text, ...using }
12
+ $: using = { default: Item, ...using }
13
13
  $: fields = { ...defaultFields, ...fields }
14
14
 
15
15
  let opened = false
package/src/Icon.svelte CHANGED
@@ -1,17 +1,31 @@
1
1
  <script>
2
2
  let className = ''
3
3
  export { className as class }
4
+ export let name
5
+ export let size = 'base'
6
+ export let role = 'img'
7
+ export let label = name
8
+ export let disabled = false
9
+ export let tabindex = 0
4
10
 
5
- export let name = ''
6
- let h
11
+ $: tabindex = role !== 'button' || disabled ? -1 : tabindex
12
+ $: small = size === 'small' || className.includes('small')
13
+ $: medium = size === 'medium' || className.includes('medium')
14
+ $: large = size === 'large' || className.includes('large')
7
15
  </script>
8
16
 
9
- <!-- svelte-ignore a11y-click-events-have-key-events -->
10
- <square-icon
11
- class="flex flex-col flex-shrink-0 h-full items-center justify-center {className}"
12
- bind:clientHeight={h}
13
- style:width="{h}px"
17
+ <!-- svelte-ignore a11y-no-noninteractive-tabindex -->
18
+ <icon
19
+ class="flex flex-shrink-0 items-center justify-center {className}"
20
+ class:small
21
+ class:medium
22
+ class:large
23
+ class:disabled
24
+ {role}
25
+ aria-label={label}
14
26
  on:click
27
+ on:keydown={(e) => e.key === 'Enter' && e.currentTarget.click()}
28
+ {tabindex}
15
29
  >
16
- <icon class={name} aria-hidden="true" />
17
- </square-icon>
30
+ <i class={name} aria-hidden="true" />
31
+ </icon>
package/src/List.svelte CHANGED
@@ -2,7 +2,7 @@
2
2
  import { navigator } from './actions'
3
3
  import { createEventDispatcher } from 'svelte'
4
4
  import { defaultFields } from './constants'
5
- import { Text } from './items'
5
+ import { Item } from './items'
6
6
 
7
7
  const dispatch = createEventDispatcher()
8
8
 
@@ -24,7 +24,7 @@
24
24
  }
25
25
 
26
26
  $: fields = { ...defaultFields, ...fields }
27
- $: using = { default: Text, ...using }
27
+ $: using = { default: Item, ...using }
28
28
  $: filtered = items.filter((item) => !item[fields.isDeleted])
29
29
  </script>
30
30
 
@@ -47,6 +47,7 @@
47
47
  ? using[item[fields.component]] || using.default
48
48
  : using.default}
49
49
  {@const path = [...hierarchy, index].join(',')}
50
+ {@const props = item[fields.props] || { fields }}
50
51
  <item
51
52
  class="flex flex-shrink-0 flex-grow-0 items-center cursor-pointer w-full gap-2 select-none item"
52
53
  role="option"
@@ -56,8 +57,8 @@
56
57
  >
57
58
  <svelte:component
58
59
  this={component}
59
- bind:content={item}
60
- {fields}
60
+ bind:value={item}
61
+ {...props}
61
62
  on:change
62
63
  />
63
64
  </item>
@@ -1,5 +1,5 @@
1
1
  <script>
2
- import { Node, Text } from './items'
2
+ import { Node, Item } from './items'
3
3
  import { defaultFields, defaultStateIcons } from './constants'
4
4
  import { getLineTypes } from './lib/connector'
5
5
 
@@ -14,7 +14,7 @@
14
14
  export let hierarchy = []
15
15
  export let icons
16
16
 
17
- $: using = { default: Text, ...using }
17
+ $: using = { default: Item, ...using }
18
18
  $: fields = { ...defaultFields, ...fields }
19
19
  $: nodeTypes = items.map((_, index) =>
20
20
  index === items.length - 1 ? 'last' : 'child'
@@ -28,35 +28,25 @@
28
28
  class:rtl
29
29
  tabindex="-1"
30
30
  >
31
- <!-- tabindex={hierarchy.length == 0 ? 0 : -1}
32
- use:navigator={{ items, fields, indices, enabled: hierarchy.length == 0 }}
33
- on:select={handle}
34
- on:move={handle}
35
- on:expand={handle}
36
- on:collapse={handle}
37
- > -->
38
- {#each items as content, index}
39
- <!-- {@const type = nodeTypes[index] === 'middle' ? 'line' : 'empty'} -->
40
- {@const hasChildren = fields.children in content}
41
- <!-- {@const connectors = types.slice(0, -1)} -->
31
+ {#each items as item, index}
32
+ {@const hasChildren = fields.children in item}
42
33
  {@const path = [...hierarchy, index]}
43
34
  {@const connectors = getLineTypes(hasChildren, types, nodeTypes[index])}
44
35
 
45
- <!-- types={[...connectors, nodeTypes[index]]} -->
46
36
  <Node
47
- bind:content
37
+ bind:value={item}
48
38
  {fields}
49
39
  {using}
50
40
  types={connectors}
51
41
  {rtl}
52
42
  {path}
53
43
  stateIcons={icons}
54
- selected={value === content}
44
+ selected={value === item}
55
45
  />
56
46
  <!-- types={[...connectors, type, nodeTypes[index]]} -->
57
- {#if hasChildren && content[fields.isOpen]}
47
+ {#if hasChildren && item[fields.isOpen]}
58
48
  <svelte:self
59
- items={content[fields.children]}
49
+ items={item[fields.children]}
60
50
  bind:value
61
51
  {fields}
62
52
  {using}
@@ -1,7 +1,7 @@
1
1
  <script>
2
2
  import BreadCrumbs from './BreadCrumbs.svelte'
3
3
  import { defaultFields } from './constants'
4
- import { Text } from './items'
4
+ import { Item } from './items'
5
5
  import { flattenNestedList } from './lib/nested'
6
6
  import { createEventDispatcher } from 'svelte'
7
7
 
@@ -50,7 +50,7 @@
50
50
 
51
51
  $: flatList = flattenNestedList(items, fields)
52
52
  $: fields = { ...defaultFields, ...(fields ?? {}) }
53
- $: using = { default: Text, ...(using ?? {}) }
53
+ $: using = { default: Item, ...(using ?? {}) }
54
54
  </script>
55
55
 
56
56
  <pages>
@@ -1,7 +1,7 @@
1
1
  <script>
2
2
  import { createEventDispatcher } from 'svelte'
3
3
  import { defaultFields } from './constants'
4
- import { Text } from './items'
4
+ import { Item } from './items'
5
5
  import { navigable } from './actions'
6
6
  import { getComponent } from './list'
7
7
 
@@ -24,7 +24,7 @@
24
24
  dispatch('select', items[index])
25
25
  }
26
26
 
27
- $: using = { default: Text, ...using }
27
+ $: using = { default: Item, ...using }
28
28
  $: fields = { ...defaultFields, ...fields }
29
29
  $: value = index >= 0 ? items[index] : null
30
30
  $: component = getComponent(value, fields)
@@ -41,7 +41,7 @@
41
41
  on:next={moveNext}
42
42
  on:previous={moveBack}
43
43
  />
44
- <!-- <svelte:component this={component} bind:content={value} {fields} on:change /> -->
44
+ <!-- <svelte:component this={component} bind:value={value} {fields} on:change /> -->
45
45
  <square class="h-full position-absolute right-0">
46
46
  <icon class="i-carbon-chevron-sort" />
47
47
  </square>
package/src/Switch.svelte CHANGED
@@ -1,52 +1,67 @@
1
1
  <script>
2
+ import { createEventDispatcher } from 'svelte'
2
3
  import { defaultFields } from './constants'
3
- import { Text } from './items'
4
+ import { Item } from './items'
5
+ import { navigator } from './actions'
6
+ import { getComponent } from './lib'
7
+
8
+ const dispatch = createEventDispatcher()
4
9
 
5
10
  let className = ''
6
11
  export { className as class }
7
12
  export let items = [false, true]
8
13
  export let fields = defaultFields
9
- export let using = { default: Text }
14
+ export let using = {}
10
15
  export let compact = true
11
16
  export let value
17
+ let cursor = []
12
18
 
13
- const getComponent = (item, fields) => {
14
- return fields.component
15
- ? item[fields.component] ?? using.default
16
- : using.default
17
- }
19
+ function handleNav(event) {
20
+ value = event.detail.node
21
+ cursor = event.detail.path
18
22
 
19
- const onItemClick = (item) => {
20
- value = item
23
+ dispatch('change', { item: value, indices: cursor })
21
24
  }
22
25
 
23
26
  $: useComponent = !items.every((item) => [false, true].includes(item))
24
27
  $: fields = { ...defaultFields, ...fields }
25
- $: using = { default: Text, ...using }
28
+ $: using = { default: Item, ...using }
26
29
  </script>
27
30
 
28
31
  {#if !Array.isArray(items) || items.length < 2}
29
32
  <error>Items should be an array with at least two items.</error>
30
33
  {:else}
31
- <!-- svelte-ignore a11y-no-noninteractive-tabindex -->
32
34
  <toggle-switch
33
35
  class="flex items-center {className}"
36
+ class:is-off={items.length == 2 && value === items[0]}
37
+ class:is-on={items.length == 2 && value === items[1]}
34
38
  class:compact
35
39
  tabindex="0"
40
+ role="listbox"
41
+ use:navigator={{
42
+ items,
43
+ fields,
44
+ vertical: false,
45
+ indices: cursor
46
+ }}
47
+ on:move={handleNav}
48
+ on:select={handleNav}
36
49
  >
37
50
  {#each items as item, index (item)}
38
- {@const component = useComponent ? getComponent(item, fields) : null}
39
- <!-- svelte-ignore a11y-click-events-have-key-events -->
51
+ {@const component = useComponent
52
+ ? getComponent(item, fields, using)
53
+ : null}
40
54
  <item
41
55
  class="flex relative"
42
- class:is-selected={item === value}
43
- on:click={() => onItemClick(item)}
56
+ role="option"
57
+ aria-selected={item === value}
58
+ data-path={index}
44
59
  >
45
60
  {#if item == value}
46
61
  <indicator class="absolute top-0 left-0 right-0 bottom-0" />
47
62
  {/if}
48
63
  {#if component}
49
- <svelte:component this={component} content={item} {fields} />
64
+ <svelte:component this={component} value={item} {fields} />
50
65
  {/if}
51
66
  </item>
52
67
  {/each}
@@ -3,25 +3,28 @@
3
3
 
4
4
  const dispatch = createEventDispatcher()
5
5
 
6
- export let icon = null
7
- export let label
8
- export let active = false
9
- export let allowClose = false
6
+ export let fields = {}
7
+ export let using = {}
8
+ export let value = null
9
+ export let index = 0
10
+ export let icons
11
+ export let selected = false
12
+ export let removable = false
13
+
14
+ $: component = value[fields.component]
15
+ ? using[value[fields.component]] || using.default
16
+ : using.default
10
17
  </script>
11
18
 
12
19
  <!-- svelte-ignore a11y-click-events-have-key-events -->
13
- <tab class="flex flex-row items-center" class:active on:click>
14
- {#if icon}
15
- <icon class={icon} aria-label={icon} />
16
- {/if}
17
- {#if label}
18
- <p class="flex flex-shrink-0 flex-grow justify-center">{label}</p>
19
- {/if}
20
- {#if allowClose}
21
- <icon
22
- class="remove small"
23
- aria-label="remove"
24
- on:click={() => dispatch('remove')}
25
- />
20
+ <tab
21
+ class="flex flex-row items-center"
22
+ role="option"
23
+ aria-selected={selected}
24
+ data-path={index}
25
+ >
26
+ <svelte:component this={component} {value} {fields} />
27
+ {#if removable}
28
+ <icon class={icons.close} on:click={() => dispatch('remove')} />
26
29
  {/if}
27
30
  </tab>
package/src/Tabs.svelte CHANGED
@@ -1,6 +1,7 @@
1
1
  <script>
2
- import { defaultFields } from './constants'
3
- import { Text } from './items'
2
+ import { defaultFields, defaultStateIcons } from './constants'
3
+ import Icon from './Icon.svelte'
4
+ import { ItemWrapper } from './items'
4
5
  import { navigator } from './actions'
5
6
  import { createEventDispatcher } from 'svelte'
6
7
 
@@ -12,20 +13,38 @@
12
13
  export let fields = {}
13
14
  export let using = {}
14
15
  export let value = null
16
+ export let below = false
17
+ export let align = 'left'
18
+ export let editable = false
19
+ export let icons = defaultStateIcons.action
20
+
15
21
  let cursor = []
16
22
 
23
+ function handleRemove(item) {
24
+ if (typeof item === Object) {
25
+ item[fields.isDeleted] = true
26
+ } else {
27
+ items = items.filter((i) => i !== item)
28
+ }
29
+
30
+ dispatch('remove', { item })
31
+ }
17
32
  function handleNav(event) {
18
33
  value = event.detail.node
19
34
  cursor = event.detail.path
20
35
 
21
36
  dispatch('select', { item: value, indices: cursor })
22
37
  }
38
+ $: icons = { ...defaultStateIcons.action, ...icons }
39
+ $: filtered = items.filter((item) => !item[fields.isDeleted])
23
40
  $: fields = { ...defaultFields, ...fields }
24
- $: using = { default: Text, ...using }
25
41
  </script>
26
42
 
27
43
  <tabs
28
44
  class="flex w-full {className}"
45
+ class:is-below={below}
46
+ class:justify-center={align == 'center'}
47
+ class:justify-end={align == 'right'}
29
48
  tabindex="0"
30
49
  role="listbox"
31
50
  use:navigator={{
@@ -37,13 +56,26 @@
37
56
  on:move={handleNav}
38
57
  on:select={handleNav}
39
58
  >
40
- {#each items as item, index}
41
- {@const component = item[fields.component]
42
- ? using[item[fields.component]] || using.default
43
- : using.default}
44
-
45
- <item class="flex" class:is-selected={item === value} data-path={index}>
46
- <svelte:component this={component} content={item} {fields} />
47
- </item>
59
+ {#each filtered as item, index}
60
+ <ItemWrapper
61
+ value={item}
62
+ {index}
63
+ {fields}
64
+ {using}
65
+ removable={editable}
66
+ selected={item === value}
67
+ {icons}
68
+ class="tab"
69
+ on:remove={handleRemove}
70
+ />
48
71
  {/each}
72
+ {#if editable}
73
+ <Icon
74
+ name="add"
75
+ role="button"
76
+ label="Add Tab"
77
+ size="small"
78
+ on:click={() => dispatch('add')}
79
+ />
80
+ {/if}
49
81
  </tabs>
package/src/Tree.svelte CHANGED
@@ -1,7 +1,7 @@
1
1
  <script>
2
2
  import { createEventDispatcher } from 'svelte'
3
3
  import NestedList from './NestedList.svelte'
4
- import { Text } from './items'
4
+ import { Item } from './items'
5
5
  import { defaultFields } from './constants'
6
6
  import { navigator } from './actions/navigator'
7
7
 
@@ -10,7 +10,7 @@
10
10
  export { className as class }
11
11
  export let items = []
12
12
  export let fields = {}
13
- export let using = { default: Text }
13
+ export let using = { default: Item }
14
14
  export let root = null
15
15
  export let value = null
16
16
 
@@ -2,7 +2,6 @@ export function navigable(
2
2
  node,
3
3
  { horizontal = true, nested = false, enabled = true } = {}
4
4
  ) {
5
- // console.log(node, enabled)
6
5
  if (!enabled) return { destroy() {} }
7
6
  const previous = () => node.dispatchEvent(new CustomEvent('previous'))
8
7
  const next = () => node.dispatchEvent(new CustomEvent('next'))
@@ -1,4 +1,3 @@
1
- // const defaultOptions = { horizontal: true, vertical: false, threshold: 100 }
2
1
  export function swipeable(
3
2
  node,
4
3
  { horizontal = true, vertical = false, threshold = 100, enabled = true } = {}
package/src/constants.js CHANGED
@@ -93,32 +93,3 @@ export function stateIconsFromNames(icons) {
93
93
  }
94
94
 
95
95
  export const defaultStateIcons = stateIconsFromNames(defaultIcons)
96
- // export const defaultStateIcons = {
97
- // accordion: {
98
- // opened: 'accordion-opened',
99
- // closed: 'accordion-closed'
100
- // },
101
- // item: {
102
- // remove: 'item-remove',
103
- // add: 'item-add',
104
- // clear: 'item-clear',
105
- // search: 'item-search'
106
- // },
107
- // node: {
108
- // opened: 'node-opened',
109
- // closed: 'node-closed'
110
- // },
111
- // list: {
112
- // selector: 'list-selector'
113
- // },
114
- // checkbox: {
115
- // checked: 'checkbox-checked',
116
- // unchecked: 'checkbox-unchecked',
117
- // unknown: 'checkbox-unknown'
118
- // },
119
- // rating: { filled: 'rating-filled', empty: 'rating-empty' },
120
- // radio: {
121
- // off: 'radio-off',
122
- // on: 'radio-on'
123
- // }
124
- // }
@@ -0,0 +1,29 @@
1
+ <script>
2
+ import { defaultFields } from '../constants'
3
+ import Icon from '../Icon.svelte'
4
+
5
+ export let value
6
+ export let fields = defaultFields
7
+
8
+ $: isObject = typeof value == 'object'
9
+ $: text = isObject ? value[fields.text] : value
10
+ </script>
11
+
12
+ {#if isObject}
13
+ {#if value[fields.icon]}
14
+ {@const iconName =
15
+ typeof value[fields.icon] == 'object'
16
+ ? value[fields.icon][value[fields.state]]
17
+ : value[fields.icon]}
18
+ <Icon name={iconName} />
19
+ {:else if value[fields.image]}
20
+ <img
21
+ class="h-4 w-4 object-cover"
22
+ alt={value[fields.text]}
23
+ src={value[fields.image]}
24
+ />
25
+ {/if}
26
+ {/if}
27
+ {#if text}
28
+ <p class="flex w-full">{text}</p>
29
+ {/if}
@@ -1,32 +1,47 @@
1
1
  <script>
2
2
  import { createEventDispatcher } from 'svelte'
3
3
  import { defaultFields, defaultStateIcons } from '../constants'
4
- import Text from './Text.svelte'
4
+ import Item from './Item.svelte'
5
+ import Icon from '../Icon.svelte'
6
+
5
7
  const dispatch = createEventDispatcher()
6
8
 
9
+ let className = ''
10
+ export { className as class }
7
11
  export let value
8
12
  export let fields = defaultFields
9
- export let using = { default: Text }
13
+ export let using = { default: Item }
10
14
  export let removable = false
15
+ export let selected = false
16
+ export let index = null
17
+ export let icons = defaultStateIcons.action
11
18
 
12
19
  function handleClick() {
13
20
  dispatch('remove', value)
14
21
  }
22
+
15
23
  $: component =
16
24
  typeof value == 'object'
17
25
  ? using[value[fields.component] ?? 'default']
18
26
  : using.default
19
27
  </script>
20
28
 
21
- <pill class="flex flex-row items-center">
29
+ <wrap-item
30
+ class="flex flex-row items-center {className}"
31
+ role="option"
32
+ aria-selected={selected}
33
+ data-path={index}
34
+ >
22
35
  <item class="flex flex-row items-center">
23
- <svelte:component this={component} content={value} {fields} />
36
+ <svelte:component this={component} bind:value {fields} />
24
37
  </item>
25
- <!-- svelte-ignore a11y-click-events-have-key-events -->
26
38
  {#if removable}
27
- <icon
28
- class="{defaultStateIcons.action.remove} cursor-pointer"
39
+ <Icon
40
+ name={icons.remove}
41
+ role="button"
42
+ label="Remove"
43
+ size="small"
29
44
  on:click={handleClick}
30
45
  />
31
46
  {/if}
32
- </pill>
47
+ </wrap-item>
@@ -1,18 +1,18 @@
1
1
  <script>
2
- import Text from './Text.svelte'
2
+ import Item from './Item.svelte'
3
3
  import { defaultFields } from '../constants'
4
4
 
5
- export let content
5
+ export let value
6
6
  export let fields = defaultFields
7
7
 
8
- $: target = fields.target ? content[fields.target] : ''
8
+ $: target = fields.target ? value[fields.target] : ''
9
9
  </script>
10
10
 
11
11
  <a
12
12
  class="flex flex-row flex-grow items-center"
13
- href={content[fields.url]}
13
+ href={value[fields.url]}
14
14
  {target}
15
15
  tabindex="-1"
16
16
  >
17
- <Text {content} {fields} />
17
+ <Item {value} {fields} />
18
18
  </a>
@@ -1,8 +1,9 @@
1
1
  <script>
2
- import Connector from './Connector.svelte'
3
2
  import { defaultFields, defaultStateIcons } from '../constants'
3
+ import Icon from '../Icon.svelte'
4
+ import Connector from './Connector.svelte'
4
5
 
5
- export let content
6
+ export let value
6
7
  export let fields = defaultFields
7
8
  export let types = []
8
9
  export let stateIcons = defaultStateIcons.node
@@ -13,13 +14,13 @@
13
14
  export let path = []
14
15
 
15
16
  $: stateIcons = { ...defaultStateIcons.node, ...(stateIcons ?? {}) }
16
- $: hasChildren = fields.children in content
17
+ $: hasChildren = fields.children in value
17
18
  $: state =
18
- hasChildren && content[fields.isOpen]
19
+ hasChildren && value[fields.isOpen]
19
20
  ? { icon: stateIcons.opened, label: 'collapse' }
20
21
  : { icon: stateIcons.closed, label: 'expand' }
21
- $: component = content[fields.component]
22
- ? using[content[fields.component]] || using.default
22
+ $: component = value[fields.component]
23
+ ? using[value[fields.component]] || using.default
23
24
  : using.default
24
25
  </script>
25
26
 
@@ -35,14 +36,12 @@
35
36
  >
36
37
  {#each types as type}
37
38
  {#if type === 'icon'}
38
- <span class="flex flex-col w-4 h-full items-center justify-center">
39
- <icon class={state.icon} aria-label={state.label} tabindex="-1" />
40
- </span>
39
+ <Icon name={state.icon} label={state.label} class="w-4 small" />
41
40
  {:else}
42
41
  <Connector {type} />
43
42
  {/if}
44
43
  {/each}
45
44
  <item>
46
- <svelte:component this={component} bind:content {fields} />
45
+ <svelte:component this={component} bind:value {fields} />
47
46
  </item>
48
47
  </node>
@@ -1,24 +1,24 @@
1
1
  <script>
2
2
  import { defaultFields } from '../constants'
3
- import Text from './Text.svelte'
3
+ import Item from './Item.svelte'
4
4
 
5
- export let content
5
+ export let value
6
6
  export let fields = {}
7
7
  export let using = {}
8
8
 
9
9
  $: fields = { ...defaultFields, ...fields }
10
- $: using = { default: Text, ...using }
11
- $: hasItems = content[fields.children] && content[fields.children].length > 0
12
- $: component = using[content[fields.component] ?? 'default']
10
+ $: using = { default: Item, ...using }
11
+ $: hasItems = value[fields.children] && value[fields.children].length > 0
12
+ $: component = using[value[fields.component] ?? 'default']
13
13
  </script>
14
14
 
15
15
  <summary
16
16
  class="flex flex-row flex-shrink-0 items-center w-full cursor-pointer"
17
17
  tabindex="-1"
18
18
  >
19
- <svelte:component this={component} bind:content {fields} />
19
+ <svelte:component this={component} bind:value {fields} />
20
20
  {#if hasItems}
21
- {#if content[fields.isOpen]}
21
+ {#if value[fields.isOpen]}
22
22
  <icon class="sm accordion-opened" aria-label="expand" />
23
23
  {:else}
24
24
  <icon class="sm accordion-closed" aria-label="collapse" />
@@ -1,8 +1,7 @@
1
- export { default as Text } from './Text.svelte'
1
+ export { default as Item } from './Item.svelte'
2
2
  export { default as Link } from './Link.svelte'
3
3
  export { default as Node } from './Node.svelte'
4
- export { default as Pill } from './Pill.svelte'
5
- export { default as Collapsible } from './Collapsible.svelte'
4
+ export { default as ItemWrapper } from './ItemWrapper.svelte'
6
5
  export { default as Connector } from './Connector.svelte'
7
6
  export { default as Separator } from './Separator.svelte'
8
7
  export { default as Summary } from './Summary.svelte'
package/src/lib/index.js CHANGED
@@ -1 +1,7 @@
1
1
  export * from './nested'
2
+
3
+ export function getComponent(item, fields, using) {
4
+ return fields.component
5
+ ? item[fields.component] ?? using.default
6
+ : using.default
7
+ }
@@ -1,7 +1,6 @@
1
1
  <script>
2
- import { defaultFields } from '../../src/constants'
3
- export let content
4
- export let fields = defaultFields
2
+ export let value
3
+ export let fields
5
4
  </script>
6
5
 
7
- <span>{content[fields.text]}</span>
6
+ <span>{value[fields.text]}</span>
@@ -1,48 +0,0 @@
1
- <script>
2
- import ListActions from './ListActions.svelte'
3
- import ListItems from './List.svelte'
4
-
5
- let className = 'list'
6
- export { className as class }
7
- export let items = []
8
- export let fields = {}
9
- export let using = {}
10
- export let value = null
11
- export let searchable = false
12
- export let editable = false
13
-
14
- let search
15
- let filtered
16
-
17
- function addItem() {
18
- items = [...items, {}]
19
- value = items[items.length - 1]
20
- }
21
- function deleteSelection() {
22
- if (value) value.isDeleted = true
23
- }
24
- function clearSelection() {
25
- value = null
26
- }
27
-
28
- $: filtered =
29
- searchable && search && search.length
30
- ? items.filter((item) => item[fields.text].includes(search))
31
- : items
32
- </script>
33
-
34
- <list class="flex flex-col w-full {className}">
35
- {#if searchable || editable}
36
- <ListActions
37
- bind:search
38
- {searchable}
39
- {editable}
40
- on:delete={deleteSelection}
41
- on:clear={clearSelection}
42
- on:add={addItem}
43
- />
44
- {/if}
45
- <scroll class="flex flex-col h-full overflow-scroll">
46
- <ListItems bind:items={filtered} {fields} {using} bind:value on:select />
47
- </scroll>
48
- </list>
@@ -1,51 +0,0 @@
1
- <script>
2
- import { createEventDispatcher } from 'svelte'
3
- import { defaultFields } from '../constants'
4
-
5
- const dispatch = createEventDispatcher()
6
-
7
- export let content
8
- export let fields = {}
9
-
10
- $: fields = { ...defaultFields, ...fields }
11
- $: hasItems = content[fields.children] && content[fields.children].length > 0
12
-
13
- function toggle() {
14
- if (hasItems) {
15
- content.isOpen = !content.isOpen
16
- }
17
- dispatch('toggle', content)
18
- }
19
- </script>
20
-
21
- <!-- svelte-ignore a11y-click-events-have-key-events -->
22
- <collapsible
23
- class="flex flex-row flex-shrink-0 items-center w-full leading-loose cursor-pointer"
24
- class:expanded={content.isOpen}
25
- on:click={toggle}
26
- >
27
- {#if content[fields.image]}
28
- <img
29
- class="h-8 w-8 rounded-full"
30
- alt={content[fields.text]}
31
- src={content[fields.image]}
32
- />
33
- {/if}
34
- {#if content[fields.icon]}
35
- <icon class={content[fields.icon]} />
36
- {/if}
37
- {#if content[fields.url]}
38
- <a href={content[fields.url]} class="flex flex-grow">
39
- {content[fields.text]}
40
- </a>
41
- {:else}
42
- <p class="flex flex-grow">{content[fields.text]}</p>
43
- {/if}
44
- {#if hasItems}
45
- {#if content.isOpen}
46
- <icon class="sm accordion-opened" aria-label="expand" />
47
- {:else}
48
- <icon class="sm accordion-closed" aria-label="collapse" />
49
- {/if}
50
- {/if}
51
- </collapsible>
@@ -1,28 +0,0 @@
1
- <script>
2
- import { defaultFields } from '../constants'
3
-
4
- export let content
5
- export let fields = defaultFields
6
-
7
- $: isObject = typeof content == 'object'
8
- $: text = isObject ? content[fields.text] : content
9
- </script>
10
-
11
- {#if isObject}
12
- {#if content[fields.icon]}
13
- {@const iconName =
14
- typeof content[fields.icon] == 'object'
15
- ? content[fields.icon][content[fields.state]]
16
- : content[fields.icon]}
17
- <icon class={iconName} />
18
- {:else if content[fields.image]}
19
- <img
20
- class="h-4 w-4 object-cover"
21
- alt={content[fields.text]}
22
- src={content[fields.image]}
23
- />
24
- {/if}
25
- {/if}
26
- {#if text}
27
- <p class="flex w-full">{text}</p>
28
- {/if}