@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,77 +0,0 @@
1
- <script server>
2
- export const src = $props.src || ''
3
- export const alt = $props.alt || ''
4
- export const initials = $props.initials || ''
5
- export const size = $props.size || 'md'
6
- export const shape = $props.shape || 'circle'
7
- export const status = $props.status || ''
8
- export const className = $props.className || ''
9
-
10
- const sizeClasses = {
11
- xs: 'w-6 h-6 text-xs',
12
- sm: 'w-8 h-8 text-sm',
13
- md: 'w-10 h-10 text-base',
14
- lg: 'w-12 h-12 text-lg',
15
- xl: 'w-16 h-16 text-xl',
16
- '2xl': 'w-20 h-20 text-2xl',
17
- }
18
-
19
- const shapeClasses = { circle: 'rounded-full', square: 'rounded-md' }
20
-
21
- const statusSizeClasses = {
22
- xs: 'w-1.5 h-1.5 border',
23
- sm: 'w-2 h-2 border',
24
- md: 'w-2.5 h-2.5 border-2',
25
- lg: 'w-3 h-3 border-2',
26
- xl: 'w-3.5 h-3.5 border-2',
27
- '2xl': 'w-4 h-4 border-2',
28
- }
29
-
30
- const statusColorClasses = {
31
- online: 'bg-green-500 dark:bg-green-400',
32
- offline: 'bg-gray-400 dark:bg-gray-600',
33
- away: 'bg-yellow-500 dark:bg-yellow-400',
34
- busy: 'bg-red-500 dark:bg-red-400',
35
- }
36
-
37
- export const containerClasses = `relative inline-block ${className}`.trim()
38
- export const avatarClasses = `flex items-center justify-center overflow-hidden bg-gray-200 dark:bg-gray-700 ${sizeClasses[size]} ${shapeClasses[shape]}`.trim()
39
- export const imageClasses = `w-full h-full object-cover`.trim()
40
- export const initialsClasses = `font-medium text-gray-600 dark:text-gray-300 uppercase select-none`.trim()
41
- export const statusClasses = status ? `absolute bottom-0 right-0 ${statusSizeClasses[size]} ${statusColorClasses[status]} ${shapeClasses[shape]} border-white dark:border-gray-900`.trim() : ''
42
- export const displayInitials = initials || (alt ? alt.split(' ').map(n => n[0]).join('').substring(0, 2) : '?')
43
- </script>
44
-
45
- <script client>
46
- const emit = defineEmits()
47
- const imageError = state(false)
48
- const hasSrc = {{ !!src }}
49
-
50
- function onImageError(event) {
51
- imageError.set(true)
52
- emit('error', event)
53
- }
54
-
55
- const showImage = derived(() => hasSrc && !imageError())
56
- </script>
57
-
58
- <div class="{{ containerClasses }}">
59
- <div class="{{ avatarClasses }}">
60
- <img
61
- :show="showImage()"
62
- src="{{ src }}"
63
- alt="{{ alt }}"
64
- class="{{ imageClasses }}"
65
- @error="onImageError($event)"
66
- />
67
- <span :show="!showImage()" class="{{ initialsClasses }}">{{ displayInitials }}</span>
68
- </div>
69
-
70
- @if(status)
71
- <span
72
- class="{{ statusClasses }}"
73
- role="status"
74
- aria-label="{{ status }}"
75
- ></span>
76
- @endif
77
- </div>
@@ -1,12 +0,0 @@
1
- export { default as Avatar } from './Avatar.stx'
2
-
3
- export interface AvatarProps {
4
- src?: string
5
- alt?: string
6
- initials?: string
7
- size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl'
8
- shape?: 'circle' | 'square'
9
- status?: 'online' | 'offline' | 'away' | 'busy' | ''
10
- onError?: (event: Event) => void
11
- className?: string
12
- }
@@ -1,62 +0,0 @@
1
- <script server>
2
- export const variant = $props.variant || 'default'
3
- export const size = $props.size || 'md'
4
- export const dot = $props.dot || false
5
- export const removable = $props.removable || false
6
- export const className = $props.className || ''
7
-
8
- const variantClasses = {
9
- default: 'bg-gray-100 text-gray-800 dark:bg-gray-700 dark:text-gray-300',
10
- primary: 'bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-200',
11
- secondary: 'bg-purple-100 text-purple-800 dark:bg-purple-900 dark:text-purple-200',
12
- success: 'bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-200',
13
- warning: 'bg-yellow-100 text-yellow-800 dark:bg-yellow-900 dark:text-yellow-200',
14
- danger: 'bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-200',
15
- info: 'bg-cyan-100 text-cyan-800 dark:bg-cyan-900 dark:text-cyan-200',
16
- }
17
-
18
- const sizeClasses = { sm: 'px-2 py-0.5 text-xs', md: 'px-2.5 py-0.5 text-sm', lg: 'px-3 py-1 text-base' }
19
-
20
- const dotColorClasses = {
21
- default: 'bg-gray-500 dark:bg-gray-400',
22
- primary: 'bg-blue-500 dark:bg-blue-400',
23
- secondary: 'bg-purple-500 dark:bg-purple-400',
24
- success: 'bg-green-500 dark:bg-green-400',
25
- warning: 'bg-yellow-500 dark:bg-yellow-400',
26
- danger: 'bg-red-500 dark:bg-red-400',
27
- info: 'bg-cyan-500 dark:bg-cyan-400',
28
- }
29
-
30
- export const badgeClasses = `inline-flex items-center gap-1.5 font-medium rounded-full ${variantClasses[variant]} ${sizeClasses[size]} ${className}`.trim()
31
- export const dotClasses = `w-2 h-2 rounded-full ${dotColorClasses[variant]}`.trim()
32
- export const removeButtonClasses = `ml-0.5 -mr-1 text-current hover:bg-black hover:bg-opacity-10 dark:hover:bg-white dark:hover:bg-opacity-10 rounded-full p-0.5 transition-colors duration-150`.trim()
33
- </script>
34
-
35
- <script client>
36
- const emit = defineEmits()
37
-
38
- function onRemove() {
39
- emit('remove')
40
- }
41
- </script>
42
-
43
- <span class="{{ badgeClasses }}" role="status">
44
- @if(dot)
45
- <span class="{{ dotClasses }}" aria-hidden="true"></span>
46
- @endif
47
-
48
- <slot />
49
-
50
- @if(removable)
51
- <button
52
- type="button"
53
- @click="onRemove()"
54
- class="{{ removeButtonClasses }}"
55
- aria-label="Remove"
56
- >
57
- <svg class="w-3 h-3" fill="none" viewBox="0 0 24 24" stroke="currentColor">
58
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
59
- </svg>
60
- </button>
61
- @endif
62
- </span>
@@ -1,10 +0,0 @@
1
- export { default as Badge } from './Badge.stx'
2
-
3
- export interface BadgeProps {
4
- variant?: 'default' | 'primary' | 'secondary' | 'success' | 'warning' | 'danger' | 'info'
5
- size?: 'sm' | 'md' | 'lg'
6
- dot?: boolean
7
- removable?: boolean
8
- onRemove?: () => void
9
- className?: string
10
- }
@@ -1,79 +0,0 @@
1
- <script server>
2
- export const items = $props.items || []
3
- export const separator = $props.separator || '/'
4
- export const maxItems = $props.maxItems || 0
5
- export const className = $props.className || ''
6
-
7
- // Handle collapse if maxItems is set
8
- let displayItems = items
9
- if (maxItems > 0 && items.length > maxItems) {
10
- const firstItems = items.slice(0, 1)
11
- const lastItems = items.slice(-(maxItems - 1))
12
- displayItems = [...firstItems, { label: '...', href: '#', collapsed: true }, ...lastItems]
13
- }
14
-
15
- // Separator element
16
- const separatorElement = separator === '/' ? '/' :
17
- separator === '>' ? '›' :
18
- separator === 'arrow' ? `<svg class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" /></svg>` :
19
- separator
20
-
21
- export const breadcrumbClasses = `flex items-center flex-wrap gap-2 text-sm ${className}`.trim()
22
- export const itemClasses = `text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-200 transition-colors duration-150`.trim()
23
- export const activeItemClasses = `text-gray-900 dark:text-gray-100 font-medium`.trim()
24
- export const separatorClasses = `text-gray-400 dark:text-gray-600 select-none`.trim()
25
- export const collapsedClasses = `text-gray-400 dark:text-gray-600 cursor-default`.trim()
26
- </script>
27
-
28
- <nav class="{{ breadcrumbClasses }}" aria-label="Breadcrumb">
29
- <ol class="flex items-center gap-2">
30
- @foreach(item in displayItems)
31
- <li class="flex items-center gap-2">
32
- @if(item.collapsed)
33
- <!-- Collapsed indicator -->
34
- <span class="{{ collapsedClasses }}">{{ item.label }}</span>
35
- @else
36
- @if($loop.last)
37
- <!-- Last item (current page) -->
38
- <span class="{{ activeItemClasses }}" aria-current="page">
39
- @if(item.icon)
40
- <span class="inline-flex items-center gap-1.5">
41
- <span innerHTML="{!! item.icon !!}"></span>
42
- <span>{{ item.label }}</span>
43
- </span>
44
- @else
45
- {{ item.label }}
46
- @endif
47
- </span>
48
- @else
49
- <!-- Link item -->
50
- <a
51
- href="{{ item.href }}"
52
- class="{{ itemClasses }}"
53
- >
54
- @if(item.icon)
55
- <span class="inline-flex items-center gap-1.5">
56
- <span innerHTML="{!! item.icon !!}"></span>
57
- <span>{{ item.label }}</span>
58
- </span>
59
- @else
60
- {{ item.label }}
61
- @endif
62
- </a>
63
- @endif
64
- @endif
65
-
66
- <!-- Separator (not after last item) -->
67
- @if(!$loop.last)
68
- <span class="{{ separatorClasses }}" aria-hidden="true">
69
- @if(separator === 'arrow')
70
- {!! separatorElement !!}
71
- @else
72
- {{ separatorElement }}
73
- @endif
74
- </span>
75
- @endif
76
- </li>
77
- @endforeach
78
- </ol>
79
- </nav>
@@ -1,15 +0,0 @@
1
- export { default as Breadcrumb } from './Breadcrumb.stx'
2
-
3
- export interface BreadcrumbItem {
4
- label: string
5
- href: string
6
- icon?: string
7
- collapsed?: boolean
8
- }
9
-
10
- export interface BreadcrumbProps {
11
- items: BreadcrumbItem[]
12
- separator?: '/' | '>' | 'arrow' | string
13
- maxItems?: number
14
- className?: string
15
- }
@@ -1,74 +0,0 @@
1
- <script server>
2
- export const variant = $props.variant || 'primary'
3
- export const size = $props.size || 'md'
4
- export const disabled = $props.disabled || false
5
- export const loading = $props.loading || false
6
- export const type = $props.type || 'button'
7
- export const fullWidth = $props.fullWidth || false
8
- export const leftIcon = $props.leftIcon || ''
9
- export const rightIcon = $props.rightIcon || ''
10
- export const className = $props.className || ''
11
-
12
- const variantClasses = {
13
- primary: 'bg-blue-500 hover:bg-blue-600 text-white shadow-md hover:shadow-lg dark:bg-blue-600 dark:hover:bg-blue-700',
14
- secondary: 'bg-neutral-200 hover:bg-neutral-300 text-neutral-900 dark:bg-neutral-700 dark:hover:bg-neutral-600 dark:text-white',
15
- outline: 'border-2 border-blue-500 text-blue-500 hover:bg-blue-50 dark:border-blue-400 dark:text-blue-400 dark:hover:bg-blue-950',
16
- ghost: 'hover:bg-neutral-100 text-neutral-700 dark:hover:bg-neutral-800 dark:text-neutral-300',
17
- danger: 'bg-red-500 hover:bg-red-600 text-white shadow-md hover:shadow-lg dark:bg-red-600 dark:hover:bg-red-700',
18
- }
19
-
20
- const sizeClasses = {
21
- xs: 'px-2.5 py-1 text-xs h-7 gap-1',
22
- sm: 'px-3 py-1.5 text-sm h-8 gap-1.5',
23
- md: 'px-4 py-2 text-base h-10 gap-2',
24
- lg: 'px-6 py-3 text-lg h-12 gap-2.5',
25
- xl: 'px-8 py-4 text-xl h-14 gap-3',
26
- }
27
-
28
- const iconSizeClasses = { xs: 'h-3 w-3', sm: 'h-4 w-4', md: 'h-5 w-5', lg: 'h-6 w-6', xl: 'h-7 w-7' }
29
- const baseClasses = 'inline-flex items-center justify-center font-semibold rounded-md transition-all duration-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 disabled:opacity-50 disabled:cursor-not-allowed disabled:pointer-events-none'
30
- const widthClasses = fullWidth ? 'w-full' : ''
31
- export const isDisabled = disabled || loading
32
-
33
- export const buttonClasses = `${baseClasses} ${variantClasses[variant]} ${sizeClasses[size]} ${widthClasses} ${className}`.trim()
34
- export const iconClasses = iconSizeClasses[size]
35
- export const spinnerClasses = `animate-spin ${iconClasses}`.trim()
36
- </script>
37
-
38
- <script client>
39
- const emit = defineEmits()
40
- const disabledNow = {{ isDisabled }}
41
-
42
- function onClick(event) {
43
- if (disabledNow) {
44
- event.preventDefault()
45
- return
46
- }
47
- emit('click', event)
48
- }
49
- </script>
50
-
51
- <button
52
- type="{{ type }}"
53
- class="{{ buttonClasses }}"
54
- @if(isDisabled)disabled@endif
55
- @click="onClick($event)"
56
- aria-busy="{{ loading ? 'true' : 'false' }}"
57
- >
58
- @if(loading)
59
- <svg class="{{ spinnerClasses }}" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
60
- <circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
61
- <path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
62
- </svg>
63
- @else
64
- @if(leftIcon)
65
- <span class="{{ iconClasses }}">{!! leftIcon !!}</span>
66
- @endif
67
- @endif
68
-
69
- <slot />
70
-
71
- @if(!loading && rightIcon)
72
- <span class="{{ iconClasses }}">{!! rightIcon !!}</span>
73
- @endif
74
- </button>
@@ -1,80 +0,0 @@
1
- # Button Component
2
-
3
- A versatile button component built with STX and headwind utility classes.
4
-
5
- ## Installation
6
-
7
- ```bash
8
- bun add @stacksjs/components
9
- ```
10
-
11
- ## Usage
12
-
13
- ```stx
14
- <Button variant="primary" size="md">Click me</Button>
15
- ```
16
-
17
- ## Props
18
-
19
- | Prop | Type | Default | Description |
20
- |------|------|---------|-------------|
21
- | `variant` | `'primary' \| 'secondary' \| 'outline' \| 'ghost' \| 'danger'` | `'primary'` | Button visual style |
22
- | `size` | `'sm' \| 'md' \| 'lg'` | `'md'` | Button size |
23
- | `disabled` | `boolean` | `false` | Disable the button |
24
- | `type` | `'button' \| 'submit' \| 'reset'` | `'button'` | Button HTML type |
25
- | `className` | `string` | `''` | Additional CSS classes |
26
- | `onClick` | `() => void` | - | Click handler |
27
-
28
- ## Examples
29
-
30
- ### Variants
31
-
32
- ```stx
33
- <Button variant="primary">Primary Button</Button>
34
-
35
- <Button variant="secondary">Secondary Button</Button>
36
-
37
- <Button variant="outline">Outline Button</Button>
38
-
39
- <Button variant="ghost">Ghost Button</Button>
40
-
41
- <Button variant="danger">Danger Button</Button>
42
- ```
43
-
44
- ### Sizes
45
-
46
- ```stx
47
- <Button size="sm">Small Button</Button>
48
-
49
- <Button size="md">Medium Button</Button>
50
-
51
- <Button size="lg">Large Button</Button>
52
- ```
53
-
54
- ### Disabled State
55
-
56
- ```stx
57
- <Button disabled>Disabled Button</Button>
58
- ```
59
-
60
- ### With Icon
61
-
62
- ```stx
63
- <Button variant="primary">
64
- <svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
65
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4" />
66
- </svg>
67
- Add Item
68
- </Button>
69
- ```
70
-
71
- ## Features
72
-
73
- - 5 visual variants (primary, secondary, outline, ghost, danger)
74
- - 3 size options (sm, md, lg)
75
- - Disabled state support
76
- - Focus ring with keyboard navigation
77
- - Dark mode support
78
- - Accessible by default
79
- - Smooth transitions
80
- - Headwind utility classes for easy customization
@@ -1,85 +0,0 @@
1
- import type { PropSchema, ValidationResult } from '../../utils/prop-validation'
2
- import { ErrorTypes, wrapErrorHandler } from '../../utils/error-handling'
3
- import { createPropValidator, PropTypes } from '../../utils/prop-validation'
4
-
5
- export { default as Button } from './Button.stx'
6
-
7
- export interface ButtonProps {
8
- variant?: 'primary' | 'secondary' | 'outline' | 'ghost' | 'danger'
9
- size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl'
10
- disabled?: boolean
11
- loading?: boolean
12
- type?: 'button' | 'submit' | 'reset'
13
- fullWidth?: boolean
14
- leftIcon?: string
15
- rightIcon?: string
16
- className?: string
17
- onClick?: (event: Event) => void
18
- }
19
-
20
- /**
21
- * Button prop validation schema
22
- */
23
- export const buttonPropSchema: PropSchema = {
24
- variant: PropTypes.oneOf(['primary', 'secondary', 'outline', 'ghost', 'danger']),
25
- size: PropTypes.oneOf(['xs', 'sm', 'md', 'lg', 'xl']),
26
- disabled: PropTypes.boolean,
27
- loading: PropTypes.boolean,
28
- type: PropTypes.oneOf(['button', 'submit', 'reset']),
29
- fullWidth: PropTypes.boolean,
30
- leftIcon: PropTypes.string,
31
- rightIcon: PropTypes.string,
32
- className: PropTypes.string,
33
- onClick: PropTypes.func,
34
- }
35
-
36
- /**
37
- * Validate Button component props
38
- * Only runs in development mode
39
- */
40
- export const validateButtonProps: (props: Record<string, any>) => ValidationResult = createPropValidator('Button', buttonPropSchema)
41
-
42
- /**
43
- * Create a safe onClick handler that catches and reports errors
44
- *
45
- * @param handler - Click handler function
46
- * @returns Wrapped handler with error handling
47
- *
48
- * @example
49
- * ```ts
50
- * const safeHandler = createSafeClickHandler(() => {
51
- * // Your click logic
52
- * })
53
- * ```
54
- */
55
- export function createSafeClickHandler(handler: (event: Event) => void): (event: Event) => void {
56
- return wrapErrorHandler(handler, 'Button', 'onClick')
57
- }
58
-
59
- /**
60
- * Helper to validate button variant
61
- */
62
- export function validateVariant(variant?: string): void {
63
- if (variant && !['primary', 'secondary', 'outline', 'ghost', 'danger'].includes(variant)) {
64
- throw ErrorTypes.invalidProp(
65
- 'Button',
66
- 'variant',
67
- variant,
68
- ['primary', 'secondary', 'outline', 'ghost', 'danger'],
69
- )
70
- }
71
- }
72
-
73
- /**
74
- * Helper to validate button size
75
- */
76
- export function validateSize(size?: string): void {
77
- if (size && !['xs', 'sm', 'md', 'lg', 'xl'].includes(size)) {
78
- throw ErrorTypes.invalidProp(
79
- 'Button',
80
- 'size',
81
- size,
82
- ['xs', 'sm', 'md', 'lg', 'xl'],
83
- )
84
- }
85
- }