@stacksjs/components 0.2.92 → 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 (188) hide show
  1. package/dist/{Sidebar-yb115a2w.stx → Sidebar-4hn7vw4n.stx} +18 -0
  2. package/dist/index.js +5 -5
  3. package/package.json +5 -6
  4. package/src/components/CodeBlock.stx +0 -54
  5. package/src/components/Footer.stx +0 -66
  6. package/src/components/Hero.stx +0 -25
  7. package/src/components/Installation.stx +0 -37
  8. package/src/components/index.ts +0 -4
  9. package/src/composables/index.ts +0 -4
  10. package/src/composables/useCopyCode.ts +0 -73
  11. package/src/composables/useDarkMode.ts +0 -100
  12. package/src/composables/useSEO.ts +0 -230
  13. package/src/composables/utilities/index.ts +0 -7
  14. package/src/composables/utilities/useClickOutside.ts +0 -72
  15. package/src/composables/utilities/useFocusTrap.ts +0 -159
  16. package/src/composables/utilities/useKeyboard.ts +0 -124
  17. package/src/composables/utilities/useLocalStorage.ts +0 -132
  18. package/src/composables/utilities/useMediaQuery.ts +0 -118
  19. package/src/index.ts +0 -99
  20. package/src/stx.d.ts +0 -4
  21. package/src/ui/accordion/Accordion.stx +0 -146
  22. package/src/ui/accordion/AccordionItem.stx +0 -37
  23. package/src/ui/accordion/index.ts +0 -47
  24. package/src/ui/audio/Audio.stx +0 -50
  25. package/src/ui/audio/README.md +0 -41
  26. package/src/ui/audio/index.ts +0 -13
  27. package/src/ui/auth/Login.stx +0 -161
  28. package/src/ui/auth/README.md +0 -142
  29. package/src/ui/auth/Signup.stx +0 -159
  30. package/src/ui/auth/TwoFactorChallenge.stx +0 -111
  31. package/src/ui/auth/index.ts +0 -32
  32. package/src/ui/avatar/Avatar.stx +0 -77
  33. package/src/ui/avatar/index.ts +0 -12
  34. package/src/ui/badge/Badge.stx +0 -62
  35. package/src/ui/badge/index.ts +0 -10
  36. package/src/ui/breadcrumb/Breadcrumb.stx +0 -79
  37. package/src/ui/breadcrumb/index.ts +0 -15
  38. package/src/ui/button/Button.stx +0 -74
  39. package/src/ui/button/README.md +0 -80
  40. package/src/ui/button/index.ts +0 -85
  41. package/src/ui/calendar/Calendar.stx +0 -189
  42. package/src/ui/calendar/README.md +0 -254
  43. package/src/ui/calendar/index.ts +0 -14
  44. package/src/ui/card/Card.stx +0 -68
  45. package/src/ui/card/index.ts +0 -13
  46. package/src/ui/checkbox/Checkbox.stx +0 -86
  47. package/src/ui/checkbox/index.ts +0 -16
  48. package/src/ui/combobox/Combobox.stx +0 -96
  49. package/src/ui/combobox/ComboboxButton.stx +0 -25
  50. package/src/ui/combobox/ComboboxInput.stx +0 -32
  51. package/src/ui/combobox/ComboboxOption.stx +0 -49
  52. package/src/ui/combobox/ComboboxOptions.stx +0 -16
  53. package/src/ui/combobox/README.md +0 -150
  54. package/src/ui/combobox/index.ts +0 -40
  55. package/src/ui/command-palette/CommandPalette.stx +0 -81
  56. package/src/ui/command-palette/CommandPaletteItem.stx +0 -27
  57. package/src/ui/command-palette/README.md +0 -42
  58. package/src/ui/command-palette/index.ts +0 -15
  59. package/src/ui/dialog/Dialog.stx +0 -41
  60. package/src/ui/dialog/DialogBackdrop.stx +0 -9
  61. package/src/ui/dialog/DialogDescription.stx +0 -11
  62. package/src/ui/dialog/DialogPanel.stx +0 -16
  63. package/src/ui/dialog/DialogTitle.stx +0 -11
  64. package/src/ui/dialog/README.md +0 -121
  65. package/src/ui/dialog/index.ts +0 -32
  66. package/src/ui/drawer/Drawer.stx +0 -120
  67. package/src/ui/drawer/README.md +0 -90
  68. package/src/ui/drawer/index.ts +0 -9
  69. package/src/ui/dropdown/Dropdown.stx +0 -82
  70. package/src/ui/dropdown/DropdownButton.stx +0 -29
  71. package/src/ui/dropdown/DropdownItem.stx +0 -35
  72. package/src/ui/dropdown/DropdownItems.stx +0 -18
  73. package/src/ui/dropdown/README.md +0 -114
  74. package/src/ui/dropdown/index.ts +0 -29
  75. package/src/ui/form/Form.stx +0 -95
  76. package/src/ui/form/index.ts +0 -67
  77. package/src/ui/heatmap/Heatmap.stx +0 -294
  78. package/src/ui/image/Image.stx +0 -165
  79. package/src/ui/image/README.md +0 -164
  80. package/src/ui/image/index.ts +0 -22
  81. package/src/ui/input/EmailInput.stx +0 -30
  82. package/src/ui/input/NumberInput.stx +0 -126
  83. package/src/ui/input/PasswordInput.stx +0 -143
  84. package/src/ui/input/SearchInput.stx +0 -44
  85. package/src/ui/input/TextInput.stx +0 -132
  86. package/src/ui/input/index.ts +0 -180
  87. package/src/ui/listbox/Listbox.stx +0 -101
  88. package/src/ui/listbox/ListboxButton.stx +0 -28
  89. package/src/ui/listbox/ListboxLabel.stx +0 -11
  90. package/src/ui/listbox/ListboxOption.stx +0 -49
  91. package/src/ui/listbox/ListboxOptions.stx +0 -16
  92. package/src/ui/listbox/README.md +0 -135
  93. package/src/ui/listbox/index.ts +0 -39
  94. package/src/ui/navigator/Navigator.stx +0 -113
  95. package/src/ui/navigator/README.md +0 -352
  96. package/src/ui/navigator/index.ts +0 -20
  97. package/src/ui/notification/Notification.stx +0 -117
  98. package/src/ui/notification/README.md +0 -114
  99. package/src/ui/notification/index.ts +0 -12
  100. package/src/ui/pagination/Pagination.stx +0 -150
  101. package/src/ui/pagination/index.ts +0 -11
  102. package/src/ui/payment/Checkout.stx +0 -31
  103. package/src/ui/payment/DefaultPaymentMethod.stx +0 -62
  104. package/src/ui/payment/PaymentMethods.stx +0 -104
  105. package/src/ui/payment/README.md +0 -345
  106. package/src/ui/payment/SubscriptionCheckout.stx +0 -323
  107. package/src/ui/payment/index.ts +0 -59
  108. package/src/ui/popover/Popover.stx +0 -60
  109. package/src/ui/popover/PopoverButton.stx +0 -29
  110. package/src/ui/popover/PopoverPanel.stx +0 -23
  111. package/src/ui/popover/README.md +0 -91
  112. package/src/ui/popover/index.ts +0 -22
  113. package/src/ui/portal/Portal.stx +0 -57
  114. package/src/ui/portal/index.ts +0 -6
  115. package/src/ui/progress/Progress.stx +0 -131
  116. package/src/ui/progress/index.ts +0 -12
  117. package/src/ui/radio/Radio.stx +0 -77
  118. package/src/ui/radio/index.ts +0 -15
  119. package/src/ui/radio-group/README.md +0 -139
  120. package/src/ui/radio-group/RadioGroup.stx +0 -60
  121. package/src/ui/radio-group/RadioGroupDescription.stx +0 -11
  122. package/src/ui/radio-group/RadioGroupLabel.stx +0 -11
  123. package/src/ui/radio-group/RadioGroupOption.stx +0 -58
  124. package/src/ui/radio-group/index.ts +0 -30
  125. package/src/ui/select/README.md +0 -180
  126. package/src/ui/select/Select.stx +0 -82
  127. package/src/ui/select/index.ts +0 -21
  128. package/src/ui/sidebar/Sidebar.stx +0 -458
  129. package/src/ui/sidebar/SidebarFooter.stx +0 -71
  130. package/src/ui/sidebar/SidebarHeader.stx +0 -103
  131. package/src/ui/sidebar/SidebarItem.stx +0 -86
  132. package/src/ui/sidebar/SidebarSection.stx +0 -83
  133. package/src/ui/sidebar/index.ts +0 -153
  134. package/src/ui/sidebar/themes.ts +0 -240
  135. package/src/ui/skeleton/Skeleton.stx +0 -48
  136. package/src/ui/skeleton/index.ts +0 -11
  137. package/src/ui/spinner/Spinner.stx +0 -109
  138. package/src/ui/spinner/index.ts +0 -9
  139. package/src/ui/stepper/README.md +0 -36
  140. package/src/ui/stepper/Stepper.stx +0 -17
  141. package/src/ui/stepper/StepperStep.stx +0 -57
  142. package/src/ui/stepper/index.ts +0 -19
  143. package/src/ui/storage/README.md +0 -193
  144. package/src/ui/storage/index.ts +0 -347
  145. package/src/ui/switch/README.md +0 -114
  146. package/src/ui/switch/Switch.stx +0 -72
  147. package/src/ui/switch/index.ts +0 -10
  148. package/src/ui/table/README.md +0 -39
  149. package/src/ui/table/Table.stx +0 -14
  150. package/src/ui/table/TableBody.stx +0 -10
  151. package/src/ui/table/TableCell.stx +0 -10
  152. package/src/ui/table/TableHead.stx +0 -10
  153. package/src/ui/table/TableHeader.stx +0 -20
  154. package/src/ui/table/TableRow.stx +0 -11
  155. package/src/ui/table/index.ts +0 -35
  156. package/src/ui/tabs/TabPanel.stx +0 -25
  157. package/src/ui/tabs/Tabs.stx +0 -202
  158. package/src/ui/tabs/index.ts +0 -50
  159. package/src/ui/teleport/Teleport.stx +0 -65
  160. package/src/ui/teleport/index.ts +0 -7
  161. package/src/ui/textarea/Textarea.stx +0 -108
  162. package/src/ui/textarea/index.ts +0 -20
  163. package/src/ui/tooltip/Tooltip.stx +0 -71
  164. package/src/ui/tooltip/index.ts +0 -10
  165. package/src/ui/transition/README.md +0 -30
  166. package/src/ui/transition/Transition.stx +0 -102
  167. package/src/ui/transition/index.ts +0 -25
  168. package/src/ui/video/README.md +0 -47
  169. package/src/ui/video/Video.stx +0 -45
  170. package/src/ui/video/index.ts +0 -16
  171. package/src/ui/virtual-list/VirtualList.stx +0 -67
  172. package/src/ui/virtual-list/index.ts +0 -10
  173. package/src/ui/virtual-table/VirtualTable.stx +0 -103
  174. package/src/ui/virtual-table/index.ts +0 -21
  175. package/src/utils/PROP_VALIDATION.md +0 -458
  176. package/src/utils/THEME_SYSTEM.md +0 -702
  177. package/src/utils/accessibility.ts +0 -841
  178. package/src/utils/animation/easing.ts +0 -368
  179. package/src/utils/animation/helpers.ts +0 -223
  180. package/src/utils/animation/index.ts +0 -5
  181. package/src/utils/animation/keyframes.ts +0 -230
  182. package/src/utils/error-handling.ts +0 -475
  183. package/src/utils/highlighter.ts +0 -93
  184. package/src/utils/i18n.ts +0 -634
  185. package/src/utils/keep-alive.ts +0 -819
  186. package/src/utils/lazy-loading.ts +0 -530
  187. package/src/utils/prop-validation.ts +0 -478
  188. package/src/utils/theme.ts +0 -626
@@ -1,25 +0,0 @@
1
- <script server>
2
- // Slot wrapper that the parent <Tabs> discovers via DOM walk. The parent
3
- // reads `data-label` (and optional `data-icon`) to build the tab list and
4
- // toggles the `hidden` attribute as the active tab changes. Hidden by
5
- // default — the parent flips the active one visible after mount. See
6
- // stacksjs/stx#1703.
7
- export const label = $props.label || ''
8
- export const icon = $props.icon || ''
9
- export const className = $props.className || ''
10
-
11
- const baseClasses = 'p-4 focus:outline-none'
12
- export const panelClasses = `${baseClasses} ${className}`.trim()
13
- </script>
14
-
15
- <div
16
- data-stx-tab-panel
17
- data-label="{{ label }}"
18
- data-icon="{{ icon }}"
19
- class="{{ panelClasses }}"
20
- role="tabpanel"
21
- tabindex="0"
22
- hidden
23
- >
24
- <slot />
25
- </div>
@@ -1,202 +0,0 @@
1
- <script server>
2
- // Two modes (see stacksjs/stx#1703):
3
- // 1. Legacy prop API — pass `tabs={[{label, content, icon}, …]}` for
4
- // simple string-content tabs (kept for backward compatibility with
5
- // existing visual snapshots and consumers).
6
- // 2. Slot API — drop `<TabPanel label="…">` children for arbitrary
7
- // content (components, forms, tables, etc.). The parent enumerates
8
- // [data-stx-tab-panel] descendants on mount and builds the tab list
9
- // dynamically.
10
- export const tabs = $props.tabs || []
11
- export const defaultTab = $props.defaultTab || 0
12
- export const orientation = $props.orientation || 'horizontal'
13
- export const variant = $props.variant || 'line'
14
- export const className = $props.className || ''
15
-
16
- const orientationClasses = {
17
- horizontal: 'flex-col',
18
- vertical: 'flex-row',
19
- }
20
-
21
- const tabListOrientationClasses = {
22
- horizontal: 'flex-row border-b',
23
- vertical: 'flex-col border-r',
24
- }
25
-
26
- const variantClasses = {
27
- line: 'border-gray-200 dark:border-gray-700',
28
- pills: 'gap-2 border-0 bg-gray-100 dark:bg-gray-800 p-1 rounded-lg',
29
- enclosed: 'border-gray-200 dark:border-gray-700',
30
- }
31
-
32
- export const containerClasses = `flex ${orientationClasses[orientation]} ${className}`.trim()
33
- export const tabListClasses = `flex ${tabListOrientationClasses[orientation]} ${variantClasses[variant]}`.trim()
34
- export const tabPanelClasses = `p-4 focus:outline-none`.trim()
35
- // True when the parent passes a non-empty `tabs` array — switches to the
36
- // legacy render path so existing snapshots stay byte-identical.
37
- export const hasPropTabs = Array.isArray(tabs) && tabs.length > 0
38
- </script>
39
-
40
- <script client>
41
- const emit = defineEmits()
42
- const tabs = {{ tabs }}
43
- const variant = {{ variant }}
44
- const orientation = {{ orientation }}
45
- const hasPropTabs = {{ hasPropTabs }}
46
- const containerRef = useRef()
47
- // In slot mode, `discoveredTabs` is populated from child <TabPanel> data
48
- // attributes on mount. In prop mode, it mirrors the `tabs` prop so the
49
- // rendering loop works the same in both modes.
50
- const discoveredTabs = state(hasPropTabs ? tabs : [])
51
- const activeTab = state({{ defaultTab }})
52
-
53
- // Walk only direct descendants of THIS container (not nested Tabs').
54
- function findOwnPanels() {
55
- const root = containerRef.value
56
- if (!root) return []
57
- // Closest ancestor with data-stx-tabs must be this container's root —
58
- // protects against nested <Tabs> contamination.
59
- return Array.from(root.querySelectorAll('[data-stx-tab-panel]'))
60
- .filter(p => p.closest('[data-stx-tabs]') === root)
61
- }
62
-
63
- onMount(() => {
64
- if (hasPropTabs) return // legacy mode: prop array already in discoveredTabs
65
- const panels = findOwnPanels()
66
- const list = panels.map(p => ({
67
- label: p.dataset.label || '',
68
- icon: p.dataset.icon || '',
69
- }))
70
- discoveredTabs.set(list)
71
- })
72
-
73
- // In slot mode, toggle each panel's `hidden` attribute as activeTab changes.
74
- // Prop mode is handled inline by the @foreach loop's :show binding below.
75
- effect(() => {
76
- if (hasPropTabs) return
77
- const panels = findOwnPanels()
78
- const idx = activeTab()
79
- panels.forEach((p, i) => {
80
- if (i === idx) p.removeAttribute('hidden')
81
- else p.setAttribute('hidden', '')
82
- })
83
- })
84
-
85
- function selectTab(index) {
86
- activeTab.set(index)
87
- const list = discoveredTabs()
88
- emit('change', { index, tab: list[index] })
89
- }
90
-
91
- function isActive(index) {
92
- return activeTab() === index
93
- }
94
-
95
- function getTabClasses(index) {
96
- const isActiveTab = isActive(index)
97
- const base = 'px-4 py-2 font-medium text-sm transition-colors duration-150 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 dark:focus:ring-offset-gray-900'
98
- if (variant === 'line') {
99
- const border = orientation === 'horizontal' ? 'border-b-2' : 'border-r-2'
100
- return `${base} ${border} ${isActiveTab ? 'border-blue-500 text-blue-600 dark:text-blue-400' : 'border-transparent text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-200 hover:border-gray-300 dark:hover:border-gray-600'}`
101
- }
102
- if (variant === 'pills') {
103
- return `${base} rounded-md ${isActiveTab ? 'bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 shadow-sm' : 'text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-200'}`
104
- }
105
- if (variant === 'enclosed') {
106
- const borders = orientation === 'horizontal' ? 'border-t border-l border-r rounded-t-md' : 'border-t border-l border-b rounded-l-md'
107
- return `${base} ${borders} ${isActiveTab ? 'bg-white dark:bg-gray-800 border-gray-200 dark:border-gray-700 -mb-px' : 'bg-gray-50 dark:bg-gray-900 border-transparent hover:border-gray-200 dark:hover:border-gray-700'}`
108
- }
109
- return base
110
- }
111
-
112
- function onTabKey(event, index) {
113
- const tabCount = discoveredTabs().length
114
- let next = index
115
- if (orientation === 'horizontal') {
116
- if (event.key === 'ArrowRight') { event.preventDefault(); next = (index + 1) % tabCount }
117
- else if (event.key === 'ArrowLeft') { event.preventDefault(); next = (index - 1 + tabCount) % tabCount }
118
- }
119
- else {
120
- if (event.key === 'ArrowDown') { event.preventDefault(); next = (index + 1) % tabCount }
121
- else if (event.key === 'ArrowUp') { event.preventDefault(); next = (index - 1 + tabCount) % tabCount }
122
- }
123
- if (event.key === 'Home') { event.preventDefault(); next = 0 }
124
- else if (event.key === 'End') { event.preventDefault(); next = tabCount - 1 }
125
- if (next !== index) {
126
- selectTab(next)
127
- document.getElementById(`tab-${next}`)?.focus()
128
- }
129
- }
130
-
131
- defineExpose({ activeTab, selectTab })
132
- </script>
133
-
134
- <div x-ref="containerRef" data-stx-tabs class="{{ containerClasses }}">
135
- <div
136
- class="{{ tabListClasses }}"
137
- role="tablist"
138
- aria-orientation="{{ orientation }}"
139
- >
140
- @if(hasPropTabs)
141
- {{-- Legacy mode: server-side iterate the prop tabs array. Buttons --}}
142
- {{-- get static class names so existing visual snapshots stay --}}
143
- {{-- byte-identical. --}}
144
- @foreach(tab in tabs)
145
- <button
146
- type="button"
147
- :class="getTabClasses({{ $loop.index }})"
148
- role="tab"
149
- :aria-selected="isActive({{ $loop.index }}) ? 'true' : 'false'"
150
- aria-controls="tab-panel-{{ $loop.index }}"
151
- id="tab-{{ $loop.index }}"
152
- :tabindex="isActive({{ $loop.index }}) ? '0' : '-1'"
153
- @click="selectTab({{ $loop.index }})"
154
- @keydown="onTabKey($event, {{ $loop.index }})"
155
- >
156
- @if(tab.icon)
157
- <span class="inline-flex items-center gap-2">
158
- <span x-html="{!! JSON.stringify(tab.icon) !!}"></span>
159
- <span>{{ tab.label }}</span>
160
- </span>
161
- @else
162
- {{ tab.label }}
163
- @endif
164
- </button>
165
- @endforeach
166
- @else
167
- {{-- Slot mode: render the tab list dynamically from --}}
168
- {{-- discoveredTabs() which is populated in onMount. --}}
169
- <button
170
- :for="(tab, idx) in discoveredTabs()"
171
- :key="idx"
172
- type="button"
173
- x-class="getTabClasses(idx)"
174
- role="tab"
175
- :aria-selected="isActive(idx) ? 'true' : 'false'"
176
- :tabindex="isActive(idx) ? 0 : -1"
177
- @click="selectTab(idx)"
178
- @keydown="onTabKey($event, idx)"
179
- >
180
- <span :if="tab.icon" class="inline-flex items-center gap-2" x-html="tab.icon"></span>
181
- <span :text="tab.label"></span>
182
- </button>
183
- @endif
184
- </div>
185
-
186
- @if(hasPropTabs)
187
- @foreach(tab in tabs)
188
- <div
189
- :show="isActive({{ $loop.index }})"
190
- id="tab-panel-{{ $loop.index }}"
191
- class="{{ tabPanelClasses }}"
192
- role="tabpanel"
193
- aria-labelledby="tab-{{ $loop.index }}"
194
- tabindex="0"
195
- >
196
- {!! tab.content !!}
197
- </div>
198
- @endforeach
199
- @else
200
- <slot />
201
- @endif
202
- </div>
@@ -1,50 +0,0 @@
1
- export { default as TabPanel } from './TabPanel.stx'
2
- export { default as Tabs } from './Tabs.stx'
3
-
4
- /**
5
- * Legacy prop API — pass `tabs` as an array of `{ label, content, icon? }`
6
- * where `content` is a HTML string. Kept for backward compatibility; prefer
7
- * the slot API below for any tab whose content needs to be a component tree.
8
- *
9
- * See stacksjs/stx#1703.
10
- */
11
- export interface Tab {
12
- label: string
13
- content: string
14
- icon?: string
15
- }
16
-
17
- export interface TabsProps {
18
- /** Legacy: array of tab definitions with string content. */
19
- tabs?: Tab[]
20
- defaultTab?: number
21
- orientation?: 'horizontal' | 'vertical'
22
- variant?: 'line' | 'pills' | 'enclosed'
23
- onChange?: (index: number, tab: Tab) => void
24
- className?: string
25
- }
26
-
27
- /**
28
- * Slot API — wrap each tab's content in a `<TabPanel label="…">`. The parent
29
- * `<Tabs>` discovers panels on mount via `[data-stx-tab-panel]` data
30
- * attributes, builds the tab list dynamically, and toggles each panel's
31
- * `hidden` attribute as the active tab changes.
32
- *
33
- * @example
34
- * ```html
35
- * <Tabs defaultTab="0" variant="pills">
36
- * <TabPanel label="Drivers">
37
- * <DriversTable :drivers="drivers()" />
38
- * </TabPanel>
39
- * <TabPanel label="Notifications" icon="bell">
40
- * <NotificationsTable />
41
- * </TabPanel>
42
- * </Tabs>
43
- * ```
44
- */
45
- export interface TabPanelProps {
46
- label: string
47
- /** Optional icon HTML (rendered via `x-html`) for the tab button. */
48
- icon?: string
49
- className?: string
50
- }
@@ -1,65 +0,0 @@
1
- <script server>
2
- export const to = $props.to || 'body'
3
- export const disabled = $props.disabled || false
4
- export const defer = $props.defer || false
5
-
6
- export const teleportId = `teleport-${Math.random().toString(36).slice(2, 11)}`
7
- </script>
8
-
9
- <script client>
10
- const to = {{ to }}
11
- const isDisabled = {{ disabled }}
12
- const shouldDefer = {{ defer }}
13
- const teleportId = {{ teleportId }}
14
-
15
- let teleportContainer = null
16
-
17
- function teleport() {
18
- if (isDisabled) return
19
- const targetElement = typeof to === 'string' ? document.querySelector(to) : to
20
- if (!targetElement) {
21
- console.warn(`Teleport target "${to}" not found`)
22
- return
23
- }
24
- const sourceElement = document.getElementById(teleportId)
25
- if (!sourceElement) return
26
- if (!teleportContainer) {
27
- teleportContainer = document.createElement('div')
28
- teleportContainer.setAttribute('data-teleport-id', teleportId)
29
- }
30
- while (sourceElement.firstChild) {
31
- teleportContainer.appendChild(sourceElement.firstChild)
32
- }
33
- targetElement.appendChild(teleportContainer)
34
- }
35
-
36
- function returnContent() {
37
- if (!teleportContainer || !teleportContainer.parentNode) return
38
- const sourceElement = document.getElementById(teleportId)
39
- if (!sourceElement) return
40
- while (teleportContainer.firstChild) {
41
- sourceElement.appendChild(teleportContainer.firstChild)
42
- }
43
- teleportContainer.parentNode.removeChild(teleportContainer)
44
- teleportContainer = null
45
- }
46
-
47
- onMount(() => {
48
- if (shouldDefer) setTimeout(teleport, 0)
49
- else teleport()
50
- window.addEventListener('beforeunload', returnContent)
51
- })
52
-
53
- onDestroy(() => {
54
- returnContent()
55
- window.removeEventListener('beforeunload', returnContent)
56
- })
57
- </script>
58
-
59
- @if(disabled)
60
- <slot />
61
- @else
62
- <div id="{{ teleportId }}" data-teleport-source="true">
63
- <slot />
64
- </div>
65
- @endif
@@ -1,7 +0,0 @@
1
- export { default as Teleport } from './Teleport.stx'
2
-
3
- export interface TeleportProps {
4
- to?: string | HTMLElement
5
- disabled?: boolean
6
- defer?: boolean
7
- }
@@ -1,108 +0,0 @@
1
- <script server>
2
- export const value = $props.value || ''
3
- export const placeholder = $props.placeholder || ''
4
- export const disabled = $props.disabled || false
5
- export const readonly = $props.readonly || false
6
- export const rows = $props.rows || 4
7
- export const autoResize = $props.autoResize || false
8
- export const maxRows = $props.maxRows || 10
9
- export const error = $props.error || false
10
- export const label = $props.label || ''
11
- export const helperText = $props.helperText || ''
12
- export const required = $props.required || false
13
- export const maxLength = $props.maxLength
14
- export const showCount = $props.showCount || false
15
- export const resize = $props.resize || 'vertical'
16
- export const className = $props.className || ''
17
-
18
- const resizeClasses = { none: 'resize-none', vertical: 'resize-y', horizontal: 'resize-x', both: 'resize' }
19
- const baseClasses = 'block w-full border-0 rounded-md shadow-sm ring-1 ring-inset transition-colors duration-200 focus:ring-2 focus:ring-inset px-4 py-2 text-base dark:bg-blue-gray-700 dark:text-gray-100'
20
- const stateClasses = error
21
- ? 'ring-red-300 dark:ring-red-600 text-red-900 dark:text-red-300 placeholder-red-300 dark:placeholder-red-500 focus:ring-red-500 dark:focus:ring-red-400'
22
- : 'ring-gray-300 dark:ring-gray-600 text-gray-900 dark:text-gray-100 placeholder-gray-400 dark:placeholder-gray-500 focus:ring-indigo-600 dark:focus:ring-indigo-400'
23
- const disabledClasses = disabled
24
- ? 'opacity-50 cursor-not-allowed bg-gray-50 dark:bg-gray-800'
25
- : readonly
26
- ? 'bg-gray-50 dark:bg-gray-800 cursor-default'
27
- : 'bg-white dark:bg-blue-gray-700'
28
-
29
- export const textareaClasses = `${baseClasses} ${stateClasses} ${disabledClasses} ${resizeClasses[resize]} ${className}`.trim()
30
- export const labelClasses = `block text-sm font-medium leading-6 mb-2 ${error ? 'text-red-600 dark:text-red-400' : 'text-gray-900 dark:text-gray-100'}`.trim()
31
- export const helperClasses = `mt-2 text-sm ${error ? 'text-red-600 dark:text-red-400' : 'text-gray-500 dark:text-gray-400'}`.trim()
32
- </script>
33
-
34
- <script client>
35
- const emit = defineEmits()
36
- const autoResize = {{ autoResize }}
37
- const maxRows = {{ maxRows }}
38
- // Reactive prop binding — parent can drive `value` via signals. See #1704.
39
- const inputValue = useReactiveProp('value', {{ value }}, { parse: (v) => v == null ? '' : String(v) })
40
-
41
- function resizeTextarea(el) {
42
- if (!autoResize) return
43
- el.style.height = 'auto'
44
- const scrollHeight = el.scrollHeight
45
- const lineHeight = Number.parseInt(window.getComputedStyle(el).lineHeight) || 20
46
- const maxHeight = lineHeight * maxRows
47
- el.style.height = `${Math.min(scrollHeight, maxHeight)}px`
48
- el.style.overflowY = scrollHeight > maxHeight ? 'auto' : 'hidden'
49
- }
50
-
51
- function onInput(event) {
52
- inputValue.set(event.target.value)
53
- resizeTextarea(event.target)
54
- emit('input', inputValue())
55
- }
56
-
57
- onMount(() => {
58
- if (autoResize) {
59
- const el = document.getElementById('textarea-input')
60
- if (el) resizeTextarea(el)
61
- }
62
- })
63
-
64
- const charCount = derived(() => `${inputValue().length} / {{ maxLength || 0 }}`)
65
-
66
- defineExpose({ value: inputValue })
67
- </script>
68
-
69
- <div class="w-full">
70
- @if(label)
71
- <label for="textarea-input" class="{{ labelClasses }}">
72
- {{ label }}
73
- @if(required)
74
- <span class="text-red-500 ml-1">*</span>
75
- @endif
76
- </label>
77
- @endif
78
-
79
- <textarea
80
- id="textarea-input"
81
- class="{{ textareaClasses }}"
82
- rows="{{ rows }}"
83
- placeholder="{{ placeholder }}"
84
- @if(disabled)disabled@endif
85
- @if(readonly)readonly@endif
86
- @if(required)required@endif
87
- @if(maxLength)maxlength="{{ maxLength }}"@endif
88
- @input="onInput($event)"
89
- :aria-invalid="{{ error ? 'true' : 'false' }}"
90
- @if(helperText)aria-describedby="helper-text"@endif
91
- >{{ value }}</textarea>
92
-
93
- @if(helperText || (showCount && maxLength))
94
- <div class="flex items-center justify-between mt-2">
95
- @if(helperText)
96
- <p id="helper-text" class="{{ helperClasses }}">
97
- {{ helperText }}
98
- </p>
99
- @else
100
- <span></span>
101
- @endif
102
-
103
- @if(showCount && maxLength)
104
- <p class="text-sm text-gray-500 dark:text-gray-400" x-text="charCount()"></p>
105
- @endif
106
- </div>
107
- @endif
108
- </div>
@@ -1,20 +0,0 @@
1
- export { default as Textarea } from './Textarea.stx'
2
-
3
- export interface TextareaProps {
4
- value?: string
5
- onChange?: (value: string) => void
6
- placeholder?: string
7
- disabled?: boolean
8
- readonly?: boolean
9
- rows?: number
10
- autoResize?: boolean
11
- maxRows?: number
12
- error?: boolean
13
- label?: string
14
- helperText?: string
15
- required?: boolean
16
- maxLength?: number
17
- showCount?: boolean
18
- resize?: 'none' | 'vertical' | 'horizontal' | 'both'
19
- className?: string
20
- }
@@ -1,71 +0,0 @@
1
- <script server>
2
- export const content = $props.content || ''
3
- export const position = $props.position || 'top'
4
- export const delay = $props.delay || 0
5
- export const className = $props.className || ''
6
- export const show = $props.show || false
7
- export const disabled = $props.disabled || false
8
-
9
- const positionClasses = {
10
- top: 'bottom-full left-1/2 -translate-x-1/2 mb-2',
11
- bottom: 'top-full left-1/2 -translate-x-1/2 mt-2',
12
- left: 'right-full top-1/2 -translate-y-1/2 mr-2',
13
- right: 'left-full top-1/2 -translate-y-1/2 ml-2',
14
- }
15
-
16
- const arrowClasses = {
17
- top: 'top-full left-1/2 -translate-x-1/2 border-t-gray-900 dark:border-t-gray-700',
18
- bottom: 'bottom-full left-1/2 -translate-x-1/2 border-b-gray-900 dark:border-b-gray-700',
19
- left: 'left-full top-1/2 -translate-y-1/2 border-l-gray-900 dark:border-l-gray-700',
20
- right: 'right-full top-1/2 -translate-y-1/2 border-r-gray-900 dark:border-r-gray-700',
21
- }
22
-
23
- export const tooltipClasses = `absolute z-50 px-3 py-2 text-sm font-medium text-white bg-gray-900 dark:bg-gray-700 rounded-lg shadow-lg whitespace-nowrap pointer-events-none transition-opacity duration-200 ${positionClasses[position]} ${className}`.trim()
24
- export const arrowClass = `absolute w-0 h-0 border-4 border-transparent ${arrowClasses[position]}`.trim()
25
- </script>
26
-
27
- <script client>
28
- const delay = {{ delay }}
29
- const isDisabled = {{ disabled }}
30
- // Reactive prop binding — parent can drive `show` via signals. See #1704.
31
- const isVisible = useReactiveProp('show', {{ show }})
32
- let timeoutId = null
33
-
34
- function showTooltip() {
35
- if (isDisabled) return
36
- if (delay > 0) {
37
- timeoutId = setTimeout(() => isVisible.set(true), delay)
38
- }
39
- else {
40
- isVisible.set(true)
41
- }
42
- }
43
-
44
- function hideTooltip() {
45
- if (timeoutId) {
46
- clearTimeout(timeoutId)
47
- timeoutId = null
48
- }
49
- isVisible.set(false)
50
- }
51
- </script>
52
-
53
- <div class="relative inline-block {{ disabled ? 'cursor-not-allowed' : '' }}">
54
- <div
55
- @mouseenter="showTooltip()"
56
- @mouseleave="hideTooltip()"
57
- @focusin="showTooltip()"
58
- @focusout="hideTooltip()"
59
- >
60
- <slot />
61
- </div>
62
-
63
- <div
64
- :show="isVisible() && !{{ disabled }}"
65
- class="{{ tooltipClasses }}"
66
- role="tooltip"
67
- >
68
- {{ content }}
69
- <div class="{{ arrowClass }}"></div>
70
- </div>
71
- </div>
@@ -1,10 +0,0 @@
1
- export { default as Tooltip } from './Tooltip.stx'
2
-
3
- export interface TooltipProps {
4
- content: string
5
- position?: 'top' | 'bottom' | 'left' | 'right'
6
- delay?: number
7
- show?: boolean
8
- disabled?: boolean
9
- className?: string
10
- }
@@ -1,30 +0,0 @@
1
- # Transition Component
2
-
3
- Smooth enter/leave transitions for showing and hiding content.
4
-
5
- ## Installation
6
-
7
- ```bash
8
- bun add @stacksjs/components
9
- ```
10
-
11
- ## Usage
12
-
13
- ```stx
14
- <script server>
15
- let isOpen = true
16
- </script>
17
-
18
- <Transition :show="isOpen">
19
- <div class="p-4 bg-white rounded-lg shadow-lg">
20
- Content with fade transition
21
- </div>
22
- </Transition>
23
- ```
24
-
25
- ## Features
26
-
27
- - Enter/leave animations
28
- - Customizable transition classes
29
- - Dark mode support
30
- - Headwind utility classes