@rokkit/core 1.0.0-next.16 → 1.0.0-next.18

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.16",
3
+ "version": "1.0.0-next.18",
4
4
  "description": "Core components, actions and stores for svelte apps.",
5
5
  "author": "Jerry Thomas <me@jerrythomas.name>",
6
6
  "license": "MIT",
@@ -16,16 +16,16 @@
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.0.2",
19
+ "@sveltejs/vite-plugin-svelte": "^2.1.1",
20
20
  "@testing-library/svelte": "^3.2.2",
21
21
  "@vitest/coverage-istanbul": "^0.28.5",
22
22
  "@vitest/ui": "~0.12.10",
23
23
  "eslint": "^7.32.0",
24
24
  "jsdom": "^19.0.0",
25
- "svelte": "^3.55.1",
25
+ "svelte": "^3.58.0",
26
26
  "typescript": "^4.9.5",
27
27
  "validators": "latest",
28
- "vite": "^4.1.1",
28
+ "vite": "^4.3.2",
29
29
  "vitest": "~0.19.1",
30
30
  "shared-config": "1.0.0"
31
31
  },
@@ -0,0 +1,34 @@
1
+ <script>
2
+ import { defaultFields } from './constants'
3
+ import { Text } from './items'
4
+
5
+ export let items = []
6
+ export let separator = '/'
7
+ export let fields = defaultFields
8
+ export let using
9
+
10
+ $: fields = { ...defaultFields, ...(fields ?? {}) }
11
+ $: using = { default: Text, ...(using ?? {}) }
12
+ </script>
13
+
14
+ <crumbs class="flex">
15
+ {#each items as item, index}
16
+ {#if item}
17
+ {@const component = item[fields.component]
18
+ ? using[item[fields.component]] || using.default
19
+ : using.default}
20
+ {#if index > 0}
21
+ <span>
22
+ {#if separator.length == 1}
23
+ {separator}
24
+ {:else}
25
+ <icon class={separator} />
26
+ {/if}
27
+ </span>
28
+ {/if}
29
+ <crumb class:is-selected={index == items.length - 1}>
30
+ <svelte:component this={component} content={item} {fields} />
31
+ </crumb>
32
+ {/if}
33
+ {/each}
34
+ </crumbs>
package/src/Icon.svelte CHANGED
@@ -6,10 +6,12 @@
6
6
  let h
7
7
  </script>
8
8
 
9
+ <!-- svelte-ignore a11y-click-events-have-key-events -->
9
10
  <square-icon
10
11
  class="flex flex-col flex-shrink-0 h-full items-center justify-center {className}"
11
12
  bind:clientHeight={h}
12
13
  style:width="{h}px"
14
+ on:click
13
15
  >
14
16
  <icon class={name} aria-hidden="true" />
15
17
  </square-icon>
@@ -1,11 +1,9 @@
1
1
  <script>
2
2
  import { Node, Text } from './items'
3
3
  import { defaultFields } from './constants'
4
- import { createEventDispatcher } from 'svelte'
5
- // import { navigator } from './actions/navigator'
6
-
7
- // const dispatch = createEventDispatcher()
8
4
 
5
+ let className = 'list'
6
+ export { className as class }
9
7
  export let items = []
10
8
  export let fields = defaultFields
11
9
  export let using = {}
@@ -14,7 +12,7 @@
14
12
  export let linesVisible = true
15
13
  export let rtl = false
16
14
  export let hierarchy = []
17
-
15
+ export let icons
18
16
  // let indices = []
19
17
 
20
18
  // function handle(event) {
@@ -34,7 +32,7 @@
34
32
  </script>
35
33
 
36
34
  <nested-list
37
- class="flex flex-col w-full"
35
+ class="flex flex-col w-full {className}"
38
36
  role="listbox"
39
37
  class:rtl
40
38
  tabindex="-1"
@@ -60,6 +58,7 @@
60
58
  {linesVisible}
61
59
  {rtl}
62
60
  {path}
61
+ stateIcons={icons}
63
62
  selected={value === content}
64
63
  />
65
64
  {#if hasChildren && content[fields.isOpen]}
@@ -68,6 +67,7 @@
68
67
  bind:value
69
68
  {fields}
70
69
  {using}
70
+ {icons}
71
71
  types={[...connectors, type, nodeTypes[index]]}
72
72
  {linesVisible}
73
73
  hierarchy={path}
@@ -0,0 +1,64 @@
1
+ <script>
2
+ import BreadCrumbs from './BreadCrumbs.svelte'
3
+ import { Text } from './items'
4
+ import { flattenNestedList } from './lib/nested'
5
+ import { createEventDispatcher } from 'svelte'
6
+
7
+ const dispatch = createEventDispatcher()
8
+ export let items
9
+ export let value
10
+ export let fields
11
+ export let using
12
+
13
+ let trail
14
+ let flatList
15
+
16
+ function handleNav(event) {
17
+ let current = flatList.findIndex((item) => item === value)
18
+ let index = current
19
+ if (event === 'previous') {
20
+ while (index > 0 && !flatList[index][fields.key]) {
21
+ index = index - 1
22
+ }
23
+ } else {
24
+ while (index < flatList.length - 1 && !flatList[index][fields.key]) {
25
+ index = index + 1
26
+ }
27
+ }
28
+ if (flatList[index][fields.key]) {
29
+ value = flatList[index]
30
+ trail = findTrail(flatList, value)
31
+ dispatch('change', { item: value, trail })
32
+ }
33
+ }
34
+ function findTrail(items, value) {
35
+ let trail = []
36
+ let index = items.findIndex((item) => item === value)
37
+ if (index === -1) return trail
38
+
39
+ let level = items[index][fields.level]
40
+ while (level > 0) {
41
+ trail.unshift(items[index])
42
+ index = items.findIndex(
43
+ (item, i) => i < index && item[fields.level] === level - 1
44
+ )
45
+ level = items[index][fields.level]
46
+ }
47
+ return trail
48
+ }
49
+
50
+ $: flatList = flattenNestedList(items, fields)
51
+ $: fields = { ...defaultFields, ...(fields ?? {}) }
52
+ $: using = { default: Text, ...(using ?? {}) }
53
+ </script>
54
+
55
+ <pages>
56
+ <!-- svelte-ignore a11y-click-events-have-key-events -->
57
+ <icon
58
+ class="arrow-left cursor-pointer"
59
+ on:click={() => handleNav('previous')}
60
+ />
61
+ <BreadCrumbs items={trail} {fields} {using} />
62
+ <!-- svelte-ignore a11y-click-events-have-key-events -->
63
+ <icon class="arrow-right cursor-pointer" on:click={() => handleNav('next')} />
64
+ </pages>
package/src/Tree.svelte CHANGED
@@ -6,13 +6,13 @@
6
6
  import { navigator } from './actions/navigator'
7
7
 
8
8
  const dispatch = createEventDispatcher()
9
-
9
+ let className = 'list'
10
+ export { className as class }
10
11
  export let items = []
11
12
  export let fields = {}
12
13
  export let using = { default: Text }
13
14
  export let root = null
14
- export let rtl = false
15
- export let value
15
+ export let value = null
16
16
 
17
17
  let indices = []
18
18
 
@@ -27,9 +27,15 @@
27
27
 
28
28
  $: fields = { ...defaultFields, ...fields }
29
29
  $: items =
30
- items.length == 1 || root == null
30
+ items[0][fields.text] == root || root == null
31
31
  ? items
32
- : [{ [fields.text]: root, [fields.children]: items }]
32
+ : [
33
+ {
34
+ [fields.text]: root,
35
+ [fields.isOpen]: true,
36
+ [fields.children]: items
37
+ }
38
+ ]
33
39
  </script>
34
40
 
35
41
  <!-- svelte-ignore a11y-no-noninteractive-tabindex -->
@@ -40,6 +46,7 @@
40
46
  on:expand={handle}
41
47
  on:collapse={handle}
42
48
  tabindex="0"
49
+ class={className}
43
50
  >
44
- <NestedList {items} {fields} {using} {rtl} {value} />
51
+ <NestedList {items} {fields} {using} {value} {...$$restProps} />
45
52
  </tree>
package/src/constants.js CHANGED
@@ -77,8 +77,10 @@ export const defaultOptions = {
77
77
  * @property {string} [notes='notes']
78
78
  * @property {string} [props='props']
79
79
  * @property {string} [isOpen='_open'] - Attribute to identify if the current item is open
80
+ * @property {string} [level='level'] - Attribute to identify level of current item
81
+ * @property {string} [parent='parent'] - Attribute to identify if the current item is a parent
80
82
  * @property {string} [isDeleted='_deleted'] - Attribute to identify if the current item is deleted
81
- * @property {FieldMapping} [fields] - Field mapping to be used on children in the next level
83
+ * @property {FieldMapping} [fields?] - Field mapping to be used on children in the next level
82
84
  */
83
85
  export const defaultFields = {
84
86
  id: 'id',
@@ -93,7 +95,9 @@ export const defaultFields = {
93
95
  props: 'props',
94
96
  target: 'target',
95
97
  isOpen: '_open',
96
- isDeleted: '_deleted'
98
+ isDeleted: '_deleted',
99
+ level: 'level',
100
+ parent: 'parent'
97
101
  }
98
102
 
99
103
  export const defaultKeyMap = {
package/src/index.js CHANGED
@@ -1,5 +1,6 @@
1
1
  export * from './constants'
2
2
  export * from './items'
3
+ export * from './lib'
3
4
 
4
5
  export { default as Icon } from './Icon.svelte'
5
6
  // export { default as List } from './List-Discard.svelte'
@@ -10,6 +11,8 @@ export { default as Searchable } from './Searchable.svelte'
10
11
  export { default as Scrollable } from './Scrollable.svelte'
11
12
  export { default as NestedList } from './NestedList.svelte'
12
13
  export { default as Tabs } from './Tabs.svelte'
14
+ export { default as BreadCrumbs } from './BreadCrumbs.svelte'
15
+ export { default as NestedPaginator } from './NestedPaginator.svelte'
13
16
 
14
17
  export { default as Alerts } from './Alerts.svelte'
15
18
  export { default as Slider } from './Slider.svelte'
@@ -14,6 +14,7 @@
14
14
  export let rtl = false
15
15
  export let path = []
16
16
 
17
+ $: stateIcons = { ...defaultStateIcons.node, ...(stateIcons ?? {}) }
17
18
  $: hasChildren = fields.children in content
18
19
  $: state =
19
20
  hasChildren && content[fields.isOpen]
@@ -34,6 +35,7 @@
34
35
  id={'id-' + path.join('-')}
35
36
  class="flex flex-row min-h-5 items-center cursor-pointer select-none"
36
37
  class:is-selected={selected}
38
+ class:flex-row-reverse={rtl}
37
39
  aria-selected={selected}
38
40
  role="option"
39
41
  data-path={path.join(',')}
@@ -48,5 +50,5 @@
48
50
  </span>
49
51
  {/if}
50
52
 
51
- <svelte:component this={component} bind:content />
53
+ <svelte:component this={component} bind:content {fields} />
52
54
  </node>
@@ -10,7 +10,7 @@
10
10
 
11
11
  {#if isObject && content[fields.image]}
12
12
  <img
13
- class="h-8 w-8 rounded-full object-cover"
13
+ class="h-4 w-4 object-cover"
14
14
  alt={content[fields.text]}
15
15
  src={content[fields.image]}
16
16
  />
@@ -0,0 +1 @@
1
+ export * from './nested'
@@ -0,0 +1,50 @@
1
+ import { omit } from 'ramda'
2
+ import { defaultFields } from '../constants'
3
+ // const defaultFields = {
4
+ // children: 'children',
5
+ // level: 'level',
6
+ // parent: 'parent'
7
+ // }
8
+
9
+ export function flattenNestedList(items, fields = defaultFields, level = 0) {
10
+ fields = { ...defaultFields, ...fields }
11
+ let data = []
12
+ items.map((item) => {
13
+ const children = item[fields.children] ?? []
14
+ data = [
15
+ ...data,
16
+ {
17
+ ...omit([fields.children], item),
18
+ [fields.level]: level,
19
+ [fields.parent]: children.length > 0
20
+ },
21
+ ...flattenNestedList(children, fields, level + 1)
22
+ ]
23
+ })
24
+ return data
25
+ }
26
+
27
+ /**
28
+ * Converts a path slug to a value in the menu
29
+ *
30
+ * @param {string} slug
31
+ * @returns {any}
32
+ */
33
+ export function findValueFromPath(slug, data, fields) {
34
+ fields = { ...defaultFields, ...fields }
35
+ const keys = slug.split('/')
36
+ let items = data
37
+ let value = null
38
+ keys.map((key, index) => {
39
+ const match = items.find((item) => item[fields.key] === key)
40
+ if (match) {
41
+ if (index < keys.length - 1) {
42
+ match[fields.isOpen] = true
43
+ items = match[fields.children]
44
+ } else {
45
+ value = match
46
+ }
47
+ }
48
+ })
49
+ return value
50
+ }
@@ -20,7 +20,7 @@ export function ThemeStore() {
20
20
  const { name, mode } = value ?? {}
21
21
  if (typeof name === 'string' && typeof mode === 'string') {
22
22
  store.set(value)
23
- } else if (value) {
23
+ } else if (value && value !== {}) {
24
24
  console.error('Both "name" and "mode" must be strings', value)
25
25
  }
26
26
  }