@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 +4 -4
- package/src/BreadCrumbs.svelte +34 -0
- package/src/Icon.svelte +2 -0
- package/src/NestedList.svelte +6 -6
- package/src/NestedPaginator.svelte +64 -0
- package/src/Tree.svelte +13 -6
- package/src/constants.js +6 -2
- package/src/index.js +3 -0
- package/src/items/Node.svelte +3 -1
- package/src/items/Text.svelte +1 -1
- package/src/lib/index.js +1 -0
- package/src/lib/nested.js +50 -0
- package/src/stores/theme.js +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rokkit/core",
|
|
3
|
-
"version": "1.0.0-next.
|
|
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.
|
|
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.
|
|
25
|
+
"svelte": "^3.58.0",
|
|
26
26
|
"typescript": "^4.9.5",
|
|
27
27
|
"validators": "latest",
|
|
28
|
-
"vite": "^4.
|
|
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>
|
package/src/NestedList.svelte
CHANGED
|
@@ -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
|
|
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.
|
|
30
|
+
items[0][fields.text] == root || root == null
|
|
31
31
|
? items
|
|
32
|
-
: [
|
|
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} {
|
|
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]
|
|
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'
|
package/src/items/Node.svelte
CHANGED
|
@@ -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>
|
package/src/items/Text.svelte
CHANGED
package/src/lib/index.js
ADDED
|
@@ -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
|
+
}
|
package/src/stores/theme.js
CHANGED
|
@@ -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
|
}
|