@rokkit/ui 1.0.0-next.133 → 1.0.0-next.136
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/README.md +106 -166
- package/package.json +11 -5
- package/src/components/BreadCrumbs.svelte +2 -10
- package/src/components/Button.svelte +1 -3
- package/src/components/ButtonGroup.svelte +2 -11
- package/src/components/Card.svelte +1 -8
- package/src/components/Carousel.svelte +1 -5
- package/src/components/FloatingAction.svelte +5 -1
- package/src/components/FloatingNavigation.svelte +25 -17
- package/src/components/LazyTree.svelte +69 -62
- package/src/components/List.svelte +10 -7
- package/src/components/Menu.svelte +9 -8
- package/src/components/MultiSelect.svelte +14 -3
- package/src/components/PaletteManager.svelte +2 -6
- package/src/components/ProgressBar.svelte +7 -7
- package/src/components/Range.svelte +20 -18
- package/src/components/Rating.svelte +6 -2
- package/src/components/SearchFilter.svelte +2 -2
- package/src/components/Select.svelte +19 -10
- package/src/components/Stepper.svelte +4 -2
- package/src/components/Table.svelte +17 -24
- package/src/components/Tabs.svelte +21 -9
- package/src/components/Tree.svelte +53 -53
- package/src/components/UploadFileStatus.svelte +25 -6
- package/src/components/UploadProgress.svelte +2 -6
- package/src/components/UploadTarget.svelte +1 -1
- package/src/utils/palette.ts +37 -5
- package/src/utils/upload.js +4 -1
|
@@ -49,13 +49,15 @@
|
|
|
49
49
|
|
|
50
50
|
const icons = $derived({ ...DEFAULT_STATE_ICONS.folder, ...userIcons })
|
|
51
51
|
|
|
52
|
-
|
|
53
52
|
const proxyTree = $derived(
|
|
54
53
|
new ProxyTree(items, fields, {
|
|
55
54
|
createProxy: (raw, f, key, level) =>
|
|
56
|
-
new LazyProxyItem(
|
|
57
|
-
|
|
58
|
-
|
|
55
|
+
new LazyProxyItem(
|
|
56
|
+
raw,
|
|
57
|
+
f,
|
|
58
|
+
key,
|
|
59
|
+
level,
|
|
60
|
+
onlazyload ? async (_value, rawItem) => onlazyload(rawItem) : null
|
|
59
61
|
)
|
|
60
62
|
})
|
|
61
63
|
)
|
|
@@ -93,73 +95,78 @@
|
|
|
93
95
|
{@const content = resolveSnippet(snippets, proxy, ITEM_SNIPPET)}
|
|
94
96
|
|
|
95
97
|
<div
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
<button
|
|
112
|
-
type="button"
|
|
113
|
-
data-tree-toggle-btn
|
|
114
|
-
onclick={() => wrapper.toggle(node.key)}
|
|
115
|
-
aria-label={isLoading ? labels.loading : proxy.expanded ? labels.collapse : labels.expand}
|
|
116
|
-
tabindex={-1}
|
|
117
|
-
>
|
|
118
|
-
{#if isLoading}
|
|
119
|
-
<span data-tree-spinner aria-hidden="true"></span>
|
|
120
|
-
{:else}
|
|
121
|
-
<span class={proxy.expanded ? icons.opened : icons.closed} aria-hidden="true"></span>
|
|
122
|
-
{/if}
|
|
123
|
-
</button>
|
|
124
|
-
{:else}
|
|
125
|
-
<Connector type={lineType} />
|
|
126
|
-
{/if}
|
|
127
|
-
{/each}
|
|
128
|
-
|
|
129
|
-
{#if proxy.get('href')}
|
|
130
|
-
<a
|
|
131
|
-
href={proxy.get('href')}
|
|
132
|
-
data-tree-item-content
|
|
133
|
-
data-path={node.key}
|
|
134
|
-
data-active={isActive || undefined}
|
|
135
|
-
aria-label={proxy.label}
|
|
136
|
-
aria-current={isActive ? 'page' : undefined}
|
|
137
|
-
>
|
|
138
|
-
{#if content}
|
|
139
|
-
{@render content(proxy)}
|
|
140
|
-
{:else}
|
|
141
|
-
<ItemContent {proxy} showIcon={!node.isExpandable} showSubtext={false} />
|
|
142
|
-
{/if}
|
|
143
|
-
</a>
|
|
144
|
-
{:else}
|
|
98
|
+
data-tree-node
|
|
99
|
+
data-tree-path={node.key}
|
|
100
|
+
data-tree-level={node.level - 1}
|
|
101
|
+
data-tree-has-children={node.isExpandable || undefined}
|
|
102
|
+
data-tree-loading={isLoading || undefined}
|
|
103
|
+
data-active={isActive || undefined}
|
|
104
|
+
role="treeitem"
|
|
105
|
+
aria-expanded={node.isExpandable ? proxy.expanded : undefined}
|
|
106
|
+
aria-selected={isActive}
|
|
107
|
+
aria-busy={isLoading || undefined}
|
|
108
|
+
aria-level={node.level}
|
|
109
|
+
>
|
|
110
|
+
<div data-tree-node-row>
|
|
111
|
+
{#each node.lineTypes as lineType, lineIndex (lineIndex)}
|
|
112
|
+
{#if lineType === 'icon'}
|
|
145
113
|
<button
|
|
146
114
|
type="button"
|
|
147
|
-
data-tree-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
115
|
+
data-tree-toggle-btn
|
|
116
|
+
onclick={() => wrapper.toggle(node.key)}
|
|
117
|
+
aria-label={isLoading
|
|
118
|
+
? labels.loading
|
|
119
|
+
: proxy.expanded
|
|
120
|
+
? labels.collapse
|
|
121
|
+
: labels.expand}
|
|
122
|
+
tabindex={-1}
|
|
151
123
|
>
|
|
152
|
-
{#if
|
|
153
|
-
|
|
124
|
+
{#if isLoading}
|
|
125
|
+
<span data-tree-spinner aria-hidden="true"></span>
|
|
154
126
|
{:else}
|
|
155
|
-
<
|
|
127
|
+
<span class={proxy.expanded ? icons.opened : icons.closed} aria-hidden="true"
|
|
128
|
+
></span>
|
|
156
129
|
{/if}
|
|
157
130
|
</button>
|
|
131
|
+
{:else}
|
|
132
|
+
<Connector type={lineType} />
|
|
158
133
|
{/if}
|
|
159
|
-
|
|
134
|
+
{/each}
|
|
135
|
+
|
|
136
|
+
{#if proxy.get('href')}
|
|
137
|
+
<a
|
|
138
|
+
href={proxy.get('href')}
|
|
139
|
+
data-tree-item-content
|
|
140
|
+
data-path={node.key}
|
|
141
|
+
data-active={isActive || undefined}
|
|
142
|
+
aria-label={proxy.label}
|
|
143
|
+
aria-current={isActive ? 'page' : undefined}
|
|
144
|
+
>
|
|
145
|
+
{#if content}
|
|
146
|
+
{@render content(proxy)}
|
|
147
|
+
{:else}
|
|
148
|
+
<ItemContent {proxy} showIcon={!node.isExpandable} showSubtext={false} />
|
|
149
|
+
{/if}
|
|
150
|
+
</a>
|
|
151
|
+
{:else}
|
|
152
|
+
<button
|
|
153
|
+
type="button"
|
|
154
|
+
data-tree-item-content
|
|
155
|
+
data-path={node.key}
|
|
156
|
+
data-active={isActive || undefined}
|
|
157
|
+
aria-label={proxy.label}
|
|
158
|
+
>
|
|
159
|
+
{#if content}
|
|
160
|
+
{@render content(proxy)}
|
|
161
|
+
{:else}
|
|
162
|
+
<ItemContent {proxy} showIcon={!node.isExpandable} showSubtext={false} />
|
|
163
|
+
{/if}
|
|
164
|
+
</button>
|
|
165
|
+
{/if}
|
|
160
166
|
</div>
|
|
167
|
+
</div>
|
|
161
168
|
{/each}
|
|
162
169
|
{#if hasMore}
|
|
163
|
-
<Button label={labels.loadMore} style="ghost"
|
|
170
|
+
<Button label={labels.loadMore} style="ghost" {size} onclick={() => wrapper.loadMore()} />
|
|
164
171
|
{/if}
|
|
165
172
|
</div>
|
|
@@ -87,11 +87,10 @@
|
|
|
87
87
|
$effect(() => {
|
|
88
88
|
wrapper.moveToValue(value)
|
|
89
89
|
})
|
|
90
|
-
|
|
91
90
|
</script>
|
|
92
91
|
|
|
93
92
|
{#snippet collapsibleIcon(proxy: ProxyItem)}
|
|
94
|
-
|
|
93
|
+
{#if collapsible && proxy.hasChildren}
|
|
95
94
|
<span
|
|
96
95
|
data-list-expand-icon
|
|
97
96
|
class={proxy.expanded ? icons.opened : icons.closed}
|
|
@@ -113,7 +112,11 @@
|
|
|
113
112
|
{#each wrapper.flatView as node (node.key)}
|
|
114
113
|
{@const proxy = node.proxy}
|
|
115
114
|
{@const isActive = proxy.value === value}
|
|
116
|
-
{@const content = resolveSnippet(
|
|
115
|
+
{@const content = resolveSnippet(
|
|
116
|
+
snippets as Record<string, unknown>,
|
|
117
|
+
proxy,
|
|
118
|
+
node.hasChildren ? GROUP_SNIPPET : ITEM_SNIPPET
|
|
119
|
+
)}
|
|
117
120
|
|
|
118
121
|
{#if node.type === 'separator'}
|
|
119
122
|
<hr data-list-separator />
|
|
@@ -137,10 +140,10 @@
|
|
|
137
140
|
{#if content}
|
|
138
141
|
{@render content(proxy)}
|
|
139
142
|
{:else}
|
|
140
|
-
|
|
143
|
+
<ItemContent {proxy} />
|
|
141
144
|
{/if}
|
|
142
145
|
|
|
143
|
-
|
|
146
|
+
{@render collapsibleIcon(proxy)}
|
|
144
147
|
</button>
|
|
145
148
|
{:else if proxy.get('href')}
|
|
146
149
|
<!--
|
|
@@ -159,7 +162,7 @@
|
|
|
159
162
|
{#if content}
|
|
160
163
|
{@render content(proxy)}
|
|
161
164
|
{:else}
|
|
162
|
-
|
|
165
|
+
<ItemContent {proxy} />
|
|
163
166
|
{/if}
|
|
164
167
|
</a>
|
|
165
168
|
{:else}
|
|
@@ -180,7 +183,7 @@
|
|
|
180
183
|
{#if content}
|
|
181
184
|
{@render content(proxy)}
|
|
182
185
|
{:else}
|
|
183
|
-
|
|
186
|
+
<ItemContent {proxy} />
|
|
184
187
|
{/if}
|
|
185
188
|
</button>
|
|
186
189
|
{/if}
|
|
@@ -137,7 +137,9 @@
|
|
|
137
137
|
isOpen = true
|
|
138
138
|
requestAnimationFrame(() => wrapper.first(null))
|
|
139
139
|
},
|
|
140
|
-
onclose: () => {
|
|
140
|
+
onclose: () => {
|
|
141
|
+
isOpen = false
|
|
142
|
+
},
|
|
141
143
|
onlast: () => requestAnimationFrame(() => wrapper.last(null))
|
|
142
144
|
})
|
|
143
145
|
return () => t.destroy()
|
|
@@ -213,16 +215,15 @@
|
|
|
213
215
|
|
|
214
216
|
{#if isOpen}
|
|
215
217
|
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
|
216
|
-
<div
|
|
217
|
-
bind:this={dropdownRef}
|
|
218
|
-
data-menu-dropdown
|
|
219
|
-
role="menu"
|
|
220
|
-
aria-orientation="vertical"
|
|
221
|
-
>
|
|
218
|
+
<div bind:this={dropdownRef} data-menu-dropdown role="menu" aria-orientation="vertical">
|
|
222
219
|
{#each wrapper.flatView as node (node.key)}
|
|
223
220
|
{@const proxy = node.proxy}
|
|
224
221
|
{@const isActive = proxy.value === value}
|
|
225
|
-
{@const content = resolveSnippet(
|
|
222
|
+
{@const content = resolveSnippet(
|
|
223
|
+
snippets as Record<string, unknown>,
|
|
224
|
+
proxy,
|
|
225
|
+
node.hasChildren ? GROUP_SNIPPET : ITEM_SNIPPET
|
|
226
|
+
)}
|
|
226
227
|
|
|
227
228
|
{#if node.type === 'separator'}
|
|
228
229
|
<hr data-menu-separator />
|
|
@@ -70,7 +70,12 @@
|
|
|
70
70
|
[key: string]: unknown
|
|
71
71
|
} = $props()
|
|
72
72
|
|
|
73
|
-
const icons = $derived({
|
|
73
|
+
const icons = $derived({
|
|
74
|
+
...DEFAULT_STATE_ICONS.selector,
|
|
75
|
+
...DEFAULT_STATE_ICONS.checkbox,
|
|
76
|
+
...DEFAULT_STATE_ICONS.action,
|
|
77
|
+
...userIcons
|
|
78
|
+
})
|
|
74
79
|
|
|
75
80
|
// ─── Dropdown state ───────────────────────────────────────────────────────
|
|
76
81
|
|
|
@@ -198,7 +203,9 @@
|
|
|
198
203
|
isOpen = true
|
|
199
204
|
requestAnimationFrame(() => wrapper.first(null))
|
|
200
205
|
},
|
|
201
|
-
onclose: () => {
|
|
206
|
+
onclose: () => {
|
|
207
|
+
isOpen = false
|
|
208
|
+
},
|
|
202
209
|
onlast: () => requestAnimationFrame(() => wrapper.last(null))
|
|
203
210
|
})
|
|
204
211
|
return () => t.destroy()
|
|
@@ -322,7 +329,11 @@
|
|
|
322
329
|
{#each wrapper.flatView as node (node.key)}
|
|
323
330
|
{@const proxy = node.proxy}
|
|
324
331
|
{@const sel = !node.hasChildren && isItemSelected(proxy.value)}
|
|
325
|
-
{@const content = resolveSnippet(
|
|
332
|
+
{@const content = resolveSnippet(
|
|
333
|
+
snippets as Record<string, unknown>,
|
|
334
|
+
proxy,
|
|
335
|
+
node.hasChildren ? GROUP_SNIPPET : ITEM_SNIPPET
|
|
336
|
+
)}
|
|
326
337
|
|
|
327
338
|
{#if node.type === 'separator'}
|
|
328
339
|
<hr data-select-separator />
|
|
@@ -117,7 +117,7 @@
|
|
|
117
117
|
|
|
118
118
|
// Add # if missing
|
|
119
119
|
if (hex && !hex.startsWith('#')) {
|
|
120
|
-
hex = `#${
|
|
120
|
+
hex = `#${hex}`
|
|
121
121
|
}
|
|
122
122
|
|
|
123
123
|
hexInputs[role] = hex
|
|
@@ -278,11 +278,7 @@
|
|
|
278
278
|
</div>
|
|
279
279
|
{/snippet}
|
|
280
280
|
|
|
281
|
-
<div
|
|
282
|
-
data-palette-manager
|
|
283
|
-
data-compact={compact || undefined}
|
|
284
|
-
class={className || undefined}
|
|
285
|
-
>
|
|
281
|
+
<div data-palette-manager data-compact={compact || undefined} class={className || undefined}>
|
|
286
282
|
{#if showPresets && presets.length > 0}
|
|
287
283
|
<div data-palette-presets>
|
|
288
284
|
<span data-palette-presets-label>Presets</span>
|
|
@@ -8,14 +8,14 @@
|
|
|
8
8
|
class?: string
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
const {
|
|
12
|
-
value = null,
|
|
13
|
-
max = 100,
|
|
14
|
-
class: className = ''
|
|
15
|
-
}: ProgressBarProps = $props()
|
|
11
|
+
const { value = null, max = 100, class: className = '' }: ProgressBarProps = $props()
|
|
16
12
|
|
|
17
|
-
const indeterminate = $derived(
|
|
18
|
-
|
|
13
|
+
const indeterminate = $derived(
|
|
14
|
+
value === null || value === undefined || max === null || max === undefined
|
|
15
|
+
)
|
|
16
|
+
const percentage = $derived(
|
|
17
|
+
indeterminate ? 100 : Math.min(100, Math.max(0, (value! / max!) * 100))
|
|
18
|
+
)
|
|
19
19
|
</script>
|
|
20
20
|
|
|
21
21
|
<div
|
|
@@ -62,9 +62,7 @@
|
|
|
62
62
|
|
|
63
63
|
let selectedLeft = $derived(rangeMode ? valueToPercent(lower) : 0)
|
|
64
64
|
let selectedWidth = $derived(
|
|
65
|
-
rangeMode
|
|
66
|
-
? valueToPercent(upper) - valueToPercent(lower)
|
|
67
|
-
: valueToPercent(value)
|
|
65
|
+
rangeMode ? valueToPercent(upper) - valueToPercent(lower) : valueToPercent(value)
|
|
68
66
|
)
|
|
69
67
|
|
|
70
68
|
// ─── Ticks ──────────────────────────────────────────────────────
|
|
@@ -87,7 +85,11 @@
|
|
|
87
85
|
if (disabled || trackWidth === 0) return
|
|
88
86
|
const dx = event.detail.dx as number
|
|
89
87
|
const currentPx = inverseLerp(rangeMode ? upper : value, min, max) * trackWidth
|
|
90
|
-
const newPx = clamp(
|
|
88
|
+
const newPx = clamp(
|
|
89
|
+
currentPx + dx,
|
|
90
|
+
rangeMode ? inverseLerp(lower, min, max) * trackWidth : 0,
|
|
91
|
+
trackWidth
|
|
92
|
+
)
|
|
91
93
|
const raw = pixelToValue(newPx)
|
|
92
94
|
const snapped = snapToStep(clamp(raw, rangeMode ? lower : min, max))
|
|
93
95
|
if (rangeMode) {
|
|
@@ -243,19 +245,11 @@
|
|
|
243
245
|
</script>
|
|
244
246
|
|
|
245
247
|
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
|
246
|
-
<div
|
|
247
|
-
data-range
|
|
248
|
-
data-disabled={disabled || undefined}
|
|
249
|
-
class={className || undefined}
|
|
250
|
-
>
|
|
248
|
+
<div data-range data-disabled={disabled || undefined} class={className || undefined}>
|
|
251
249
|
<!-- svelte-ignore a11y_click_events_have_key_events -->
|
|
252
250
|
<div data-range-track onclick={handleTrackClick}>
|
|
253
251
|
<div data-range-bar bind:clientWidth={trackWidth}></div>
|
|
254
|
-
<div
|
|
255
|
-
data-range-selected
|
|
256
|
-
style:left="{selectedLeft}%"
|
|
257
|
-
style:width="{selectedWidth}%"
|
|
258
|
-
></div>
|
|
252
|
+
<div data-range-selected style:left="{selectedLeft}%" style:width="{selectedWidth}%"></div>
|
|
259
253
|
|
|
260
254
|
{#if rangeMode}
|
|
261
255
|
<!-- Lower thumb -->
|
|
@@ -270,8 +264,12 @@
|
|
|
270
264
|
onpanmove={handleLowerPanMove}
|
|
271
265
|
onpanend={handleLowerPanEnd}
|
|
272
266
|
onkeydown={handleLowerKeyDown}
|
|
273
|
-
onfocus={() => {
|
|
274
|
-
|
|
267
|
+
onfocus={() => {
|
|
268
|
+
if (!disabled) slidingLower = true
|
|
269
|
+
}}
|
|
270
|
+
onblur={() => {
|
|
271
|
+
slidingLower = false
|
|
272
|
+
}}
|
|
275
273
|
role="slider"
|
|
276
274
|
aria-valuenow={lower}
|
|
277
275
|
aria-valuemin={min}
|
|
@@ -293,8 +291,12 @@
|
|
|
293
291
|
onpanmove={handleUpperPanMove}
|
|
294
292
|
onpanend={handleUpperPanEnd}
|
|
295
293
|
onkeydown={handleUpperKeyDown}
|
|
296
|
-
onfocus={() => {
|
|
297
|
-
|
|
294
|
+
onfocus={() => {
|
|
295
|
+
if (!disabled) slidingUpper = true
|
|
296
|
+
}}
|
|
297
|
+
onblur={() => {
|
|
298
|
+
slidingUpper = false
|
|
299
|
+
}}
|
|
298
300
|
role="slider"
|
|
299
301
|
aria-valuenow={rangeMode ? upper : value}
|
|
300
302
|
aria-valuemin={rangeMode ? lower : min}
|
|
@@ -92,8 +92,12 @@
|
|
|
92
92
|
aria-checked={filled}
|
|
93
93
|
aria-label="Rate {index + 1} of {max}"
|
|
94
94
|
onclick={() => handleClick(index)}
|
|
95
|
-
onmouseenter={() => {
|
|
96
|
-
|
|
95
|
+
onmouseenter={() => {
|
|
96
|
+
if (!disabled) hoverIndex = index
|
|
97
|
+
}}
|
|
98
|
+
onmouseleave={() => {
|
|
99
|
+
hoverIndex = -1
|
|
100
|
+
}}
|
|
97
101
|
>
|
|
98
102
|
<span data-rating-icon class={filled ? icons.filled : icons.empty} aria-hidden="true"></span>
|
|
99
103
|
</span>
|
|
@@ -84,7 +84,11 @@
|
|
|
84
84
|
[key: string]: unknown
|
|
85
85
|
} = $props()
|
|
86
86
|
|
|
87
|
-
const icons = $derived({
|
|
87
|
+
const icons = $derived({
|
|
88
|
+
...DEFAULT_STATE_ICONS.selector,
|
|
89
|
+
...DEFAULT_STATE_ICONS.checkbox,
|
|
90
|
+
...userIcons
|
|
91
|
+
})
|
|
88
92
|
|
|
89
93
|
// ─── Dropdown state ───────────────────────────────────────────────────────
|
|
90
94
|
|
|
@@ -109,11 +113,17 @@
|
|
|
109
113
|
const children = item[childrenField]
|
|
110
114
|
if (Array.isArray(children) && children.length > 0) {
|
|
111
115
|
const matching = children.filter((child) =>
|
|
112
|
-
String(child[textField] ?? '')
|
|
116
|
+
String(child[textField] ?? '')
|
|
117
|
+
.toLowerCase()
|
|
118
|
+
.includes(query)
|
|
113
119
|
)
|
|
114
120
|
return matching.length > 0 ? { ...item, [childrenField]: matching } : null
|
|
115
121
|
}
|
|
116
|
-
return String(item[textField] ?? '')
|
|
122
|
+
return String(item[textField] ?? '')
|
|
123
|
+
.toLowerCase()
|
|
124
|
+
.includes(query)
|
|
125
|
+
? item
|
|
126
|
+
: null
|
|
117
127
|
})
|
|
118
128
|
.filter(Boolean)
|
|
119
129
|
})
|
|
@@ -325,12 +335,7 @@
|
|
|
325
335
|
|
|
326
336
|
{#if isOpen}
|
|
327
337
|
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
|
328
|
-
<div
|
|
329
|
-
bind:this={dropdownRef}
|
|
330
|
-
data-select-dropdown
|
|
331
|
-
role="listbox"
|
|
332
|
-
aria-orientation="vertical"
|
|
333
|
-
>
|
|
338
|
+
<div bind:this={dropdownRef} data-select-dropdown role="listbox" aria-orientation="vertical">
|
|
334
339
|
{#if filterable}
|
|
335
340
|
<div data-select-filter>
|
|
336
341
|
<!-- svelte-ignore a11y_autofocus -->
|
|
@@ -347,7 +352,11 @@
|
|
|
347
352
|
{#each wrapper.flatView as node (node.key)}
|
|
348
353
|
{@const proxy = node.proxy}
|
|
349
354
|
{@const sel = !node.hasChildren && proxy.value === value}
|
|
350
|
-
{@const content = resolveSnippet(
|
|
355
|
+
{@const content = resolveSnippet(
|
|
356
|
+
snippets as Record<string, unknown>,
|
|
357
|
+
proxy,
|
|
358
|
+
node.hasChildren ? GROUP_SNIPPET : ITEM_SNIPPET
|
|
359
|
+
)}
|
|
351
360
|
|
|
352
361
|
{#if node.type === 'separator'}
|
|
353
362
|
<hr data-select-separator />
|
|
@@ -151,8 +151,10 @@
|
|
|
151
151
|
<button
|
|
152
152
|
type="button"
|
|
153
153
|
data-stepper-dot
|
|
154
|
-
data-active={index === current && stageIndex === currentStage || undefined}
|
|
155
|
-
data-completed={step.completed ||
|
|
154
|
+
data-active={(index === current && stageIndex === currentStage) || undefined}
|
|
155
|
+
data-completed={step.completed ||
|
|
156
|
+
(index === current && stageIndex < currentStage) ||
|
|
157
|
+
undefined}
|
|
156
158
|
disabled={!isClickable(index)}
|
|
157
159
|
aria-label="Stage {stageIndex + 1}"
|
|
158
160
|
onclick={() => handleDotClick(index, stageIndex)}
|
|
@@ -28,11 +28,14 @@
|
|
|
28
28
|
|
|
29
29
|
// ─── Controller ─────────────────────────────────────────────────
|
|
30
30
|
|
|
31
|
-
let controller = untrack(
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
31
|
+
let controller = untrack(
|
|
32
|
+
() =>
|
|
33
|
+
new TableController(data, {
|
|
34
|
+
columns: userColumns,
|
|
35
|
+
fields: userFields,
|
|
36
|
+
value
|
|
37
|
+
})
|
|
38
|
+
)
|
|
36
39
|
let tableRef = $state<HTMLElement | null>(null)
|
|
37
40
|
|
|
38
41
|
// Sync data changes to controller
|
|
@@ -141,11 +144,7 @@
|
|
|
141
144
|
onfocusin={handleFocusIn}
|
|
142
145
|
use:navigator={{ wrapper: controller, orientation: 'vertical' }}
|
|
143
146
|
>
|
|
144
|
-
<table
|
|
145
|
-
role="grid"
|
|
146
|
-
aria-label={caption}
|
|
147
|
-
data-striped={striped || undefined}
|
|
148
|
-
>
|
|
147
|
+
<table role="grid" aria-label={caption} data-striped={striped || undefined}>
|
|
149
148
|
{#if caption}
|
|
150
149
|
<caption data-table-caption>{caption}</caption>
|
|
151
150
|
{/if}
|
|
@@ -162,7 +161,11 @@
|
|
|
162
161
|
data-sortable={column.sortable !== false || undefined}
|
|
163
162
|
data-sort-order={column.sorted ?? 'none'}
|
|
164
163
|
scope="col"
|
|
165
|
-
aria-sort={column.sorted === 'ascending'
|
|
164
|
+
aria-sort={column.sorted === 'ascending'
|
|
165
|
+
? 'ascending'
|
|
166
|
+
: column.sorted === 'descending'
|
|
167
|
+
? 'descending'
|
|
168
|
+
: 'none'}
|
|
166
169
|
style:width={column.width}
|
|
167
170
|
style:text-align={column.align}
|
|
168
171
|
onclick={(e) => handleSort(e, column)}
|
|
@@ -188,9 +191,7 @@
|
|
|
188
191
|
</tr>
|
|
189
192
|
{:else}
|
|
190
193
|
<tr data-table-empty-row>
|
|
191
|
-
<td data-table-empty colspan={controller.columns.length}>
|
|
192
|
-
No data
|
|
193
|
-
</td>
|
|
194
|
+
<td data-table-empty colspan={controller.columns.length}> No data </td>
|
|
194
195
|
</tr>
|
|
195
196
|
{/if}
|
|
196
197
|
{:else}
|
|
@@ -212,20 +213,12 @@
|
|
|
212
213
|
>
|
|
213
214
|
{#each controller.columns as column (column.name)}
|
|
214
215
|
{#if cellSnippet}
|
|
215
|
-
<td
|
|
216
|
-
data-table-cell
|
|
217
|
-
data-column={column.name}
|
|
218
|
-
style:text-align={column.align}
|
|
219
|
-
>
|
|
216
|
+
<td data-table-cell data-column={column.name} style:text-align={column.align}>
|
|
220
217
|
{@render cellSnippet(getCellValue(row, column), column, row)}
|
|
221
218
|
</td>
|
|
222
219
|
{:else}
|
|
223
220
|
{@const cellIcon = getCellIcon(row, column)}
|
|
224
|
-
<td
|
|
225
|
-
data-table-cell
|
|
226
|
-
data-column={column.name}
|
|
227
|
-
style:text-align={column.align}
|
|
228
|
-
>
|
|
221
|
+
<td data-table-cell data-column={column.name} style:text-align={column.align}>
|
|
229
222
|
{#if cellIcon}
|
|
230
223
|
<span data-cell-icon class={cellIcon} aria-hidden="true"></span>
|
|
231
224
|
{/if}
|
|
@@ -49,7 +49,15 @@
|
|
|
49
49
|
// ─── Wrapper ──────────────────────────────────────────────────────────────
|
|
50
50
|
|
|
51
51
|
const proxyTree = $derived(new ProxyTree(options, userFields))
|
|
52
|
-
const wrapper = $derived(
|
|
52
|
+
const wrapper = $derived(
|
|
53
|
+
new Wrapper(proxyTree, {
|
|
54
|
+
onchange,
|
|
55
|
+
onselect: (v, proxy) => {
|
|
56
|
+
value = v
|
|
57
|
+
onselect?.(v, proxy)
|
|
58
|
+
}
|
|
59
|
+
})
|
|
60
|
+
)
|
|
53
61
|
|
|
54
62
|
// ─── Navigator ────────────────────────────────────────────────────────────
|
|
55
63
|
|
|
@@ -90,8 +98,17 @@
|
|
|
90
98
|
role="button"
|
|
91
99
|
tabindex="-1"
|
|
92
100
|
aria-label={labels.remove}
|
|
93
|
-
onclick={(e) => {
|
|
94
|
-
|
|
101
|
+
onclick={(e) => {
|
|
102
|
+
e.stopPropagation()
|
|
103
|
+
handleRemove(proxy)
|
|
104
|
+
}}
|
|
105
|
+
onkeydown={(e) => {
|
|
106
|
+
if (e.key === 'Enter' || e.key === ' ') {
|
|
107
|
+
e.stopPropagation()
|
|
108
|
+
e.preventDefault()
|
|
109
|
+
handleRemove(proxy)
|
|
110
|
+
}
|
|
111
|
+
}}
|
|
95
112
|
>
|
|
96
113
|
<span class={DEFAULT_STATE_ICONS.action.close} aria-hidden="true"></span>
|
|
97
114
|
</span>
|
|
@@ -153,12 +170,7 @@
|
|
|
153
170
|
</button>
|
|
154
171
|
{/each}
|
|
155
172
|
{#if editable}
|
|
156
|
-
<button
|
|
157
|
-
type="button"
|
|
158
|
-
data-tabs-add
|
|
159
|
-
aria-label={labels.add}
|
|
160
|
-
onclick={handleAdd}
|
|
161
|
-
>
|
|
173
|
+
<button type="button" data-tabs-add aria-label={labels.add} onclick={handleAdd}>
|
|
162
174
|
<span class="i-lucide:plus" aria-hidden="true"></span>
|
|
163
175
|
</button>
|
|
164
176
|
{/if}
|