rip-lang 3.13.93 → 3.13.95

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 (63) hide show
  1. package/README.md +1 -1
  2. package/docs/dist/rip.js +142 -38
  3. package/docs/dist/rip.min.js +174 -174
  4. package/docs/dist/rip.min.js.br +0 -0
  5. package/package.json +1 -1
  6. package/src/ui.rip +65 -0
  7. package/docs/ui/accordion.rip +0 -113
  8. package/docs/ui/alert-dialog.rip +0 -96
  9. package/docs/ui/autocomplete.rip +0 -141
  10. package/docs/ui/avatar.rip +0 -37
  11. package/docs/ui/badge.rip +0 -15
  12. package/docs/ui/breadcrumb.rip +0 -46
  13. package/docs/ui/button-group.rip +0 -26
  14. package/docs/ui/button.rip +0 -23
  15. package/docs/ui/card.rip +0 -25
  16. package/docs/ui/carousel.rip +0 -110
  17. package/docs/ui/checkbox-group.rip +0 -65
  18. package/docs/ui/checkbox.rip +0 -33
  19. package/docs/ui/collapsible.rip +0 -50
  20. package/docs/ui/combobox.rip +0 -155
  21. package/docs/ui/context-menu.rip +0 -105
  22. package/docs/ui/date-picker.rip +0 -214
  23. package/docs/ui/dialog.rip +0 -107
  24. package/docs/ui/drawer.rip +0 -79
  25. package/docs/ui/editable-value.rip +0 -80
  26. package/docs/ui/field.rip +0 -53
  27. package/docs/ui/fieldset.rip +0 -22
  28. package/docs/ui/form.rip +0 -39
  29. package/docs/ui/grid.rip +0 -901
  30. package/docs/ui/hljs-rip.js +0 -209
  31. package/docs/ui/index.css +0 -1772
  32. package/docs/ui/index.html +0 -2433
  33. package/docs/ui/input-group.rip +0 -28
  34. package/docs/ui/input.rip +0 -36
  35. package/docs/ui/label.rip +0 -16
  36. package/docs/ui/menu.rip +0 -162
  37. package/docs/ui/menubar.rip +0 -155
  38. package/docs/ui/meter.rip +0 -36
  39. package/docs/ui/multi-select.rip +0 -158
  40. package/docs/ui/native-select.rip +0 -32
  41. package/docs/ui/nav-menu.rip +0 -129
  42. package/docs/ui/number-field.rip +0 -162
  43. package/docs/ui/otp-field.rip +0 -89
  44. package/docs/ui/pagination.rip +0 -123
  45. package/docs/ui/popover.rip +0 -143
  46. package/docs/ui/preview-card.rip +0 -73
  47. package/docs/ui/progress.rip +0 -25
  48. package/docs/ui/radio-group.rip +0 -67
  49. package/docs/ui/resizable.rip +0 -123
  50. package/docs/ui/scroll-area.rip +0 -145
  51. package/docs/ui/select.rip +0 -184
  52. package/docs/ui/separator.rip +0 -17
  53. package/docs/ui/skeleton.rip +0 -22
  54. package/docs/ui/slider.rip +0 -165
  55. package/docs/ui/spinner.rip +0 -17
  56. package/docs/ui/table.rip +0 -27
  57. package/docs/ui/tabs.rip +0 -124
  58. package/docs/ui/textarea.rip +0 -48
  59. package/docs/ui/toast.rip +0 -87
  60. package/docs/ui/toggle-group.rip +0 -78
  61. package/docs/ui/toggle.rip +0 -24
  62. package/docs/ui/toolbar.rip +0 -46
  63. package/docs/ui/tooltip.rip +0 -115
@@ -1,2433 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>Rip UI</title>
7
- <link rel="preconnect" href="https://fonts.googleapis.com">
8
- <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
9
- <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
10
- <link rel="stylesheet" href="index.css">
11
- <style>body { opacity: 0; } body.ready { opacity: 1; transition: opacity 200ms ease-in; }</style>
12
- <script defer src="../dist/rip.min.js" data-src="
13
- otp-field.rip
14
- multi-select.rip
15
- editable-value.rip
16
- date-picker.rip
17
- field.rip
18
- fieldset.rip
19
- form.rip
20
- preview-card.rip
21
- menubar.rip
22
- nav-menu.rip
23
- toggle-group.rip
24
- radio-group.rip
25
- checkbox-group.rip
26
- avatar.rip
27
- context-menu.rip
28
- toolbar.rip
29
- drawer.rip
30
- autocomplete.rip
31
- scroll-area.rip
32
- number-field.rip
33
- slider.rip
34
- separator.rip
35
- button.rip
36
- input.rip
37
- toggle.rip
38
- progress.rip
39
- meter.rip
40
- checkbox.rip
41
- toast.rip
42
- dialog.rip
43
- select.rip
44
- combobox.rip
45
- tooltip.rip
46
- tabs.rip
47
- menu.rip
48
- popover.rip
49
- accordion.rip
50
- grid.rip
51
- badge.rip
52
- skeleton.rip
53
- spinner.rip
54
- card.rip
55
- label.rip
56
- textarea.rip
57
- native-select.rip
58
- input-group.rip
59
- button-group.rip
60
- alert-dialog.rip
61
- breadcrumb.rip
62
- table.rip
63
- collapsible.rip
64
- pagination.rip
65
- carousel.rip
66
- resizable.rip
67
- " data-mount="WidgetGallery">
68
- </script>
69
- </head>
70
- <body>
71
-
72
- <script type="text/rip">
73
- do ->
74
- orig = HTMLElement::focus
75
- HTMLElement::focus = (o) -> orig.call this, { preventScroll: true, ...o }
76
-
77
- export SectionHead = component
78
- accept _gallery
79
- @tag := ''
80
- @name := ''
81
- @lines := 0
82
-
83
- render
84
- .section-title
85
- = @name
86
- if @lines > 0
87
- span.badge @click: (=> _gallery._viewSource(@tag)), "#{@lines} lines ❐"
88
- else
89
- span.badge "pattern"
90
- .section-nav
91
- a @click: (=> _gallery._navSection(@tag, 'prev')), "‹"
92
- a @click: (=> _gallery._navSection(@tag, 'home')), "⌂"
93
- a @click: (=> _gallery._navSection(@tag, 'next')), "›"
94
-
95
- export WidgetGallery = component
96
- offer _gallery := this
97
-
98
- # ---- State ----
99
- check1 := false
100
- check2 := true
101
- switch1 := false
102
- toasts := []
103
- showDialog := false
104
- fruit := null
105
- role := null
106
- searchQuery := ''
107
- allFruits := ['Apple', 'Apricot', 'Avocado', 'Banana', 'Blueberry', 'Cherry', 'Cranberry', 'Date', 'Fig', 'Grape', 'Kiwi', 'Lemon', 'Lime', 'Mango', 'Orange', 'Papaya', 'Peach', 'Pear', 'Plum', 'Raspberry', 'Strawberry']
108
- filteredFruits := allFruits
109
- currentTab := 'overview'
110
- isBold := false
111
- isItalic := false
112
- userName := ''
113
- progressVal := 0.65
114
- meterVal := 72
115
- sliderVal := 40
116
- rangeVal := [20, 70]
117
- showDrawer := false
118
- citySearch := ''
119
- cities := ['Albuquerque', 'Anchorage', 'Arlington', 'Atlanta', 'Aurora', 'Austin', 'Anaheim', 'Asheville', 'Baltimore', 'Baton Rouge', 'Birmingham', 'Boise', 'Boston', 'Buffalo', 'Bakersfield', 'Bridgeport', 'Charlotte', 'Chicago', 'Dallas', 'Denver', 'Detroit', 'El Paso', 'Houston', 'Miami', 'New York', 'Phoenix', 'Portland', 'San Diego', 'San Francisco', 'Seattle']
120
- quantity := 1
121
- price := 9.99
122
- alignment := 'left'
123
- fontSize := 'md'
124
- toppings := ['Cheese']
125
- cbToppings := ['Cheese']
126
- fieldEmail := ''
127
- fieldError := ''
128
- otpCode := ''
129
- selectedColors := ['Red']
130
- editName := 'John Doe'
131
- pickedDate := null
132
- dateRange := null
133
- darkMode := false
134
- showAlertDialog := false
135
- textareaVal := ''
136
- nativeSelectVal := ''
137
- collapsibleOpen := false
138
- currentPage := 1
139
- sourceCode := null
140
- sourceName := ''
141
- sourceLines := 0
142
- tocActive := null
143
- tocFilter := ''
144
- tocGroups := [
145
- { label: 'Selection', ids: ['select', 'combobox', 'multi-select', 'autocomplete'] }
146
- { label: 'Toggle', ids: ['checkbox', 'toggle', 'toggle-group', 'radio-group', 'checkbox-group'] }
147
- { label: 'Input', ids: ['input', 'textarea', 'native-select', 'number-field', 'slider', 'otp-field', 'date-picker', 'editable-value', 'input-group'] }
148
- { label: 'Navigation', ids: ['tabs', 'menu', 'context-menu', 'menubar', 'nav-menu', 'toolbar', 'breadcrumb'] }
149
- { label: 'Overlay', ids: ['dialog', 'alert-dialog', 'drawer', 'popover', 'tooltip', 'preview-card', 'toast'] }
150
- { label: 'Display', ids: ['button', 'badge', 'card', 'separator', 'progress', 'meter', 'spinner', 'skeleton', 'avatar', 'label', 'scroll-area'] }
151
- { label: 'Form', ids: ['field', 'fieldset', 'form', 'button-group'] }
152
- { label: 'Data', ids: ['grid', 'accordion', 'table', 'collapsible'] }
153
- { label: 'Interactive', ids: ['pagination', 'carousel', 'resizable'] }
154
- ]
155
- _nameFor: (id) -> (tocData.find((c) -> c.id is id))?.name or id
156
- _viewSource: (id) ->
157
- entry = tocData.find((c) -> c.id is id)
158
- return unless entry
159
- sourceName = entry.name
160
- sourceLines = entry.lines
161
- resp = fetch! "#{id}.rip"
162
- sourceCode = resp.text!
163
- _closeSource: -> sourceCode = null
164
- _ensureHljs: (cb) ->
165
- if window.hljs then return cb()
166
- link = document.createElement('link')
167
- link.rel = 'stylesheet'
168
- link.href = 'https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/styles/github.min.css'
169
- document.head.appendChild(link)
170
- script = document.createElement('script')
171
- script.src = 'https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/highlight.min.js'
172
- script.onload = =>
173
- fetch('hljs-rip.js').then((r) -> r.text()).then (src) =>
174
- fn = new Function('return ' + src.replace(/[\s\S]*export default /, ''))()
175
- hljs.registerLanguage 'rip', fn
176
- cb()
177
- document.head.appendChild(script)
178
- _onFilter: (e) -> tocFilter = e.target.value
179
- _getVisibleLinks: -> Array.from(document.querySelectorAll('.toc-nav .toc-group a:not([data-hidden])') or [])
180
-
181
- _onFilterKey: (e) ->
182
- if e.key is '/'
183
- e.preventDefault()
184
- @_navSection('', 'home')
185
- tocFilter = ''
186
- e.target.value = ''
187
- document.addEventListener 'keyup', (=> e.target.focus()), { once: true }
188
- return
189
- if e.key is 'Escape'
190
- tocFilter = ''
191
- e.target.value = ''
192
- else if e.key is 'Enter'
193
- links = @_getVisibleLinks()
194
- if links.length is 1
195
- e.preventDefault()
196
- tocActive = links[0].getAttribute('href')?.slice(1)
197
- @_fadeTo(document.getElementById(tocActive))
198
- tocFilter = ''
199
- e.target.value = ''
200
- else if e.key is 'Tab' and not e.shiftKey
201
- links = @_getVisibleLinks()
202
- if links.length
203
- e.preventDefault()
204
- tocActive = links[0].getAttribute('href')?.slice(1)
205
- links[0].focus()
206
-
207
- _getTocGrid: ->
208
- groups = Array.from(document.querySelectorAll('.toc-nav .toc-group') or [])
209
- grid = []
210
- for grp in groups
211
- col = Array.from(grp.querySelectorAll('a:not([data-hidden])') or [])
212
- grid.push(col) if col.length
213
- grid
214
-
215
- _focusTocLink: (link) ->
216
- tocActive = link.getAttribute('href')?.slice(1)
217
- link.focus()
218
-
219
- _onTocKeydown: (e) ->
220
- grid = @_getTocGrid()
221
- return unless grid.length
222
- focused = document.activeElement
223
- col = -1
224
- row = -1
225
- for c, ci in grid
226
- ri = c.indexOf(focused)
227
- if ri >= 0
228
- col = ci
229
- row = ri
230
- break
231
- return if col < 0
232
- switch e.key
233
- when 'ArrowDown'
234
- e.preventDefault()
235
- if row < grid[col].length - 1
236
- @_focusTocLink(grid[col][row + 1])
237
- else if col < grid.length - 1
238
- @_focusTocLink(grid[col + 1][0])
239
- when 'ArrowUp'
240
- e.preventDefault()
241
- if row > 0
242
- @_focusTocLink(grid[col][row - 1])
243
- else if col > 0
244
- prev = grid[col - 1]
245
- @_focusTocLink(prev[prev.length - 1])
246
- else
247
- @_root?.querySelector('.toc-search')?.focus()
248
- when 'ArrowRight'
249
- e.preventDefault()
250
- if col < grid.length - 1
251
- target = grid[col + 1]
252
- @_focusTocLink(target[Math.min(row, target.length - 1)])
253
- when 'ArrowLeft'
254
- e.preventDefault()
255
- if col > 0
256
- target = grid[col - 1]
257
- @_focusTocLink(target[Math.min(row, target.length - 1)])
258
- when 'Home'
259
- e.preventDefault()
260
- @_focusTocLink(grid[0][0])
261
- when 'End'
262
- e.preventDefault()
263
- last = grid[grid.length - 1]
264
- @_focusTocLink(last[last.length - 1])
265
- when 'Enter', ' '
266
- e.preventDefault()
267
- @_fadeTo(document.getElementById(tocActive))
268
- when 'Escape'
269
- @_root?.querySelector('.toc-search')?.focus()
270
-
271
- ~>
272
- q = tocFilter.toLowerCase()
273
- visible = []
274
- for el in Array.from(document.querySelectorAll('.toc-nav a') or [])
275
- if q and not el.textContent.toLowerCase().includes(q)
276
- el.setAttribute('data-hidden', '')
277
- else
278
- el.removeAttribute('data-hidden')
279
- visible.push(el) if q
280
- if visible.length is 1
281
- tocActive = visible[0].getAttribute('href')?.slice(1)
282
- tocData := [
283
- { id: 'select', name: 'Select', lines: 147, desc: 'Dropdown with typeahead, keyboard nav, ARIA listbox.', props: ['@value', '@placeholder', '@disabled'], events: ['change'], keys: ['↕', 'Enter', 'Space', 'Esc', 'Home', 'End', 'type-ahead'], attrs: ['$open', '$placeholder', '$disabled', '$value', '$highlighted', '$selected'] }
284
- { id: 'combobox', name: 'Combobox', lines: 124, desc: 'Filterable input + listbox for search-as-you-type.', props: ['@query', '@items', '@placeholder', '@disabled', '@autoHighlight'], events: ['filter', 'select'], keys: ['↕', 'Enter', 'Esc', 'Tab'], attrs: ['$open', '$disabled', '$clear', '$value', '$highlighted', '$empty'] }
285
- { id: 'multi-select', name: 'MultiSelect', lines: 130, desc: 'Multi-select with chips, filtering, and keyboard nav.', props: ['@value', '@items', '@placeholder', '@disabled'], events: ['change'], keys: ['↕', 'Enter', 'Esc', 'Backspace', 'Tab'], attrs: ['$open', '$disabled', '$chips', '$chip', '$remove', '$clear', '$highlighted', '$selected'] }
286
- { id: 'autocomplete', name: 'Autocomplete', lines: 115, desc: 'Suggestion input — type to filter, select to fill.', props: ['@value', '@items', '@placeholder', '@disabled'], events: ['select'], keys: ['↕', 'Enter', 'Esc', 'Tab'], attrs: ['$open', '$disabled', '$clear'] }
287
- { id: 'checkbox', name: 'Checkbox', lines: 18, desc: 'Toggle with checkbox or switch semantics.', props: ['@checked', '@disabled', '@indeterminate', '@switch'], events: ['change'], keys: [], attrs: ['$checked', '$indeterminate', '$disabled'] }
288
- { id: 'toggle', name: 'Toggle', lines: 13, desc: 'Two-state toggle button with pressed state.', props: ['@pressed', '@disabled'], events: ['change'], keys: [], attrs: ['$pressed', '$disabled'] }
289
- { id: 'toggle-group', name: 'ToggleGroup', lines: 59, desc: 'Single or multi-select toggle buttons.', props: ['@value', '@disabled', '@multiple', '@orientation'], events: ['change'], keys: ['← →', '↕', 'Home', 'End'], attrs: ['$orientation', '$disabled', '$pressed', '$value'] }
290
- { id: 'radio-group', name: 'RadioGroup', lines: 50, desc: 'Exactly one option selected with arrow key nav.', props: ['@value', '@disabled', '@orientation', '@name'], events: ['change'], keys: ['← →', '↕', 'Home', 'End'], attrs: ['$orientation', '$disabled', '$checked', '$value'] }
291
- { id: 'checkbox-group', name: 'CheckboxGroup', lines: 46, desc: 'Multiple options checked independently.', props: ['@value', '@disabled', '@orientation', '@label'], events: ['change'], keys: ['← →', '↕'], attrs: ['$orientation', '$disabled', '$checked', '$value'] }
292
- { id: 'input', name: 'Input', lines: 24, desc: 'Headless input tracking focus, touch, and validation.', props: ['@value', '@placeholder', '@type', '@disabled', '@required'], events: [], keys: [], attrs: ['$disabled', '$focused', '$touched'] }
293
- { id: 'number-field', name: 'NumberField', lines: 132, desc: 'Number input with stepper buttons and hold-to-repeat.', props: ['@value', '@min', '@max', '@step', '@disabled', '@readOnly'], events: ['input', 'change'], keys: ['↕', 'PgUp', 'PgDn', 'Home', 'End'], attrs: ['$disabled', '$readonly', '$decrement', '$increment'] }
294
- { id: 'slider', name: 'Slider', lines: 130, desc: 'Draggable range input with pointer capture and keyboard.', props: ['@value', '@min', '@max', '@step', '@orientation', '@disabled'], events: ['input', 'change'], keys: ['← →', '↕', 'PgUp', 'PgDn', 'Home', 'End'], attrs: ['$orientation', '$disabled', '$dragging', '$track', '$indicator', '$thumb', '$active'] }
295
- { id: 'otp-field', name: 'OTPField', lines: 72, desc: 'Multi-digit code input with auto-advance and paste.', props: ['@length', '@value', '@disabled', '@mask'], events: ['input', 'complete'], keys: ['← →', 'Backspace', 'Home', 'End', 'paste'], attrs: ['$disabled', '$complete', '$filled'] }
296
- { id: 'date-picker', name: 'DatePicker', lines: 172, desc: 'Calendar dropdown for single date or range selection.', props: ['@value', '@placeholder', '@disabled', '@range', '@firstDayOfWeek'], events: ['change'], keys: ['Esc', 'Enter', 'Space'], attrs: ['$open', '$disabled', '$range', '$calendar', '$selected', '$today', '$in-range'] }
297
- { id: 'editable-value', name: 'EditableValue', lines: 58, desc: 'Click-to-edit inline value with popover form.', props: ['@disabled'], events: ['save'], keys: ['Esc', 'Enter'], attrs: ['$editing', '$disabled', '$saving', '$edit-trigger'] }
298
- { id: 'tabs', name: 'Tabs', lines: 91, desc: 'Tab panel with roving tabindex and arrow key nav.', props: ['@active', '@orientation', '@activation'], events: ['change'], keys: ['← →', '↕', 'Home', 'End', 'Enter', 'Space'], attrs: ['$tab', '$panel', '$active', '$disabled'] }
299
- { id: 'menu', name: 'Menu', lines: 133, desc: 'Dropdown action menu with keyboard navigation.', props: ['@disabled'], events: ['select'], keys: ['↕', 'Home', 'End', 'Enter', 'Space', 'Esc', 'Tab', 'type-ahead'], attrs: ['$open', '$disabled', '$highlighted', '$value'] }
300
- { id: 'context-menu', name: 'ContextMenu', lines: 80, desc: 'Right-click context menu with keyboard navigation.', props: ['@disabled'], events: ['select'], keys: ['↕', 'Home', 'End', 'Enter', 'Space', 'Esc', 'Tab'], attrs: ['$open', '$highlighted', '$disabled', '$value'] }
301
- { id: 'menubar', name: 'Menubar', lines: 125, desc: 'Horizontal menu bar with dropdown menus.', props: ['@disabled'], events: ['select'], keys: ['← →', '↕', 'Enter', 'Space', 'Esc', 'Tab'], attrs: ['$disabled', '$open', '$highlighted', '$value'] }
302
- { id: 'nav-menu', name: 'NavMenu', lines: 99, desc: 'Site navigation with hover/click dropdown panels.', props: ['@orientation', '@hoverDelay', '@hoverCloseDelay'], events: [], keys: ['← →', '↓', 'Esc'], attrs: ['$orientation', '$open'] }
303
- { id: 'toolbar', name: 'Toolbar', lines: 31, desc: 'Groups controls with roving tabindex keyboard nav.', props: ['@orientation', '@label'], events: [], keys: ['← →', '↕', 'Home', 'End'], attrs: ['$orientation'] }
304
- { id: 'dialog', name: 'Dialog', lines: 83, desc: 'Modal with focus trap, scroll lock, escape dismiss.', props: ['@open', '@dismissable', '@initialFocus'], events: ['close'], keys: ['Esc', 'Tab'], attrs: ['$open'] }
305
- { id: 'drawer', name: 'Drawer', lines: 60, desc: 'Slide-out panel with focus trap and scroll lock.', props: ['@open', '@side', '@dismissable'], events: ['close'], keys: ['Esc', 'Tab'], attrs: ['$open', '$side'] }
306
- { id: 'popover', name: 'Popover', lines: 117, desc: 'Anchored floating content with flip/shift positioning.', props: ['@placement', '@offset', '@disabled', '@openOnHover', '@hoverDelay', '@hoverCloseDelay'], events: [], keys: ['Esc', 'Enter', 'Space', '↓'], attrs: ['$open', '$placement'] }
307
- { id: 'tooltip', name: 'Tooltip', lines: 92, desc: 'Hover/focus tooltip with delay and positioning.', props: ['@text', '@placement', '@delay', '@offset', '@hoverable'], events: [], keys: [], attrs: ['$open', '$entering', '$exiting', '$placement'] }
308
- { id: 'preview-card', name: 'PreviewCard', lines: 56, desc: 'Hover/focus preview card with delay.', props: ['@delay', '@closeDelay'], events: [], keys: [], attrs: ['$open'] }
309
- { id: 'toast', name: 'Toast', lines: 56, desc: 'Auto-dismiss notification with ARIA live region.', props: ['@toasts', '@toast', '@placement'], events: ['dismiss'], keys: [], attrs: ['$placement', '$type', '$leaving'] }
310
- { id: 'button', name: 'Button', lines: 10, desc: 'Accessible button with disabled-but-focusable pattern.', props: ['@disabled'], events: ['press'], keys: [], attrs: ['$disabled'] }
311
- { id: 'separator', name: 'Separator', lines: 7, desc: 'Decorative or semantic divider between sections.', props: ['@orientation', '@decorative'], events: [], keys: [], attrs: ['$orientation'] }
312
- { id: 'progress', name: 'Progress', lines: 14, desc: 'Progress bar with CSS custom property for value.', props: ['@value', '@max', '@label'], events: [], keys: [], attrs: ['$complete'] }
313
- { id: 'meter', name: 'Meter', lines: 23, desc: 'Gauge for known-range measurements with thresholds.', props: ['@value', '@min', '@max', '@low', '@high', '@optimum', '@label'], events: [], keys: [], attrs: ['$level'] }
314
- { id: 'avatar', name: 'Avatar', lines: 23, desc: 'Image with fallback to initials or placeholder.', props: ['@src', '@alt', '@fallback'], events: [], keys: [], attrs: ['$status', '$initials', '$placeholder'] }
315
- { id: 'scroll-area', name: 'ScrollArea', lines: 115, desc: 'Custom scrollbar with draggable thumb and auto-hide.', props: ['@orientation'], events: [], keys: [], attrs: ['$orientation', '$hovering', '$scrolling', '$dragging', '$viewport', '$scrollbar', '$thumb'] }
316
- { id: 'field', name: 'Field', lines: 39, desc: 'Form field wrapper with label, description, and error.', props: ['@label', '@description', '@error', '@disabled', '@required'], events: [], keys: [], attrs: ['$disabled', '$invalid', '$label', '$required', '$description', '$error'] }
317
- { id: 'fieldset', name: 'Fieldset', lines: 9, desc: 'Grouped fields with legend and cascading disable.', props: ['@legend', '@disabled'], events: [], keys: [], attrs: ['$disabled', '$legend'] }
318
- { id: 'form', name: 'Form', lines: 21, desc: 'Form wrapper with submit handling and validation state.', props: ['@disabled'], events: ['submit'], keys: [], attrs: ['$disabled', '$submitting', '$submitted'] }
319
- { id: 'grid', name: 'Grid', lines: 799, desc: 'Virtual-scrolling data grid — 100K+ rows at 60fps.', props: ['@data', '@columns', '@rowHeight', '@overscan', '@striped', '@beforeEdit', '@afterEdit'], events: [], keys: ['Arrows', 'Tab', 'Enter', 'F2', 'Esc', 'Home', 'End', 'PgUp', 'PgDn', 'Ctrl+A', 'Ctrl+C', 'Ctrl+V', 'Ctrl+X'], attrs: ['$editing', '$selecting', '$sorted'] }
320
- { id: 'accordion', name: 'Accordion', lines: 86, desc: 'Expand/collapse sections, single or multiple mode.', props: ['@multiple'], events: ['change'], keys: ['Enter', 'Space', '↕', 'Home', 'End'], attrs: ['$item', '$trigger', '$content', '$open', '$disabled'] }
321
- { id: 'badge', name: 'Badge', lines: 5, desc: 'Inline label with variant (solid/outline/subtle).', props: ['@variant'], events: [], keys: [], attrs: ['$variant'] }
322
- { id: 'skeleton', name: 'Skeleton', lines: 10, desc: 'Loading placeholder with shimmer animation.', props: ['@width', '@height', '@circle', '@label'], events: [], keys: [], attrs: ['$circle'] }
323
- { id: 'spinner', name: 'Spinner', lines: 6, desc: 'Loading indicator with accessible status.', props: ['@label', '@size'], events: [], keys: [], attrs: [] }
324
- { id: 'card', name: 'Card', lines: 6, desc: 'Structured container with header/content/footer.', props: ['@interactive'], events: [], keys: [], attrs: ['$interactive'] }
325
- { id: 'label', name: 'Label', lines: 6, desc: 'Standalone accessible form label.', props: ['@for', '@required'], events: [], keys: [], attrs: ['$required'] }
326
- { id: 'textarea', name: 'Textarea', lines: 33, desc: 'Auto-resizing text area with focus and validation tracking.', props: ['@value', '@placeholder', '@disabled', '@required', '@rows', '@autoResize'], events: [], keys: [], attrs: ['$disabled', '$focused', '$touched'] }
327
- { id: 'native-select', name: 'NativeSelect', lines: 18, desc: 'Styled native select element with state tracking.', props: ['@value', '@disabled', '@required'], events: ['change'], keys: [], attrs: ['$disabled', '$focused'] }
328
- { id: 'input-group', name: 'InputGroup', lines: 11, desc: 'Input with prefix/suffix addon elements.', props: ['@disabled'], events: [], keys: [], attrs: ['$disabled', '$focused'] }
329
- { id: 'button-group', name: 'ButtonGroup', lines: 11, desc: 'Grouped buttons with ARIA group semantics.', props: ['@orientation', '@disabled', '@label'], events: [], keys: [], attrs: ['$orientation', '$disabled'] }
330
- { id: 'alert-dialog', name: 'AlertDialog', lines: 74, desc: 'Non-dismissable modal requiring explicit user action.', props: ['@open', '@initialFocus'], events: ['close'], keys: ['Tab'], attrs: ['$open'] }
331
- { id: 'breadcrumb', name: 'Breadcrumb', lines: 25, desc: 'Navigation trail with separator and current page.', props: ['@separator', '@label'], events: [], keys: [], attrs: ['$current'] }
332
- { id: 'table', name: 'Table', lines: 9, desc: 'Semantic table wrapper with optional caption and striped rows.', props: ['@caption', '@striped'], events: [], keys: [], attrs: ['$striped'] }
333
- { id: 'collapsible', name: 'Collapsible', lines: 33, desc: 'Single open/close section with animated expand.', props: ['@open', '@disabled'], events: ['change'], keys: ['Enter', 'Space'], attrs: ['$open', '$disabled'] }
334
- { id: 'pagination', name: 'Pagination', lines: 96, desc: 'Page navigation with prev/next and ellipsis gaps.', props: ['@page', '@total', '@perPage', '@siblingCount'], events: ['change'], keys: ['← →', 'Home', 'End'], attrs: ['$active', '$disabled', '$ellipsis'] }
335
- { id: 'carousel', name: 'Carousel', lines: 78, desc: 'Slide carousel with autoplay, loop, and keyboard nav.', props: ['@orientation', '@loop', '@autoplay', '@interval', '@label'], events: ['change'], keys: ['← →', '↕', 'Home', 'End'], attrs: ['$orientation', '$active', '$prev', '$next'] }
336
- { id: 'resizable', name: 'Resizable', lines: 89, desc: 'Draggable resize handles between panels.', props: ['@orientation', '@minSize', '@maxSize'], events: ['resize'], keys: ['← →', '↕'], attrs: ['$orientation', '$dragging'] }
337
- ]
338
- _infoName := ''
339
- _infoDesc := ''
340
- _infoLines := 0
341
- _infoProps := []
342
- _infoEvents := []
343
- _infoKeys := []
344
- _infoAttrs := []
345
-
346
- ~>
347
- info = tocData.find (c) -> c.id is tocActive
348
- if info
349
- _infoName = info.name
350
- _infoDesc = info.desc
351
- _infoLines = info.lines
352
- _infoProps = info.props
353
- _infoEvents = info.events
354
- _infoKeys = info.keys
355
- _infoAttrs = info.attrs
356
-
357
- ~>
358
- raw = sourceCode
359
- return unless raw
360
- setTimeout =>
361
- codeEl = document.querySelector('.source-code')
362
- gutterEl = document.querySelector('.source-gutter')
363
- return unless codeEl
364
- text = raw.replace(/^\n+/, '').replace(/\n+$/, '')
365
- lines = text.split('\n')
366
- gutterEl.textContent = lines.map((_, i) -> String(i + 1)).join('\n') if gutterEl
367
- codeEl.textContent = text
368
- codeEl.className = 'source-code language-rip'
369
- @_ensureHljs =>
370
- hljs.highlightElement(codeEl) if window.hljs
371
- , 0
372
-
373
- ~>
374
- if sourceCode
375
- onKey = (e) => @_closeSource() if e.key is 'Escape'
376
- document.addEventListener 'keydown', onKey
377
- return -> document.removeEventListener 'keydown', onKey
378
-
379
- _toggleDark: ->
380
- darkMode = not darkMode
381
- document.documentElement.classList.add('no-transition')
382
- document.documentElement.dataset.theme = if darkMode then 'dark' else ''
383
- localStorage.setItem('rip-ui-theme', if darkMode then 'dark' else 'light')
384
- requestAnimationFrame -> requestAnimationFrame -> document.documentElement.classList.remove('no-transition')
385
-
386
- mounted: ->
387
- if localStorage.getItem('rip-ui-theme') is 'dark'
388
- darkMode = true
389
- document.documentElement.dataset.theme = 'dark'
390
- document.addEventListener 'keydown', (e) =>
391
- if e.key is '/' and not (e.target.tagName in ['INPUT', 'TEXTAREA', 'SELECT']) and not e.target.isContentEditable
392
- e.preventDefault()
393
- @_navSection('', 'home')
394
- tocFilter = ''
395
- document.addEventListener 'keyup', (=>
396
- @_root?.querySelector('.toc-search')?.focus()
397
- ), { once: true }
398
- gc = document.querySelector('.grid-container')
399
- if gc
400
- gc.addEventListener 'mousedown', => setTimeout (=> @_updateGridRef()), 0
401
- gc.addEventListener 'keyup', => setTimeout (=> @_updateGridRef()), 0
402
- hash = location.hash.slice(1)
403
- if hash and document.getElementById(hash)
404
- tocActive = hash
405
- setTimeout =>
406
- document.getElementById(hash)?.scrollIntoView({ behavior: 'instant', block: 'start' })
407
- document.body.classList.add('ready')
408
- , 50
409
- else
410
- document.body.classList.add('ready')
411
-
412
- gridCellRef := ''
413
-
414
- _updateGridRef: ->
415
- cell = document.querySelector('.grid-container td[data-active]')
416
- if cell
417
- tr = cell.parentElement
418
- rowNum = tr?.firstElementChild?.textContent?.trim()
419
- ci = Array.from(tr.children).indexOf(cell)
420
- gridCellRef = if rowNum then "R#{rowNum}:C#{ci + 1}" else ''
421
- else
422
- gridCellRef = ''
423
-
424
- _loadGridRows: (n) ->
425
- firstNames = ['Alice', 'Bob', 'Carol', 'Dan', 'Eve', 'Frank', 'Grace', 'Hank', 'Iris', 'Jack', 'Karen', 'Leo', 'Mia', 'Nora', 'Omar', 'Pia', 'Quinn', 'Rosa', 'Sam', 'Tina']
426
- lastNames = ['Chen', 'Park', 'Singh', 'Nakamura', 'Torres', 'Liu', 'Kim', 'Patel', 'Wang', 'Brown', 'Lee', 'Martin', 'Garcia', 'Davis', 'Lopez', 'Clark', 'Hall', 'Young', 'King', 'Wright']
427
- roles = ['Engineer', 'Designer', 'Manager', 'Director', 'Analyst', 'Lead', 'Intern']
428
- cityList = ['Seattle', 'Portland', 'Denver', 'Austin', 'Chicago', 'Boston', 'Miami', 'Phoenix', 'Dallas', 'Atlanta']
429
- gc = document.querySelector('.grid-container')
430
- gc?.scrollTop = 0
431
- gridData = Array.from { length: n }, (_, idx) ->
432
- fn = firstNames[idx %% firstNames.length]
433
- ln = lastNames[Math.floor(Math.random() * lastNames.length)]
434
- { _row: idx + 1, name: "#{fn} #{ln}", role: roles[idx %% roles.length], age: 22 + (idx %% 40), city: cityList[idx %% cityList.length] }
435
- gridCellRef = ''
436
-
437
- gridColumns := [
438
- { key: '_row', title: '#', width: 60, align: 'right' },
439
- { key: 'name', title: 'Name', width: 180 },
440
- { key: 'role', title: 'Role', width: 140 },
441
- { key: 'age', title: 'Age', width: 80, align: 'right' },
442
- { key: 'city', title: 'City', width: 140 },
443
- ]
444
- gridData := [
445
- { _row: 1, name: 'Alice Chen', role: 'Engineer', age: 28, city: 'Seattle' },
446
- { _row: 2, name: 'Bob Park', role: 'Designer', age: 34, city: 'Portland' },
447
- { _row: 3, name: 'Carol Singh', role: 'Manager', age: 41, city: 'Denver' },
448
- { _row: 4, name: 'Dan Nakamura', role: 'Engineer', age: 26, city: 'Austin' },
449
- { _row: 5, name: 'Eve Torres', role: 'Director', age: 45, city: 'Chicago' },
450
- { _row: 6, name: 'Frank Liu', role: 'Designer', age: 31, city: 'Boston' },
451
- { _row: 7, name: 'Grace Kim', role: 'Engineer', age: 29, city: 'Seattle' },
452
- { _row: 8, name: 'Hank Patel', role: 'Manager', age: 38, city: 'Denver' },
453
- { _row: 9, name: 'Iris Wang', role: 'Engineer', age: 33, city: 'Austin' },
454
- { _row: 10, name: 'Jack Brown', role: 'Designer', age: 27, city: 'Portland' },
455
- { _row: 11, name: 'Karen Lee', role: 'Director', age: 52, city: 'Chicago' },
456
- { _row: 12, name: 'Leo Martin', role: 'Engineer', age: 24, city: 'Boston' },
457
- ]
458
-
459
- sectionIds =! ['select', 'combobox', 'multi-select', 'autocomplete', 'checkbox', 'toggle', 'toggle-group', 'radio-group', 'checkbox-group', 'input', 'textarea', 'native-select', 'number-field', 'slider', 'otp-field', 'date-picker', 'editable-value', 'input-group', 'tabs', 'menu', 'context-menu', 'menubar', 'nav-menu', 'toolbar', 'breadcrumb', 'dialog', 'alert-dialog', 'drawer', 'popover', 'tooltip', 'preview-card', 'toast', 'button', 'badge', 'card', 'separator', 'progress', 'meter', 'spinner', 'skeleton', 'avatar', 'label', 'scroll-area', 'field', 'form', 'button-group', 'grid', 'accordion', 'table', 'collapsible', 'pagination', 'carousel', 'resizable']
460
-
461
- _fadeTo: (el) ->
462
- return unless el
463
- gallery = document.querySelector('.gallery')
464
- gallery.style.transition = 'opacity 80ms ease-out'
465
- gallery.style.opacity = '0'
466
- setTimeout =>
467
- el.scrollIntoView({ behavior: 'instant', block: 'start' })
468
- history.replaceState(null, '', '#' + el.id) if el.id
469
- gallery.style.transition = 'opacity 120ms ease-in'
470
- gallery.style.opacity = '1'
471
- , 80
472
-
473
- _jumpTo: (e) ->
474
- e.preventDefault()
475
- @_fadeTo(document.getElementById(tocActive))
476
-
477
- _navSection: (currentId, dir) ->
478
- if dir is 'home'
479
- gallery = document.querySelector('.gallery')
480
- gallery.style.transition = 'opacity 80ms ease-out'
481
- gallery.style.opacity = '0'
482
- setTimeout =>
483
- window.scrollTo({ top: 0, behavior: 'instant' })
484
- history.replaceState(null, '', location.pathname)
485
- gallery.style.transition = 'opacity 120ms ease-in'
486
- gallery.style.opacity = '1'
487
- , 80
488
- return
489
- idx = sectionIds.indexOf(currentId)
490
- return if idx < 0
491
- nextId = sectionIds[if dir is 'prev' then idx - 1 else idx + 1]
492
- @_fadeTo(document.getElementById(nextId)) if nextId
493
-
494
- render
495
- .gallery
496
-
497
- .gallery-header
498
- .
499
- h1 "Rip UI"
500
- button.theme-toggle @click: (=> @_toggleDark())
501
- if darkMode then "☀" else "☾"
502
- p "54 headless, accessible components. Zero CSS, zero dependencies."
503
-
504
- .toc
505
- .toc-nav @keydown: @_onTocKeydown
506
- input.toc-search type: "text", placeholder: "Filter components...", @input: @_onFilter, @keydown: @_onFilterKey
507
- .toc-group
508
- .toc-label "Selection"
509
- a @mouseenter: (=> tocActive = 'select'), @click: (=> tocActive = 'select'), href: "#select", $active: (tocActive is 'select')?!, "Select"
510
- a @mouseenter: (=> tocActive = 'combobox'), @click: (=> tocActive = 'combobox'), href: "#combobox", $active: (tocActive is 'combobox')?!, "Combobox"
511
- a @mouseenter: (=> tocActive = 'multi-select'), @click: (=> tocActive = 'multi-select'), href: "#multi-select", $active: (tocActive is 'multi-select')?!, "MultiSelect"
512
- a @mouseenter: (=> tocActive = 'autocomplete'), @click: (=> tocActive = 'autocomplete'), href: "#autocomplete", $active: (tocActive is 'autocomplete')?!, "Autocomplete"
513
- .toc-group
514
- .toc-label "Toggle"
515
- a @mouseenter: (=> tocActive = 'checkbox'), @click: (=> tocActive = 'checkbox'), href: "#checkbox", $active: (tocActive is 'checkbox')?!, "Checkbox"
516
- a @mouseenter: (=> tocActive = 'toggle'), @click: (=> tocActive = 'toggle'), href: "#toggle", $active: (tocActive is 'toggle')?!, "Toggle"
517
- a @mouseenter: (=> tocActive = 'toggle-group'), @click: (=> tocActive = 'toggle-group'), href: "#toggle-group", $active: (tocActive is 'toggle-group')?!, "ToggleGroup"
518
- a @mouseenter: (=> tocActive = 'radio-group'), @click: (=> tocActive = 'radio-group'), href: "#radio-group", $active: (tocActive is 'radio-group')?!, "RadioGroup"
519
- a @mouseenter: (=> tocActive = 'checkbox-group'), @click: (=> tocActive = 'checkbox-group'), href: "#checkbox-group", $active: (tocActive is 'checkbox-group')?!, "CheckboxGroup"
520
- .toc-group
521
- .toc-label "Input"
522
- a @mouseenter: (=> tocActive = 'input'), @click: (=> tocActive = 'input'), href: "#input", $active: (tocActive is 'input')?!, "Input"
523
- a @mouseenter: (=> tocActive = 'textarea'), @click: (=> tocActive = 'textarea'), href: "#textarea", $active: (tocActive is 'textarea')?!, "Textarea"
524
- a @mouseenter: (=> tocActive = 'native-select'), @click: (=> tocActive = 'native-select'), href: "#native-select", $active: (tocActive is 'native-select')?!, "NativeSelect"
525
- a @mouseenter: (=> tocActive = 'number-field'), @click: (=> tocActive = 'number-field'), href: "#number-field", $active: (tocActive is 'number-field')?!, "NumberField"
526
- a @mouseenter: (=> tocActive = 'slider'), @click: (=> tocActive = 'slider'), href: "#slider", $active: (tocActive is 'slider')?!, "Slider"
527
- a @mouseenter: (=> tocActive = 'otp-field'), @click: (=> tocActive = 'otp-field'), href: "#otp-field", $active: (tocActive is 'otp-field')?!, "OTPField"
528
- a @mouseenter: (=> tocActive = 'date-picker'), @click: (=> tocActive = 'date-picker'), href: "#date-picker", $active: (tocActive is 'date-picker')?!, "DatePicker"
529
- a @mouseenter: (=> tocActive = 'editable-value'), @click: (=> tocActive = 'editable-value'), href: "#editable-value", $active: (tocActive is 'editable-value')?!, "EditableValue"
530
- a @mouseenter: (=> tocActive = 'input-group'), @click: (=> tocActive = 'input-group'), href: "#input-group", $active: (tocActive is 'input-group')?!, "InputGroup"
531
- .toc-group
532
- .toc-label "Navigation"
533
- a @mouseenter: (=> tocActive = 'tabs'), @click: (=> tocActive = 'tabs'), href: "#tabs", $active: (tocActive is 'tabs')?!, "Tabs"
534
- a @mouseenter: (=> tocActive = 'menu'), @click: (=> tocActive = 'menu'), href: "#menu", $active: (tocActive is 'menu')?!, "Menu"
535
- a @mouseenter: (=> tocActive = 'context-menu'), @click: (=> tocActive = 'context-menu'), href: "#context-menu", $active: (tocActive is 'context-menu')?!, "ContextMenu"
536
- a @mouseenter: (=> tocActive = 'menubar'), @click: (=> tocActive = 'menubar'), href: "#menubar", $active: (tocActive is 'menubar')?!, "Menubar"
537
- a @mouseenter: (=> tocActive = 'nav-menu'), @click: (=> tocActive = 'nav-menu'), href: "#nav-menu", $active: (tocActive is 'nav-menu')?!, "NavMenu"
538
- a @mouseenter: (=> tocActive = 'toolbar'), @click: (=> tocActive = 'toolbar'), href: "#toolbar", $active: (tocActive is 'toolbar')?!, "Toolbar"
539
- a @mouseenter: (=> tocActive = 'breadcrumb'), @click: (=> tocActive = 'breadcrumb'), href: "#breadcrumb", $active: (tocActive is 'breadcrumb')?!, "Breadcrumb"
540
- .toc-group
541
- .toc-label "Overlay"
542
- a @mouseenter: (=> tocActive = 'dialog'), @click: (=> tocActive = 'dialog'), href: "#dialog", $active: (tocActive is 'dialog')?!, "Dialog"
543
- a @mouseenter: (=> tocActive = 'alert-dialog'), @click: (=> tocActive = 'alert-dialog'), href: "#alert-dialog", $active: (tocActive is 'alert-dialog')?!, "AlertDialog"
544
- a @mouseenter: (=> tocActive = 'drawer'), @click: (=> tocActive = 'drawer'), href: "#drawer", $active: (tocActive is 'drawer')?!, "Drawer"
545
- a @mouseenter: (=> tocActive = 'popover'), @click: (=> tocActive = 'popover'), href: "#popover", $active: (tocActive is 'popover')?!, "Popover"
546
- a @mouseenter: (=> tocActive = 'tooltip'), @click: (=> tocActive = 'tooltip'), href: "#tooltip", $active: (tocActive is 'tooltip')?!, "Tooltip"
547
- a @mouseenter: (=> tocActive = 'preview-card'), @click: (=> tocActive = 'preview-card'), href: "#preview-card", $active: (tocActive is 'preview-card')?!, "PreviewCard"
548
- a @mouseenter: (=> tocActive = 'toast'), @click: (=> tocActive = 'toast'), href: "#toast", $active: (tocActive is 'toast')?!, "Toast"
549
- .toc-group
550
- .toc-label "Display"
551
- a @mouseenter: (=> tocActive = 'button'), @click: (=> tocActive = 'button'), href: "#button", $active: (tocActive is 'button')?!, "Button"
552
- a @mouseenter: (=> tocActive = 'badge'), @click: (=> tocActive = 'badge'), href: "#badge", $active: (tocActive is 'badge')?!, "Badge"
553
- a @mouseenter: (=> tocActive = 'card'), @click: (=> tocActive = 'card'), href: "#card", $active: (tocActive is 'card')?!, "Card"
554
- a @mouseenter: (=> tocActive = 'separator'), @click: (=> tocActive = 'separator'), href: "#separator", $active: (tocActive is 'separator')?!, "Separator"
555
- a @mouseenter: (=> tocActive = 'progress'), @click: (=> tocActive = 'progress'), href: "#progress", $active: (tocActive is 'progress')?!, "Progress"
556
- a @mouseenter: (=> tocActive = 'meter'), @click: (=> tocActive = 'meter'), href: "#meter", $active: (tocActive is 'meter')?!, "Meter"
557
- a @mouseenter: (=> tocActive = 'spinner'), @click: (=> tocActive = 'spinner'), href: "#spinner", $active: (tocActive is 'spinner')?!, "Spinner"
558
- a @mouseenter: (=> tocActive = 'skeleton'), @click: (=> tocActive = 'skeleton'), href: "#skeleton", $active: (tocActive is 'skeleton')?!, "Skeleton"
559
- a @mouseenter: (=> tocActive = 'avatar'), @click: (=> tocActive = 'avatar'), href: "#avatar", $active: (tocActive is 'avatar')?!, "Avatar"
560
- a @mouseenter: (=> tocActive = 'label'), @click: (=> tocActive = 'label'), href: "#label", $active: (tocActive is 'label')?!, "Label"
561
- a @mouseenter: (=> tocActive = 'scroll-area'), @click: (=> tocActive = 'scroll-area'), href: "#scroll-area", $active: (tocActive is 'scroll-area')?!, "ScrollArea"
562
- .toc-group
563
- .toc-label "Form"
564
- a @mouseenter: (=> tocActive = 'field'), @click: (=> tocActive = 'field'), href: "#field", $active: (tocActive is 'field')?!, "Field"
565
- a @mouseenter: (=> tocActive = 'fieldset'), @click: (=> tocActive = 'fieldset'), href: "#fieldset", $active: (tocActive is 'fieldset')?!, "Fieldset"
566
- a @mouseenter: (=> tocActive = 'form'), @click: (=> tocActive = 'form'), href: "#form", $active: (tocActive is 'form')?!, "Form"
567
- a @mouseenter: (=> tocActive = 'button-group'), @click: (=> tocActive = 'button-group'), href: "#button-group", $active: (tocActive is 'button-group')?!, "ButtonGroup"
568
- .toc-group
569
- .toc-label "Data"
570
- a @mouseenter: (=> tocActive = 'grid'), @click: (=> tocActive = 'grid'), href: "#grid", $active: (tocActive is 'grid')?!, "Grid"
571
- a @mouseenter: (=> tocActive = 'accordion'), @click: (=> tocActive = 'accordion'), href: "#accordion", $active: (tocActive is 'accordion')?!, "Accordion"
572
- a @mouseenter: (=> tocActive = 'table'), @click: (=> tocActive = 'table'), href: "#table", $active: (tocActive is 'table')?!, "Table"
573
- a @mouseenter: (=> tocActive = 'collapsible'), @click: (=> tocActive = 'collapsible'), href: "#collapsible", $active: (tocActive is 'collapsible')?!, "Collapsible"
574
- .toc-group
575
- .toc-label "Interactive"
576
- a @mouseenter: (=> tocActive = 'pagination'), @click: (=> tocActive = 'pagination'), href: "#pagination", $active: (tocActive is 'pagination')?!, "Pagination"
577
- a @mouseenter: (=> tocActive = 'carousel'), @click: (=> tocActive = 'carousel'), href: "#carousel", $active: (tocActive is 'carousel')?!, "Carousel"
578
- a @mouseenter: (=> tocActive = 'resizable'), @click: (=> tocActive = 'resizable'), href: "#resizable", $active: (tocActive is 'resizable')?!, "Resizable"
579
- .toc-detail
580
- if tocActive
581
- .
582
- h3
583
- _infoName
584
- span.badge @click: (=> @_viewSource(tocActive)), "#{_infoLines} lines ❐"
585
- p.toc-desc _infoDesc
586
- .api
587
- dl
588
- dt "Props"
589
- dd
590
- for item in _infoProps
591
- code item
592
- if _infoEvents.length
593
- dt "Events"
594
- dd
595
- for item in _infoEvents
596
- code item
597
- if _infoKeys.length
598
- dt "Keyboard"
599
- dd
600
- for item in _infoKeys
601
- kbd item
602
- dt "Data"
603
- dd
604
- for item in _infoAttrs
605
- code item
606
- a.jump href: "##{tocActive}", @click: ((e) => @_jumpTo(e))
607
- "Jump to demo ↓"
608
- else
609
- .toc-empty "← Hover a component to see its API"
610
-
611
- # ========================================================================
612
- # SELECT
613
- # ========================================================================
614
- .section id: "select"
615
- SectionHead tag: "select", name: "Select", lines: 147
616
- .section-desc "Dropdown with typeahead, keyboard nav, ARIA listbox."
617
- .demo-row
618
- .demo-label "Basic select"
619
- Select value <=> fruit, @change: (=> null)
620
- for f in allFruits
621
- option value: f.toLowerCase(), f
622
- .status "selected: #{fruit ?? 'none'}"
623
- .demo-row
624
- .demo-label "With placeholder"
625
- Select value <=> role, placeholder: "Choose a role..."
626
- option value: "eng", "Engineer"
627
- option value: "des", "Designer"
628
- option value: "mgr", "Manager"
629
- option value: "dir", "Director"
630
- .status "selected: #{role ?? 'none'}"
631
- .api
632
- dl
633
- dt "Props"
634
- dd
635
- code "@value"
636
- code "@placeholder"
637
- code "@disabled"
638
- dt "Events"
639
- dd
640
- code "change"
641
- dt "Keyboard"
642
- dd
643
- kbd "↕"
644
- kbd "Enter"
645
- kbd "Space"
646
- kbd "Esc"
647
- kbd "Home"
648
- kbd "End"
649
- kbd "type-ahead"
650
- dt "Data"
651
- dd
652
- code "$open"
653
- code "$placeholder"
654
- code "$disabled"
655
- code "$value"
656
- code "$highlighted"
657
- code "$selected"
658
-
659
- # ========================================================================
660
- # COMBOBOX
661
- # ========================================================================
662
- .section id: "combobox"
663
- SectionHead tag: "combobox", name: "Combobox", lines: 124
664
- .section-desc "Filterable input + listbox for search-as-you-type."
665
- .demo-row
666
- .demo-label "Search fruits"
667
- Combobox query <=> searchQuery, items: filteredFruits, placeholder: "Type to search..."
668
- @select: (e) => (searchQuery = e.detail if e.detail?; filteredFruits = allFruits)
669
- @filter: (=> filteredFruits = allFruits.filter (f) -> f.toLowerCase().includes(searchQuery.toLowerCase()))
670
- .status "query: '#{searchQuery}'"
671
- .api
672
- dl
673
- dt "Props"
674
- dd
675
- code "@query"
676
- code "@items"
677
- code "@placeholder"
678
- code "@disabled"
679
- code "@autoHighlight"
680
- dt "Events"
681
- dd
682
- code "filter"
683
- code "select"
684
- dt "Keyboard"
685
- dd
686
- kbd "↕"
687
- kbd "Enter"
688
- kbd "Esc"
689
- kbd "Tab"
690
- dt "Data"
691
- dd
692
- code "$open"
693
- code "$disabled"
694
- code "$clear"
695
- code "$value"
696
- code "$highlighted"
697
- code "$empty"
698
-
699
- # ========================================================================
700
- # MULTI-SELECT
701
- # ========================================================================
702
- .section id: "multi-select"
703
- SectionHead tag: "multi-select", name: "MultiSelect", lines: 130
704
- .section-desc "Multi-select with chips, filtering, and keyboard navigation."
705
- .demo-row
706
- .demo-label "Pick colors"
707
- MultiSelect value <=> selectedColors, items: ['Red', 'Orange', 'Yellow', 'Green', 'Blue', 'Indigo', 'Violet'], placeholder: "Choose colors..."
708
- .status "selected: #{selectedColors.join(', ')}"
709
- .api
710
- dl
711
- dt "Props"
712
- dd
713
- code "@value"
714
- code "@items"
715
- code "@placeholder"
716
- code "@disabled"
717
- dt "Events"
718
- dd
719
- code "change"
720
- dt "Keyboard"
721
- dd
722
- kbd "↕"
723
- kbd "Enter"
724
- kbd "Esc"
725
- kbd "Backspace"
726
- kbd "Tab"
727
- dt "Data"
728
- dd
729
- code "$open"
730
- code "$disabled"
731
- code "$chips"
732
- code "$chip"
733
- code "$remove"
734
- code "$clear"
735
- code "$highlighted"
736
- code "$selected"
737
-
738
- # ========================================================================
739
- # AUTOCOMPLETE
740
- # ========================================================================
741
- .section id: "autocomplete"
742
- SectionHead tag: "autocomplete", name: "Autocomplete", lines: 115
743
- .section-desc "Suggestion input — type to filter, select to fill."
744
- .demo-row
745
- .demo-label "Search cities"
746
- Autocomplete value <=> citySearch, items: cities
747
- .status "value: #{citySearch}"
748
- .api
749
- dl
750
- dt "Props"
751
- dd
752
- code "@value"
753
- code "@items"
754
- code "@placeholder"
755
- code "@disabled"
756
- dt "Events"
757
- dd
758
- code "select"
759
- dt "Keyboard"
760
- dd
761
- kbd "↕"
762
- kbd "Enter"
763
- kbd "Esc"
764
- kbd "Tab"
765
- dt "Data"
766
- dd
767
- code "$open"
768
- code "$disabled"
769
- code "$clear"
770
-
771
- # ========================================================================
772
- # CHECKBOX
773
- # ========================================================================
774
- .section id: "checkbox"
775
- SectionHead tag: "checkbox", name: "Checkbox", lines: 18
776
- .section-desc "Toggle with checkbox or switch semantics. Supports indeterminate."
777
- .demo-row
778
- .demo-label "Checkbox (unchecked)"
779
- Checkbox checked <=> check1, @change: (=> p "Clicked!")
780
- "Enable notifications"
781
- .status "checked: #{check1}"
782
- .demo-row
783
- .demo-label "Checkbox (pre-checked)"
784
- Checkbox checked <=> check2
785
- "Accept terms"
786
- .status "checked: #{check2}"
787
- .demo-row
788
- .demo-label "Switch variant"
789
- Checkbox checked <=> switch1, switch: true
790
- "Dark mode"
791
- .status "on: #{switch1}"
792
- .api
793
- dl
794
- dt "Props"
795
- dd
796
- code "@checked"
797
- code "@disabled"
798
- code "@indeterminate"
799
- code "@switch"
800
- dt "Events"
801
- dd
802
- code "change"
803
- dt "Data"
804
- dd
805
- code "$checked"
806
- code "$indeterminate"
807
- code "$disabled"
808
-
809
- # ========================================================================
810
- # TOGGLE
811
- # ========================================================================
812
- .section id: "toggle"
813
- SectionHead tag: "toggle", name: "Toggle", lines: 13
814
- .section-desc "Stateful toggle button with pressed state."
815
- .demo-row
816
- .demo-label "Tap to toggle"
817
- .toggle-heart
818
- Toggle pressed <=> isBold
819
- span.heart (if isBold then "♥" else "♡")
820
- .api
821
- dl
822
- dt "Props"
823
- dd
824
- code "@pressed"
825
- code "@disabled"
826
- dt "Events"
827
- dd
828
- code "change"
829
- dt "Data"
830
- dd
831
- code "$pressed"
832
- code "$disabled"
833
-
834
- # ========================================================================
835
- # TOGGLE GROUP
836
- # ========================================================================
837
- .section id: "toggle-group"
838
- SectionHead tag: "toggle-group", name: "ToggleGroup", lines: 59
839
- .section-desc "Single or multi-select toggle buttons."
840
- .demo-row
841
- .demo-label "Text alignment"
842
- ToggleGroup value <=> alignment
843
- div $value: "left", "Left"
844
- div $value: "center", "Center"
845
- div $value: "right", "Right"
846
- .status "alignment: #{alignment ?? 'none'}"
847
- .demo-row
848
- .demo-label "Multi-select"
849
- ToggleGroup value <=> toppings, multiple: true
850
- div $value: "Cheese", "Cheese"
851
- div $value: "Bacon", "Bacon"
852
- div $value: "Lettuce", "Lettuce"
853
- .status "toppings: #{toppings.join(', ')}"
854
- .api
855
- dl
856
- dt "Props"
857
- dd
858
- code "@value"
859
- code "@disabled"
860
- code "@multiple"
861
- code "@orientation"
862
- dt "Events"
863
- dd
864
- code "change"
865
- dt "Keyboard"
866
- dd
867
- kbd "← →"
868
- kbd "↕"
869
- kbd "Home"
870
- kbd "End"
871
- dt "Data"
872
- dd
873
- code "$orientation"
874
- code "$disabled"
875
- code "$pressed"
876
- code "$value"
877
-
878
- # ========================================================================
879
- # RADIO GROUP
880
- # ========================================================================
881
- .section id: "radio-group"
882
- SectionHead tag: "radio-group", name: "RadioGroup", lines: 50
883
- .section-desc "Exactly one option selected. Arrow keys move focus and selection."
884
- .demo-row
885
- .demo-label "Font size"
886
- RadioGroup value <=> fontSize
887
- div $value: "sm", "Small"
888
- div $value: "md", "Medium"
889
- div $value: "lg", "Large"
890
- .status "fontSize: #{fontSize ?? 'none'}"
891
- .api
892
- dl
893
- dt "Props"
894
- dd
895
- code "@value"
896
- code "@disabled"
897
- code "@orientation"
898
- code "@name"
899
- dt "Events"
900
- dd
901
- code "change"
902
- dt "Keyboard"
903
- dd
904
- kbd "← →"
905
- kbd "↕"
906
- kbd "Home"
907
- kbd "End"
908
- dt "Data"
909
- dd
910
- code "$orientation"
911
- code "$disabled"
912
- code "$checked"
913
- code "$value"
914
-
915
- # ========================================================================
916
- # CHECKBOX GROUP
917
- # ========================================================================
918
- .section id: "checkbox-group"
919
- SectionHead tag: "checkbox-group", name: "CheckboxGroup", lines: 46
920
- .section-desc "Multiple options checked independently."
921
- .demo-row
922
- .demo-label "Toppings"
923
- CheckboxGroup value <=> cbToppings, label: "Pizza toppings"
924
- div $value: "Cheese", "Cheese"
925
- div $value: "Bacon", "Bacon"
926
- div $value: "Lettuce", "Lettuce"
927
- div $value: "Tomato", "Tomato"
928
- .status "selected: #{cbToppings.join(', ')}"
929
- .api
930
- dl
931
- dt "Props"
932
- dd
933
- code "@value"
934
- code "@disabled"
935
- code "@orientation"
936
- code "@label"
937
- dt "Events"
938
- dd
939
- code "change"
940
- dt "Keyboard"
941
- dd
942
- kbd "← →"
943
- kbd "↕"
944
- dt "Data"
945
- dd
946
- code "$orientation"
947
- code "$disabled"
948
- code "$checked"
949
- code "$value"
950
-
951
- # ========================================================================
952
- # INPUT
953
- # ========================================================================
954
- .section id: "input"
955
- SectionHead tag: "input", name: "Input", lines: 24
956
- .section-desc "Headless input tracking focus, touch, and validation state."
957
- .demo-row
958
- .demo-label "Text input"
959
- Input value <=> userName, placeholder: "Enter your name"
960
- .status "value: #{userName}"
961
- .api
962
- dl
963
- dt "Props"
964
- dd
965
- code "@value"
966
- code "@placeholder"
967
- code "@type"
968
- code "@disabled"
969
- code "@required"
970
- dt "Data"
971
- dd
972
- code "$disabled"
973
- code "$focused"
974
- code "$touched"
975
-
976
- # ========================================================================
977
- # NUMBER FIELD
978
- # ========================================================================
979
- .section id: "number-field"
980
- SectionHead tag: "number-field", name: "NumberField", lines: 132
981
- .section-desc "Number input with increment/decrement buttons, hold-to-repeat, and keyboard stepping."
982
- .demo-row
983
- .demo-label "Quantity (1-99)"
984
- .nf-wrap
985
- NumberField value <=> quantity, min: 1, max: 99
986
- .status "quantity: #{quantity}"
987
- .demo-row
988
- .demo-label "Price (step: 0.01)"
989
- .nf-wrap
990
- NumberField value <=> price, min: 0, max: 999.99, step: 0.01
991
- .status "price: #{price}"
992
- .api
993
- dl
994
- dt "Props"
995
- dd
996
- code "@value"
997
- code "@min"
998
- code "@max"
999
- code "@step"
1000
- code "@disabled"
1001
- code "@readOnly"
1002
- dt "Events"
1003
- dd
1004
- code "input"
1005
- code "change"
1006
- dt "Keyboard"
1007
- dd
1008
- kbd "↕"
1009
- kbd "PgUp"
1010
- kbd "PgDn"
1011
- kbd "Home"
1012
- kbd "End"
1013
- dt "Data"
1014
- dd
1015
- code "$disabled"
1016
- code "$readonly"
1017
- code "$decrement"
1018
- code "$increment"
1019
-
1020
- # ========================================================================
1021
- # SLIDER
1022
- # ========================================================================
1023
- .section id: "slider"
1024
- SectionHead tag: "slider", name: "Slider", lines: 130
1025
- .section-desc "Draggable range input with pointer capture and keyboard stepping."
1026
- .demo-row
1027
- .demo-label "Single thumb"
1028
- .slider-wrap
1029
- Slider value <=> sliderVal
1030
- .status "value: #{sliderVal}"
1031
- .demo-row
1032
- .demo-label "Range (two thumbs)"
1033
- .slider-wrap
1034
- Slider value <=> rangeVal
1035
- .status "range: #{rangeVal}"
1036
- .api
1037
- dl
1038
- dt "Props"
1039
- dd
1040
- code "@value"
1041
- code "@min"
1042
- code "@max"
1043
- code "@step"
1044
- code "@orientation"
1045
- code "@disabled"
1046
- dt "Events"
1047
- dd
1048
- code "input"
1049
- code "change"
1050
- dt "Keyboard"
1051
- dd
1052
- kbd "← →"
1053
- kbd "↕"
1054
- kbd "PgUp"
1055
- kbd "PgDn"
1056
- kbd "Home"
1057
- kbd "End"
1058
- dt "Data"
1059
- dd
1060
- code "$orientation"
1061
- code "$disabled"
1062
- code "$dragging"
1063
- code "$track"
1064
- code "$indicator"
1065
- code "$thumb"
1066
- code "$active"
1067
-
1068
- # ========================================================================
1069
- # OTP FIELD
1070
- # ========================================================================
1071
- .section id: "otp-field"
1072
- SectionHead tag: "otp-field", name: "OTPField", lines: 72
1073
- .section-desc "Multi-digit code input with auto-advance, backspace nav, and paste."
1074
- .demo-row
1075
- .demo-label "6-digit code"
1076
- OTPField length: 6, value <=> otpCode
1077
- .status "code: '#{otpCode}'"
1078
- .demo-row
1079
- .demo-label "4-digit masked"
1080
- OTPField length: 4, mask: true
1081
- .api
1082
- dl
1083
- dt "Props"
1084
- dd
1085
- code "@length"
1086
- code "@value"
1087
- code "@disabled"
1088
- code "@mask"
1089
- dt "Events"
1090
- dd
1091
- code "input"
1092
- code "complete"
1093
- dt "Keyboard"
1094
- dd
1095
- kbd "← →"
1096
- kbd "Backspace"
1097
- kbd "Home"
1098
- kbd "End"
1099
- kbd "paste"
1100
- dt "Data"
1101
- dd
1102
- code "$disabled"
1103
- code "$complete"
1104
- code "$filled"
1105
-
1106
- # ========================================================================
1107
- # DATE PICKER
1108
- # ========================================================================
1109
- .section id: "date-picker"
1110
- SectionHead tag: "date-picker", name: "DatePicker", lines: 172
1111
- .section-desc "Calendar dropdown for single date or range selection."
1112
- .demo-row
1113
- .demo-label "Single date"
1114
- DatePicker value <=> pickedDate
1115
- .status "date: #{if pickedDate then pickedDate.toLocaleDateString() else 'none'}"
1116
- .demo-row
1117
- .demo-label "Date range"
1118
- DatePicker value <=> dateRange, range: true
1119
- .status "range: #{if dateRange and dateRange[0] then dateRange[0].toLocaleDateString() else 'none'} – #{if dateRange and dateRange[1] then dateRange[1].toLocaleDateString() else '...'}"
1120
- .api
1121
- dl
1122
- dt "Props"
1123
- dd
1124
- code "@value"
1125
- code "@placeholder"
1126
- code "@disabled"
1127
- code "@range"
1128
- code "@firstDayOfWeek"
1129
- dt "Events"
1130
- dd
1131
- code "change"
1132
- dt "Keyboard"
1133
- dd
1134
- kbd "Esc"
1135
- kbd "Enter"
1136
- kbd "Space"
1137
- dt "Data"
1138
- dd
1139
- code "$open"
1140
- code "$disabled"
1141
- code "$range"
1142
- code "$calendar"
1143
- code "$selected"
1144
- code "$today"
1145
- code "$in-range"
1146
-
1147
- # ========================================================================
1148
- # EDITABLE VALUE
1149
- # ========================================================================
1150
- .section id: "editable-value"
1151
- SectionHead tag: "editable-value", name: "EditableValue", lines: 58
1152
- .section-desc "Click the edit icon to modify the value inline."
1153
- .demo-row
1154
- EditableValue @save: (=> editName = editName)
1155
- span $display: true
1156
- editName
1157
- div $editor: true, hidden: true
1158
- input type: "text", value: editName
1159
- @input: (e) => editName = e.target.value
1160
- .api
1161
- dl
1162
- dt "Props"
1163
- dd
1164
- code "@disabled"
1165
- dt "Events"
1166
- dd
1167
- code "save"
1168
- dt "Keyboard"
1169
- dd
1170
- kbd "Esc"
1171
- kbd "Enter"
1172
- dt "Data"
1173
- dd
1174
- code "$editing"
1175
- code "$disabled"
1176
- code "$saving"
1177
- code "$edit-trigger"
1178
-
1179
- # ========================================================================
1180
- # TEXTAREA
1181
- # ========================================================================
1182
- .section id: "textarea"
1183
- SectionHead tag: "textarea", name: "Textarea", lines: 33
1184
- .section-desc "Auto-resizing text area with focus and validation tracking."
1185
- .demo-row
1186
- .demo-label "Auto-resize textarea"
1187
- Textarea value <=> textareaVal, placeholder: "Type something...", autoResize: true
1188
- .status "length: #{textareaVal.length}"
1189
- .api
1190
- dl
1191
- dt "Props"
1192
- dd
1193
- code "@value"
1194
- code "@placeholder"
1195
- code "@disabled"
1196
- code "@required"
1197
- code "@rows"
1198
- code "@autoResize"
1199
- dt "Data"
1200
- dd
1201
- code "$disabled"
1202
- code "$focused"
1203
- code "$touched"
1204
-
1205
- # ========================================================================
1206
- # NATIVE SELECT
1207
- # ========================================================================
1208
- .section id: "native-select"
1209
- SectionHead tag: "native-select", name: "NativeSelect", lines: 18
1210
- .section-desc "Native browser select element with state tracking."
1211
- .demo-row.native-select-demo
1212
- .demo-label "Choose a color"
1213
- NativeSelect value <=> nativeSelectVal
1214
- option value: "", "Pick one..."
1215
- option value: "red", "Red"
1216
- option value: "green", "Green"
1217
- option value: "blue", "Blue"
1218
- .status "value: '#{nativeSelectVal}'"
1219
- .api
1220
- dl
1221
- dt "Props"
1222
- dd
1223
- code "@value"
1224
- code "@disabled"
1225
- code "@required"
1226
- dt "Events"
1227
- dd
1228
- code "change"
1229
- dt "Data"
1230
- dd
1231
- code "$disabled"
1232
- code "$focused"
1233
-
1234
- # ========================================================================
1235
- # INPUT GROUP
1236
- # ========================================================================
1237
- .section id: "input-group"
1238
- SectionHead tag: "input-group", name: "InputGroup", lines: 11
1239
- .section-desc "Input with prefix/suffix addon elements."
1240
- .demo-row.input-group-demo
1241
- .demo-label "With prefix"
1242
- InputGroup
1243
- span $prefix: true, "$"
1244
- input type: "text", placeholder: "Amount"
1245
- .demo-row.input-group-demo
1246
- .demo-label "With suffix"
1247
- InputGroup
1248
- input type: "text", placeholder: "Search..."
1249
- button $suffix: true, "Go"
1250
- .api
1251
- dl
1252
- dt "Props"
1253
- dd
1254
- code "@disabled"
1255
- dt "Data"
1256
- dd
1257
- code "$disabled"
1258
- code "$focused"
1259
-
1260
- # ========================================================================
1261
- # TABS
1262
- # ========================================================================
1263
- .section id: "tabs"
1264
- SectionHead tag: "tabs", name: "Tabs", lines: 91
1265
- .section-desc "Tab panel with roving tabindex and arrow key navigation."
1266
- .demo-row
1267
- .demo-label "Basic tabs"
1268
- Tabs active <=> currentTab
1269
- div data-tab: "overview", "Overview"
1270
- div data-tab: "details", "Details"
1271
- div data-tab: "settings", "Settings"
1272
- div data-panel: "overview"
1273
- p "This is the overview panel."
1274
- div data-panel: "details"
1275
- p "These are the details."
1276
- div data-panel: "settings"
1277
- p "Settings go here."
1278
- .status "active: #{currentTab}"
1279
- .api
1280
- dl
1281
- dt "Props"
1282
- dd
1283
- code "@active"
1284
- code "@orientation"
1285
- code "@activation"
1286
- dt "Events"
1287
- dd
1288
- code "change"
1289
- dt "Keyboard"
1290
- dd
1291
- kbd "← →"
1292
- kbd "↕"
1293
- kbd "Home"
1294
- kbd "End"
1295
- kbd "Enter"
1296
- kbd "Space"
1297
- dt "Data"
1298
- dd
1299
- code "$tab"
1300
- code "$panel"
1301
- code "$active"
1302
- code "$disabled"
1303
-
1304
- # ========================================================================
1305
- # MENU
1306
- # ========================================================================
1307
- .section id: "menu"
1308
- SectionHead tag: "menu", name: "Menu", lines: 133
1309
- .section-desc "Dropdown action menu with keyboard navigation."
1310
- .demo-row
1311
- .demo-label "Click to open menu"
1312
- Menu
1313
- @select: (e) => console.log("Selected: #{e.detail}")
1314
- span "Actions"
1315
- div data-item: "edit", "Edit"
1316
- div data-item: "duplicate", "Duplicate"
1317
- div data-item: "archive", "Archive"
1318
- div data-item: "delete", "Delete"
1319
- .api
1320
- dl
1321
- dt "Props"
1322
- dd
1323
- code "@disabled"
1324
- dt "Events"
1325
- dd
1326
- code "select"
1327
- dt "Keyboard"
1328
- dd
1329
- kbd "↕"
1330
- kbd "Home"
1331
- kbd "End"
1332
- kbd "Enter"
1333
- kbd "Space"
1334
- kbd "Esc"
1335
- kbd "Tab"
1336
- kbd "type-ahead"
1337
- dt "Data"
1338
- dd
1339
- code "$open"
1340
- code "$disabled"
1341
- code "$highlighted"
1342
- code "$value"
1343
-
1344
- # ========================================================================
1345
- # CONTEXT MENU
1346
- # ========================================================================
1347
- .section id: "context-menu"
1348
- SectionHead tag: "context-menu", name: "ContextMenu", lines: 80
1349
- .section-desc "Right-click the dashed area to open a context menu."
1350
- ContextMenu
1351
- div $trigger: true
1352
- .context-zone
1353
- "Right-click here"
1354
- div $item: "cut", "Cut"
1355
- div $item: "copy", "Copy"
1356
- div $item: "paste", "Paste"
1357
- .api
1358
- dl
1359
- dt "Props"
1360
- dd
1361
- code "@disabled"
1362
- dt "Events"
1363
- dd
1364
- code "select"
1365
- dt "Keyboard"
1366
- dd
1367
- kbd "↕"
1368
- kbd "Home"
1369
- kbd "End"
1370
- kbd "Enter"
1371
- kbd "Space"
1372
- kbd "Esc"
1373
- kbd "Tab"
1374
- dt "Data"
1375
- dd
1376
- code "$open"
1377
- code "$highlighted"
1378
- code "$disabled"
1379
- code "$value"
1380
-
1381
- # ========================================================================
1382
- # MENUBAR
1383
- # ========================================================================
1384
- .section id: "menubar"
1385
- SectionHead tag: "menubar", name: "Menubar", lines: 125
1386
- .section-desc "Horizontal menu bar with dropdown menus."
1387
- .demo-row
1388
- Menubar
1389
- div $menu: "File"
1390
- div $item: "new", "New"
1391
- div $item: "open", "Open"
1392
- div $item: "save", "Save"
1393
- div $menu: "Edit"
1394
- div $item: "undo", "Undo"
1395
- div $item: "redo", "Redo"
1396
- div $item: "cut", "Cut"
1397
- div $menu: "View"
1398
- div $item: "zoom-in", "Zoom In"
1399
- div $item: "zoom-out", "Zoom Out"
1400
- .api
1401
- dl
1402
- dt "Props"
1403
- dd
1404
- code "@disabled"
1405
- dt "Events"
1406
- dd
1407
- code "select"
1408
- dt "Keyboard"
1409
- dd
1410
- kbd "← →"
1411
- kbd "↕"
1412
- kbd "Enter"
1413
- kbd "Space"
1414
- kbd "Esc"
1415
- kbd "Tab"
1416
- dt "Data"
1417
- dd
1418
- code "$disabled"
1419
- code "$open"
1420
- code "$highlighted"
1421
- code "$value"
1422
-
1423
- # ========================================================================
1424
- # NAVIGATION MENU
1425
- # ========================================================================
1426
- .section id: "nav-menu"
1427
- SectionHead tag: "nav-menu", name: "NavigationMenu", lines: 99
1428
- .section-desc "Site navigation with dropdown panels."
1429
- .demo-row
1430
- NavigationMenu
1431
- a $link: true, href: "javascript:void(0)"
1432
- "Home"
1433
- div $trigger: "Products"
1434
- div $panel: true
1435
- a href: "javascript:void(0)", "Components"
1436
- a href: "javascript:void(0)", "Templates"
1437
- a href: "javascript:void(0)", "Playground"
1438
- div $trigger: "Learn"
1439
- div $panel: true
1440
- a href: "javascript:void(0)", "Documentation"
1441
- a href: "javascript:void(0)", "Blog"
1442
- a href: "javascript:void(0)", "Changelog"
1443
- a $link: true, href: "javascript:void(0)"
1444
- "GitHub"
1445
- .api
1446
- dl
1447
- dt "Props"
1448
- dd
1449
- code "@orientation"
1450
- code "@hoverDelay"
1451
- code "@hoverCloseDelay"
1452
- dt "Keyboard"
1453
- dd
1454
- kbd "← →"
1455
- kbd "↓"
1456
- kbd "Esc"
1457
- dt "Data"
1458
- dd
1459
- code "$orientation"
1460
- code "$open"
1461
-
1462
- # ========================================================================
1463
- # TOOLBAR
1464
- # ========================================================================
1465
- .section id: "toolbar"
1466
- SectionHead tag: "toolbar", name: "Toolbar", lines: 31
1467
- .section-desc "Groups controls with roving tabindex keyboard navigation."
1468
- .demo-row
1469
- .demo-label "Text"
1470
- Toolbar label: "Formatting"
1471
- Button
1472
- "Save"
1473
- Button
1474
- "Undo"
1475
- Separator orientation: "vertical"
1476
- Toggle pressed <=> isBold
1477
- "Bold"
1478
- Toggle pressed <=> isItalic
1479
- "Italic"
1480
- .demo-row
1481
- .demo-label "Icons + Text"
1482
- Toolbar label: "Formatting"
1483
- Button
1484
- "💾 Save"
1485
- Button
1486
- "↩ Undo"
1487
- Separator orientation: "vertical"
1488
- Toggle pressed <=> isBold
1489
- "𝐁 Bold"
1490
- Toggle pressed <=> isItalic
1491
- "𝐼 Italic"
1492
- .demo-row
1493
- .demo-label "Icons Only"
1494
- Toolbar label: "Formatting"
1495
- Button aria-label: "Save"
1496
- "💾"
1497
- Button aria-label: "Undo"
1498
- "↩"
1499
- Separator orientation: "vertical"
1500
- Toggle pressed <=> isBold, aria-label: "Bold"
1501
- "𝐁"
1502
- Toggle pressed <=> isItalic, aria-label: "Italic"
1503
- "𝐼"
1504
- .api
1505
- dl
1506
- dt "Props"
1507
- dd
1508
- code "@orientation"
1509
- code "@label"
1510
- dt "Keyboard"
1511
- dd
1512
- kbd "← →"
1513
- kbd "↕"
1514
- kbd "Home"
1515
- kbd "End"
1516
- dt "Data"
1517
- dd
1518
- code "$orientation"
1519
-
1520
- # ========================================================================
1521
- # BREADCRUMB
1522
- # ========================================================================
1523
- .section id: "breadcrumb"
1524
- SectionHead tag: "breadcrumb", name: "Breadcrumb", lines: 25
1525
- .section-desc "Navigation trail with separator and current page."
1526
- .demo-row
1527
- .demo-label "Basic breadcrumb"
1528
- Breadcrumb
1529
- a $item: true, href: "#breadcrumb", "Home"
1530
- a $item: true, href: "#breadcrumb", "Products"
1531
- a $item: true, href: "#breadcrumb", "Widgets"
1532
- span $item: true, "Widget Pro"
1533
- .api
1534
- dl
1535
- dt "Props"
1536
- dd
1537
- code "@separator"
1538
- code "@label"
1539
- dt "Data"
1540
- dd
1541
- code "$current"
1542
-
1543
- # ========================================================================
1544
- # DIALOG
1545
- # ========================================================================
1546
- .section id: "dialog"
1547
- SectionHead tag: "dialog", name: "Dialog", lines: 83
1548
- .section-desc "Modal with focus trap and scroll lock. Press Escape or click outside to dismiss."
1549
- .demo-row
1550
- .demo-label "Click to open"
1551
- button.demo-btn @click: (=> showDialog = true)
1552
- "Open Dialog"
1553
- .status "open: #{showDialog}"
1554
- Dialog open <=> showDialog, @close: (=> showDialog = false)
1555
- .dialog-panel
1556
- h2 style: "font-size:18px;font-weight:600;margin-bottom:8px", "Confirm Action"
1557
- p.dialog-desc "Are you sure you want to proceed?"
1558
- . style: "display:flex;gap:8px;justify-content:flex-end"
1559
- button.demo-btn @click: (=> showDialog = false)
1560
- "Cancel"
1561
- button style: "padding:6px 16px;border:none;border-radius:6px;background:#1d4ed8;color:white;font-weight:600", @click: (=> showDialog = false)
1562
- "Confirm"
1563
- .api
1564
- dl
1565
- dt "Props"
1566
- dd
1567
- code "@open"
1568
- code "@dismissable"
1569
- code "@initialFocus"
1570
- dt "Events"
1571
- dd
1572
- code "close"
1573
- dt "Keyboard"
1574
- dd
1575
- kbd "Esc"
1576
- kbd "Tab"
1577
- dt "Data"
1578
- dd
1579
- code "$open"
1580
-
1581
- # ========================================================================
1582
- # ALERT DIALOG
1583
- # ========================================================================
1584
- .section id: "alert-dialog"
1585
- SectionHead tag: "alert-dialog", name: "AlertDialog", lines: 74
1586
- .section-desc "Non-dismissable modal — Escape and click-outside are blocked. User must choose an action."
1587
- .demo-row
1588
- .demo-label "Requires explicit action"
1589
- button.demo-btn @click: (=> showAlertDialog = true)
1590
- "Delete Account"
1591
- .status "open: #{showAlertDialog}"
1592
- AlertDialog open <=> showAlertDialog
1593
- .dialog-panel
1594
- h2 style: "font-size:18px;font-weight:600;margin-bottom:8px", "Delete Account?"
1595
- p.dialog-desc "This action is permanent and cannot be undone."
1596
- . style: "display:flex;gap:8px;justify-content:flex-end"
1597
- button.demo-btn @click: (=> showAlertDialog = false)
1598
- "Cancel"
1599
- button style: "padding:6px 16px;border:none;border-radius:6px;background:#dc2626;color:white;font-weight:600", @click: (=> showAlertDialog = false)
1600
- "Delete"
1601
- .api
1602
- dl
1603
- dt "Props"
1604
- dd
1605
- code "@open"
1606
- code "@initialFocus"
1607
- dt "Events"
1608
- dd
1609
- code "close"
1610
- dt "Keyboard"
1611
- dd
1612
- kbd "Tab"
1613
- dt "Data"
1614
- dd
1615
- code "$open"
1616
-
1617
- # ========================================================================
1618
- # DRAWER
1619
- # ========================================================================
1620
- .section id: "drawer"
1621
- SectionHead tag: "drawer", name: "Drawer", lines: 60
1622
- .section-desc "Slide-out panel from edge of screen with focus trap and scroll lock."
1623
- .demo-row
1624
- .demo-label "Open from right"
1625
- .btn-demo
1626
- .btn-row
1627
- button @click: (=> showDrawer = true)
1628
- "Open Drawer"
1629
- Drawer open <=> showDrawer, side: "right"
1630
- .drawer-panel
1631
- h2 "Settings"
1632
- p "This is a drawer panel that slides in from the right."
1633
- p "Press Escape or click outside to close."
1634
- button @click: (=> showDrawer = false)
1635
- "Close"
1636
- .api
1637
- dl
1638
- dt "Props"
1639
- dd
1640
- code "@open"
1641
- code "@side"
1642
- code "@dismissable"
1643
- dt "Events"
1644
- dd
1645
- code "close"
1646
- dt "Keyboard"
1647
- dd
1648
- kbd "Esc"
1649
- kbd "Tab"
1650
- dt "Data"
1651
- dd
1652
- code "$open"
1653
- code "$side"
1654
-
1655
- # ========================================================================
1656
- # POPOVER
1657
- # ========================================================================
1658
- .section id: "popover"
1659
- SectionHead tag: "popover", name: "Popover", lines: 117
1660
- .section-desc "Anchored floating content with flip/shift positioning."
1661
- .demo-row
1662
- .demo-label "Click to toggle"
1663
- Popover placement: "bottom-start"
1664
- button.demo-btn data-trigger: true
1665
- "Open Popover"
1666
- div.floating-panel data-content: true
1667
- p.floating-title "Popover content"
1668
- p.floating-desc "Click outside or press Escape to close."
1669
- .api
1670
- dl
1671
- dt "Props"
1672
- dd
1673
- code "@placement"
1674
- code "@offset"
1675
- code "@disabled"
1676
- code "@openOnHover"
1677
- code "@hoverDelay"
1678
- code "@hoverCloseDelay"
1679
- dt "Keyboard"
1680
- dd
1681
- kbd "Esc"
1682
- kbd "Enter"
1683
- kbd "Space"
1684
- kbd "↓"
1685
- dt "Data"
1686
- dd
1687
- code "$open"
1688
- code "$placement"
1689
-
1690
- # ========================================================================
1691
- # TOOLTIP
1692
- # ========================================================================
1693
- .section id: "tooltip"
1694
- SectionHead tag: "tooltip", name: "Tooltip", lines: 92
1695
- .section-desc "Hover/focus tooltip with delay and positioning."
1696
- .demo-row
1697
- .demo-label "Hover the buttons"
1698
- . style: "display:flex;gap:12px"
1699
- Tooltip text: "Save your changes", placement: "top"
1700
- button.demo-btn
1701
- "Save (top)"
1702
- Tooltip text: "Delete this item", placement: "bottom"
1703
- button.demo-btn
1704
- "Delete (bottom)"
1705
- .api
1706
- dl
1707
- dt "Props"
1708
- dd
1709
- code "@text"
1710
- code "@placement"
1711
- code "@delay"
1712
- code "@offset"
1713
- code "@hoverable"
1714
- dt "Data"
1715
- dd
1716
- code "$open"
1717
- code "$entering"
1718
- code "$exiting"
1719
- code "$placement"
1720
-
1721
- # ========================================================================
1722
- # PREVIEW CARD
1723
- # ========================================================================
1724
- .section id: "preview-card"
1725
- SectionHead tag: "preview-card", name: "PreviewCard", lines: 56
1726
- .section-desc "Hover or focus the link to see a preview card."
1727
- .demo-row
1728
- PreviewCard delay: 300
1729
- a $trigger: true, href: "#preview-card", @click: ((e) => e.preventDefault())
1730
- "Hover me for preview"
1731
- div $content: true, hidden: true
1732
- .floating-panel style: "width:240px"
1733
- p.floating-title "Preview Card"
1734
- p.floating-desc "This content appears on hover or focus. Useful for link previews."
1735
- .api
1736
- dl
1737
- dt "Props"
1738
- dd
1739
- code "@delay"
1740
- code "@closeDelay"
1741
- dt "Data"
1742
- dd
1743
- code "$open"
1744
-
1745
- # ========================================================================
1746
- # TOAST
1747
- # ========================================================================
1748
- .section id: "toast"
1749
- SectionHead tag: "toast", name: "Toast", lines: 56
1750
- .section-desc "Auto-dismiss notification with ARIA live region."
1751
- .demo-row
1752
- .demo-label "Click to show toasts"
1753
- button.demo-btn @click: (=> toasts = [...toasts, { message: 'Hello!', type: 'info' }])
1754
- "Info Toast"
1755
- button.demo-btn style: "margin-left:8px", @click: (=> toasts = [...toasts, { message: 'Saved!', type: 'success' }])
1756
- "Success Toast"
1757
- .toast-wrap
1758
- ToastViewport toasts <=> toasts
1759
- .api
1760
- dl
1761
- dt "Props"
1762
- dd
1763
- code "@toasts"
1764
- code "@toast"
1765
- code "@placement"
1766
- dt "Events"
1767
- dd
1768
- code "dismiss"
1769
- dt "Data"
1770
- dd
1771
- code "$placement"
1772
- code "$type"
1773
- code "$leaving"
1774
-
1775
- # ========================================================================
1776
- # BUTTON
1777
- # ========================================================================
1778
- .section id: "button"
1779
- SectionHead tag: "button", name: "Button", lines: 10
1780
- .section-desc "Headless button with disabled-but-focusable pattern."
1781
- .demo-row.btn-demo
1782
- .demo-label "Normal, primary, and disabled"
1783
- .btn-row
1784
- Button @press: (=> p "Pressed!")
1785
- "Click Me"
1786
- Button @press: (=> p "Saved!")
1787
- "Save"
1788
- Button disabled: true
1789
- "Disabled"
1790
- .api
1791
- dl
1792
- dt "Props"
1793
- dd
1794
- code "@disabled"
1795
- dt "Events"
1796
- dd
1797
- code "press"
1798
- dt "Data"
1799
- dd
1800
- code "$disabled"
1801
-
1802
- # ========================================================================
1803
- # BADGE
1804
- # ========================================================================
1805
- .section id: "badge"
1806
- SectionHead tag: "badge", name: "Badge", lines: 5
1807
- .section-desc "Inline label with variant styles."
1808
- .demo-row
1809
- .demo-label "Variants"
1810
- . style: "display:flex;gap:8px;align-items:center"
1811
- Badge "Solid"
1812
- Badge variant: "outline", "Outline"
1813
- Badge variant: "subtle", "Subtle"
1814
- .api
1815
- dl
1816
- dt "Props"
1817
- dd
1818
- code "@variant"
1819
- dt "Data"
1820
- dd
1821
- code "$variant"
1822
-
1823
- # ========================================================================
1824
- # CARD
1825
- # ========================================================================
1826
- .section id: "card"
1827
- SectionHead tag: "card", name: "Card", lines: 6
1828
- .section-desc "Structured container with header, content, and footer."
1829
- .demo-row.card-demo
1830
- Card
1831
- div $header: true
1832
- h3 "Card Title"
1833
- div $content: true
1834
- "This is the card body. Cards can contain any content."
1835
- div $footer: true
1836
- button.demo-btn @click: (=> toasts = [...toasts, { message: 'Card action clicked!', type: 'success' }]), "Action"
1837
- .api
1838
- dl
1839
- dt "Props"
1840
- dd
1841
- code "@interactive"
1842
- dt "Data"
1843
- dd
1844
- code "$interactive"
1845
-
1846
- # ========================================================================
1847
- # SEPARATOR
1848
- # ========================================================================
1849
- .section id: "separator"
1850
- SectionHead tag: "separator", name: "Separator", lines: 7
1851
- .section-desc "Decorative or semantic divider between sections."
1852
- .demo-row
1853
- .demo-label "Horizontal (default)"
1854
- div style: "width:100%"
1855
- p "Above the separator"
1856
- Separator
1857
- p "Below the separator"
1858
- .demo-row
1859
- .demo-label "Vertical"
1860
- div style: "display:flex;align-items:center;gap:12px;height:32px"
1861
- span "Left"
1862
- Separator orientation: "vertical"
1863
- span "Right"
1864
- .api
1865
- dl
1866
- dt "Props"
1867
- dd
1868
- code "@orientation"
1869
- code "@decorative"
1870
- dt "Data"
1871
- dd
1872
- code "$orientation"
1873
-
1874
- # ========================================================================
1875
- # PROGRESS
1876
- # ========================================================================
1877
- .section id: "progress"
1878
- SectionHead tag: "progress", name: "Progress", lines: 14
1879
- .section-desc "Progress bar with value exposed as CSS custom property."
1880
- .demo-row
1881
- .demo-label "65% complete"
1882
- Progress value: progressVal
1883
- div.progress-track
1884
- div.progress-fill style: "width: var(--progress-percent)"
1885
- .api
1886
- dl
1887
- dt "Props"
1888
- dd
1889
- code "@value"
1890
- code "@max"
1891
- code "@label"
1892
- dt "Data"
1893
- dd
1894
- code "$complete"
1895
-
1896
- # ========================================================================
1897
- # METER
1898
- # ========================================================================
1899
- .section id: "meter"
1900
- SectionHead tag: "meter", name: "Meter", lines: 23
1901
- .section-desc "Gauge for known-range measurements with low/high/optimum thresholds."
1902
- .demo-row
1903
- .demo-label "Score: 72/100"
1904
- Meter value: meterVal, min: 0, max: 100, low: 30, high: 80, optimum: 60
1905
- .api
1906
- dl
1907
- dt "Props"
1908
- dd
1909
- code "@value"
1910
- code "@min"
1911
- code "@max"
1912
- code "@low"
1913
- code "@high"
1914
- code "@optimum"
1915
- code "@label"
1916
- dt "Data"
1917
- dd
1918
- code "$level"
1919
-
1920
- # ========================================================================
1921
- # SPINNER
1922
- # ========================================================================
1923
- .section id: "spinner"
1924
- SectionHead tag: "spinner", name: "Spinner", lines: 6
1925
- .section-desc "Loading indicator with accessible status."
1926
- .demo-row.spinner-demo
1927
- .demo-label "Default"
1928
- . style: "display:flex;gap:16px;align-items:center"
1929
- Spinner
1930
- Spinner size: "32px"
1931
- Spinner label: "Saving...", size: "20px"
1932
- .api
1933
- dl
1934
- dt "Props"
1935
- dd
1936
- code "@label"
1937
- code "@size"
1938
-
1939
- # ========================================================================
1940
- # SKELETON
1941
- # ========================================================================
1942
- .section id: "skeleton"
1943
- SectionHead tag: "skeleton", name: "Skeleton", lines: 10
1944
- .section-desc "Loading placeholder with shimmer animation."
1945
- .demo-row
1946
- .demo-label "Shapes"
1947
- . style: "display:flex;gap:12px;align-items:center"
1948
- Skeleton circle: true, width: "40px", height: "40px"
1949
- . style: "display:flex;flex-direction:column;gap:6px"
1950
- Skeleton width: "200px", height: "14px"
1951
- Skeleton width: "150px", height: "14px"
1952
- .api
1953
- dl
1954
- dt "Props"
1955
- dd
1956
- code "@width"
1957
- code "@height"
1958
- code "@circle"
1959
- code "@label"
1960
- dt "Data"
1961
- dd
1962
- code "$circle"
1963
-
1964
- # ========================================================================
1965
- # AVATAR
1966
- # ========================================================================
1967
- .section id: "avatar"
1968
- SectionHead tag: "avatar", name: "Avatar", lines: 23
1969
- .section-desc "Image with fallback to initials or placeholder."
1970
- .demo-row
1971
- .demo-label "With image"
1972
- Avatar src: "https://i.pravatar.cc/80?u=linda", alt: "Alice Chen"
1973
- .demo-row
1974
- .demo-label "Initials fallback"
1975
- Avatar alt: "Bob Park", fallback: "BP"
1976
- .demo-row
1977
- .demo-label "Placeholder"
1978
- Avatar
1979
- .api
1980
- dl
1981
- dt "Props"
1982
- dd
1983
- code "@src"
1984
- code "@alt"
1985
- code "@fallback"
1986
- dt "Data"
1987
- dd
1988
- code "$status"
1989
- code "$initials"
1990
- code "$placeholder"
1991
-
1992
- # ========================================================================
1993
- # LABEL
1994
- # ========================================================================
1995
- .section id: "label"
1996
- SectionHead tag: "label", name: "Label", lines: 6
1997
- .section-desc "Standalone accessible form label."
1998
- .demo-row
1999
- .demo-label "With required indicator"
2000
- Label required: true
2001
- "Email address"
2002
- .api
2003
- dl
2004
- dt "Props"
2005
- dd
2006
- code "@for"
2007
- code "@required"
2008
- dt "Data"
2009
- dd
2010
- code "$required"
2011
-
2012
- # ========================================================================
2013
- # SCROLL AREA
2014
- # ========================================================================
2015
- .section id: "scroll-area"
2016
- SectionHead tag: "scroll-area", name: "ScrollArea", lines: 115
2017
- .section-desc "Custom scrollbar with draggable thumb and auto-hide."
2018
- .demo-row
2019
- .demo-label "Scrollable content"
2020
- .scroll-demo
2021
- ScrollArea
2022
- div style: "padding: 4px 12px"
2023
- p "Item 1 — Lorem ipsum dolor sit amet, consectetur adipiscing elit."
2024
- p "Item 2 — Sed do eiusmod tempor incididunt ut labore et dolore."
2025
- p "Item 3 — Ut enim ad minim veniam, quis nostrud exercitation."
2026
- p "Item 4 — Duis aute irure dolor in reprehenderit in voluptate."
2027
- p "Item 5 — Excepteur sint occaecat cupidatat non proident."
2028
- p "Item 6 — Sunt in culpa qui officia deserunt mollit anim id."
2029
- p "Item 7 — Lorem ipsum dolor sit amet, consectetur adipiscing."
2030
- p "Item 8 — Sed do eiusmod tempor incididunt ut labore et dolore."
2031
- p "Item 9 — Ut enim ad minim veniam, quis nostrud exercitation."
2032
- p "Item 10 — Duis aute irure dolor in reprehenderit in voluptate."
2033
- p "Item 11 — Excepteur sint occaecat cupidatat non proident."
2034
- p "Item 12 — Sunt in culpa qui officia deserunt mollit anim id."
2035
- p "Item 13 — Lorem ipsum dolor sit amet, consectetur adipiscing."
2036
- p "Item 14 — Sed do eiusmod tempor incididunt ut labore et dolore."
2037
- p "Item 15 — Ut enim ad minim veniam, quis nostrud exercitation."
2038
- .api
2039
- dl
2040
- dt "Props"
2041
- dd
2042
- code "@orientation"
2043
- dt "Data"
2044
- dd
2045
- code "$orientation"
2046
- code "$hovering"
2047
- code "$scrolling"
2048
- code "$dragging"
2049
- code "$viewport"
2050
- code "$scrollbar"
2051
- code "$thumb"
2052
-
2053
- # ========================================================================
2054
- # FIELD + FIELDSET
2055
- # ========================================================================
2056
- .section id: "field"
2057
- SectionHead tag: "field", name: "Field + Fieldset", lines: 48
2058
- .section-desc "Form field wrapper with label, description, and error."
2059
- .demo-row
2060
- Field label: "Email", description: "We'll never share your email.", required: true, error: fieldError
2061
- input type: "email", placeholder: "you@example.com", value: fieldEmail
2062
- @input: (e) =>
2063
- fieldEmail = e.target.value
2064
- fieldError = if fieldEmail and not fieldEmail.includes('@') then 'Invalid email address' else ''
2065
- .demo-row
2066
- Fieldset legend: "Account Info"
2067
- Field label: "Username"
2068
- input type: "text", placeholder: "username"
2069
- Field label: "Password"
2070
- input type: "password", placeholder: "password"
2071
- .api
2072
- dl
2073
- dt "Field"
2074
- dd
2075
- code "@label"
2076
- code "@description"
2077
- code "@error"
2078
- code "@disabled"
2079
- code "@required"
2080
- dt "Fieldset"
2081
- dd
2082
- code "@legend"
2083
- code "@disabled"
2084
- dt "Data"
2085
- dd
2086
- code "$disabled"
2087
- code "$invalid"
2088
- code "$label"
2089
- code "$required"
2090
- code "$description"
2091
- code "$error"
2092
- code "$legend"
2093
-
2094
- # ========================================================================
2095
- # FORM
2096
- # ========================================================================
2097
- .section id: "form"
2098
- SectionHead tag: "form", name: "Form", lines: 21
2099
- .section-desc "Form wrapper with submit handling and validation state."
2100
- .demo-row
2101
- Form
2102
- Field label: "Name"
2103
- input type: "text", placeholder: "Your name"
2104
- Field label: "Email"
2105
- input type: "email", placeholder: "you@example.com"
2106
- button type: "submit"
2107
- "Submit"
2108
- .api
2109
- dl
2110
- dt "Props"
2111
- dd
2112
- code "@disabled"
2113
- dt "Events"
2114
- dd
2115
- code "submit"
2116
- dt "Data"
2117
- dd
2118
- code "$disabled"
2119
- code "$submitting"
2120
- code "$submitted"
2121
-
2122
- # ========================================================================
2123
- # BUTTON GROUP
2124
- # ========================================================================
2125
- .section id: "button-group"
2126
- SectionHead tag: "button-group", name: "ButtonGroup", lines: 11
2127
- .section-desc "Groups related buttons with ARIA group semantics."
2128
- .demo-row
2129
- .demo-label "Horizontal"
2130
- ButtonGroup label: "Actions"
2131
- button "Cut"
2132
- button "Copy"
2133
- button "Paste"
2134
- .api
2135
- dl
2136
- dt "Props"
2137
- dd
2138
- code "@orientation"
2139
- code "@disabled"
2140
- code "@label"
2141
- dt "Data"
2142
- dd
2143
- code "$orientation"
2144
- code "$disabled"
2145
-
2146
- # ========================================================================
2147
- # GRID
2148
- # ========================================================================
2149
- .section id: "grid"
2150
- SectionHead tag: "grid", name: "Grid", lines: 799
2151
- .section-desc "Virtual-scrolling data grid. Click to select, arrows to navigate, double-click to edit."
2152
- .demo-row
2153
- . style: "display:flex;justify-content:space-between;align-items:baseline;margin-bottom:8px"
2154
- .demo-label style: "margin-bottom:0", "#{gridData.length} rows, #{gridColumns.length} columns"
2155
- span.grid-cell-ref gridCellRef
2156
- Grid data: gridData, columns: gridColumns, striped: true
2157
- . style: "margin-top:12px;display:flex;gap:8px;align-items:center"
2158
- button.demo-btn @click: (=> @_loadGridRows(1000))
2159
- "1K rows"
2160
- button.demo-btn @click: (=> @_loadGridRows(10000))
2161
- "10K rows"
2162
- button.demo-btn @click: (=> @_loadGridRows(100000))
2163
- "100K rows"
2164
- .api
2165
- dl
2166
- dt "Props"
2167
- dd
2168
- code "@data"
2169
- code "@columns"
2170
- code "@rowHeight"
2171
- code "@overscan"
2172
- code "@striped"
2173
- code "@beforeEdit"
2174
- code "@afterEdit"
2175
- dt "Keyboard"
2176
- dd
2177
- kbd "Arrows"
2178
- kbd "Tab"
2179
- kbd "Enter"
2180
- kbd "F2"
2181
- kbd "Esc"
2182
- kbd "Home"
2183
- kbd "End"
2184
- kbd "PgUp"
2185
- kbd "PgDn"
2186
- kbd "Ctrl+A"
2187
- kbd "Ctrl+C"
2188
- kbd "Ctrl+V"
2189
- kbd "Ctrl+X"
2190
- dt "Data"
2191
- dd
2192
- code "$editing"
2193
- code "$selecting"
2194
- code "$sorted"
2195
-
2196
- # ========================================================================
2197
- # ACCORDION
2198
- # ========================================================================
2199
- .section id: "accordion"
2200
- SectionHead tag: "accordion", name: "Accordion", lines: 86
2201
- .section-desc "Expand/collapse sections, single or multiple mode."
2202
- .demo-row
2203
- .demo-label "Single mode"
2204
- Accordion
2205
- div data-item: "a"
2206
- button.accordion-trigger data-trigger: true
2207
- "Section A"
2208
- div.accordion-content data-content: true
2209
- p "Content for section A."
2210
- div data-item: "b"
2211
- button.accordion-trigger data-trigger: true
2212
- "Section B"
2213
- div.accordion-content data-content: true
2214
- p "Content for section B."
2215
- div data-item: "c"
2216
- button.accordion-trigger data-trigger: true
2217
- "Section C"
2218
- div.accordion-content data-content: true
2219
- p "Content for section C."
2220
- .api
2221
- dl
2222
- dt "Props"
2223
- dd
2224
- code "@multiple"
2225
- dt "Events"
2226
- dd
2227
- code "change"
2228
- dt "Keyboard"
2229
- dd
2230
- kbd "Enter"
2231
- kbd "Space"
2232
- kbd "↕"
2233
- kbd "Home"
2234
- kbd "End"
2235
- dt "Data"
2236
- dd
2237
- code "$item"
2238
- code "$trigger"
2239
- code "$content"
2240
- code "$open"
2241
- code "$disabled"
2242
-
2243
- # ========================================================================
2244
- # TABLE
2245
- # ========================================================================
2246
- .section id: "table"
2247
- SectionHead tag: "table", name: "Table", lines: 9
2248
- .section-desc "Semantic table wrapper. For data-heavy tables, use Grid."
2249
- .demo-row.table-demo
2250
- Table caption: "Team", striped: true
2251
- thead
2252
- tr
2253
- th "Name"
2254
- th "Role"
2255
- th "City"
2256
- tbody
2257
- tr
2258
- td "Alice"
2259
- td "Engineer"
2260
- td "Seattle"
2261
- tr
2262
- td "Bob"
2263
- td "Designer"
2264
- td "Portland"
2265
- tr
2266
- td "Carol"
2267
- td "Manager"
2268
- td "Denver"
2269
- .api
2270
- dl
2271
- dt "Props"
2272
- dd
2273
- code "@caption"
2274
- code "@striped"
2275
- dt "Data"
2276
- dd
2277
- code "$striped"
2278
-
2279
- # ========================================================================
2280
- # COLLAPSIBLE
2281
- # ========================================================================
2282
- .section id: "collapsible"
2283
- SectionHead tag: "collapsible", name: "Collapsible", lines: 33
2284
- .section-desc "Single open/close section. Simpler than Accordion."
2285
- .demo-row.collapsible-demo
2286
- Collapsible open <=> collapsibleOpen
2287
- button $trigger: true
2288
- span style: "font-size:10px;margin-right:6px"
2289
- if collapsibleOpen then "▼" else "▶"
2290
- "Show details"
2291
- div $content: true
2292
- p "These are the collapsible details. Click the trigger or press Enter/Space to toggle."
2293
- .status "open: #{collapsibleOpen}"
2294
- .api
2295
- dl
2296
- dt "Props"
2297
- dd
2298
- code "@open"
2299
- code "@disabled"
2300
- dt "Events"
2301
- dd
2302
- code "change"
2303
- dt "Keyboard"
2304
- dd
2305
- kbd "Enter"
2306
- kbd "Space"
2307
- dt "Data"
2308
- dd
2309
- code "$open"
2310
- code "$disabled"
2311
-
2312
- # ========================================================================
2313
- # PAGINATION
2314
- # ========================================================================
2315
- .section id: "pagination"
2316
- SectionHead tag: "pagination", name: "Pagination", lines: 96
2317
- .section-desc "Page navigation with prev/next buttons and ellipsis gaps."
2318
- .demo-row
2319
- .demo-label "10 pages"
2320
- Pagination page <=> currentPage, total: 100, perPage: 10
2321
- .status "page: #{currentPage}"
2322
- .api
2323
- dl
2324
- dt "Props"
2325
- dd
2326
- code "@page"
2327
- code "@total"
2328
- code "@perPage"
2329
- code "@siblingCount"
2330
- dt "Events"
2331
- dd
2332
- code "change"
2333
- dt "Keyboard"
2334
- dd
2335
- kbd "← →"
2336
- kbd "Home"
2337
- kbd "End"
2338
- dt "Data"
2339
- dd
2340
- code "$active"
2341
- code "$disabled"
2342
- code "$ellipsis"
2343
-
2344
- # ========================================================================
2345
- # CAROUSEL
2346
- # ========================================================================
2347
- .section id: "carousel"
2348
- SectionHead tag: "carousel", name: "Carousel", lines: 78
2349
- .section-desc "Slide carousel with loop and keyboard navigation."
2350
- .demo-row
2351
- Carousel loop: true
2352
- div $slide: true
2353
- "🍎 Slide 1 — Apples"
2354
- div $slide: true
2355
- "🍌 Slide 2 — Bananas"
2356
- div $slide: true
2357
- "🍒 Slide 3 — Cherries"
2358
- .api
2359
- dl
2360
- dt "Props"
2361
- dd
2362
- code "@orientation"
2363
- code "@loop"
2364
- code "@autoplay"
2365
- code "@interval"
2366
- code "@label"
2367
- dt "Events"
2368
- dd
2369
- code "change"
2370
- dt "Keyboard"
2371
- dd
2372
- kbd "← →"
2373
- kbd "↕"
2374
- kbd "Home"
2375
- kbd "End"
2376
- dt "Data"
2377
- dd
2378
- code "$orientation"
2379
- code "$active"
2380
- code "$prev"
2381
- code "$next"
2382
-
2383
- # ========================================================================
2384
- # RESIZABLE
2385
- # ========================================================================
2386
- .section id: "resizable"
2387
- SectionHead tag: "resizable", name: "Resizable", lines: 89
2388
- .section-desc "Draggable resize handles between panels."
2389
- .demo-row.resizable-demo
2390
- Resizable
2391
- div $panel: true, "Left"
2392
- div $handle: true
2393
- div $panel: true, "Right"
2394
- .api
2395
- dl
2396
- dt "Props"
2397
- dd
2398
- code "@orientation"
2399
- code "@minSize"
2400
- code "@maxSize"
2401
- dt "Events"
2402
- dd
2403
- code "resize"
2404
- dt "Keyboard"
2405
- dd
2406
- kbd "← →"
2407
- kbd "↕"
2408
- dt "Data"
2409
- dd
2410
- code "$orientation"
2411
- code "$dragging"
2412
-
2413
- # ========================================================================
2414
- # SOURCE CODE VIEWER
2415
- # ========================================================================
2416
- if sourceCode
2417
- .source-overlay @click: (=> @_closeSource())
2418
- .source-modal @click: (e => e.stopPropagation())
2419
- .source-header
2420
- .source-title
2421
- span.source-name sourceName
2422
- span.source-badge "#{sourceLines} lines"
2423
- button.source-close @click: (=> @_closeSource())
2424
- "×"
2425
- .source-body
2426
- pre.source-pre
2427
- span.source-gutter
2428
- code.source-code
2429
-
2430
- </script>
2431
-
2432
- </body>
2433
- </html>