@rokkit/ui 1.0.0-next.125 → 1.0.0-next.127
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 +198 -101
- package/package.json +52 -34
- package/src/components/BreadCrumbs.svelte +82 -0
- package/src/components/Button.svelte +87 -0
- package/src/components/ButtonGroup.svelte +18 -0
- package/src/components/Card.svelte +61 -0
- package/src/components/Carousel.svelte +169 -0
- package/src/components/Code.svelte +185 -0
- package/src/components/Connector.svelte +46 -0
- package/src/components/FloatingAction.svelte +331 -0
- package/src/components/FloatingNavigation.svelte +228 -0
- package/src/components/ItemContent.svelte +24 -0
- package/src/components/List.svelte +476 -0
- package/src/components/Menu.svelte +421 -0
- package/src/components/MultiSelect.svelte +521 -0
- package/src/components/PaletteManager.svelte +354 -0
- package/src/components/Pill.svelte +78 -0
- package/src/components/ProgressBar.svelte +31 -0
- package/src/components/Range.svelte +325 -0
- package/src/components/Rating.svelte +91 -0
- package/src/components/Reveal.svelte +58 -0
- package/src/components/SearchFilter.svelte +80 -0
- package/src/components/Select.svelte +585 -0
- package/src/{Shine.svelte → components/Shine.svelte} +29 -21
- package/src/components/Stepper.svelte +169 -0
- package/src/components/Switch.svelte +75 -0
- package/src/components/Table.svelte +243 -0
- package/src/components/Tabs.svelte +268 -0
- package/src/components/Tilt.svelte +68 -0
- package/src/components/Timeline.svelte +61 -0
- package/src/components/Toggle.svelte +157 -0
- package/src/components/Toolbar.svelte +307 -0
- package/src/components/ToolbarGroup.svelte +17 -0
- package/src/components/Tree.svelte +613 -0
- package/src/components/index.ts +33 -0
- package/src/index.ts +41 -0
- package/src/types/button.ts +83 -0
- package/src/types/code.ts +46 -0
- package/src/types/floating-action.ts +118 -0
- package/src/types/floating-navigation.ts +68 -0
- package/src/types/index.ts +53 -0
- package/src/types/item-proxy.ts +358 -0
- package/src/types/list.ts +196 -0
- package/src/types/menu.ts +195 -0
- package/src/types/palette.ts +143 -0
- package/src/types/range.ts +51 -0
- package/src/types/search-filter.ts +67 -0
- package/src/types/select.ts +206 -0
- package/src/types/switch.ts +64 -0
- package/src/types/table.ts +210 -0
- package/src/types/tabs.ts +124 -0
- package/src/types/timeline.ts +51 -0
- package/src/types/toggle.ts +109 -0
- package/src/types/toolbar.ts +164 -0
- package/src/types/tree.ts +259 -0
- package/src/utils/palette.ts +582 -0
- package/src/utils/shiki.ts +122 -0
- package/dist/constants.d.ts +0 -2
- package/dist/index.d.ts +0 -41
- package/dist/lib/fields.d.ts +0 -16
- package/dist/lib/form.d.ts +0 -95
- package/dist/lib/index.d.ts +0 -6
- package/dist/lib/layout.d.ts +0 -7
- package/dist/lib/nested.d.ts +0 -48
- package/dist/lib/schema.d.ts +0 -7
- package/dist/lib/select.d.ts +0 -8
- package/dist/lib/tree.d.ts +0 -9
- package/dist/tree/List.spec.svelte.d.ts +0 -1
- package/dist/tree/Node.spec.svelte.d.ts +0 -1
- package/dist/tree/Root.spec.svelte.d.ts +0 -1
- package/dist/types.d.ts +0 -5
- package/dist/wrappers/index.d.ts +0 -3
- package/src/Accordion.svelte +0 -118
- package/src/BreadCrumbs.svelte +0 -32
- package/src/Button.svelte +0 -57
- package/src/Calendar.svelte +0 -93
- package/src/Card.svelte +0 -45
- package/src/Carousel.svelte +0 -49
- package/src/CheckBox.svelte +0 -56
- package/src/Connector.svelte +0 -40
- package/src/DropDown.svelte +0 -68
- package/src/DropSearch.svelte +0 -37
- package/src/Fillable.svelte +0 -19
- package/src/GraphPaper.svelte +0 -43
- package/src/Icon.svelte +0 -81
- package/src/Item.svelte +0 -25
- package/src/Link.svelte +0 -21
- package/src/List.svelte +0 -89
- package/src/ListBody.svelte +0 -43
- package/src/Message.svelte +0 -11
- package/src/MultiSelect.svelte +0 -48
- package/src/NestedList.svelte +0 -78
- package/src/NestedPaginator.svelte +0 -63
- package/src/Node.svelte +0 -76
- package/src/Overlay.svelte +0 -21
- package/src/PageNavigator.svelte +0 -94
- package/src/PickOne.svelte +0 -60
- package/src/Pill.svelte +0 -41
- package/src/ProgressBar.svelte +0 -21
- package/src/ProgressDots.svelte +0 -53
- package/src/RadioGroup.svelte +0 -52
- package/src/Range.svelte +0 -45
- package/src/RangeMinMax.svelte +0 -124
- package/src/RangeSlider.svelte +0 -79
- package/src/RangeTick.svelte +0 -28
- package/src/Rating.svelte +0 -95
- package/src/ResponsiveGrid.svelte +0 -88
- package/src/Scrollable.svelte +0 -7
- package/src/Select.svelte +0 -114
- package/src/Separator.svelte +0 -1
- package/src/Slider.svelte +0 -14
- package/src/SlidingColumns.svelte +0 -50
- package/src/Stage.svelte +0 -41
- package/src/Stepper.svelte +0 -66
- package/src/Summary.svelte +0 -22
- package/src/Switch.svelte +0 -106
- package/src/TableCell.svelte +0 -51
- package/src/TableHeaderCell.svelte +0 -54
- package/src/Tabs.svelte +0 -176
- package/src/Tilt.svelte +0 -66
- package/src/Toggle.svelte +0 -58
- package/src/ToggleThemeMode.svelte +0 -23
- package/src/Tree.svelte +0 -80
- package/src/TreeTable.svelte +0 -171
- package/src/ValidationReport.svelte +0 -23
- package/src/constants.js +0 -4
- package/src/index.js +0 -48
- package/src/lib/fields.js +0 -118
- package/src/lib/form.js +0 -72
- package/src/lib/index.js +0 -13
- package/src/lib/layout.js +0 -63
- package/src/lib/nested.js +0 -192
- package/src/lib/schema.js +0 -32
- package/src/lib/select.js +0 -38
- package/src/lib/tree.js +0 -22
- package/src/tree/List.spec.svelte.js +0 -84
- package/src/tree/List.svelte +0 -78
- package/src/tree/Node.spec.svelte.js +0 -104
- package/src/tree/Node.svelte +0 -80
- package/src/tree/Root.spec.svelte.js +0 -63
- package/src/tree/Root.svelte +0 -81
- package/src/types.js +0 -9
- package/src/wrappers/Category.svelte +0 -27
- package/src/wrappers/Section.svelte +0 -16
- package/src/wrappers/Wrapper.svelte +0 -12
- package/src/wrappers/index.js +0 -3
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ItemProxy - A class that wraps an item with field mapping
|
|
3
|
+
*
|
|
4
|
+
* Provides a clean API for accessing mapped fields from data items.
|
|
5
|
+
* Based on the rokkit Proxy pattern from @rokkit/states.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Common fields configuration for data-driven components.
|
|
10
|
+
* Supports menu, toolbar, list, and other list-like components.
|
|
11
|
+
*/
|
|
12
|
+
export interface ItemFields {
|
|
13
|
+
/** Field for display text - default: 'text' */
|
|
14
|
+
text?: string
|
|
15
|
+
|
|
16
|
+
/** Field for the value to emit on select/click - default: 'value' */
|
|
17
|
+
value?: string
|
|
18
|
+
|
|
19
|
+
/** Field for icon class name - default: 'icon' */
|
|
20
|
+
icon?: string
|
|
21
|
+
|
|
22
|
+
/** Field for secondary descriptive text - default: 'description' */
|
|
23
|
+
description?: string
|
|
24
|
+
|
|
25
|
+
/** Field for keyboard shortcut display - default: 'shortcut' */
|
|
26
|
+
shortcut?: string
|
|
27
|
+
|
|
28
|
+
/** Field for aria-label override - default: 'label' */
|
|
29
|
+
label?: string
|
|
30
|
+
|
|
31
|
+
/** Field for disabled state - default: 'disabled' */
|
|
32
|
+
disabled?: string
|
|
33
|
+
|
|
34
|
+
/** Field for active/pressed state - default: 'active' */
|
|
35
|
+
active?: string
|
|
36
|
+
|
|
37
|
+
/** Field for item type - default: 'type' */
|
|
38
|
+
type?: string
|
|
39
|
+
|
|
40
|
+
/** Field for children array (for grouping) - default: 'children' */
|
|
41
|
+
children?: string
|
|
42
|
+
|
|
43
|
+
/** Field for custom snippet name - default: 'snippet' */
|
|
44
|
+
snippet?: string
|
|
45
|
+
|
|
46
|
+
/** Field for navigation URL (renders as link) - default: 'href' */
|
|
47
|
+
href?: string
|
|
48
|
+
|
|
49
|
+
/** Field for badge/indicator content - default: 'badge' */
|
|
50
|
+
badge?: string
|
|
51
|
+
|
|
52
|
+
/** Nested field mapping for children - default: inherits parent */
|
|
53
|
+
fields?: ItemFields
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Default field mapping values
|
|
58
|
+
*/
|
|
59
|
+
export const defaultItemFields: Required<Omit<ItemFields, 'fields'>> = {
|
|
60
|
+
text: 'text',
|
|
61
|
+
value: 'value',
|
|
62
|
+
icon: 'icon',
|
|
63
|
+
description: 'description',
|
|
64
|
+
shortcut: 'shortcut',
|
|
65
|
+
label: 'label',
|
|
66
|
+
disabled: 'disabled',
|
|
67
|
+
active: 'active',
|
|
68
|
+
type: 'type',
|
|
69
|
+
children: 'children',
|
|
70
|
+
snippet: 'snippet',
|
|
71
|
+
href: 'href',
|
|
72
|
+
badge: 'badge'
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* ItemProxy wraps a data item with field mapping for clean property access.
|
|
77
|
+
*
|
|
78
|
+
* @example
|
|
79
|
+
* ```ts
|
|
80
|
+
* const item = { name: 'Save', kbd: 'Ctrl+S', actionId: 'save' }
|
|
81
|
+
* const fields = { text: 'name', shortcut: 'kbd', value: 'actionId' }
|
|
82
|
+
* const proxy = new ItemProxy(item, fields)
|
|
83
|
+
*
|
|
84
|
+
* proxy.text // 'Save'
|
|
85
|
+
* proxy.shortcut // 'Ctrl+S'
|
|
86
|
+
* proxy.itemValue // 'save'
|
|
87
|
+
* proxy.has('icon') // false
|
|
88
|
+
* ```
|
|
89
|
+
*/
|
|
90
|
+
export class ItemProxy<T extends Record<string, unknown> = Record<string, unknown>> {
|
|
91
|
+
readonly #original: T | string | number
|
|
92
|
+
readonly #value: Record<string, unknown>
|
|
93
|
+
#fields: Required<Omit<ItemFields, 'fields'>> & { fields?: ItemFields }
|
|
94
|
+
|
|
95
|
+
constructor(value: T | string | number, fields?: ItemFields) {
|
|
96
|
+
this.#fields = this.#mergeFields(fields)
|
|
97
|
+
this.#original = value
|
|
98
|
+
|
|
99
|
+
// Normalize value to object form
|
|
100
|
+
if (typeof value === 'object' && value !== null) {
|
|
101
|
+
this.#value = value as Record<string, unknown>
|
|
102
|
+
} else {
|
|
103
|
+
this.#value = { [this.#fields.text]: value }
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Merge user fields with defaults
|
|
109
|
+
*/
|
|
110
|
+
#mergeFields(
|
|
111
|
+
fields?: ItemFields
|
|
112
|
+
): Required<Omit<ItemFields, 'fields'>> & { fields?: ItemFields } {
|
|
113
|
+
return {
|
|
114
|
+
...defaultItemFields,
|
|
115
|
+
...fields
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Get the field mapping configuration
|
|
121
|
+
*/
|
|
122
|
+
get fields(): Required<Omit<ItemFields, 'fields'>> & { fields?: ItemFields } {
|
|
123
|
+
return this.#fields
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Get the original unwrapped value
|
|
128
|
+
*/
|
|
129
|
+
get original(): T | string | number {
|
|
130
|
+
return this.#original
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Get the normalized value object
|
|
135
|
+
*/
|
|
136
|
+
get value(): Record<string, unknown> {
|
|
137
|
+
return this.#value
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Gets a mapped attribute from the item
|
|
142
|
+
*
|
|
143
|
+
* @param fieldName - Name of the field to get (e.g., 'text', 'icon', 'shortcut')
|
|
144
|
+
* @param defaultValue - Default value to return if not found
|
|
145
|
+
* @returns The attribute value or defaultValue if not found
|
|
146
|
+
*/
|
|
147
|
+
get<V = unknown>(fieldName: keyof ItemFields, defaultValue: V | null = null): V | null {
|
|
148
|
+
if (this.has(fieldName)) {
|
|
149
|
+
const mappedField = (this.#fields as Record<string, unknown>)[fieldName]
|
|
150
|
+
if (typeof mappedField === 'string') {
|
|
151
|
+
return this.#value[mappedField] as V
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
return defaultValue
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Checks if a mapped attribute exists in the item
|
|
159
|
+
*
|
|
160
|
+
* @param fieldName - Name of the field to check
|
|
161
|
+
* @returns true if the field exists and has a value
|
|
162
|
+
*/
|
|
163
|
+
has(fieldName: keyof ItemFields): boolean {
|
|
164
|
+
const mappedField = (this.#fields as Record<string, unknown>)[fieldName]
|
|
165
|
+
if (typeof mappedField !== 'string') {
|
|
166
|
+
return false
|
|
167
|
+
}
|
|
168
|
+
return (
|
|
169
|
+
mappedField in this.#value &&
|
|
170
|
+
this.#value[mappedField] !== undefined &&
|
|
171
|
+
this.#value[mappedField] !== null
|
|
172
|
+
)
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Get the display text for this item
|
|
177
|
+
*/
|
|
178
|
+
get text(): string {
|
|
179
|
+
const value = this.get<string>('text')
|
|
180
|
+
if (value !== null) return String(value)
|
|
181
|
+
|
|
182
|
+
// Fallback to common field names
|
|
183
|
+
const fallbacks = ['label', 'name', 'title', 'text']
|
|
184
|
+
for (const fallback of fallbacks) {
|
|
185
|
+
if (
|
|
186
|
+
fallback in this.#value &&
|
|
187
|
+
this.#value[fallback] !== null &&
|
|
188
|
+
this.#value[fallback] !== undefined
|
|
189
|
+
) {
|
|
190
|
+
return String(this.#value[fallback])
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// Last resort: stringify primitive
|
|
195
|
+
if (typeof this.#original !== 'object') {
|
|
196
|
+
return String(this.#original)
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
return ''
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Get the value for this item
|
|
204
|
+
*/
|
|
205
|
+
get itemValue(): unknown {
|
|
206
|
+
const value = this.get('value')
|
|
207
|
+
if (value !== null) return value
|
|
208
|
+
|
|
209
|
+
// Fallback to common field names
|
|
210
|
+
const fallbacks = ['id', 'key', 'value']
|
|
211
|
+
for (const fallback of fallbacks) {
|
|
212
|
+
if (fallback in this.#value && this.#value[fallback] !== undefined) {
|
|
213
|
+
return this.#value[fallback]
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
return this.#original
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Get the icon class for this item
|
|
222
|
+
*/
|
|
223
|
+
get icon(): string | null {
|
|
224
|
+
const icon = this.get<string>('icon')
|
|
225
|
+
return typeof icon === 'string' && icon.length > 0 ? icon : null
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Get the description for this item
|
|
230
|
+
*/
|
|
231
|
+
get description(): string | null {
|
|
232
|
+
const desc = this.get<string>('description')
|
|
233
|
+
if (desc !== null) return String(desc)
|
|
234
|
+
|
|
235
|
+
// Fallback to common field names
|
|
236
|
+
const fallbacks = ['hint', 'subtitle', 'summary']
|
|
237
|
+
for (const fallback of fallbacks) {
|
|
238
|
+
if (
|
|
239
|
+
fallback in this.#value &&
|
|
240
|
+
this.#value[fallback] !== null &&
|
|
241
|
+
this.#value[fallback] !== undefined
|
|
242
|
+
) {
|
|
243
|
+
return String(this.#value[fallback])
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
return null
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* Get the keyboard shortcut for this item
|
|
252
|
+
*/
|
|
253
|
+
get shortcut(): string | null {
|
|
254
|
+
const shortcut = this.get<string>('shortcut')
|
|
255
|
+
if (typeof shortcut === 'string' && shortcut.length > 0) {
|
|
256
|
+
return shortcut
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// Fallback to common field names
|
|
260
|
+
const fallbacks = ['kbd', 'hotkey', 'accelerator', 'keyBinding']
|
|
261
|
+
for (const fallback of fallbacks) {
|
|
262
|
+
if (
|
|
263
|
+
fallback in this.#value &&
|
|
264
|
+
this.#value[fallback] !== null &&
|
|
265
|
+
this.#value[fallback] !== undefined
|
|
266
|
+
) {
|
|
267
|
+
return String(this.#value[fallback])
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
return null
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* Get the aria-label for this item
|
|
276
|
+
*/
|
|
277
|
+
get label(): string {
|
|
278
|
+
const label = this.get<string>('label')
|
|
279
|
+
if (label !== null) return String(label)
|
|
280
|
+
return this.text
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Check if this item is disabled
|
|
285
|
+
*/
|
|
286
|
+
get disabled(): boolean {
|
|
287
|
+
return this.get('disabled') === true
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* Check if this item is active/pressed
|
|
292
|
+
*/
|
|
293
|
+
get active(): boolean {
|
|
294
|
+
return this.get('active') === true
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* Get the item type (e.g., 'button', 'toggle', 'separator', 'spacer')
|
|
299
|
+
*/
|
|
300
|
+
get itemType(): string {
|
|
301
|
+
const type = this.get<string>('type')
|
|
302
|
+
return typeof type === 'string' ? type : 'button'
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* Check if this item has children (is a group)
|
|
307
|
+
*/
|
|
308
|
+
get hasChildren(): boolean {
|
|
309
|
+
const childrenField = this.#fields.children
|
|
310
|
+
const children = this.#value[childrenField]
|
|
311
|
+
return Array.isArray(children) && children.length > 0
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/**
|
|
315
|
+
* Check if this item can load children on demand (has truthy children field that isn't an array)
|
|
316
|
+
* Convention: `children: true` means "has children, not yet loaded"
|
|
317
|
+
*/
|
|
318
|
+
get canLoadChildren(): boolean {
|
|
319
|
+
const childrenField = this.#fields.children
|
|
320
|
+
const children = this.#value[childrenField]
|
|
321
|
+
return Boolean(children) && !Array.isArray(children)
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
/**
|
|
325
|
+
* Get children array from this item
|
|
326
|
+
*/
|
|
327
|
+
get children(): Record<string, unknown>[] {
|
|
328
|
+
const childrenField = this.#fields.children
|
|
329
|
+
const children = this.#value[childrenField]
|
|
330
|
+
return Array.isArray(children) ? children : []
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
/**
|
|
334
|
+
* Get the snippet name for custom rendering, if specified
|
|
335
|
+
*/
|
|
336
|
+
get snippetName(): string | null {
|
|
337
|
+
const snippet = this.get<string>('snippet')
|
|
338
|
+
return typeof snippet === 'string' && snippet.length > 0 ? snippet : null
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
/**
|
|
342
|
+
* Create a proxy for a child item, inheriting or using nested fields
|
|
343
|
+
*/
|
|
344
|
+
createChildProxy(child: Record<string, unknown>): ItemProxy {
|
|
345
|
+
const childFields = this.#fields.fields ?? this.#fields
|
|
346
|
+
return new ItemProxy(child, childFields)
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
/**
|
|
351
|
+
* Factory function to create an ItemProxy
|
|
352
|
+
*/
|
|
353
|
+
export function createItemProxy<T extends Record<string, unknown>>(
|
|
354
|
+
item: T | string | number,
|
|
355
|
+
fields?: ItemFields
|
|
356
|
+
): ItemProxy<T> {
|
|
357
|
+
return new ItemProxy(item, fields)
|
|
358
|
+
}
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* List Component Types
|
|
3
|
+
*
|
|
4
|
+
* Provides types for the data-driven List component.
|
|
5
|
+
* Supports navigation links, button items, and grouped items with collapsible sections.
|
|
6
|
+
* Field mapping and data access is handled by ItemProxy.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { defaultStateIcons } from '@rokkit/core'
|
|
10
|
+
|
|
11
|
+
// =============================================================================
|
|
12
|
+
// Field Mapping Types
|
|
13
|
+
// =============================================================================
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Field mapping configuration for list data.
|
|
17
|
+
*/
|
|
18
|
+
export interface ListFields {
|
|
19
|
+
/** Field for display text - default: 'text' */
|
|
20
|
+
text?: string
|
|
21
|
+
|
|
22
|
+
/** Field for the value to use for selection matching - default: 'value' */
|
|
23
|
+
value?: string
|
|
24
|
+
|
|
25
|
+
/** Field for navigation URL (renders as <a>) - default: 'href' */
|
|
26
|
+
href?: string
|
|
27
|
+
|
|
28
|
+
/** Field for icon class name - default: 'icon' */
|
|
29
|
+
icon?: string
|
|
30
|
+
|
|
31
|
+
/** Field for secondary descriptive text - default: 'description' */
|
|
32
|
+
description?: string
|
|
33
|
+
|
|
34
|
+
/** Field for aria-label override - default: 'label' */
|
|
35
|
+
label?: string
|
|
36
|
+
|
|
37
|
+
/** Field for disabled state - default: 'disabled' */
|
|
38
|
+
disabled?: string
|
|
39
|
+
|
|
40
|
+
/** Field for children array (for grouping) - default: 'children' */
|
|
41
|
+
children?: string
|
|
42
|
+
|
|
43
|
+
/** Field for custom snippet name - default: 'snippet' */
|
|
44
|
+
snippet?: string
|
|
45
|
+
|
|
46
|
+
/** Field for badge/indicator content - default: 'badge' */
|
|
47
|
+
badge?: string
|
|
48
|
+
|
|
49
|
+
/** Nested field mapping for children - default: inherits parent */
|
|
50
|
+
fields?: ListFields
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Default field mapping values
|
|
55
|
+
*/
|
|
56
|
+
export const defaultListFields: Required<Omit<ListFields, 'fields'>> = {
|
|
57
|
+
text: 'text',
|
|
58
|
+
value: 'value',
|
|
59
|
+
href: 'href',
|
|
60
|
+
icon: 'icon',
|
|
61
|
+
description: 'description',
|
|
62
|
+
label: 'label',
|
|
63
|
+
disabled: 'disabled',
|
|
64
|
+
children: 'children',
|
|
65
|
+
snippet: 'snippet',
|
|
66
|
+
badge: 'badge'
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// =============================================================================
|
|
70
|
+
// List Item Types
|
|
71
|
+
// =============================================================================
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Generic list item - can be any object with mapped fields
|
|
75
|
+
*/
|
|
76
|
+
export type ListItem = Record<string, unknown>
|
|
77
|
+
|
|
78
|
+
// =============================================================================
|
|
79
|
+
// Snippet Types
|
|
80
|
+
// =============================================================================
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Handlers passed to custom item snippets
|
|
84
|
+
*/
|
|
85
|
+
export interface ListItemHandlers {
|
|
86
|
+
/** Call to trigger item selection (for button items) */
|
|
87
|
+
onclick: () => void
|
|
88
|
+
/** Forward keyboard events for accessibility */
|
|
89
|
+
onkeydown: (event: KeyboardEvent) => void
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Snippet type for rendering list items.
|
|
94
|
+
* Parameters: item, fields, handlers, isActive
|
|
95
|
+
*/
|
|
96
|
+
export type ListItemSnippet = import('svelte').Snippet<
|
|
97
|
+
[ListItem, ListFields, ListItemHandlers, boolean]
|
|
98
|
+
>
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Snippet type for rendering group labels
|
|
102
|
+
* Parameters: item (group), fields, toggleExpanded, isExpanded
|
|
103
|
+
*/
|
|
104
|
+
export type ListGroupLabelSnippet = import('svelte').Snippet<
|
|
105
|
+
[ListItem, ListFields, () => void, boolean]
|
|
106
|
+
>
|
|
107
|
+
|
|
108
|
+
// =============================================================================
|
|
109
|
+
// Component Props Types
|
|
110
|
+
// =============================================================================
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Props for the List component
|
|
114
|
+
*/
|
|
115
|
+
export interface ListProps {
|
|
116
|
+
/** Array of list items or groups */
|
|
117
|
+
items?: ListItem[]
|
|
118
|
+
|
|
119
|
+
/** Field mapping configuration */
|
|
120
|
+
fields?: ListFields
|
|
121
|
+
|
|
122
|
+
/** Currently selected value (for highlighting button items) */
|
|
123
|
+
value?: unknown
|
|
124
|
+
|
|
125
|
+
/** Size variant */
|
|
126
|
+
size?: 'sm' | 'md' | 'lg'
|
|
127
|
+
|
|
128
|
+
/** Whether the entire list is disabled */
|
|
129
|
+
disabled?: boolean
|
|
130
|
+
|
|
131
|
+
/** Whether groups can be collapsed */
|
|
132
|
+
collapsible?: boolean
|
|
133
|
+
|
|
134
|
+
/** Enable multiple item selection (Ctrl+click toggle, Shift+click range) */
|
|
135
|
+
multiselect?: boolean
|
|
136
|
+
|
|
137
|
+
/** Which groups are expanded (bindable) - keyed by group value/text */
|
|
138
|
+
expanded?: Record<string, boolean>
|
|
139
|
+
|
|
140
|
+
/** Selected items array (bindable) - populated in multiselect mode */
|
|
141
|
+
selected?: unknown[]
|
|
142
|
+
|
|
143
|
+
/** Active item value - List looks up item by this value to highlight it */
|
|
144
|
+
active?: unknown
|
|
145
|
+
|
|
146
|
+
/** Called when a button item is selected */
|
|
147
|
+
onselect?: (value: unknown, item: ListItem) => void
|
|
148
|
+
|
|
149
|
+
/** Called when selected items change in multiselect mode */
|
|
150
|
+
onselectedchange?: (selected: unknown[]) => void
|
|
151
|
+
|
|
152
|
+
/** Called when expanded state changes (for bindable expanded) */
|
|
153
|
+
onexpandedchange?: (expanded: Record<string, boolean>) => void
|
|
154
|
+
|
|
155
|
+
/** Additional CSS classes */
|
|
156
|
+
class?: string
|
|
157
|
+
|
|
158
|
+
/** Icons for list group states (expand/collapse arrow) */
|
|
159
|
+
icons?: ListStateIcons
|
|
160
|
+
|
|
161
|
+
/** Custom snippet for rendering list items */
|
|
162
|
+
item?: ListItemSnippet
|
|
163
|
+
|
|
164
|
+
/** Custom snippet for rendering group labels/headers */
|
|
165
|
+
groupLabel?: ListGroupLabelSnippet
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// =============================================================================
|
|
169
|
+
// State Icons
|
|
170
|
+
// =============================================================================
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Icons configuration for list collapsible group states.
|
|
174
|
+
* Keys match the naming convention in @rokkit/core defaultStateIcons.
|
|
175
|
+
*/
|
|
176
|
+
export interface ListStateIcons {
|
|
177
|
+
/** Icon class for expanded group */
|
|
178
|
+
opened?: string
|
|
179
|
+
/** Icon class for collapsed group */
|
|
180
|
+
closed?: string
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Default state icons — uses semantic names from @rokkit/core
|
|
185
|
+
* that get resolved to actual icon classes via UnoCSS shortcuts.
|
|
186
|
+
*/
|
|
187
|
+
export const defaultListStateIcons: ListStateIcons = {
|
|
188
|
+
opened: defaultStateIcons.accordion.opened,
|
|
189
|
+
closed: defaultStateIcons.accordion.closed
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// =============================================================================
|
|
193
|
+
// Helper Functions
|
|
194
|
+
// =============================================================================
|
|
195
|
+
|
|
196
|
+
export { getSnippet } from './menu.js'
|