@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,347 +0,0 @@
1
- // Storage utilities for localStorage and sessionStorage
2
-
3
- export interface StorageOptions {
4
- expire?: number // Expiration in milliseconds
5
- namespace?: string // Prefix for keys
6
- encrypt?: boolean // Encrypt data (basic XOR encryption)
7
- compress?: boolean // Compress large objects
8
- }
9
-
10
- type StorageWatchCallback = (_newValue: any, _oldValue: any, _key: string) => void
11
-
12
- export class StorageManager {
13
- private storage: globalThis.Storage
14
- private namespace: string
15
- private watchers: Map<string, Set<StorageWatchCallback>> = new Map()
16
- private encryptionKey = 'stx-storage-key' // Simple encryption key
17
-
18
- constructor(type: 'local' | 'session' = 'local', namespace = '') {
19
- this.storage = type === 'local' ? globalThis.localStorage : globalThis.sessionStorage
20
- this.namespace = namespace
21
-
22
- // Listen for storage events from other tabs/windows
23
- if (typeof window !== 'undefined') {
24
- window.addEventListener('storage', this.handleStorageEvent.bind(this))
25
- }
26
- }
27
-
28
- private handleStorageEvent(event: StorageEvent): void {
29
- if (!event.key)
30
- return
31
-
32
- const key = this.namespace && event.key.startsWith(`${this.namespace}:`)
33
- ? event.key.slice(this.namespace.length + 1)
34
- : event.key
35
-
36
- const callbacks = this.watchers.get(key)
37
- if (callbacks) {
38
- const oldValue = event.oldValue ? JSON.parse(event.oldValue).value : null
39
- const newValue = event.newValue ? JSON.parse(event.newValue).value : null
40
- callbacks.forEach(callback => callback(newValue, oldValue, key))
41
- }
42
- }
43
-
44
- private encrypt(data: string): string {
45
- // Simple XOR encryption (not cryptographically secure, just obfuscation)
46
- let result = ''
47
- for (let i = 0; i < data.length; i++) {
48
- result += String.fromCharCode(data.charCodeAt(i) ^ this.encryptionKey.charCodeAt(i % this.encryptionKey.length))
49
- }
50
- return btoa(result) // Base64 encode
51
- }
52
-
53
- private decrypt(data: string): string {
54
- try {
55
- const decoded = atob(data) // Base64 decode
56
- let result = ''
57
- for (let i = 0; i < decoded.length; i++) {
58
- result += String.fromCharCode(decoded.charCodeAt(i) ^ this.encryptionKey.charCodeAt(i % this.encryptionKey.length))
59
- }
60
- return result
61
- }
62
- catch {
63
- return data // Return as-is if decryption fails
64
- }
65
- }
66
-
67
- private compress(data: string): string {
68
- // Simple LZ-based compression for large strings
69
- if (data.length < 100)
70
- return data // Don't compress small strings
71
-
72
- const dict: Record<string, number> = {}
73
- let dictSize = 256
74
- const result: number[] = []
75
- let w = ''
76
-
77
- for (let i = 0; i < data.length; i++) {
78
- const c = data.charAt(i)
79
- const wc = w + c
80
-
81
- if (dict[wc] !== undefined) {
82
- w = wc
83
- }
84
- else {
85
- result.push(w.length > 1 ? dict[w] : w.charCodeAt(0))
86
- dict[wc] = dictSize++
87
- w = c
88
- }
89
- }
90
-
91
- if (w !== '') {
92
- result.push(w.length > 1 ? dict[w] : w.charCodeAt(0))
93
- }
94
-
95
- return JSON.stringify(result)
96
- }
97
-
98
- private decompress(data: string): string {
99
- try {
100
- const compressed = JSON.parse(data)
101
- if (!Array.isArray(compressed))
102
- return data
103
-
104
- const dict: Record<number, string> = {}
105
- let dictSize = 256
106
- let w = String.fromCharCode(compressed[0])
107
- let result = w
108
-
109
- for (let i = 1; i < compressed.length; i++) {
110
- const k = compressed[i]
111
- let entry: string
112
-
113
- if (dict[k] !== undefined) {
114
- entry = dict[k]
115
- }
116
- else if (k === dictSize) {
117
- entry = w + w.charAt(0)
118
- }
119
- else {
120
- return data // Decompression failed
121
- }
122
-
123
- result += entry
124
- dict[dictSize++] = w + entry.charAt(0)
125
- w = entry
126
- }
127
-
128
- return result
129
- }
130
- catch {
131
- return data // Return as-is if decompression fails
132
- }
133
- }
134
-
135
- private getKey(key: string): string {
136
- return this.namespace ? `${this.namespace}:${key}` : key
137
- }
138
-
139
- set(key: string, value: any, options?: StorageOptions): void {
140
- const fullKey = this.getKey(key)
141
- const oldValue = this.get(key)
142
-
143
- const data = {
144
- value,
145
- timestamp: Date.now(),
146
- expire: options?.expire,
147
- encrypted: options?.encrypt || false,
148
- compressed: options?.compress || false,
149
- }
150
-
151
- try {
152
- let serialized = JSON.stringify(data)
153
-
154
- // Compress if enabled
155
- if (options?.compress) {
156
- serialized = this.compress(serialized)
157
- }
158
-
159
- // Encrypt if enabled
160
- if (options?.encrypt) {
161
- serialized = this.encrypt(serialized)
162
- }
163
-
164
- this.storage.setItem(fullKey, serialized)
165
-
166
- // Notify watchers
167
- this.notifyWatchers(key, value, oldValue)
168
- }
169
- catch (error) {
170
- console.error('Storage set error:', error)
171
- }
172
- }
173
-
174
- get<T = any>(key: string): T | null {
175
- const fullKey = this.getKey(key)
176
-
177
- try {
178
- let item = this.storage.getItem(fullKey)
179
- if (!item)
180
- return null
181
-
182
- // Try to decrypt if it looks encrypted (base64)
183
- if (item.match(/^[A-Z0-9+/]+=*$/i)) {
184
- try {
185
- item = this.decrypt(item)
186
- }
187
- catch {
188
- // Not encrypted, continue
189
- }
190
- }
191
-
192
- // Try to decompress if it looks compressed (starts with [)
193
- if (item.startsWith('[')) {
194
- try {
195
- item = this.decompress(item)
196
- }
197
- catch {
198
- // Not compressed, continue
199
- }
200
- }
201
-
202
- const data = JSON.parse(item)
203
-
204
- // Check expiration
205
- if (data.expire && Date.now() - data.timestamp > data.expire) {
206
- this.remove(key)
207
- return null
208
- }
209
-
210
- return data.value as T
211
- }
212
- catch (error) {
213
- console.error('Storage get error:', error)
214
- return null
215
- }
216
- }
217
-
218
- watch(key: string, callback: StorageWatchCallback): () => void {
219
- if (!this.watchers.has(key)) {
220
- this.watchers.set(key, new Set())
221
- }
222
-
223
- this.watchers.get(key)!.add(callback)
224
-
225
- // Return unwatch function
226
- return () => {
227
- const callbacks = this.watchers.get(key)
228
- if (callbacks) {
229
- callbacks.delete(callback)
230
- if (callbacks.size === 0) {
231
- this.watchers.delete(key)
232
- }
233
- }
234
- }
235
- }
236
-
237
- private notifyWatchers(key: string, newValue: any, oldValue: any): void {
238
- const callbacks = this.watchers.get(key)
239
- if (callbacks) {
240
- callbacks.forEach(callback => callback(newValue, oldValue, key))
241
- }
242
- }
243
-
244
- remove(key: string): void {
245
- const fullKey = this.getKey(key)
246
- const oldValue = this.get(key)
247
- this.storage.removeItem(fullKey)
248
-
249
- // Notify watchers
250
- this.notifyWatchers(key, null, oldValue)
251
- }
252
-
253
- clear(): void {
254
- if (this.namespace) {
255
- // Clear only namespaced items
256
- const keys = this.keys()
257
- keys.forEach(key => this.remove(key))
258
- }
259
- else {
260
- this.storage.clear()
261
- }
262
- }
263
-
264
- has(key: string): boolean {
265
- return this.get(key) !== null
266
- }
267
-
268
- keys(): string[] {
269
- const allKeys = Object.keys(this.storage)
270
-
271
- if (this.namespace) {
272
- const prefix = `${this.namespace}:`
273
- return allKeys
274
- .filter(key => key.startsWith(prefix))
275
- .map(key => key.slice(prefix.length))
276
- }
277
-
278
- return allKeys
279
- }
280
-
281
- size(): number {
282
- return this.keys().length
283
- }
284
-
285
- // Get storage quota information (if available)
286
- getQuota(): { usage: number, quota: number, percentage: number } | null {
287
- if ('storage' in navigator && 'estimate' in navigator.storage) {
288
- // Use async/await pattern but return promise
289
- return null // This would need to be async, but keeping sync API
290
- }
291
-
292
- // Fallback: estimate based on current data
293
- try {
294
- let totalSize = 0
295
- for (let i = 0; i < this.storage.length; i++) {
296
- const key = this.storage.key(i)
297
- if (key) {
298
- const value = this.storage.getItem(key) || ''
299
- totalSize += key.length + value.length
300
- }
301
- }
302
-
303
- // Typical localStorage quota is 5-10MB
304
- const estimatedQuota = 5 * 1024 * 1024 // 5MB
305
- return {
306
- usage: totalSize * 2, // Multiply by 2 for UTF-16 encoding
307
- quota: estimatedQuota,
308
- percentage: (totalSize * 2 / estimatedQuota) * 100,
309
- }
310
- }
311
- catch {
312
- return null
313
- }
314
- }
315
-
316
- // Batch operations
317
- setMany(items: Record<string, any>, options?: StorageOptions): void {
318
- Object.entries(items).forEach(([key, value]) => {
319
- this.set(key, value, options)
320
- })
321
- }
322
-
323
- getMany<T = any>(keys: string[]): Record<string, T | null> {
324
- const result: Record<string, T | null> = {}
325
- keys.forEach((key) => {
326
- result[key] = this.get<T>(key)
327
- })
328
- return result
329
- }
330
-
331
- removeMany(keys: string[]): void {
332
- keys.forEach(key => this.remove(key))
333
- }
334
- }
335
-
336
- // Convenience exports
337
- export const storage: {
338
- local: StorageManager
339
- session: StorageManager
340
- } = {
341
- local: new StorageManager('local'),
342
- session: new StorageManager('session'),
343
- }
344
-
345
- export function createStorage(type: 'local' | 'session' = 'local', namespace?: string): StorageManager {
346
- return new StorageManager(type, namespace)
347
- }
@@ -1,114 +0,0 @@
1
- # Switch Component
2
-
3
- A modern toggle switch component built with STX and headwind utility classes, inspired by Headless UI.
4
-
5
- ## Installation
6
-
7
- ```bash
8
- bun add @stacksjs/components
9
- ```
10
-
11
- ## Usage
12
-
13
- ```stx
14
- <Switch checked label="Enable notifications" />
15
- ```
16
-
17
- ## Props
18
-
19
- | Prop | Type | Default | Description |
20
- |------|------|---------|-------------|
21
- | `checked` | `boolean` | `false` | Whether the switch is checked |
22
- | `disabled` | `boolean` | `false` | Disable the switch |
23
- | `size` | `'sm' \| 'md' \| 'lg'` | `'md'` | Switch size |
24
- | `className` | `string` | `''` | Additional CSS classes |
25
- | `onChange` | `(checked: boolean) => void` | - | Change handler |
26
- | `label` | `string` | `''` | Optional label text |
27
-
28
- ## Examples
29
-
30
- ### Basic Switch
31
-
32
- ```stx
33
- <script server>
34
- let enabled = false
35
-
36
- function handleChange(checked) {
37
- enabled = checked
38
- console.log('Switch is now:', checked)
39
- }
40
- </script>
41
-
42
- <Switch :checked="enabled" :onChange="handleChange" />
43
- ```
44
-
45
- ### With Label
46
-
47
- ```stx
48
- <Switch checked label="Enable notifications" :onChange="handleChange" />
49
- ```
50
-
51
- ### Sizes
52
-
53
- ```stx
54
- <Switch size="sm" checked />
55
-
56
- <Switch size="md" checked />
57
-
58
- <Switch size="lg" checked />
59
- ```
60
-
61
- ### Disabled State
62
-
63
- ```stx
64
- <Switch checked disabled label="Cannot toggle" />
65
- ```
66
-
67
- ### Custom Styling
68
-
69
- ```stx
70
- <Switch checked className="my-4" />
71
- ```
72
-
73
- ## Accessibility
74
-
75
- The Switch component follows WAI-ARIA best practices:
76
-
77
- - Proper `role="switch"` attribute
78
- - `aria-checked` reflects the current state
79
- - `aria-disabled` when disabled
80
- - Screen reader text via `sr-only` class
81
- - Keyboard accessible (can be toggled with Space/Enter)
82
- - Focus visible ring for keyboard navigation
83
-
84
- ## Features
85
-
86
- - Smooth animations and transitions
87
- - Three size options (sm, md, lg)
88
- - Dark mode support
89
- - Disabled state
90
- - Optional label
91
- - Accessible by default
92
- - Headwind utility classes for easy customization
93
- - Inspired by Headless UI design
94
-
95
- ## Styling
96
-
97
- The component uses headwind utility classes for styling. You can customize it by:
98
-
99
- 1. Passing additional classes via `className` prop
100
- 2. Modifying the component source
101
- 3. Using headwind configuration to adjust the design system
102
-
103
- ### Color Customization
104
-
105
- To customize colors, you can:
106
-
107
- - Override the checked state background color in your headwind config
108
- - Pass custom classes via `className` prop
109
- - Modify the component's source code
110
-
111
- Example:
112
- ```stx
113
- <Switch checked className="!bg-green-500" />
114
- ```
@@ -1,72 +0,0 @@
1
- <script server>
2
- export const checked = $props.checked || false
3
- export const disabled = $props.disabled || false
4
- export const size = $props.size || 'md'
5
- export const className = $props.className || ''
6
- export const label = $props.label || ''
7
-
8
- const sizeConfig = {
9
- sm: { track: 'h-5 w-9', thumb: 'h-4 w-4', translate: 'translate-x-4' },
10
- md: { track: 'h-[38px] w-[74px]', thumb: 'h-[34px] w-[34px]', translate: 'translate-x-9' },
11
- lg: { track: 'h-12 w-24', thumb: 'h-11 w-11', translate: 'translate-x-12' },
12
- }
13
-
14
- export const config = sizeConfig[size]
15
-
16
- export const trackBaseClasses = 'relative inline-flex shrink-0 cursor-pointer border-2 border-transparent rounded-full transition-colors duration-200 ease-in-out focus:outline-none focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-offset-2 focus-visible:ring-offset-neutral-300 dark:focus-visible:ring-offset-neutral-700'
17
- export const trackDisabledClasses = disabled ? 'opacity-50 cursor-not-allowed pointer-events-none' : ''
18
- export const thumbBaseClasses = 'pointer-events-none inline-block transform rounded-full bg-white shadow-lg ring-0 transition duration-200 ease-in-out'
19
- </script>
20
-
21
- <script client>
22
- const emit = defineEmits()
23
- const isDisabled = {{ disabled }}
24
- const config = {{ config }}
25
- const trackBase = {{ trackBaseClasses }}
26
- const trackDisabled = {{ trackDisabledClasses }}
27
- const thumbBase = {{ thumbBaseClasses }}
28
- const extraClass = {{ className }}
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 toggle() {
34
- if (isDisabled) return
35
- isChecked.set(!isChecked())
36
- emit('change', isChecked())
37
- }
38
-
39
- function trackClasses() {
40
- const stateClass = isChecked()
41
- ? 'bg-blue-500 dark:bg-blue-600'
42
- : 'bg-neutral-400 dark:bg-neutral-600'
43
- return `${trackBase} ${stateClass} ${trackDisabled} ${config.track} ${extraClass}`.trim()
44
- }
45
-
46
- function thumbClasses() {
47
- const pos = isChecked() ? config.translate : 'translate-x-0'
48
- return `${thumbBase} ${pos} ${config.thumb}`.trim()
49
- }
50
-
51
- defineExpose({ isChecked, toggle })
52
- </script>
53
-
54
- <label class="inline-flex items-center gap-3 cursor-pointer">
55
- @if(label)
56
- <span class="text-sm font-medium text-neutral-700 dark:text-neutral-300">
57
- {{ label }}
58
- </span>
59
- @endif
60
-
61
- <button
62
- type="button"
63
- role="switch"
64
- :aria-checked="isChecked() ? 'true' : 'false'"
65
- :class="trackClasses()"
66
- @if(disabled)disabled aria-disabled="true"@endif
67
- @click="toggle()"
68
- >
69
- <span class="sr-only">@if(label){{ label }}@else Toggle switch@endif</span>
70
- <span aria-hidden="true" :class="thumbClasses()"></span>
71
- </button>
72
- </label>
@@ -1,10 +0,0 @@
1
- export { default as Switch } from './Switch.stx'
2
-
3
- export interface SwitchProps {
4
- checked?: boolean
5
- disabled?: boolean
6
- size?: 'sm' | 'md' | 'lg'
7
- className?: string
8
- onChange?: (checked: boolean) => void
9
- label?: string
10
- }
@@ -1,39 +0,0 @@
1
- # Table Component
2
-
3
- Responsive table component with sorting and styling options.
4
-
5
- ## Installation
6
-
7
- ```bash
8
- bun add @stacksjs/components
9
- ```
10
-
11
- ## Usage
12
-
13
- ```stx
14
- <Table>
15
- <TableHead>
16
- <TableRow>
17
- <TableHeader>Name</TableHeader>
18
- <TableHeader>Email</TableHeader>
19
- <TableHeader>Role</TableHeader>
20
- </TableRow>
21
- </TableHead>
22
-
23
- <TableBody>
24
- <TableRow>
25
- <TableCell>John Doe</TableCell>
26
- <TableCell>john@example.com</TableCell>
27
- <TableCell>Admin</TableCell>
28
- </TableRow>
29
- </TableBody>
30
- </Table>
31
- ```
32
-
33
- ## Features
34
-
35
- - Responsive design
36
- - Sortable columns
37
- - Striped rows
38
- - Hover effects
39
- - Dark mode support
@@ -1,14 +0,0 @@
1
- <script server>
2
- export const className = $props.className || ''
3
- export const striped = $props.striped || false
4
- export const hoverable = $props.hoverable !== false
5
-
6
- const baseClasses = 'min-w-full divide-y divide-neutral-200 dark:divide-neutral-700'
7
- const tableClasses = `${baseClasses} ${className}`.trim()
8
- </script>
9
-
10
- <div class="overflow-x-auto">
11
- <table class="{{ tableClasses }}">
12
- <slot :striped="striped" :hoverable="hoverable" />
13
- </table>
14
- </div>
@@ -1,10 +0,0 @@
1
- <script server>
2
- export const className = $props.className || ''
3
-
4
- const baseClasses = 'bg-white divide-y divide-neutral-200 dark:bg-neutral-900 dark:divide-neutral-700'
5
- const bodyClasses = `${baseClasses} ${className}`.trim()
6
- </script>
7
-
8
- <tbody class="{{ bodyClasses }}">
9
- <slot />
10
- </tbody>
@@ -1,10 +0,0 @@
1
- <script server>
2
- export const className = $props.className || ''
3
-
4
- const baseClasses = 'px-6 py-4 whitespace-nowrap text-sm text-neutral-900 dark:text-neutral-100'
5
- const cellClasses = `${baseClasses} ${className}`.trim()
6
- </script>
7
-
8
- <td class="{{ cellClasses }}">
9
- <slot />
10
- </td>
@@ -1,10 +0,0 @@
1
- <script server>
2
- export const className = $props.className || ''
3
-
4
- const baseClasses = 'bg-neutral-50 dark:bg-neutral-800'
5
- const headClasses = `${baseClasses} ${className}`.trim()
6
- </script>
7
-
8
- <thead class="{{ headClasses }}">
9
- <slot />
10
- </thead>
@@ -1,20 +0,0 @@
1
- <script server>
2
- export const className = $props.className || ''
3
- export const sortable = $props.sortable || false
4
-
5
- const baseClasses = 'px-6 py-3 text-left text-xs font-medium text-neutral-500 uppercase tracking-wider dark:text-neutral-400'
6
- const sortableClasses = sortable ? 'cursor-pointer hover:text-neutral-700 dark:hover:text-neutral-200' : ''
7
- export const headerClasses = `${baseClasses} ${sortableClasses} ${className}`.trim()
8
- </script>
9
-
10
- <script client>
11
- const emit = defineEmits()
12
-
13
- function onClick() {
14
- emit('click')
15
- }
16
- </script>
17
-
18
- <th class="{{ headerClasses }}" @if(sortable)@click="onClick()"@endif>
19
- <slot />
20
- </th>
@@ -1,11 +0,0 @@
1
- <script server>
2
- export const className = $props.className || ''
3
- export const hoverable = $props.hoverable !== false
4
-
5
- const hoverClasses = hoverable ? 'hover:bg-neutral-50 dark:hover:bg-neutral-800' : ''
6
- const rowClasses = `${hoverClasses} ${className}`.trim()
7
- </script>
8
-
9
- <tr class="{{ rowClasses }}">
10
- <slot />
11
- </tr>
@@ -1,35 +0,0 @@
1
- export { default as Table } from './Table.stx'
2
- export { default as TableBody } from './TableBody.stx'
3
- export { default as TableCell } from './TableCell.stx'
4
- export { default as TableHead } from './TableHead.stx'
5
- export { default as TableHeader } from './TableHeader.stx'
6
- export { default as TableRow } from './TableRow.stx'
7
-
8
- export interface TableProps {
9
- className?: string
10
- striped?: boolean
11
- hoverable?: boolean
12
- }
13
-
14
- export interface TableHeadProps {
15
- className?: string
16
- }
17
-
18
- export interface TableBodyProps {
19
- className?: string
20
- }
21
-
22
- export interface TableRowProps {
23
- className?: string
24
- hoverable?: boolean
25
- }
26
-
27
- export interface TableHeaderProps {
28
- className?: string
29
- sortable?: boolean
30
- onClick?: () => void
31
- }
32
-
33
- export interface TableCellProps {
34
- className?: string
35
- }