@rokkit/ui 1.0.0-next.127 → 1.0.0-next.129
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 +6 -16
- package/src/components/BreadCrumbs.svelte +37 -17
- package/src/components/Button.svelte +11 -5
- package/src/components/Carousel.svelte +11 -6
- package/src/components/Code.svelte +6 -2
- package/src/components/FloatingAction.svelte +24 -21
- package/src/components/FloatingNavigation.svelte +36 -29
- package/src/components/Grid.svelte +128 -0
- package/src/components/ItemContent.svelte +21 -20
- package/src/components/LazyTree.svelte +165 -0
- package/src/components/List.svelte +146 -434
- package/src/components/Menu.svelte +195 -346
- package/src/components/MultiSelect.svelte +238 -390
- package/src/components/PaletteManager.svelte +15 -5
- package/src/components/Pill.svelte +19 -14
- package/src/components/Range.svelte +8 -3
- package/src/components/Rating.svelte +19 -9
- package/src/components/Reveal.svelte +1 -13
- package/src/components/SearchFilter.svelte +11 -3
- package/src/components/Select.svelte +265 -454
- package/src/components/Stepper.svelte +9 -6
- package/src/components/Switch.svelte +11 -11
- package/src/components/Table.svelte +0 -1
- package/src/components/Tabs.svelte +96 -172
- package/src/components/Timeline.svelte +5 -5
- package/src/components/Toggle.svelte +55 -119
- package/src/components/Toolbar.svelte +24 -23
- package/src/components/Tree.svelte +115 -584
- package/src/components/UploadFileStatus.svelte +83 -0
- package/src/components/UploadProgress.svelte +131 -0
- package/src/components/UploadTarget.svelte +124 -0
- package/src/components/index.ts +5 -0
- package/src/index.ts +6 -1
- package/src/types/button.ts +3 -0
- package/src/types/code.ts +4 -4
- package/src/types/floating-action.ts +13 -8
- package/src/types/floating-navigation.ts +14 -2
- package/src/types/index.ts +5 -3
- package/src/types/list.ts +10 -6
- package/src/types/menu.ts +38 -138
- package/src/types/palette.ts +17 -0
- package/src/types/select.ts +33 -63
- package/src/types/switch.ts +9 -5
- package/src/types/table.ts +6 -6
- package/src/types/tabs.ts +13 -34
- package/src/types/timeline.ts +5 -3
- package/src/types/toggle.ts +15 -56
- package/src/types/toolbar.ts +1 -1
- package/src/types/tree.ts +9 -18
- package/src/types/upload-file-status.ts +45 -0
- package/src/types/upload-progress.ts +111 -0
- package/src/types/upload-target.ts +68 -0
- package/src/utils/upload.js +128 -0
- package/src/types/item-proxy.ts +0 -358
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { Snippet } from 'svelte'
|
|
3
|
+
import { DEFAULT_STATE_ICONS } from '@rokkit/core'
|
|
4
|
+
import { messages } from '@rokkit/states'
|
|
3
5
|
|
|
4
6
|
interface StepperStep {
|
|
5
7
|
/** Step label (shown below circle) */
|
|
@@ -15,8 +17,8 @@
|
|
|
15
17
|
}
|
|
16
18
|
|
|
17
19
|
interface StepperIcons {
|
|
18
|
-
/** Icon class for completed state
|
|
19
|
-
|
|
20
|
+
/** Icon class for check/completed state */
|
|
21
|
+
check?: string
|
|
20
22
|
}
|
|
21
23
|
|
|
22
24
|
interface StepperProps {
|
|
@@ -41,7 +43,7 @@
|
|
|
41
43
|
}
|
|
42
44
|
|
|
43
45
|
const defaultIcons: StepperIcons = {
|
|
44
|
-
|
|
46
|
+
check: DEFAULT_STATE_ICONS.action.check
|
|
45
47
|
}
|
|
46
48
|
|
|
47
49
|
let {
|
|
@@ -50,11 +52,12 @@
|
|
|
50
52
|
currentStage = $bindable(0),
|
|
51
53
|
linear = false,
|
|
52
54
|
orientation = 'horizontal',
|
|
55
|
+
label = messages.current.stepper.label,
|
|
53
56
|
icons: userIcons,
|
|
54
57
|
onclick,
|
|
55
58
|
content,
|
|
56
59
|
class: className = ''
|
|
57
|
-
}: StepperProps = $props()
|
|
60
|
+
}: StepperProps & { label?: string } = $props()
|
|
58
61
|
|
|
59
62
|
const icons = $derived<StepperIcons>({ ...defaultIcons, ...userIcons })
|
|
60
63
|
|
|
@@ -105,7 +108,7 @@
|
|
|
105
108
|
data-orientation={orientation}
|
|
106
109
|
class={className || undefined}
|
|
107
110
|
role="group"
|
|
108
|
-
aria-label=
|
|
111
|
+
aria-label={label}
|
|
109
112
|
>
|
|
110
113
|
{#each steps as step, index (index)}
|
|
111
114
|
<!-- Connector line before step (except first) -->
|
|
@@ -133,7 +136,7 @@
|
|
|
133
136
|
onclick={() => handleStepClick(index)}
|
|
134
137
|
>
|
|
135
138
|
{#if step.completed}
|
|
136
|
-
<span class={icons.
|
|
139
|
+
<span data-stepper-check-icon class={icons.check} aria-hidden="true"></span>
|
|
137
140
|
{:else}
|
|
138
141
|
{step.label ?? index + 1}
|
|
139
142
|
{/if}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { SwitchProps, SwitchItem } from '../types/switch.js'
|
|
3
|
-
import {
|
|
3
|
+
import { ProxyItem } from '@rokkit/states'
|
|
4
4
|
|
|
5
5
|
const DEFAULT_OPTIONS: [SwitchItem, SwitchItem] = [false, true]
|
|
6
6
|
|
|
@@ -15,15 +15,15 @@
|
|
|
15
15
|
class: className = ''
|
|
16
16
|
}: SwitchProps = $props()
|
|
17
17
|
|
|
18
|
-
let offProxy = $derived(new
|
|
19
|
-
let onProxy = $derived(new
|
|
20
|
-
let isChecked = $derived(value === onProxy.
|
|
18
|
+
let offProxy = $derived(new ProxyItem(options[0], userFields))
|
|
19
|
+
let onProxy = $derived(new ProxyItem(options[1], userFields))
|
|
20
|
+
let isChecked = $derived(value === onProxy.value)
|
|
21
21
|
let currentProxy = $derived(isChecked ? onProxy : offProxy)
|
|
22
22
|
|
|
23
23
|
function toggle() {
|
|
24
24
|
if (disabled) return
|
|
25
25
|
const next = isChecked ? offProxy : onProxy
|
|
26
|
-
const nextValue = next.
|
|
26
|
+
const nextValue = next.value
|
|
27
27
|
value = nextValue
|
|
28
28
|
onchange?.(nextValue, next.original as SwitchItem)
|
|
29
29
|
}
|
|
@@ -55,8 +55,8 @@
|
|
|
55
55
|
data-switch-size={size}
|
|
56
56
|
data-switch-disabled={disabled || undefined}
|
|
57
57
|
aria-checked={isChecked}
|
|
58
|
-
aria-label={currentProxy.
|
|
59
|
-
title={currentProxy.
|
|
58
|
+
aria-label={currentProxy.label || undefined}
|
|
59
|
+
title={currentProxy.get('subtext') ?? currentProxy.label ?? undefined}
|
|
60
60
|
{disabled}
|
|
61
61
|
class={className || undefined}
|
|
62
62
|
onclick={toggle}
|
|
@@ -64,12 +64,12 @@
|
|
|
64
64
|
>
|
|
65
65
|
<span data-switch-track>
|
|
66
66
|
<span data-switch-thumb>
|
|
67
|
-
{#if currentProxy.icon}
|
|
68
|
-
<span data-switch-icon class={currentProxy.icon} aria-hidden="true"></span>
|
|
67
|
+
{#if currentProxy.get('icon')}
|
|
68
|
+
<span data-switch-icon class={currentProxy.get('icon')} aria-hidden="true"></span>
|
|
69
69
|
{/if}
|
|
70
70
|
</span>
|
|
71
71
|
</span>
|
|
72
|
-
{#if showLabels && currentProxy.
|
|
73
|
-
<span data-switch-label>{currentProxy.
|
|
72
|
+
{#if showLabels && currentProxy.label}
|
|
73
|
+
<span data-switch-label>{currentProxy.label}</span>
|
|
74
74
|
{/if}
|
|
75
75
|
</button>
|
|
@@ -1,13 +1,32 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
2
|
+
/**
|
|
3
|
+
* Tabs — Wrapper + Navigator + ProxyItem implementation.
|
|
4
|
+
*
|
|
5
|
+
* Architecture:
|
|
6
|
+
* Wrapper — owns focusedKey $state + flatView $derived
|
|
7
|
+
* Navigator — attaches DOM event handlers, calls wrapper[action](path)
|
|
8
|
+
* owns focus + scrollIntoView after every keyboard action
|
|
9
|
+
* flatView loop — single flat {#each} for tab triggers
|
|
10
|
+
*
|
|
11
|
+
* Snippet customization:
|
|
12
|
+
* itemContent — replaces inner content of <button> for tab triggers
|
|
13
|
+
* tabPanel — replaces panel content
|
|
14
|
+
* [named] — per-item override via item.snippet = 'name'; falls back to itemContent
|
|
15
|
+
* empty — rendered when no options
|
|
16
|
+
*
|
|
17
|
+
* Tab panels are rendered separately from triggers. Only the active panel
|
|
18
|
+
* receives data-panel-active. Navigator ignores panels (no data-path on them).
|
|
19
|
+
*/
|
|
20
|
+
// @ts-nocheck
|
|
21
|
+
import type { TabsProps } from '../types/tabs.js'
|
|
22
|
+
import type { ProxyItem } from '@rokkit/states'
|
|
23
|
+
import { Wrapper, ProxyTree, messages } from '@rokkit/states'
|
|
24
|
+
import { Navigator } from '@rokkit/actions'
|
|
25
|
+
import { resolveSnippet, ITEM_SNIPPET, DEFAULT_STATE_ICONS } from '@rokkit/core'
|
|
7
26
|
|
|
8
27
|
let {
|
|
9
28
|
options = [],
|
|
10
|
-
fields: userFields,
|
|
29
|
+
fields: userFields = {},
|
|
11
30
|
value = $bindable(),
|
|
12
31
|
orientation = 'horizontal',
|
|
13
32
|
position = 'before',
|
|
@@ -16,177 +35,72 @@
|
|
|
16
35
|
editable = false,
|
|
17
36
|
placeholder = 'Select a tab to view its content.',
|
|
18
37
|
disabled = false,
|
|
38
|
+
labels: userLabels = {},
|
|
19
39
|
class: className = '',
|
|
20
40
|
onchange,
|
|
21
41
|
onselect,
|
|
22
42
|
onadd,
|
|
23
43
|
onremove,
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
empty: emptySnippet
|
|
27
|
-
}: TabsProps = $props()
|
|
44
|
+
...snippets
|
|
45
|
+
}: TabsProps & { labels?: Record<string, string>; [key: string]: unknown } = $props()
|
|
28
46
|
|
|
29
|
-
|
|
30
|
-
const contentField = $derived((userFields as Record<string, string> | undefined)?.content ?? 'content')
|
|
47
|
+
const labels = $derived({ ...messages.current.tabs, ...userLabels })
|
|
31
48
|
|
|
32
|
-
|
|
33
|
-
let containerRef: HTMLElement | null = $state(null)
|
|
34
|
-
let lastSyncedValue: unknown = value
|
|
49
|
+
// ─── Wrapper ──────────────────────────────────────────────────────────────
|
|
35
50
|
|
|
36
|
-
$
|
|
37
|
-
|
|
38
|
-
})
|
|
51
|
+
const proxyTree = $derived(new ProxyTree(options, userFields))
|
|
52
|
+
const wrapper = $derived(new Wrapper(proxyTree, { onchange, onselect }))
|
|
39
53
|
|
|
40
|
-
//
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
lastSyncedValue = value
|
|
44
|
-
controller.moveToValue(value)
|
|
45
|
-
}
|
|
46
|
-
})
|
|
54
|
+
// ─── Navigator ────────────────────────────────────────────────────────────
|
|
55
|
+
|
|
56
|
+
let containerRef = $state<HTMLElement | null>(null)
|
|
47
57
|
|
|
48
|
-
// Focus the tab matching controller.focusedKey on navigator move events
|
|
49
58
|
$effect(() => {
|
|
50
59
|
if (!containerRef) return
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
function handleAction(event: Event) {
|
|
54
|
-
const detail = (event as CustomEvent).detail
|
|
55
|
-
|
|
56
|
-
if (detail.name === 'move') {
|
|
57
|
-
const key = controller.focusedKey
|
|
58
|
-
if (key) {
|
|
59
|
-
const target = el.querySelector(`[data-path="${key}"]`) as HTMLElement | null
|
|
60
|
-
if (target && target !== document.activeElement) {
|
|
61
|
-
target.focus()
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
if (detail.name === 'select') {
|
|
67
|
-
handleSelectAction()
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
el.addEventListener('action', handleAction)
|
|
72
|
-
return () => el.removeEventListener('action', handleAction)
|
|
60
|
+
const nav = new Navigator(containerRef, wrapper, { orientation })
|
|
61
|
+
return () => nav.destroy()
|
|
73
62
|
})
|
|
74
63
|
|
|
75
|
-
|
|
76
|
-
* Create an ItemProxy for the given item
|
|
77
|
-
*/
|
|
78
|
-
function createProxy(item: TabsItem): ItemProxy {
|
|
79
|
-
return new ItemProxy(item, userFields)
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* Check if an item is currently selected
|
|
84
|
-
*/
|
|
85
|
-
function isSelected(proxy: ItemProxy): boolean {
|
|
86
|
-
return proxy.itemValue === value
|
|
87
|
-
}
|
|
64
|
+
// ─── Sync external value → focused key ────────────────────────────────────
|
|
88
65
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
function handleSelectAction() {
|
|
93
|
-
const key = controller.focusedKey
|
|
94
|
-
if (!key) return
|
|
95
|
-
|
|
96
|
-
const proxy = controller.lookup.get(key)
|
|
97
|
-
if (!proxy) return
|
|
98
|
-
|
|
99
|
-
const itemProxy = createProxy(proxy.value)
|
|
100
|
-
selectTab(itemProxy)
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
/**
|
|
104
|
-
* Select a tab by its proxy
|
|
105
|
-
*/
|
|
106
|
-
function selectTab(proxy: ItemProxy) {
|
|
107
|
-
if (proxy.disabled || disabled) return
|
|
108
|
-
const itemValue = proxy.itemValue
|
|
109
|
-
if (itemValue !== value) {
|
|
110
|
-
value = itemValue
|
|
111
|
-
lastSyncedValue = itemValue
|
|
112
|
-
controller.moveToValue(itemValue)
|
|
113
|
-
onchange?.(itemValue, proxy.original as TabsItem)
|
|
114
|
-
}
|
|
115
|
-
onselect?.(itemValue, proxy.original as TabsItem)
|
|
116
|
-
}
|
|
66
|
+
$effect(() => {
|
|
67
|
+
wrapper.moveToValue(value)
|
|
68
|
+
})
|
|
117
69
|
|
|
118
|
-
|
|
119
|
-
* Handle keyboard events on individual tabs (Enter/Space)
|
|
120
|
-
*/
|
|
121
|
-
function handleKeyDown(event: KeyboardEvent, proxy: ItemProxy) {
|
|
122
|
-
if (event.key === 'Enter' || event.key === ' ') {
|
|
123
|
-
event.preventDefault()
|
|
124
|
-
selectTab(proxy)
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
/**
|
|
129
|
-
* Create handlers object for custom snippets
|
|
130
|
-
*/
|
|
131
|
-
function createHandlers(proxy: ItemProxy): TabsItemHandlers {
|
|
132
|
-
return {
|
|
133
|
-
onclick: () => selectTab(proxy),
|
|
134
|
-
onkeydown: (event: KeyboardEvent) => handleKeyDown(event, proxy)
|
|
135
|
-
}
|
|
136
|
-
}
|
|
70
|
+
// ─── Editable handlers ────────────────────────────────────────────────────
|
|
137
71
|
|
|
138
72
|
function handleAdd() {
|
|
139
73
|
onadd?.()
|
|
140
74
|
}
|
|
141
75
|
|
|
142
|
-
function handleRemove(proxy:
|
|
143
|
-
onremove?.(proxy.
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
/**
|
|
147
|
-
* Get the panel content for a tab item
|
|
148
|
-
*/
|
|
149
|
-
function getContent(item: TabsItem): unknown {
|
|
150
|
-
return item[contentField]
|
|
76
|
+
function handleRemove(proxy: ProxyItem) {
|
|
77
|
+
onremove?.(proxy.value)
|
|
151
78
|
}
|
|
152
79
|
</script>
|
|
153
80
|
|
|
154
|
-
{#snippet
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
|
173
|
-
<span
|
|
174
|
-
data-tabs-remove
|
|
175
|
-
role="button"
|
|
176
|
-
tabindex="-1"
|
|
177
|
-
aria-label="Remove tab"
|
|
178
|
-
onclick={(e) => { e.stopPropagation(); handleRemove(proxy) }}
|
|
179
|
-
onkeydown={(e) => { if (e.key === 'Enter' || e.key === ' ') { e.stopPropagation(); e.preventDefault(); handleRemove(proxy) } }}
|
|
180
|
-
>
|
|
181
|
-
<span class="i-lucide:x" aria-hidden="true"></span>
|
|
182
|
-
</span>
|
|
183
|
-
{/if}
|
|
184
|
-
</button>
|
|
81
|
+
{#snippet defaultTabContent(proxy: ProxyItem)}
|
|
82
|
+
{#if proxy.get('icon')}
|
|
83
|
+
<span data-tabs-icon class={proxy.get('icon')} aria-hidden="true"></span>
|
|
84
|
+
{/if}
|
|
85
|
+
<span data-tabs-label>{proxy.label}</span>
|
|
86
|
+
{#if editable}
|
|
87
|
+
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
|
88
|
+
<span
|
|
89
|
+
data-tabs-remove
|
|
90
|
+
role="button"
|
|
91
|
+
tabindex="-1"
|
|
92
|
+
aria-label={labels.remove}
|
|
93
|
+
onclick={(e) => { e.stopPropagation(); handleRemove(proxy) }}
|
|
94
|
+
onkeydown={(e) => { if (e.key === 'Enter' || e.key === ' ') { e.stopPropagation(); e.preventDefault(); handleRemove(proxy) } }}
|
|
95
|
+
>
|
|
96
|
+
<span class={DEFAULT_STATE_ICONS.action.close} aria-hidden="true"></span>
|
|
97
|
+
</span>
|
|
98
|
+
{/if}
|
|
185
99
|
{/snippet}
|
|
186
100
|
|
|
187
|
-
{#snippet defaultPanel(
|
|
101
|
+
{#snippet defaultPanel(proxy: ProxyItem)}
|
|
188
102
|
<div data-tabs-content>
|
|
189
|
-
{
|
|
103
|
+
{proxy.get('content')}
|
|
190
104
|
</div>
|
|
191
105
|
{/snippet}
|
|
192
106
|
|
|
@@ -204,35 +118,45 @@
|
|
|
204
118
|
data-disabled={disabled || undefined}
|
|
205
119
|
class={className || undefined}
|
|
206
120
|
aria-label={name}
|
|
207
|
-
use:navigator={{ wrapper: controller, orientation }}
|
|
208
121
|
>
|
|
209
122
|
{#if options.length === 0}
|
|
210
123
|
<div data-tabs-empty>
|
|
211
|
-
{#if
|
|
212
|
-
{@render
|
|
124
|
+
{#if snippets.empty}
|
|
125
|
+
{@render snippets.empty()}
|
|
213
126
|
{:else}
|
|
214
127
|
{@render defaultEmpty()}
|
|
215
128
|
{/if}
|
|
216
129
|
</div>
|
|
217
130
|
{:else}
|
|
218
131
|
<div data-tabs-list role="tablist" aria-orientation={orientation}>
|
|
219
|
-
{#each
|
|
220
|
-
{@const proxy =
|
|
221
|
-
{@const
|
|
222
|
-
{@const
|
|
223
|
-
{@const key = String(index)}
|
|
132
|
+
{#each wrapper.flatView as node (node.key)}
|
|
133
|
+
{@const proxy = node.proxy}
|
|
134
|
+
{@const sel = proxy.value === value}
|
|
135
|
+
{@const content = resolveSnippet(snippets, proxy, ITEM_SNIPPET)}
|
|
224
136
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
{
|
|
229
|
-
|
|
137
|
+
<button
|
|
138
|
+
type="button"
|
|
139
|
+
data-tabs-trigger
|
|
140
|
+
data-path={node.key}
|
|
141
|
+
data-selected={sel || undefined}
|
|
142
|
+
data-disabled={proxy.disabled || undefined}
|
|
143
|
+
role="tab"
|
|
144
|
+
aria-selected={sel}
|
|
145
|
+
aria-label={proxy.get('label') || proxy.label}
|
|
146
|
+
disabled={proxy.disabled || disabled}
|
|
147
|
+
>
|
|
148
|
+
{#if content}
|
|
149
|
+
{@render content(proxy, sel)}
|
|
150
|
+
{:else}
|
|
151
|
+
{@render defaultTabContent(proxy)}
|
|
152
|
+
{/if}
|
|
153
|
+
</button>
|
|
230
154
|
{/each}
|
|
231
155
|
{#if editable}
|
|
232
156
|
<button
|
|
233
157
|
type="button"
|
|
234
158
|
data-tabs-add
|
|
235
|
-
aria-label=
|
|
159
|
+
aria-label={labels.add}
|
|
236
160
|
onclick={handleAdd}
|
|
237
161
|
>
|
|
238
162
|
<span class="i-lucide:plus" aria-hidden="true"></span>
|
|
@@ -240,21 +164,21 @@
|
|
|
240
164
|
{/if}
|
|
241
165
|
</div>
|
|
242
166
|
|
|
243
|
-
{#each
|
|
244
|
-
{@const proxy =
|
|
245
|
-
{@const active =
|
|
167
|
+
{#each wrapper.flatView as node (node.key)}
|
|
168
|
+
{@const proxy = node.proxy}
|
|
169
|
+
{@const active = proxy.value === value}
|
|
246
170
|
|
|
247
171
|
<div
|
|
248
172
|
data-tabs-panel
|
|
249
173
|
data-panel-active={active || undefined}
|
|
250
174
|
role="tabpanel"
|
|
251
|
-
id="tab-panel-{
|
|
252
|
-
aria-labelledby="tab-{
|
|
175
|
+
id="tab-panel-{node.key}"
|
|
176
|
+
aria-labelledby="tab-{node.key}"
|
|
253
177
|
>
|
|
254
|
-
{#if
|
|
255
|
-
{@render
|
|
178
|
+
{#if snippets.tabPanel}
|
|
179
|
+
{@render snippets.tabPanel(proxy)}
|
|
256
180
|
{:else}
|
|
257
|
-
{@render defaultPanel(
|
|
181
|
+
{@render defaultPanel(proxy)}
|
|
258
182
|
{/if}
|
|
259
183
|
</div>
|
|
260
184
|
{/each}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { TimelineProps } from '../types/timeline.js'
|
|
3
3
|
import { defaultTimelineFields, defaultTimelineIcons } from '../types/timeline.js'
|
|
4
|
-
import {
|
|
4
|
+
import { ProxyItem } from '@rokkit/states'
|
|
5
5
|
|
|
6
6
|
let {
|
|
7
7
|
items = [],
|
|
@@ -17,10 +17,10 @@
|
|
|
17
17
|
|
|
18
18
|
<div data-timeline class={className || undefined} role="list">
|
|
19
19
|
{#each items as item, index (index)}
|
|
20
|
-
{@const proxy = new
|
|
21
|
-
{@const text = proxy.
|
|
22
|
-
{@const icon = proxy.icon}
|
|
23
|
-
{@const description = proxy.
|
|
20
|
+
{@const proxy = new ProxyItem(item, fields)}
|
|
21
|
+
{@const text = proxy.label}
|
|
22
|
+
{@const icon = proxy.get('icon')}
|
|
23
|
+
{@const description = proxy.get('subtext')}
|
|
24
24
|
{@const completed = Boolean(item.completed)}
|
|
25
25
|
{@const active = Boolean(item.active)}
|
|
26
26
|
|