@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.
Files changed (146) hide show
  1. package/README.md +198 -101
  2. package/package.json +52 -34
  3. package/src/components/BreadCrumbs.svelte +82 -0
  4. package/src/components/Button.svelte +87 -0
  5. package/src/components/ButtonGroup.svelte +18 -0
  6. package/src/components/Card.svelte +61 -0
  7. package/src/components/Carousel.svelte +169 -0
  8. package/src/components/Code.svelte +185 -0
  9. package/src/components/Connector.svelte +46 -0
  10. package/src/components/FloatingAction.svelte +331 -0
  11. package/src/components/FloatingNavigation.svelte +228 -0
  12. package/src/components/ItemContent.svelte +24 -0
  13. package/src/components/List.svelte +476 -0
  14. package/src/components/Menu.svelte +421 -0
  15. package/src/components/MultiSelect.svelte +521 -0
  16. package/src/components/PaletteManager.svelte +354 -0
  17. package/src/components/Pill.svelte +78 -0
  18. package/src/components/ProgressBar.svelte +31 -0
  19. package/src/components/Range.svelte +325 -0
  20. package/src/components/Rating.svelte +91 -0
  21. package/src/components/Reveal.svelte +58 -0
  22. package/src/components/SearchFilter.svelte +80 -0
  23. package/src/components/Select.svelte +585 -0
  24. package/src/{Shine.svelte → components/Shine.svelte} +29 -21
  25. package/src/components/Stepper.svelte +169 -0
  26. package/src/components/Switch.svelte +75 -0
  27. package/src/components/Table.svelte +243 -0
  28. package/src/components/Tabs.svelte +268 -0
  29. package/src/components/Tilt.svelte +68 -0
  30. package/src/components/Timeline.svelte +61 -0
  31. package/src/components/Toggle.svelte +157 -0
  32. package/src/components/Toolbar.svelte +307 -0
  33. package/src/components/ToolbarGroup.svelte +17 -0
  34. package/src/components/Tree.svelte +613 -0
  35. package/src/components/index.ts +33 -0
  36. package/src/index.ts +41 -0
  37. package/src/types/button.ts +83 -0
  38. package/src/types/code.ts +46 -0
  39. package/src/types/floating-action.ts +118 -0
  40. package/src/types/floating-navigation.ts +68 -0
  41. package/src/types/index.ts +53 -0
  42. package/src/types/item-proxy.ts +358 -0
  43. package/src/types/list.ts +196 -0
  44. package/src/types/menu.ts +195 -0
  45. package/src/types/palette.ts +143 -0
  46. package/src/types/range.ts +51 -0
  47. package/src/types/search-filter.ts +67 -0
  48. package/src/types/select.ts +206 -0
  49. package/src/types/switch.ts +64 -0
  50. package/src/types/table.ts +210 -0
  51. package/src/types/tabs.ts +124 -0
  52. package/src/types/timeline.ts +51 -0
  53. package/src/types/toggle.ts +109 -0
  54. package/src/types/toolbar.ts +164 -0
  55. package/src/types/tree.ts +259 -0
  56. package/src/utils/palette.ts +582 -0
  57. package/src/utils/shiki.ts +122 -0
  58. package/dist/constants.d.ts +0 -2
  59. package/dist/index.d.ts +0 -41
  60. package/dist/lib/fields.d.ts +0 -16
  61. package/dist/lib/form.d.ts +0 -95
  62. package/dist/lib/index.d.ts +0 -6
  63. package/dist/lib/layout.d.ts +0 -7
  64. package/dist/lib/nested.d.ts +0 -48
  65. package/dist/lib/schema.d.ts +0 -7
  66. package/dist/lib/select.d.ts +0 -8
  67. package/dist/lib/tree.d.ts +0 -9
  68. package/dist/tree/List.spec.svelte.d.ts +0 -1
  69. package/dist/tree/Node.spec.svelte.d.ts +0 -1
  70. package/dist/tree/Root.spec.svelte.d.ts +0 -1
  71. package/dist/types.d.ts +0 -5
  72. package/dist/wrappers/index.d.ts +0 -3
  73. package/src/Accordion.svelte +0 -118
  74. package/src/BreadCrumbs.svelte +0 -32
  75. package/src/Button.svelte +0 -57
  76. package/src/Calendar.svelte +0 -93
  77. package/src/Card.svelte +0 -45
  78. package/src/Carousel.svelte +0 -49
  79. package/src/CheckBox.svelte +0 -56
  80. package/src/Connector.svelte +0 -40
  81. package/src/DropDown.svelte +0 -68
  82. package/src/DropSearch.svelte +0 -37
  83. package/src/Fillable.svelte +0 -19
  84. package/src/GraphPaper.svelte +0 -43
  85. package/src/Icon.svelte +0 -81
  86. package/src/Item.svelte +0 -25
  87. package/src/Link.svelte +0 -21
  88. package/src/List.svelte +0 -89
  89. package/src/ListBody.svelte +0 -43
  90. package/src/Message.svelte +0 -11
  91. package/src/MultiSelect.svelte +0 -48
  92. package/src/NestedList.svelte +0 -78
  93. package/src/NestedPaginator.svelte +0 -63
  94. package/src/Node.svelte +0 -76
  95. package/src/Overlay.svelte +0 -21
  96. package/src/PageNavigator.svelte +0 -94
  97. package/src/PickOne.svelte +0 -60
  98. package/src/Pill.svelte +0 -41
  99. package/src/ProgressBar.svelte +0 -21
  100. package/src/ProgressDots.svelte +0 -53
  101. package/src/RadioGroup.svelte +0 -52
  102. package/src/Range.svelte +0 -45
  103. package/src/RangeMinMax.svelte +0 -124
  104. package/src/RangeSlider.svelte +0 -79
  105. package/src/RangeTick.svelte +0 -28
  106. package/src/Rating.svelte +0 -95
  107. package/src/ResponsiveGrid.svelte +0 -88
  108. package/src/Scrollable.svelte +0 -7
  109. package/src/Select.svelte +0 -114
  110. package/src/Separator.svelte +0 -1
  111. package/src/Slider.svelte +0 -14
  112. package/src/SlidingColumns.svelte +0 -50
  113. package/src/Stage.svelte +0 -41
  114. package/src/Stepper.svelte +0 -66
  115. package/src/Summary.svelte +0 -22
  116. package/src/Switch.svelte +0 -106
  117. package/src/TableCell.svelte +0 -51
  118. package/src/TableHeaderCell.svelte +0 -54
  119. package/src/Tabs.svelte +0 -176
  120. package/src/Tilt.svelte +0 -66
  121. package/src/Toggle.svelte +0 -58
  122. package/src/ToggleThemeMode.svelte +0 -23
  123. package/src/Tree.svelte +0 -80
  124. package/src/TreeTable.svelte +0 -171
  125. package/src/ValidationReport.svelte +0 -23
  126. package/src/constants.js +0 -4
  127. package/src/index.js +0 -48
  128. package/src/lib/fields.js +0 -118
  129. package/src/lib/form.js +0 -72
  130. package/src/lib/index.js +0 -13
  131. package/src/lib/layout.js +0 -63
  132. package/src/lib/nested.js +0 -192
  133. package/src/lib/schema.js +0 -32
  134. package/src/lib/select.js +0 -38
  135. package/src/lib/tree.js +0 -22
  136. package/src/tree/List.spec.svelte.js +0 -84
  137. package/src/tree/List.svelte +0 -78
  138. package/src/tree/Node.spec.svelte.js +0 -104
  139. package/src/tree/Node.svelte +0 -80
  140. package/src/tree/Root.spec.svelte.js +0 -63
  141. package/src/tree/Root.svelte +0 -81
  142. package/src/types.js +0 -9
  143. package/src/wrappers/Category.svelte +0 -27
  144. package/src/wrappers/Section.svelte +0 -16
  145. package/src/wrappers/Wrapper.svelte +0 -12
  146. 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'