@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,146 +0,0 @@
1
- <script server>
2
- // Two modes (see stacksjs/stx#1703):
3
- // 1. Legacy prop API — pass `items={[{title, content}, …]}` for simple
4
- // string-content accordions (kept for backward compatibility with
5
- // existing visual snapshots and consumers).
6
- // 2. Slot API — drop `<AccordionItem title="…">` children for arbitrary
7
- // content. Each AccordionItem renders its own header + content panel;
8
- // this parent attaches click handlers and toggles content visibility.
9
- export const items = $props.items || []
10
- export const allowMultiple = $props.allowMultiple || false
11
- export const defaultOpen = $props.defaultOpen || []
12
- export const className = $props.className || ''
13
-
14
- export const accordionClasses = `divide-y divide-gray-200 dark:divide-gray-700 border border-gray-200 dark:border-gray-700 rounded-lg ${className}`.trim()
15
- export const headerClasses = `w-full flex items-center justify-between px-4 py-3 text-left font-medium text-gray-900 dark:text-gray-100 hover:bg-gray-50 dark:hover:bg-gray-800 transition-colors duration-150 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 dark:focus:ring-offset-gray-900`.trim()
16
- export const iconClasses = `w-5 h-5 text-gray-500 dark:text-gray-400 transition-transform duration-200`.trim()
17
- export const contentClasses = `px-4 py-3 text-gray-700 dark:text-gray-300`.trim()
18
- export const hasPropItems = Array.isArray(items) && items.length > 0
19
- </script>
20
-
21
- <script client>
22
- const emit = defineEmits()
23
- const allowMultiple = {{ allowMultiple }}
24
- const hasPropItems = {{ hasPropItems }}
25
- const containerRef = useRef()
26
- const openItems = state({{ defaultOpen }})
27
-
28
- function findOwnItems() {
29
- const root = containerRef.value
30
- if (!root) return []
31
- return Array.from(root.querySelectorAll('[data-stx-accordion-item]'))
32
- .filter(item => item.closest('[data-stx-accordion]') === root)
33
- }
34
-
35
- onMount(() => {
36
- if (hasPropItems) return // legacy mode: server-rendered, no wiring needed
37
- const items = findOwnItems()
38
- items.forEach((item, idx) => {
39
- const header = item.querySelector(':scope > [data-stx-accordion-header]')
40
- if (header && !header.__stx_wired) {
41
- header.__stx_wired = true
42
- header.addEventListener('click', () => toggleItem(idx))
43
- header.addEventListener('keydown', (e) => onHeaderKey(e, idx))
44
- }
45
- })
46
- })
47
-
48
- // Sync the open state into the DOM: show/hide content panels, update
49
- // aria-expanded on headers, rotate chevrons.
50
- effect(() => {
51
- if (hasPropItems) return
52
- const items = findOwnItems()
53
- const open = openItems()
54
- items.forEach((item, idx) => {
55
- const isOpenItem = open.includes(idx)
56
- const header = item.querySelector(':scope > [data-stx-accordion-header]')
57
- const content = item.querySelector(':scope > [data-stx-accordion-content]')
58
- const chevron = item.querySelector(':scope > [data-stx-accordion-header] [data-stx-accordion-chevron]')
59
- if (header) header.setAttribute('aria-expanded', isOpenItem ? 'true' : 'false')
60
- if (content) {
61
- if (isOpenItem) content.removeAttribute('hidden')
62
- else content.setAttribute('hidden', '')
63
- }
64
- if (chevron) chevron.style.transform = `rotate(${isOpenItem ? 180 : 0}deg)`
65
- })
66
- })
67
-
68
- function toggleItem(index) {
69
- const cur = openItems()
70
- if (allowMultiple) {
71
- openItems.set(cur.includes(index) ? cur.filter(i => i !== index) : [...cur, index])
72
- }
73
- else {
74
- openItems.set(cur.includes(index) ? [] : [index])
75
- }
76
- emit('change', openItems())
77
- }
78
-
79
- function isOpen(index) {
80
- return openItems().includes(index)
81
- }
82
-
83
- function onHeaderKey(event, index) {
84
- const root = containerRef.value
85
- if (!root) return
86
- const buttons = root.querySelectorAll('button[data-stx-accordion-header], button[data-accordion-header]')
87
- if (event.key === 'ArrowDown') {
88
- event.preventDefault()
89
- buttons[index + 1]?.focus()
90
- }
91
- else if (event.key === 'ArrowUp') {
92
- event.preventDefault()
93
- buttons[index - 1]?.focus()
94
- }
95
- else if (event.key === 'Home') {
96
- event.preventDefault()
97
- buttons[0]?.focus()
98
- }
99
- else if (event.key === 'End') {
100
- event.preventDefault()
101
- buttons[buttons.length - 1]?.focus()
102
- }
103
- }
104
-
105
- defineExpose({ openItems, toggleItem })
106
- </script>
107
-
108
- <div x-ref="containerRef" data-stx-accordion class="{{ accordionClasses }}" role="region">
109
- @if(hasPropItems)
110
- @foreach(item in items)
111
- <div>
112
- <button
113
- type="button"
114
- data-accordion-header
115
- class="{{ headerClasses }}"
116
- @click="toggleItem({{ $loop.index }})"
117
- @keydown="onHeaderKey($event, {{ $loop.index }})"
118
- :aria-expanded="isOpen({{ $loop.index }}) ? 'true' : 'false'"
119
- aria-controls="accordion-content-{{ $loop.index }}"
120
- >
121
- <span>{{ item.title }}</span>
122
- <svg
123
- class="{{ iconClasses }}"
124
- :style="`transform: rotate(${isOpen({{ $loop.index }}) ? 180 : 0}deg)`"
125
- fill="none"
126
- viewBox="0 0 24 24"
127
- stroke="currentColor"
128
- >
129
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7" />
130
- </svg>
131
- </button>
132
-
133
- <div
134
- :show="isOpen({{ $loop.index }})"
135
- id="accordion-content-{{ $loop.index }}"
136
- class="{{ contentClasses }}"
137
- role="region"
138
- >
139
- {!! item.content !!}
140
- </div>
141
- </div>
142
- @endforeach
143
- @else
144
- <slot />
145
- @endif
146
- </div>
@@ -1,37 +0,0 @@
1
- <script server>
2
- // Slot wrapper that the parent <Accordion> discovers and wires up on mount.
3
- // Renders its own header button + content panel; the parent attaches click
4
- // handlers and toggles the content panel's `hidden` attribute as openItems
5
- // changes. Hard-coded styling here matches the legacy prop-mode markup so
6
- // snapshots compare cleanly in both modes. See stacksjs/stx#1703.
7
- export const title = $props.title || ''
8
- export const className = $props.className || ''
9
-
10
- const headerClasses = 'w-full flex items-center justify-between px-4 py-3 text-left font-medium text-gray-900 dark:text-gray-100 hover:bg-gray-50 dark:hover:bg-gray-800 transition-colors duration-150 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 dark:focus:ring-offset-gray-900'
11
- const iconClasses = 'w-5 h-5 text-gray-500 dark:text-gray-400 transition-transform duration-200'
12
- const contentClasses = 'px-4 py-3 text-gray-700 dark:text-gray-300'
13
- </script>
14
-
15
- <div data-stx-accordion-item data-title="{{ title }}" class="{{ className }}">
16
- <button
17
- type="button"
18
- data-stx-accordion-header
19
- data-accordion-header
20
- class="{{ headerClasses }}"
21
- aria-expanded="false"
22
- >
23
- <span>{{ title }}</span>
24
- <svg
25
- data-stx-accordion-chevron
26
- class="{{ iconClasses }}"
27
- fill="none"
28
- viewBox="0 0 24 24"
29
- stroke="currentColor"
30
- >
31
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7" />
32
- </svg>
33
- </button>
34
- <div data-stx-accordion-content class="{{ contentClasses }}" role="region" hidden>
35
- <slot />
36
- </div>
37
- </div>
@@ -1,47 +0,0 @@
1
- export { default as Accordion } from './Accordion.stx'
2
- export { default as AccordionItem } from './AccordionItem.stx'
3
-
4
- /**
5
- * Legacy prop API — pass `items` as an array of `{ title, content }` where
6
- * `content` is a HTML string. Kept for backward compatibility; prefer the
7
- * slot API below for any accordion whose content needs to be a component tree.
8
- *
9
- * See stacksjs/stx#1703.
10
- */
11
- export interface AccordionLegacyItem {
12
- title: string
13
- content: string
14
- }
15
-
16
- export type AccordionItemDefinition = AccordionLegacyItem
17
-
18
- export interface AccordionProps {
19
- /** Legacy: array of item definitions with string content. */
20
- items?: AccordionItemDefinition[]
21
- allowMultiple?: boolean
22
- defaultOpen?: number[]
23
- onChange?: (openItems: number[]) => void
24
- className?: string
25
- }
26
-
27
- /**
28
- * Slot API — wrap each section's content in `<AccordionItem title="…">`.
29
- * Each `<AccordionItem>` renders its own header + content panel; the parent
30
- * `<Accordion>` attaches click handlers and toggles the content visibility.
31
- *
32
- * @example
33
- * ```html
34
- * <Accordion allowMultiple>
35
- * <AccordionItem title="Profile">
36
- * <ProfileEditor :user="user()" />
37
- * </AccordionItem>
38
- * <AccordionItem title="Zones">
39
- * <ZonesEditor />
40
- * </AccordionItem>
41
- * </Accordion>
42
- * ```
43
- */
44
- export interface AccordionItemProps {
45
- title: string
46
- className?: string
47
- }
@@ -1,50 +0,0 @@
1
- <script server>
2
- export const src = $props.src || ''
3
- export const autoplay = $props.autoplay || false
4
- export const loop = $props.loop || false
5
- export const muted = $props.muted || false
6
- export const controls = $props.controls ?? true
7
- export const preload = $props.preload || 'metadata'
8
- export const className = $props.className || ''
9
- export const showWaveform = $props.showWaveform || false
10
- export const title = $props.title || ''
11
-
12
- export const containerClasses = `relative w-full ${className}`.trim()
13
- export const audioClasses = 'w-full rounded-md bg-gray-100 dark:bg-gray-800'
14
- </script>
15
-
16
- <div class="{{ containerClasses }}">
17
- @if(title)
18
- <div class="mb-2 px-1">
19
- <h3 class="text-sm font-medium text-gray-900 dark:text-gray-100">
20
- {{ title }}
21
- </h3>
22
- </div>
23
- @endif
24
-
25
- <audio
26
- class="{{ audioClasses }}"
27
- src="{{ src }}"
28
- @if(controls)controls@endif
29
- @if(autoplay)autoplay@endif
30
- @if(loop)loop@endif
31
- @if(muted)muted@endif
32
- preload="{{ preload }}"
33
- >
34
- Your browser does not support the audio element.
35
- </audio>
36
-
37
- @if(showWaveform)
38
- <div class="mt-2 h-16 bg-gray-100 dark:bg-gray-800 rounded-md flex items-center justify-center">
39
- <svg class="w-full h-full px-4" viewBox="0 0 100 40" preserveAspectRatio="none">
40
- <path
41
- d="M 0,20 L 10,15 L 20,10 L 30,5 L 40,15 L 50,20 L 60,25 L 70,30 L 80,20 L 90,15 L 100,20"
42
- fill="none"
43
- stroke="currentColor"
44
- stroke-width="2"
45
- class="text-indigo-500 dark:text-indigo-400"
46
- />
47
- </svg>
48
- </div>
49
- @endif
50
- </div>
@@ -1,41 +0,0 @@
1
- # Audio Component
2
-
3
- A styled audio player with optional waveform visualization.
4
-
5
- ## Installation
6
-
7
- ```bash
8
- bun add @stacksjs/components
9
- ```
10
-
11
- ## Usage
12
-
13
- ```stx
14
- <Audio
15
- src="/audio/podcast.mp3"
16
- title="Episode 42: Building with STX"
17
- controls
18
- />
19
- ```
20
-
21
- ## Props
22
-
23
- | Prop | Type | Default | Description |
24
- |------|------|---------|-------------|
25
- | `src` | `string` | - | Audio file URL (required) |
26
- | `autoplay` | `boolean` | `false` | Auto-play on load |
27
- | `loop` | `boolean` | `false` | Loop playback |
28
- | `muted` | `boolean` | `false` | Start muted |
29
- | `controls` | `boolean` | `true` | Show native controls |
30
- | `preload` | `'none' \| 'metadata' \| 'auto'` | `'metadata'` | Preload strategy |
31
- | `className` | `string` | `''` | Additional CSS classes |
32
- | `showWaveform` | `boolean` | `false` | Show waveform visualization |
33
- | `title` | `string` | `''` | Optional title above player |
34
-
35
- ## Features
36
-
37
- - **Native controls** - Uses browser's native audio controls
38
- - **Dark mode** - Styled for dark mode
39
- - **Waveform** - Optional visual waveform display
40
- - **Accessible** - Proper fallback text
41
- - **Responsive** - Full-width design
@@ -1,13 +0,0 @@
1
- export { default as Audio } from './Audio.stx'
2
-
3
- export interface AudioProps {
4
- src: string
5
- autoplay?: boolean
6
- loop?: boolean
7
- muted?: boolean
8
- controls?: boolean
9
- preload?: 'none' | 'metadata' | 'auto'
10
- className?: string
11
- showWaveform?: boolean
12
- title?: string
13
- }
@@ -1,161 +0,0 @@
1
- <script server>
2
- export const showLogo = $props.showLogo ?? true
3
- export const headingText = $props.headingText || 'Sign in to your account'
4
- export const showSocialLogin = $props.showSocialLogin ?? true
5
- export const showRememberMe = $props.showRememberMe ?? true
6
- export const showForgotPassword = $props.showForgotPassword ?? true
7
- export const showSignup = $props.showSignup ?? true
8
- export const signupText = $props.signupText || 'Start a 14 day free trial'
9
- export const className = $props.className || ''
10
-
11
- export const containerClasses = `min-h-full flex flex-col justify-center py-12 lg:px-8 sm:px-6 dark:bg-blue-gray-900 ${className}`.trim()
12
- </script>
13
-
14
- <script client>
15
- const emit = defineEmits()
16
-
17
- function onSubmit(event) {
18
- event.preventDefault()
19
- const formData = new FormData(event.target)
20
- const email = formData.get('email')
21
- const password = formData.get('password')
22
- emit('submit', { email, password })
23
- setTimeout(() => {
24
- const pw = event.target.querySelector('#password')
25
- if (pw) pw.value = ''
26
- }, 1000)
27
- }
28
- </script>
29
-
30
- <div class="{{ containerClasses }}">
31
- <div class="sm:mx-auto sm:max-w-md sm:w-full">
32
- @if(showLogo)
33
- <img src="/logo.svg" alt="Logo" class="mx-auto h-11 w-auto" />
34
- @endif
35
- <h2 class="mt-6 text-center text-2xl text-gray-900 dark:text-gray-100 font-bold leading-9 tracking-tight">
36
- {{ headingText }}
37
- </h2>
38
- </div>
39
-
40
- <form @submit="onSubmit($event)">
41
- <div class="mt-10 sm:mx-auto sm:max-w-[480px] sm:w-full">
42
- <div class="bg-white dark:bg-blue-gray-800 px-6 py-12 shadow sm:rounded-lg sm:px-12">
43
- <div class="space-y-6">
44
- <div>
45
- <label for="email" class="block text-sm text-gray-900 dark:text-gray-100 font-medium leading-6">
46
- Email address
47
- </label>
48
- <div class="mt-2">
49
- <input
50
- id="email"
51
- name="email"
52
- type="email"
53
- autocomplete="email"
54
- required
55
- class="block w-full border-0 rounded-md py-1.5 text-gray-900 dark:text-gray-100 shadow-sm ring-1 ring-gray-300 dark:ring-gray-600 ring-inset sm:text-sm placeholder:text-gray-400 dark:placeholder:text-gray-500 sm:leading-6 focus:ring-2 focus:ring-indigo-600 focus:ring-inset dark:bg-blue-gray-700"
56
- />
57
- </div>
58
- </div>
59
-
60
- <div>
61
- <label for="password" class="block text-sm text-gray-900 dark:text-gray-100 font-medium leading-6">
62
- Password
63
- </label>
64
- <div class="mt-2">
65
- <input
66
- id="password"
67
- name="password"
68
- type="password"
69
- autocomplete="current-password"
70
- required
71
- class="block w-full border-0 rounded-md py-1.5 text-gray-900 dark:text-gray-100 shadow-sm ring-1 ring-gray-300 dark:ring-gray-600 ring-inset sm:text-sm placeholder:text-gray-400 dark:placeholder:text-gray-500 sm:leading-6 focus:ring-2 focus:ring-indigo-600 focus:ring-inset dark:bg-blue-gray-700"
72
- />
73
- </div>
74
- </div>
75
-
76
- <div class="flex items-center justify-between">
77
- @if(showRememberMe)
78
- <div class="flex items-center">
79
- <input
80
- id="remember-me"
81
- name="remember-me"
82
- type="checkbox"
83
- class="h-4 w-4 border-gray-300 dark:border-gray-600 rounded text-indigo-600 focus:ring-indigo-600 dark:bg-blue-gray-700"
84
- />
85
- <label for="remember-me" class="ml-3 block text-sm text-gray-900 dark:text-gray-100 leading-6">
86
- Remember me
87
- </label>
88
- </div>
89
- @endif
90
-
91
- @if(showForgotPassword)
92
- <div class="text-sm leading-6">
93
- <a href="#" class="text-indigo-600 dark:text-indigo-400 font-semibold hover:text-indigo-500 dark:hover:text-indigo-300">
94
- Forgot password?
95
- </a>
96
- </div>
97
- @endif
98
- </div>
99
-
100
- <div>
101
- <button
102
- type="submit"
103
- class="w-full flex justify-center rounded-md bg-indigo-600 px-3 py-1.5 text-sm text-white font-semibold leading-6 shadow-sm hover:bg-indigo-500 focus-visible:outline-2 focus-visible:outline-indigo-600 focus-visible:outline-offset-2 focus-visible:outline"
104
- >
105
- Sign in
106
- </button>
107
- </div>
108
- </div>
109
-
110
- @if(showSocialLogin)
111
- <div>
112
- <div class="relative mt-10">
113
- <div class="absolute inset-0 flex items-center" aria-hidden="true">
114
- <div class="w-full border-t border-gray-200 dark:border-gray-600"></div>
115
- </div>
116
- <div class="relative flex justify-center text-sm font-medium leading-6">
117
- <span class="bg-white dark:bg-blue-gray-800 px-6 text-gray-900 dark:text-gray-100">
118
- Or continue with
119
- </span>
120
- </div>
121
- </div>
122
-
123
- <div class="grid grid-cols-2 mt-6 gap-4">
124
- <a
125
- href="#"
126
- class="w-full flex items-center justify-center gap-3 rounded-md bg-white dark:bg-blue-gray-700 px-3 py-2 text-sm text-gray-900 dark:text-gray-100 font-semibold shadow-sm ring-1 ring-gray-300 dark:ring-gray-600 ring-inset hover:bg-gray-50 dark:hover:bg-blue-gray-600 focus-visible:ring-transparent"
127
- >
128
- <svg class="h-5 w-5" viewBox="0 0 24 24" aria-hidden="true">
129
- <path d="M12.0003 4.75C13.7703 4.75 15.3553 5.36002 16.6053 6.54998L20.0303 3.125C17.9502 1.19 15.2353 0 12.0003 0C7.31028 0 3.25527 2.69 1.28027 6.60998L5.27028 9.70498C6.21525 6.86002 8.87028 4.75 12.0003 4.75Z" fill="#EA4335" />
130
- <path d="M23.49 12.275C23.49 11.49 23.415 10.73 23.3 10H12V14.51H18.47C18.18 15.99 17.34 17.25 16.08 18.1L19.945 21.1C22.2 19.01 23.49 15.92 23.49 12.275Z" fill="#4285F4" />
131
- <path d="M5.26498 14.2949C5.02498 13.5699 4.88501 12.7999 4.88501 11.9999C4.88501 11.1999 5.01998 10.4299 5.26498 9.7049L1.275 6.60986C0.46 8.22986 0 10.0599 0 11.9999C0 13.9399 0.46 15.7699 1.28 17.3899L5.26498 14.2949Z" fill="#FBBC05" />
132
- <path d="M12.0004 24.0001C15.2404 24.0001 17.9654 22.935 19.9454 21.095L16.0804 18.095C15.0054 18.82 13.6204 19.245 12.0004 19.245C8.8704 19.245 6.21537 17.135 5.2654 14.29L1.27539 17.385C3.25539 21.31 7.3104 24.0001 12.0004 24.0001Z" fill="#34A853" />
133
- </svg>
134
- <span class="text-sm font-semibold leading-6">Google</span>
135
- </a>
136
-
137
- <a
138
- href="#"
139
- class="w-full flex items-center justify-center gap-3 rounded-md bg-white dark:bg-blue-gray-700 px-3 py-2 text-sm text-gray-900 dark:text-gray-100 font-semibold shadow-sm ring-1 ring-gray-300 dark:ring-gray-600 ring-inset hover:bg-gray-50 dark:hover:bg-blue-gray-600 focus-visible:ring-transparent"
140
- >
141
- <svg class="h-5 w-5 fill-[#24292F]" fill="currentColor" viewBox="0 0 20 20" aria-hidden="true">
142
- <path fill-rule="evenodd" d="M10 0C4.477 0 0 4.484 0 10.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0110 4.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.203 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.942.359.31.678.921.678 1.856 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0020 10.017C20 4.484 15.522 0 10 0z" clip-rule="evenodd" />
143
- </svg>
144
- <span class="text-sm font-semibold leading-6">GitHub</span>
145
- </a>
146
- </div>
147
- </div>
148
- @endif
149
- </div>
150
-
151
- @if(showSignup)
152
- <p class="mt-10 text-center text-sm text-gray-500 dark:text-gray-400">
153
- Not a member?
154
- <a href="#" class="text-indigo-600 dark:text-indigo-400 font-semibold leading-6 hover:text-indigo-500 dark:hover:text-indigo-300">
155
- {{ signupText }}
156
- </a>
157
- </p>
158
- @endif
159
- </div>
160
- </form>
161
- </div>
@@ -1,142 +0,0 @@
1
- # Auth Components
2
-
3
- Authentication UI components including Login, Signup, and Two-Factor Authentication.
4
-
5
- ## Components
6
-
7
- ### Login
8
- A full-featured login form with email/password and optional social login.
9
-
10
- ### Signup
11
- A registration form with name, email, email confirmation, and password fields.
12
-
13
- ### TwoFactorChallenge
14
- A 2FA code entry component with auto-focus and recovery code option.
15
-
16
- ## Installation
17
-
18
- ```bash
19
- bun add @stacksjs/components
20
- ```
21
-
22
- ## Usage
23
-
24
- ### Login Component
25
-
26
- ```stx
27
- <script server>
28
- const handleLogin = (data) => {
29
- console.log('Login:', data.email, data.password)
30
- }
31
- </script>
32
-
33
- <Login
34
- showLogo
35
- headingText="Sign in to your account"
36
- showSocialLogin
37
- showRememberMe
38
- showForgotPassword
39
- showSignup
40
- signupText="Start a 14 day free trial"
41
- :onSubmit="handleLogin"
42
- />
43
- ```
44
-
45
- ### Signup Component
46
-
47
- ```stx
48
- <script server>
49
- const handleSignup = (data) => {
50
- console.log('Signup:', data.name, data.email, data.password)
51
- }
52
- </script>
53
-
54
- <Signup
55
- headingText="Sign up for Stacks"
56
- showSocialSignup
57
- :onSubmit="handleSignup"
58
- />
59
- ```
60
-
61
- ### TwoFactorChallenge Component
62
-
63
- ```stx
64
- <script server>
65
- const handleVerify = (code) => {
66
- console.log('2FA Code:', code)
67
- }
68
-
69
- const handleRecoveryCode = () => {
70
- console.log('Using recovery code')
71
- }
72
- </script>
73
-
74
- <TwoFactorChallenge
75
- headingText="Two Factor Authentication"
76
- labelText="Authentication code"
77
- instructionText="Open your 2FA app to view your authentication code."
78
- :codeLength="6"
79
- :onSubmit="handleVerify"
80
- :onUseRecoveryCode="handleRecoveryCode"
81
- />
82
- ```
83
-
84
- ## Props
85
-
86
- ### Login Props
87
-
88
- | Prop | Type | Default | Description |
89
- |------|------|---------|-------------|
90
- | `showLogo` | `boolean` | `true` | Show logo at top |
91
- | `headingText` | `string` | `'Sign in to your account'` | Heading text |
92
- | `showSocialLogin` | `boolean` | `true` | Show social login buttons |
93
- | `showRememberMe` | `boolean` | `true` | Show remember me checkbox |
94
- | `showForgotPassword` | `boolean` | `true` | Show forgot password link |
95
- | `showSignup` | `boolean` | `true` | Show signup link at bottom |
96
- | `signupText` | `string` | `'Start a 14 day free trial'` | Signup link text |
97
- | `onSubmit` | `function` | - | Callback when form submitted |
98
- | `className` | `string` | `''` | Additional CSS classes |
99
-
100
- ### Signup Props
101
-
102
- | Prop | Type | Default | Description |
103
- |------|------|---------|-------------|
104
- | `headingText` | `string` | `'Sign up for Stacks'` | Heading text |
105
- | `showSocialSignup` | `boolean` | `true` | Show social signup buttons |
106
- | `onSubmit` | `function` | - | Callback when form submitted |
107
- | `className` | `string` | `''` | Additional CSS classes |
108
-
109
- ### TwoFactorChallenge Props
110
-
111
- | Prop | Type | Default | Description |
112
- |------|------|---------|-------------|
113
- | `headingText` | `string` | `'Two Factor Authentication'` | Heading text |
114
- | `labelText` | `string` | `'Authentication code'` | Input label |
115
- | `instructionText` | `string` | `'Open your Symantec 2FA app...'` | Instructions |
116
- | `codeLength` | `number` | `6` | Number of code digits |
117
- | `onSubmit` | `function` | - | Callback with complete code |
118
- | `onUseRecoveryCode` | `function` | - | Callback for recovery code |
119
- | `className` | `string` | `''` | Additional CSS classes |
120
-
121
- ## Features
122
-
123
- - **Modern ES module exports** - Clean, modern JavaScript
124
- - **Dark mode support** - All components support dark mode
125
- - **Fully accessible** - Proper labels, ARIA attributes
126
- - **Social login** - Google and GitHub integration
127
- - **Auto-focus** - 2FA inputs auto-focus next field
128
- - **Validation** - Email confirmation validation in Signup
129
- - **TypeScript** - Full type definitions
130
- - **Headwind styling** - Utility-first CSS classes
131
-
132
- ## Accessibility
133
-
134
- - Proper label associations
135
- - ARIA attributes where needed
136
- - Keyboard navigation support
137
- - Focus management in 2FA component
138
- - Required field indicators
139
-
140
- ## Customization
141
-
142
- All components accept a `className` prop for additional styling and support full customization through props.