@stacksjs/components 0.2.93 → 0.2.94

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 (187) hide show
  1. package/dist/index.js +4 -4
  2. package/package.json +5 -6
  3. package/src/components/CodeBlock.stx +0 -54
  4. package/src/components/Footer.stx +0 -66
  5. package/src/components/Hero.stx +0 -25
  6. package/src/components/Installation.stx +0 -37
  7. package/src/components/index.ts +0 -4
  8. package/src/composables/index.ts +0 -4
  9. package/src/composables/useCopyCode.ts +0 -73
  10. package/src/composables/useDarkMode.ts +0 -100
  11. package/src/composables/useSEO.ts +0 -230
  12. package/src/composables/utilities/index.ts +0 -7
  13. package/src/composables/utilities/useClickOutside.ts +0 -72
  14. package/src/composables/utilities/useFocusTrap.ts +0 -159
  15. package/src/composables/utilities/useKeyboard.ts +0 -124
  16. package/src/composables/utilities/useLocalStorage.ts +0 -132
  17. package/src/composables/utilities/useMediaQuery.ts +0 -118
  18. package/src/index.ts +0 -99
  19. package/src/stx.d.ts +0 -4
  20. package/src/ui/accordion/Accordion.stx +0 -146
  21. package/src/ui/accordion/AccordionItem.stx +0 -37
  22. package/src/ui/accordion/index.ts +0 -47
  23. package/src/ui/audio/Audio.stx +0 -50
  24. package/src/ui/audio/README.md +0 -41
  25. package/src/ui/audio/index.ts +0 -13
  26. package/src/ui/auth/Login.stx +0 -161
  27. package/src/ui/auth/README.md +0 -142
  28. package/src/ui/auth/Signup.stx +0 -159
  29. package/src/ui/auth/TwoFactorChallenge.stx +0 -111
  30. package/src/ui/auth/index.ts +0 -32
  31. package/src/ui/avatar/Avatar.stx +0 -77
  32. package/src/ui/avatar/index.ts +0 -12
  33. package/src/ui/badge/Badge.stx +0 -62
  34. package/src/ui/badge/index.ts +0 -10
  35. package/src/ui/breadcrumb/Breadcrumb.stx +0 -79
  36. package/src/ui/breadcrumb/index.ts +0 -15
  37. package/src/ui/button/Button.stx +0 -74
  38. package/src/ui/button/README.md +0 -80
  39. package/src/ui/button/index.ts +0 -85
  40. package/src/ui/calendar/Calendar.stx +0 -189
  41. package/src/ui/calendar/README.md +0 -254
  42. package/src/ui/calendar/index.ts +0 -14
  43. package/src/ui/card/Card.stx +0 -68
  44. package/src/ui/card/index.ts +0 -13
  45. package/src/ui/checkbox/Checkbox.stx +0 -86
  46. package/src/ui/checkbox/index.ts +0 -16
  47. package/src/ui/combobox/Combobox.stx +0 -96
  48. package/src/ui/combobox/ComboboxButton.stx +0 -25
  49. package/src/ui/combobox/ComboboxInput.stx +0 -32
  50. package/src/ui/combobox/ComboboxOption.stx +0 -49
  51. package/src/ui/combobox/ComboboxOptions.stx +0 -16
  52. package/src/ui/combobox/README.md +0 -150
  53. package/src/ui/combobox/index.ts +0 -40
  54. package/src/ui/command-palette/CommandPalette.stx +0 -81
  55. package/src/ui/command-palette/CommandPaletteItem.stx +0 -27
  56. package/src/ui/command-palette/README.md +0 -42
  57. package/src/ui/command-palette/index.ts +0 -15
  58. package/src/ui/dialog/Dialog.stx +0 -41
  59. package/src/ui/dialog/DialogBackdrop.stx +0 -9
  60. package/src/ui/dialog/DialogDescription.stx +0 -11
  61. package/src/ui/dialog/DialogPanel.stx +0 -16
  62. package/src/ui/dialog/DialogTitle.stx +0 -11
  63. package/src/ui/dialog/README.md +0 -121
  64. package/src/ui/dialog/index.ts +0 -32
  65. package/src/ui/drawer/Drawer.stx +0 -120
  66. package/src/ui/drawer/README.md +0 -90
  67. package/src/ui/drawer/index.ts +0 -9
  68. package/src/ui/dropdown/Dropdown.stx +0 -82
  69. package/src/ui/dropdown/DropdownButton.stx +0 -29
  70. package/src/ui/dropdown/DropdownItem.stx +0 -35
  71. package/src/ui/dropdown/DropdownItems.stx +0 -18
  72. package/src/ui/dropdown/README.md +0 -114
  73. package/src/ui/dropdown/index.ts +0 -29
  74. package/src/ui/form/Form.stx +0 -95
  75. package/src/ui/form/index.ts +0 -67
  76. package/src/ui/heatmap/Heatmap.stx +0 -294
  77. package/src/ui/image/Image.stx +0 -165
  78. package/src/ui/image/README.md +0 -164
  79. package/src/ui/image/index.ts +0 -22
  80. package/src/ui/input/EmailInput.stx +0 -30
  81. package/src/ui/input/NumberInput.stx +0 -126
  82. package/src/ui/input/PasswordInput.stx +0 -143
  83. package/src/ui/input/SearchInput.stx +0 -44
  84. package/src/ui/input/TextInput.stx +0 -132
  85. package/src/ui/input/index.ts +0 -180
  86. package/src/ui/listbox/Listbox.stx +0 -101
  87. package/src/ui/listbox/ListboxButton.stx +0 -28
  88. package/src/ui/listbox/ListboxLabel.stx +0 -11
  89. package/src/ui/listbox/ListboxOption.stx +0 -49
  90. package/src/ui/listbox/ListboxOptions.stx +0 -16
  91. package/src/ui/listbox/README.md +0 -135
  92. package/src/ui/listbox/index.ts +0 -39
  93. package/src/ui/navigator/Navigator.stx +0 -113
  94. package/src/ui/navigator/README.md +0 -352
  95. package/src/ui/navigator/index.ts +0 -20
  96. package/src/ui/notification/Notification.stx +0 -117
  97. package/src/ui/notification/README.md +0 -114
  98. package/src/ui/notification/index.ts +0 -12
  99. package/src/ui/pagination/Pagination.stx +0 -150
  100. package/src/ui/pagination/index.ts +0 -11
  101. package/src/ui/payment/Checkout.stx +0 -31
  102. package/src/ui/payment/DefaultPaymentMethod.stx +0 -62
  103. package/src/ui/payment/PaymentMethods.stx +0 -104
  104. package/src/ui/payment/README.md +0 -345
  105. package/src/ui/payment/SubscriptionCheckout.stx +0 -323
  106. package/src/ui/payment/index.ts +0 -59
  107. package/src/ui/popover/Popover.stx +0 -60
  108. package/src/ui/popover/PopoverButton.stx +0 -29
  109. package/src/ui/popover/PopoverPanel.stx +0 -23
  110. package/src/ui/popover/README.md +0 -91
  111. package/src/ui/popover/index.ts +0 -22
  112. package/src/ui/portal/Portal.stx +0 -57
  113. package/src/ui/portal/index.ts +0 -6
  114. package/src/ui/progress/Progress.stx +0 -131
  115. package/src/ui/progress/index.ts +0 -12
  116. package/src/ui/radio/Radio.stx +0 -77
  117. package/src/ui/radio/index.ts +0 -15
  118. package/src/ui/radio-group/README.md +0 -139
  119. package/src/ui/radio-group/RadioGroup.stx +0 -60
  120. package/src/ui/radio-group/RadioGroupDescription.stx +0 -11
  121. package/src/ui/radio-group/RadioGroupLabel.stx +0 -11
  122. package/src/ui/radio-group/RadioGroupOption.stx +0 -58
  123. package/src/ui/radio-group/index.ts +0 -30
  124. package/src/ui/select/README.md +0 -180
  125. package/src/ui/select/Select.stx +0 -82
  126. package/src/ui/select/index.ts +0 -21
  127. package/src/ui/sidebar/Sidebar.stx +0 -476
  128. package/src/ui/sidebar/SidebarFooter.stx +0 -71
  129. package/src/ui/sidebar/SidebarHeader.stx +0 -103
  130. package/src/ui/sidebar/SidebarItem.stx +0 -86
  131. package/src/ui/sidebar/SidebarSection.stx +0 -83
  132. package/src/ui/sidebar/index.ts +0 -153
  133. package/src/ui/sidebar/themes.ts +0 -240
  134. package/src/ui/skeleton/Skeleton.stx +0 -48
  135. package/src/ui/skeleton/index.ts +0 -11
  136. package/src/ui/spinner/Spinner.stx +0 -109
  137. package/src/ui/spinner/index.ts +0 -9
  138. package/src/ui/stepper/README.md +0 -36
  139. package/src/ui/stepper/Stepper.stx +0 -17
  140. package/src/ui/stepper/StepperStep.stx +0 -57
  141. package/src/ui/stepper/index.ts +0 -19
  142. package/src/ui/storage/README.md +0 -193
  143. package/src/ui/storage/index.ts +0 -347
  144. package/src/ui/switch/README.md +0 -114
  145. package/src/ui/switch/Switch.stx +0 -72
  146. package/src/ui/switch/index.ts +0 -10
  147. package/src/ui/table/README.md +0 -39
  148. package/src/ui/table/Table.stx +0 -14
  149. package/src/ui/table/TableBody.stx +0 -10
  150. package/src/ui/table/TableCell.stx +0 -10
  151. package/src/ui/table/TableHead.stx +0 -10
  152. package/src/ui/table/TableHeader.stx +0 -20
  153. package/src/ui/table/TableRow.stx +0 -11
  154. package/src/ui/table/index.ts +0 -35
  155. package/src/ui/tabs/TabPanel.stx +0 -25
  156. package/src/ui/tabs/Tabs.stx +0 -202
  157. package/src/ui/tabs/index.ts +0 -50
  158. package/src/ui/teleport/Teleport.stx +0 -65
  159. package/src/ui/teleport/index.ts +0 -7
  160. package/src/ui/textarea/Textarea.stx +0 -108
  161. package/src/ui/textarea/index.ts +0 -20
  162. package/src/ui/tooltip/Tooltip.stx +0 -71
  163. package/src/ui/tooltip/index.ts +0 -10
  164. package/src/ui/transition/README.md +0 -30
  165. package/src/ui/transition/Transition.stx +0 -102
  166. package/src/ui/transition/index.ts +0 -25
  167. package/src/ui/video/README.md +0 -47
  168. package/src/ui/video/Video.stx +0 -45
  169. package/src/ui/video/index.ts +0 -16
  170. package/src/ui/virtual-list/VirtualList.stx +0 -67
  171. package/src/ui/virtual-list/index.ts +0 -10
  172. package/src/ui/virtual-table/VirtualTable.stx +0 -103
  173. package/src/ui/virtual-table/index.ts +0 -21
  174. package/src/utils/PROP_VALIDATION.md +0 -458
  175. package/src/utils/THEME_SYSTEM.md +0 -702
  176. package/src/utils/accessibility.ts +0 -841
  177. package/src/utils/animation/easing.ts +0 -368
  178. package/src/utils/animation/helpers.ts +0 -223
  179. package/src/utils/animation/index.ts +0 -5
  180. package/src/utils/animation/keyframes.ts +0 -230
  181. package/src/utils/error-handling.ts +0 -475
  182. package/src/utils/highlighter.ts +0 -93
  183. package/src/utils/i18n.ts +0 -634
  184. package/src/utils/keep-alive.ts +0 -819
  185. package/src/utils/lazy-loading.ts +0 -530
  186. package/src/utils/prop-validation.ts +0 -478
  187. package/src/utils/theme.ts +0 -626
@@ -1,86 +0,0 @@
1
- <script server>
2
- export const checked = $props.checked || false
3
- export const disabled = $props.disabled || false
4
- export const indeterminate = $props.indeterminate || false
5
- export const size = $props.size || 'md'
6
- export const label = $props.label || ''
7
- export const description = $props.description || ''
8
- export const error = $props.error || false
9
- export const required = $props.required || false
10
- export const value = $props.value || ''
11
- export const name = $props.name || ''
12
- export const className = $props.className || ''
13
-
14
- const sizeClasses = { sm: 'h-4 w-4', md: 'h-5 w-5', lg: 'h-6 w-6' }
15
- const baseClasses = 'rounded border-gray-300 dark:border-gray-600 text-indigo-600 dark:text-indigo-500 focus:ring-indigo-600 dark:focus:ring-indigo-500 focus:ring-2 focus:ring-offset-2 dark:focus:ring-offset-gray-900 transition-colors'
16
- const stateClasses = error ? 'border-red-300 dark:border-red-600 text-red-600 dark:text-red-500 focus:ring-red-500 dark:focus:ring-red-400' : ''
17
- const disabledClasses = disabled ? 'opacity-50 cursor-not-allowed' : 'cursor-pointer'
18
-
19
- export const checkboxClasses = `${baseClasses} ${sizeClasses[size]} ${stateClasses} ${disabledClasses}`.trim()
20
- export const labelClasses = `text-sm font-medium ${error ? 'text-red-600 dark:text-red-400' : 'text-gray-900 dark:text-gray-100'} ${disabled ? 'opacity-50 cursor-not-allowed' : 'cursor-pointer'}`.trim()
21
- export const descriptionClasses = `text-sm ${error ? 'text-red-500 dark:text-red-400' : 'text-gray-500 dark:text-gray-400'}`.trim()
22
- export const inputId = `checkbox-${value || label}`
23
- </script>
24
-
25
- <script client>
26
- const emit = defineEmits()
27
- const isDisabled = {{ disabled }}
28
- const isIndeterminate = {{ indeterminate }}
29
- // Reactive prop binding so the parent can drive `checked` via signals.
30
- // See stacksjs/stx#1704.
31
- const isChecked = useReactiveProp('checked', {{ checked }})
32
-
33
- function onInputChange(event) {
34
- if (isDisabled) {
35
- event.target.checked = isChecked()
36
- return
37
- }
38
- isChecked.set(event.target.checked)
39
- emit('change', isChecked())
40
- }
41
-
42
- onMount(() => {
43
- if (isIndeterminate) {
44
- const el = document.getElementById({{ inputId }})
45
- if (el) el.indeterminate = true
46
- }
47
- })
48
-
49
- defineExpose({ isChecked })
50
- </script>
51
-
52
- <div class="relative flex items-start {{ className }}">
53
- <div class="flex h-6 items-center">
54
- <input
55
- id="{{ inputId }}"
56
- type="checkbox"
57
- name="{{ name }}"
58
- value="{{ value }}"
59
- :checked="isChecked()"
60
- @if(disabled)disabled@endif
61
- @if(required)required@endif
62
- class="{{ checkboxClasses }}"
63
- @change="onInputChange($event)"
64
- :aria-invalid="{{ error ? 'true' : 'false' }}"
65
- @if(description)aria-describedby="checkbox-description"@endif
66
- />
67
- </div>
68
-
69
- @if(label || description)
70
- <div class="ml-3 text-sm leading-6">
71
- @if(label)
72
- <label for="{{ inputId }}" class="{{ labelClasses }}">
73
- {{ label }}
74
- @if(required)
75
- <span class="text-red-500 ml-1">*</span>
76
- @endif
77
- </label>
78
- @endif
79
- @if(description)
80
- <p id="checkbox-description" class="{{ descriptionClasses }}">
81
- {{ description }}
82
- </p>
83
- @endif
84
- </div>
85
- @endif
86
- </div>
@@ -1,16 +0,0 @@
1
- export { default as Checkbox } from './Checkbox.stx'
2
-
3
- export interface CheckboxProps {
4
- checked?: boolean
5
- onChange?: (checked: boolean) => void
6
- disabled?: boolean
7
- indeterminate?: boolean
8
- size?: 'sm' | 'md' | 'lg'
9
- label?: string
10
- description?: string
11
- error?: boolean
12
- required?: boolean
13
- value?: string
14
- name?: string
15
- className?: string
16
- }
@@ -1,96 +0,0 @@
1
- <script server>
2
- export const value = $props.value
3
- export const className = $props.className || ''
4
- export const as = $props.as || 'div'
5
-
6
- const baseClasses = 'relative'
7
- export const comboboxClasses = `${baseClasses} ${className}`.trim()
8
- export const comboboxInstanceId = `stx-cb-${Math.random().toString(36).slice(2, 11)}`
9
- </script>
10
-
11
- <script client>
12
- const emit = defineEmits()
13
- const comboboxInstanceId = {{ comboboxInstanceId }}
14
- const initialValue = {{ value === undefined ? 'null' : value }}
15
-
16
- const isOpen = state(false)
17
- const selected = state(initialValue)
18
- const query = state('')
19
- let rootEl = null
20
- let outsideHandler = null
21
-
22
- function isSelectedValue(v) {
23
- return selected() === v
24
- }
25
-
26
- function selectValue(v) {
27
- selected.set(v)
28
- isOpen.set(false)
29
- syncOptionStates()
30
- emit('change', v)
31
- }
32
-
33
- function syncOptionStates() {
34
- if (!rootEl) return
35
- const options = rootEl.querySelectorAll('[data-stx-combobox-option]')
36
- for (const opt of options) {
37
- const raw = opt.dataset.optionValue
38
- let v
39
- try { v = JSON.parse(raw ?? 'null') }
40
- catch { v = raw }
41
- const sel = isSelectedValue(v)
42
- opt.setAttribute('aria-selected', sel ? 'true' : 'false')
43
- opt.setAttribute('data-selected', sel ? 'true' : 'false')
44
- }
45
- }
46
-
47
- function open() { if (!isOpen()) { isOpen.set(true) } }
48
- function close() { if (isOpen()) isOpen.set(false) }
49
- function toggle() { isOpen() ? close() : open() }
50
-
51
- function onToggle(event) { event.stopPropagation(); toggle() }
52
- function onSelect(event) { event.stopPropagation(); selectValue(event.detail) }
53
- function onQuery(event) {
54
- event.stopPropagation()
55
- query.set(event.detail)
56
- if (!isOpen()) open()
57
- emit('query', event.detail)
58
- }
59
-
60
- onMount(() => {
61
- rootEl = document.querySelector(`[data-combobox-id="${comboboxInstanceId}"]`)
62
- syncOptionStates()
63
- outsideHandler = (event) => {
64
- if (!isOpen()) return
65
- if (rootEl && !rootEl.contains(event.target)) close()
66
- }
67
- document.addEventListener('click', outsideHandler, true)
68
- })
69
-
70
- onDestroy(() => {
71
- if (outsideHandler) document.removeEventListener('click', outsideHandler, true)
72
- })
73
-
74
- const dataState = derived(() => isOpen() ? 'open' : 'closed')
75
-
76
- defineExpose({ isOpen, selected, query, toggle, open, close, selectValue })
77
- </script>
78
-
79
- <component
80
- :is="{{ as }}"
81
- class="{{ comboboxClasses }}"
82
- data-stx-combobox
83
- data-combobox-id="{{ comboboxInstanceId }}"
84
- :data-state="dataState()"
85
- @stx:combobox-toggle="onToggle($event)"
86
- @stx:combobox-select="onSelect($event)"
87
- @stx:combobox-query="onQuery($event)"
88
- >
89
- <slot />
90
- </component>
91
-
92
- <style>
93
- [data-stx-combobox][data-state="closed"] [data-stx-combobox-options] {
94
- display: none;
95
- }
96
- </style>
@@ -1,25 +0,0 @@
1
- <script server>
2
- export const className = $props.className || ''
3
- export const as = $props.as || 'button'
4
-
5
- const baseClasses = 'absolute inset-y-0 right-0 flex items-center pr-2'
6
- export const buttonClasses = `${baseClasses} ${className}`.trim()
7
- </script>
8
-
9
- <script client>
10
- function onClick(event) {
11
- event.currentTarget.dispatchEvent(new CustomEvent('stx:combobox-toggle', { bubbles: true }))
12
- }
13
- </script>
14
-
15
- <component
16
- :is="{{ as }}"
17
- class="{{ buttonClasses }}"
18
- data-stx-combobox-button
19
- tabindex="-1"
20
- @click="onClick($event)"
21
- >
22
- <svg class="h-5 w-5 text-neutral-400" viewBox="0 0 20 20" fill="none" stroke="currentColor">
23
- <path d="M7 7l3-3 3 3m0 6l-3 3-3-3" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
24
- </svg>
25
- </component>
@@ -1,32 +0,0 @@
1
- <script server>
2
- export const displayValue = $props.displayValue
3
- export const className = $props.className || ''
4
- export const placeholder = $props.placeholder || ''
5
- export const disabled = $props.disabled || false
6
-
7
- const baseClasses = 'w-full rounded-lg border-none bg-white dark:bg-neutral-800 py-2 pl-3 pr-10 text-sm leading-5 text-neutral-900 dark:text-white focus:ring-0 focus:outline-none focus-visible:border-blue-500 focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-opacity-75 focus-visible:ring-offset-2'
8
- const disabledClasses = disabled ? 'opacity-50 cursor-not-allowed' : ''
9
- export const inputClasses = `${baseClasses} ${disabledClasses} ${className}`.trim()
10
- </script>
11
-
12
- <script client>
13
- const isDisabled = {{ disabled }}
14
-
15
- function onInput(event) {
16
- if (isDisabled) return
17
- event.currentTarget.dispatchEvent(
18
- new CustomEvent('stx:combobox-query', { bubbles: true, detail: event.target.value }),
19
- )
20
- }
21
- </script>
22
-
23
- <input
24
- type="text"
25
- class="{{ inputClasses }}"
26
- data-stx-combobox-input
27
- placeholder="{{ placeholder }}"
28
- value="{{ displayValue }}"
29
- @if(disabled)disabled@endif
30
- @input="onInput($event)"
31
- autocomplete="off"
32
- />
@@ -1,49 +0,0 @@
1
- <script server>
2
- export const value = $props.value
3
- export const disabled = $props.disabled || false
4
- export const className = $props.className || ''
5
- export const as = $props.as || 'li'
6
-
7
- const baseClasses = 'relative cursor-pointer select-none py-2 pl-10 pr-4 text-neutral-900 dark:text-neutral-100 hover:bg-blue-100 dark:hover:bg-blue-900'
8
- const disabledClasses = disabled ? 'opacity-50 cursor-not-allowed' : ''
9
- export const optionClasses = `${baseClasses} ${disabledClasses} ${className}`.trim()
10
- export const valueJson = JSON.stringify(value === undefined ? null : value)
11
- </script>
12
-
13
- <script client>
14
- const isDisabled = {{ disabled }}
15
- const optionValue = {{ value === undefined ? 'null' : value }}
16
-
17
- function onClick(event) {
18
- if (isDisabled) return
19
- event.currentTarget.dispatchEvent(
20
- new CustomEvent('stx:combobox-select', { bubbles: true, detail: optionValue }),
21
- )
22
- }
23
- </script>
24
-
25
- <component
26
- :is="{{ as }}"
27
- class="{{ optionClasses }}"
28
- data-stx-combobox-option
29
- data-option-value="{{ valueJson }}"
30
- role="option"
31
- aria-selected="false"
32
- @if(disabled)aria-disabled="true"@endif
33
- @click="onClick($event)"
34
- >
35
- <span class="absolute inset-y-0 left-0 flex items-center pl-3 text-blue-600 dark:text-blue-400" data-stx-combobox-check>
36
- <svg class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
37
- <path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd" />
38
- </svg>
39
- </span>
40
-
41
- <slot :disabled="disabled" />
42
- </component>
43
-
44
- <style>
45
- [data-stx-combobox-option][data-selected="false"] [data-stx-combobox-check],
46
- [data-stx-combobox-option]:not([data-selected]) [data-stx-combobox-check] {
47
- display: none;
48
- }
49
- </style>
@@ -1,16 +0,0 @@
1
- <script server>
2
- export const className = $props.className || ''
3
- export const as = $props.as || 'ul'
4
-
5
- const baseClasses = 'absolute z-10 mt-1 max-h-60 w-full overflow-auto rounded-md bg-white dark:bg-neutral-800 py-1 text-base shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none'
6
- export const optionsClasses = `${baseClasses} ${className}`.trim()
7
- </script>
8
-
9
- <component
10
- :is="{{ as }}"
11
- class="{{ optionsClasses }}"
12
- data-stx-combobox-options
13
- role="listbox"
14
- >
15
- <slot />
16
- </component>
@@ -1,150 +0,0 @@
1
- # Combobox Component
2
-
3
- A searchable select component that combines an input with a listbox.
4
-
5
- ## Installation
6
-
7
- ```bash
8
- bun add @stacksjs/components
9
- ```
10
-
11
- ## Usage
12
-
13
- ```stx
14
- <script server>
15
- const people = [
16
- { id: 1, name: 'Wade Cooper' },
17
- { id: 2, name: 'Arlene Mccoy' },
18
- { id: 3, name: 'Devon Webb' }
19
- ]
20
-
21
- let selected = people[0]
22
- let query = ''
23
-
24
- const filtered = query === ''
25
- ? people
26
- : people.filter(person =>
27
- person.name.toLowerCase().includes(query.toLowerCase())
28
- )
29
-
30
- function handleChange(person) {
31
- selected = person
32
- query = ''
33
- }
34
-
35
- function handleQueryChange(value) {
36
- query = value
37
- }
38
- </script>
39
-
40
- <Combobox :value="selected" :onChange="handleChange">
41
- <div class="relative mt-1">
42
- <ComboboxInput
43
- :displayValue="selected.name"
44
- :onChange="handleQueryChange"
45
- placeholder="Search people..."
46
- />
47
-
48
- <ComboboxButton />
49
-
50
- <ComboboxOptions>
51
- @if(filtered.length === 0 && query !== '')
52
- <div class="relative cursor-default select-none py-2 px-4 text-neutral-700 dark:text-neutral-300">
53
- Nothing found.
54
- </div>
55
- @else
56
- @foreach(person in filtered)
57
- <ComboboxOption :value="person" :currentValue="selected" :onChange="handleChange">
58
- {{ person.name }}
59
- </ComboboxOption>
60
- @endforeach
61
- @endif
62
- </ComboboxOptions>
63
- </div>
64
- </Combobox>
65
- ```
66
-
67
- ## Props
68
-
69
- ### Combobox
70
- | Prop | Type | Default | Description |
71
- |------|------|---------|-------------|
72
- | `value` | `any` | - | Currently selected value |
73
- | `onChange` | `(value: any) => void` | - | Change handler |
74
- | `className` | `string` | `''` | Additional CSS classes |
75
- | `as` | `string` | `'div'` | HTML element to render |
76
-
77
- ### ComboboxInput
78
- | Prop | Type | Default | Description |
79
- |------|------|---------|-------------|
80
- | `displayValue` | `any` | - | Value to display in input |
81
- | `onChange` | `(value: string) => void` | - | Input change handler |
82
- | `className` | `string` | `''` | Additional CSS classes |
83
- | `placeholder` | `string` | `''` | Input placeholder |
84
- | `disabled` | `boolean` | `false` | Disable the input |
85
-
86
- ### ComboboxButton
87
- | Prop | Type | Default | Description |
88
- |------|------|---------|-------------|
89
- | `className` | `string` | `''` | Additional CSS classes |
90
- | `as` | `string` | `'button'` | HTML element to render |
91
-
92
- ### ComboboxOptions
93
- | Prop | Type | Default | Description |
94
- |------|------|---------|-------------|
95
- | `className` | `string` | `''` | Additional CSS classes |
96
- | `as` | `string` | `'ul'` | HTML element to render |
97
- | `static` | `boolean` | `false` | Keep visible regardless of state |
98
-
99
- ### ComboboxOption
100
- | Prop | Type | Default | Description |
101
- |------|------|---------|-------------|
102
- | `value` | `any` | - | Option value |
103
- | `disabled` | `boolean` | `false` | Disable the option |
104
- | `className` | `string` | `''` | Additional CSS classes |
105
- | `as` | `string` | `'li'` | HTML element to render |
106
- | `currentValue` | `any` | - | Current selected value |
107
- | `onChange` | `(value: any) => void` | - | Change handler |
108
-
109
- ## Examples
110
-
111
- ### With Empty State
112
-
113
- ```stx
114
- <ComboboxOptions>
115
- @if(filtered.length === 0)
116
- <div class="py-2 px-4 text-neutral-500 dark:text-neutral-400">
117
- No results found for "{{ query }}"
118
- </div>
119
- @else
120
- @foreach(item in filtered)
121
- <ComboboxOption :value="item">
122
- {{ item.name }}
123
- </ComboboxOption>
124
- @endforeach
125
- @endif
126
- </ComboboxOptions>
127
- ```
128
-
129
- ### With Avatars
130
-
131
- ```stx
132
- <ComboboxOption :value="person">
133
- <div class="flex items-center gap-2">
134
- <img src="{{ person.avatar }}" alt="" class="h-6 w-6 rounded-full" />
135
- <span>{{ person.name }}</span>
136
- </div>
137
- </ComboboxOption>
138
- ```
139
-
140
- ## Features
141
-
142
- - Searchable/filterable
143
- - Keyboard navigation
144
- - Empty state support
145
- - Dark mode support
146
- - Accessible (WAI-ARIA)
147
- - Disabled state
148
- - Active state on hover
149
- - Check icon for selected item
150
- - Customizable styling
@@ -1,40 +0,0 @@
1
- export { default as Combobox } from './Combobox.stx'
2
- export { default as ComboboxButton } from './ComboboxButton.stx'
3
- export { default as ComboboxInput } from './ComboboxInput.stx'
4
- export { default as ComboboxOption } from './ComboboxOption.stx'
5
- export { default as ComboboxOptions } from './ComboboxOptions.stx'
6
-
7
- export interface ComboboxProps {
8
- value?: any
9
- onChange?: (value: any) => void
10
- className?: string
11
- as?: string
12
- }
13
-
14
- export interface ComboboxInputProps {
15
- displayValue?: any
16
- onChange?: (value: string) => void
17
- className?: string
18
- placeholder?: string
19
- disabled?: boolean
20
- }
21
-
22
- export interface ComboboxButtonProps {
23
- className?: string
24
- as?: string
25
- }
26
-
27
- export interface ComboboxOptionsProps {
28
- className?: string
29
- as?: string
30
- static?: boolean
31
- }
32
-
33
- export interface ComboboxOptionProps {
34
- value: any
35
- disabled?: boolean
36
- className?: string
37
- as?: string
38
- currentValue?: any
39
- onChange?: (value: any) => void
40
- }
@@ -1,81 +0,0 @@
1
- <script server>
2
- export const open = $props.open || false
3
- export const initialQuery = $props.query || ''
4
- export const className = $props.className || ''
5
-
6
- const baseClasses = 'fixed inset-0 z-50 overflow-y-auto p-4 sm:p-6 md:p-20'
7
- export const paletteClasses = `${baseClasses} ${className}`.trim()
8
- export const paletteInstanceId = `stx-cmd-${Math.random().toString(36).slice(2, 11)}`
9
- </script>
10
-
11
- <script client>
12
- const emit = defineEmits()
13
- const paletteInstanceId = {{ paletteInstanceId }}
14
- const isOpen = state({{ open }})
15
- const query = state({{ initialQuery }})
16
- let escHandler = null
17
-
18
- function close() {
19
- if (!isOpen()) return
20
- isOpen.set(false)
21
- emit('close')
22
- }
23
-
24
- function show() {
25
- if (isOpen()) return
26
- isOpen.set(true)
27
- }
28
-
29
- function onQueryInput(event) {
30
- query.set(event.target.value)
31
- emit('query', event.target.value)
32
- }
33
-
34
- function onItemSelect(event) {
35
- event.stopPropagation()
36
- emit('select', event.detail)
37
- close()
38
- }
39
-
40
- onMount(() => {
41
- escHandler = (event) => {
42
- if (event.key === 'Escape' && isOpen()) close()
43
- }
44
- document.addEventListener('keydown', escHandler)
45
- })
46
-
47
- onDestroy(() => {
48
- if (escHandler) document.removeEventListener('keydown', escHandler)
49
- })
50
-
51
- defineExpose({ isOpen, query, show, close })
52
- </script>
53
-
54
- <div
55
- :show="isOpen()"
56
- class="{{ paletteClasses }}"
57
- data-stx-command-palette
58
- data-palette-id="{{ paletteInstanceId }}"
59
- @stx:command-select="onItemSelect($event)"
60
- >
61
- <div class="fixed inset-0 bg-neutral-500 bg-opacity-25 dark:bg-opacity-50 transition-opacity" @click="close()"></div>
62
-
63
- <div class="mx-auto max-w-xl transform divide-y divide-neutral-100 dark:divide-neutral-800 overflow-hidden rounded-xl bg-white dark:bg-neutral-900 shadow-2xl ring-1 ring-black ring-opacity-5 transition-all relative">
64
- <div class="relative">
65
- <svg class="pointer-events-none absolute top-3.5 left-4 h-5 w-5 text-neutral-400" viewBox="0 0 20 20" fill="currentColor">
66
- <path fill-rule="evenodd" d="M8 4a4 4 0 100 8 4 4 0 000-8zM2 8a6 6 0 1110.89 3.476l4.817 4.817a1 1 0 01-1.414 1.414l-4.816-4.816A6 6 0 012 8z" clip-rule="evenodd" />
67
- </svg>
68
- <input
69
- type="text"
70
- class="h-12 w-full border-0 bg-transparent pl-11 pr-4 text-neutral-900 dark:text-white placeholder-neutral-400 focus:ring-0 sm:text-sm"
71
- placeholder="Search..."
72
- :value="query()"
73
- @input="onQueryInput($event)"
74
- />
75
- </div>
76
-
77
- <div class="max-h-96 overflow-y-auto py-2">
78
- <slot />
79
- </div>
80
- </div>
81
- </div>
@@ -1,27 +0,0 @@
1
- <script server>
2
- export const className = $props.className || ''
3
- export const value = $props.value
4
-
5
- const baseClasses = 'flex cursor-pointer select-none items-center px-4 py-2 text-neutral-900 dark:text-neutral-100 hover:bg-blue-600 hover:text-white'
6
- export const itemClasses = `${baseClasses} ${className}`.trim()
7
- </script>
8
-
9
- <script client>
10
- const emit = defineEmits()
11
- const itemValue = {{ value === undefined ? 'null' : value }}
12
-
13
- function onClick(event) {
14
- emit('click', event)
15
- event.currentTarget.dispatchEvent(
16
- new CustomEvent('stx:command-select', { bubbles: true, detail: itemValue }),
17
- )
18
- }
19
- </script>
20
-
21
- <div
22
- class="{{ itemClasses }}"
23
- data-stx-command-item
24
- @click="onClick($event)"
25
- >
26
- <slot />
27
- </div>
@@ -1,42 +0,0 @@
1
- # Command Palette Component
2
-
3
- A searchable command menu for quick actions and navigation.
4
-
5
- ## Installation
6
-
7
- ```bash
8
- bun add @stacksjs/components
9
- ```
10
-
11
- ## Usage
12
-
13
- ```stx
14
- <script server>
15
- let open = false
16
- let query = ''
17
-
18
- const commands = [
19
- { name: 'Create new file', action: () => console.log('create') },
20
- { name: 'Open settings', action: () => console.log('settings') }
21
- ]
22
-
23
- const filtered = query === ''
24
- ? commands
25
- : commands.filter(cmd => cmd.name.toLowerCase().includes(query.toLowerCase()))
26
- </script>
27
-
28
- <CommandPalette :open="open" :onClose="() => open = false" :query="query" :onQueryChange="(q) => query = q">
29
- @foreach(command in filtered)
30
- <CommandPaletteItem :onClick="command.action">
31
- {{ command.name }}
32
- </CommandPaletteItem>
33
- @endforeach
34
- </CommandPalette>
35
- ```
36
-
37
- ## Features
38
-
39
- - Searchable
40
- - Keyboard navigation
41
- - Dark mode support
42
- - Accessible
@@ -1,15 +0,0 @@
1
- export { default as CommandPalette } from './CommandPalette.stx'
2
- export { default as CommandPaletteItem } from './CommandPaletteItem.stx'
3
-
4
- export interface CommandPaletteProps {
5
- open?: boolean
6
- onClose?: () => void
7
- query?: string
8
- onQueryChange?: (query: string) => void
9
- className?: string
10
- }
11
-
12
- export interface CommandPaletteItemProps {
13
- className?: string
14
- onClick?: () => void
15
- }