@rokkit/ui 1.0.0-next.147 → 1.0.0-next.148
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 +1 -1
- package/src/components/List.svelte +23 -5
- package/src/components/Swatch.svelte +96 -0
- package/src/components/index.ts +1 -0
- package/src/index.ts +1 -0
- package/src/types/button.ts +1 -1
package/package.json
CHANGED
|
@@ -82,12 +82,30 @@
|
|
|
82
82
|
return () => nav.destroy()
|
|
83
83
|
})
|
|
84
84
|
|
|
85
|
-
// Expand
|
|
86
|
-
// collapsible=false: groups are fixed section headers —
|
|
87
|
-
// collapsible=true:
|
|
85
|
+
// Expand groups based on collapsible mode and active value.
|
|
86
|
+
// collapsible=false: groups are fixed section headers — always expanded.
|
|
87
|
+
// collapsible=true: only expand the ancestor group of the active value;
|
|
88
|
+
// all other groups start collapsed (user can toggle them).
|
|
88
89
|
$effect(() => {
|
|
89
|
-
|
|
90
|
-
|
|
90
|
+
if (!collapsible) {
|
|
91
|
+
for (const [, proxy] of wrapper.lookup) {
|
|
92
|
+
if (proxy.hasChildren) proxy.expanded = true
|
|
93
|
+
}
|
|
94
|
+
} else {
|
|
95
|
+
let activeKey: string | null = null
|
|
96
|
+
for (const [key, proxy] of wrapper.lookup) {
|
|
97
|
+
if (proxy.value === value) {
|
|
98
|
+
activeKey = key
|
|
99
|
+
break
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
for (const [key, proxy] of wrapper.lookup) {
|
|
103
|
+
if (proxy.hasChildren) {
|
|
104
|
+
proxy.expanded =
|
|
105
|
+
activeKey !== null &&
|
|
106
|
+
(activeKey === key || activeKey.startsWith(`${key }-`))
|
|
107
|
+
}
|
|
108
|
+
}
|
|
91
109
|
}
|
|
92
110
|
})
|
|
93
111
|
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
// @ts-nocheck
|
|
3
|
+
import { Wrapper, ProxyTree, messages } from '@rokkit/states'
|
|
4
|
+
import { Navigator } from '@rokkit/actions'
|
|
5
|
+
|
|
6
|
+
let {
|
|
7
|
+
options = [],
|
|
8
|
+
fields: userFields = {},
|
|
9
|
+
value = $bindable(),
|
|
10
|
+
multiple = false,
|
|
11
|
+
shape = 'square',
|
|
12
|
+
size = 'md',
|
|
13
|
+
disabled = false,
|
|
14
|
+
label = messages.current.swatch?.label ?? 'Select',
|
|
15
|
+
class: className = '',
|
|
16
|
+
onchange,
|
|
17
|
+
item: itemSnippet,
|
|
18
|
+
..._rest
|
|
19
|
+
} = $props()
|
|
20
|
+
|
|
21
|
+
const proxyTree = $derived(new ProxyTree(options, userFields))
|
|
22
|
+
const wrapper = $derived(new Wrapper(proxyTree, { onselect: handleSelect }))
|
|
23
|
+
|
|
24
|
+
let containerRef = $state<HTMLElement | null>(null)
|
|
25
|
+
|
|
26
|
+
$effect(() => {
|
|
27
|
+
if (!containerRef) return
|
|
28
|
+
const nav = new Navigator(containerRef, wrapper, { orientation: 'horizontal' })
|
|
29
|
+
return () => nav.destroy()
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
$effect(() => {
|
|
33
|
+
wrapper.moveToValue(value)
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
function isSelected(proxy) {
|
|
37
|
+
if (multiple && Array.isArray(value)) return value.includes(proxy.value)
|
|
38
|
+
return proxy.value === value
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function handleSelect(extracted, proxy) {
|
|
42
|
+
if (proxy.disabled || disabled) return
|
|
43
|
+
if (multiple) {
|
|
44
|
+
const arr = Array.isArray(value) ? [...value] : []
|
|
45
|
+
const idx = arr.indexOf(extracted)
|
|
46
|
+
if (idx >= 0) arr.splice(idx, 1)
|
|
47
|
+
else arr.push(extracted)
|
|
48
|
+
value = arr
|
|
49
|
+
onchange?.(value, proxy.original)
|
|
50
|
+
} else if (extracted !== value) {
|
|
51
|
+
value = extracted
|
|
52
|
+
onchange?.(extracted, proxy.original)
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
</script>
|
|
56
|
+
|
|
57
|
+
<div
|
|
58
|
+
bind:this={containerRef}
|
|
59
|
+
data-swatch
|
|
60
|
+
data-swatch-size={size}
|
|
61
|
+
data-swatch-shape={shape}
|
|
62
|
+
data-swatch-disabled={disabled || undefined}
|
|
63
|
+
data-swatch-multiple={multiple || undefined}
|
|
64
|
+
role={multiple ? 'group' : 'radiogroup'}
|
|
65
|
+
aria-label={label}
|
|
66
|
+
aria-disabled={disabled || undefined}
|
|
67
|
+
class={className || undefined}
|
|
68
|
+
>
|
|
69
|
+
{#each wrapper.flatView as node (node.key)}
|
|
70
|
+
{@const proxy = node.proxy}
|
|
71
|
+
{@const sel = isSelected(proxy)}
|
|
72
|
+
{@const fill = proxy.get(userFields.fill ?? 'fill')}
|
|
73
|
+
{@const stroke = proxy.get(userFields.stroke ?? 'stroke')}
|
|
74
|
+
<button
|
|
75
|
+
type="button"
|
|
76
|
+
data-swatch-item
|
|
77
|
+
data-path={node.key}
|
|
78
|
+
data-selected={sel || undefined}
|
|
79
|
+
data-disabled={proxy.disabled || undefined}
|
|
80
|
+
role={multiple ? 'checkbox' : 'radio'}
|
|
81
|
+
aria-checked={sel}
|
|
82
|
+
aria-label={proxy.label}
|
|
83
|
+
title={proxy.label}
|
|
84
|
+
disabled={proxy.disabled || disabled}
|
|
85
|
+
style={fill ? `--swatch-fill:${fill};--swatch-stroke:${stroke ?? fill}` : undefined}
|
|
86
|
+
>
|
|
87
|
+
{#if itemSnippet}
|
|
88
|
+
{@render itemSnippet(proxy, sel)}
|
|
89
|
+
{:else if shape === 'circle'}
|
|
90
|
+
<span data-swatch-circle></span>
|
|
91
|
+
{:else}
|
|
92
|
+
<span data-swatch-square></span>
|
|
93
|
+
{/if}
|
|
94
|
+
</button>
|
|
95
|
+
{/each}
|
|
96
|
+
</div>
|
package/src/components/index.ts
CHANGED
|
@@ -10,6 +10,7 @@ export { default as Toolbar } from './Toolbar.svelte'
|
|
|
10
10
|
export { default as ToolbarGroup } from './ToolbarGroup.svelte'
|
|
11
11
|
export { default as Tabs } from './Tabs.svelte'
|
|
12
12
|
export { default as Toggle } from './Toggle.svelte'
|
|
13
|
+
export { default as Swatch } from './Swatch.svelte'
|
|
13
14
|
export { default as List } from './List.svelte'
|
|
14
15
|
export { default as Tree } from './Tree.svelte'
|
|
15
16
|
export { default as LazyTree } from './LazyTree.svelte'
|
package/src/index.ts
CHANGED
package/src/types/button.ts
CHANGED
|
@@ -12,7 +12,7 @@ import type { Snippet } from 'svelte'
|
|
|
12
12
|
// =============================================================================
|
|
13
13
|
|
|
14
14
|
/** Semantic color variant */
|
|
15
|
-
export type ButtonVariant = 'default' | 'primary' | 'secondary' | 'danger'
|
|
15
|
+
export type ButtonVariant = 'default' | 'primary' | 'secondary' | 'accent' | 'danger'
|
|
16
16
|
|
|
17
17
|
/** Visual style treatment */
|
|
18
18
|
export type ButtonStyle = 'default' | 'outline' | 'ghost' | 'gradient' | 'link'
|