@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,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
- }
@@ -1,189 +0,0 @@
1
- <script server>
2
- export const value = $props.value || null
3
- export const minDate = $props.minDate || null
4
- export const maxDate = $props.maxDate || null
5
- export const disabledDates = $props.disabledDates || []
6
- export const locale = $props.locale || 'en-US'
7
- export const firstDayOfWeek = $props.firstDayOfWeek || 0
8
- export const showToday = $props.showToday !== false
9
- export const className = $props.className || ''
10
- export const highlightToday = $props.highlightToday !== false
11
-
12
- const baseClasses = 'bg-white dark:bg-gray-800 rounded-lg shadow-lg p-4 w-full max-w-sm'
13
- export const calendarClasses = `${baseClasses} ${className}`.trim()
14
- export const headerClasses = 'flex items-center justify-between mb-4'
15
- export const monthYearClasses = 'text-lg font-semibold text-gray-900 dark:text-gray-100'
16
- export const buttonClasses = 'p-2 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-md transition-colors'
17
- export const weekdaysClasses = 'grid grid-cols-7 gap-1 mb-2'
18
- export const weekdayClasses = 'text-center text-xs font-medium text-gray-600 dark:text-gray-400 py-2'
19
- export const daysGridClasses = 'grid grid-cols-7 gap-1'
20
-
21
- const valueIso = value ? new Date(value).toISOString() : null
22
- export const initialValueIso = valueIso
23
- const minIso = minDate ? new Date(minDate).toISOString() : null
24
- const maxIso = maxDate ? new Date(maxDate).toISOString() : null
25
- export const minIsoValue = minIso
26
- export const maxIsoValue = maxIso
27
- export const disabledIsoList = disabledDates.map(d => new Date(d).toISOString())
28
- </script>
29
-
30
- <script client>
31
- const emit = defineEmits()
32
- const locale = {{ locale }}
33
- const firstDayOfWeek = {{ firstDayOfWeek }}
34
- const highlightToday = {{ highlightToday }}
35
- const minDate = {{ minIsoValue === null ? 'null' : minIsoValue }} ? new Date({{ minIsoValue === null ? 'null' : minIsoValue }}) : null
36
- const maxDate = {{ maxIsoValue === null ? 'null' : maxIsoValue }} ? new Date({{ maxIsoValue === null ? 'null' : maxIsoValue }}) : null
37
- const disabledDates = ({{ disabledIsoList }}).map(s => new Date(s))
38
- const initialValue = {{ initialValueIso === null ? 'null' : initialValueIso }} ? new Date({{ initialValueIso === null ? 'null' : initialValueIso }}) : null
39
-
40
- const today = new Date()
41
- const currentMonth = state(initialValue ? new Date(initialValue) : new Date())
42
- const selectedDate = state(initialValue)
43
-
44
- function isSameDay(d1, d2) {
45
- if (!d1 || !d2) return false
46
- return d1.getFullYear() === d2.getFullYear() && d1.getMonth() === d2.getMonth() && d1.getDate() === d2.getDate()
47
- }
48
-
49
- function isToday(d) { return isSameDay(d, today) }
50
-
51
- function isDisabled(d) {
52
- if (minDate && d < minDate) return true
53
- if (maxDate && d > maxDate) return true
54
- return disabledDates.some(x => isSameDay(x, d))
55
- }
56
-
57
- function getDaysInMonth(d) { return new Date(d.getFullYear(), d.getMonth() + 1, 0).getDate() }
58
- function getFirstDayOfMonth(d) { return new Date(d.getFullYear(), d.getMonth(), 1).getDay() }
59
-
60
- const monthYearLabel = derived(() => {
61
- const m = currentMonth()
62
- return `${m.toLocaleDateString(locale, { month: 'long' })} ${m.getFullYear()}`
63
- })
64
-
65
- const dayNames = (() => {
66
- const days = []
67
- const baseDate = new Date(2024, 0, firstDayOfWeek)
68
- for (let i = 0; i < 7; i++) {
69
- const day = new Date(baseDate)
70
- day.setDate(baseDate.getDate() + i)
71
- days.push(day.toLocaleDateString(locale, { weekday: 'short' }))
72
- }
73
- return days
74
- })()
75
-
76
- const calendarDays = derived(() => {
77
- const month = currentMonth()
78
- const daysInMonth = getDaysInMonth(month)
79
- const firstDay = (getFirstDayOfMonth(month) - firstDayOfWeek + 7) % 7
80
- const days = []
81
- const prev = new Date(month.getFullYear(), month.getMonth() - 1, 1)
82
- const daysInPrev = getDaysInMonth(prev)
83
- for (let i = firstDay - 1; i >= 0; i--) {
84
- days.push({ date: new Date(prev.getFullYear(), prev.getMonth(), daysInPrev - i), isCurrentMonth: false })
85
- }
86
- for (let i = 1; i <= daysInMonth; i++) {
87
- days.push({ date: new Date(month.getFullYear(), month.getMonth(), i), isCurrentMonth: true })
88
- }
89
- const remaining = 42 - days.length
90
- const next = new Date(month.getFullYear(), month.getMonth() + 1, 1)
91
- for (let i = 1; i <= remaining; i++) {
92
- days.push({ date: new Date(next.getFullYear(), next.getMonth(), i), isCurrentMonth: false })
93
- }
94
- return days
95
- })
96
-
97
- function previousMonth() {
98
- const m = currentMonth()
99
- currentMonth.set(new Date(m.getFullYear(), m.getMonth() - 1, 1))
100
- }
101
-
102
- function nextMonthFn() {
103
- const m = currentMonth()
104
- currentMonth.set(new Date(m.getFullYear(), m.getMonth() + 1, 1))
105
- }
106
-
107
- function selectDate(date) {
108
- if (isDisabled(date)) return
109
- selectedDate.set(date)
110
- emit('change', date)
111
- }
112
-
113
- function goToToday() {
114
- currentMonth.set(new Date(today))
115
- selectDate(today)
116
- }
117
-
118
- function dayClasses(day) {
119
- const base = 'flex items-center justify-center h-10 w-10 rounded-md text-sm transition-colors'
120
- const isSelected = isSameDay(day.date, selectedDate())
121
- const isTodayDate = isToday(day.date)
122
- const disabled = isDisabled(day.date)
123
- let cls = base
124
- cls += day.isCurrentMonth ? ' text-gray-900 dark:text-gray-100' : ' text-gray-400 dark:text-gray-600'
125
- cls += disabled ? ' opacity-50 cursor-not-allowed' : ' cursor-pointer hover:bg-gray-100 dark:hover:bg-gray-700'
126
- if (isSelected) cls += ' bg-blue-600 text-white hover:bg-blue-700 dark:bg-blue-500 dark:hover:bg-blue-600'
127
- if (isTodayDate && highlightToday && !isSelected) cls += ' border-2 border-blue-600 dark:border-blue-400'
128
- return cls
129
- }
130
-
131
- defineExpose({ selectedDate, currentMonth, selectDate })
132
- </script>
133
-
134
- <div class="{{ calendarClasses }}">
135
- <div class="{{ headerClasses }}">
136
- <button
137
- type="button"
138
- class="{{ buttonClasses }}"
139
- @click="previousMonth()"
140
- aria-label="Previous month"
141
- >
142
- <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
143
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7" />
144
- </svg>
145
- </button>
146
-
147
- <div class="{{ monthYearClasses }}" x-text="monthYearLabel()"></div>
148
-
149
- <button
150
- type="button"
151
- class="{{ buttonClasses }}"
152
- @click="nextMonthFn()"
153
- aria-label="Next month"
154
- >
155
- <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
156
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
157
- </svg>
158
- </button>
159
- </div>
160
-
161
- <div class="{{ weekdaysClasses }}">
162
- <div :for="d in dayNames" :key="d" class="{{ weekdayClasses }}" x-text="d"></div>
163
- </div>
164
-
165
- <div class="{{ daysGridClasses }}">
166
- <button
167
- :for="day in calendarDays()"
168
- :key="day.date.toISOString()"
169
- type="button"
170
- :class="dayClasses(day)"
171
- @click="selectDate(day.date)"
172
- :aria-label="day.date.toLocaleDateString(locale)"
173
- :disabled="isDisabled(day.date)"
174
- x-text="day.date.getDate()"
175
- ></button>
176
- </div>
177
-
178
- @if(showToday)
179
- <div class="mt-4 flex justify-center">
180
- <button
181
- type="button"
182
- class="px-4 py-2 text-sm font-medium text-blue-600 dark:text-blue-400 hover:bg-blue-50 dark:hover:bg-gray-700 rounded-md transition-colors"
183
- @click="goToToday()"
184
- >
185
- Today
186
- </button>
187
- </div>
188
- @endif
189
- </div>
@@ -1,254 +0,0 @@
1
- # Calendar Component
2
-
3
- A fully-featured calendar/date picker component with support for date selection, range constraints, and localization.
4
-
5
- ## Features
6
-
7
- - ✅ Date selection with visual feedback
8
- - ✅ Month/year navigation
9
- - ✅ Min/max date constraints
10
- - ✅ Disabled dates support
11
- - ✅ Localization support
12
- - ✅ Configurable first day of week
13
- - ✅ Today button for quick navigation
14
- - ✅ Today highlighting
15
- - ✅ Dark mode support
16
- - ✅ Accessible with ARIA labels
17
- - ✅ Keyboard navigation ready
18
-
19
- ## Usage
20
-
21
- ### Basic Calendar
22
-
23
- ```stx
24
- <script>
25
- import { Calendar } from '@stacksjs/components'
26
-
27
- let selectedDate = new Date()
28
-
29
- function handleDateChange(date) {
30
- selectedDate = date
31
- console.log('Selected date:', date)
32
- }
33
- </script>
34
-
35
- <Calendar value={selectedDate} onChange={handleDateChange} />
36
- ```
37
-
38
- ### With Date Constraints
39
-
40
- ```stx
41
- <script>
42
- import { Calendar } from '@stacksjs/components'
43
-
44
- const today = new Date()
45
- const minDate = new Date(today.getFullYear(), today.getMonth(), 1) // First day of month
46
- const maxDate = new Date(today.getFullYear(), today.getMonth() + 1, 0) // Last day of month
47
-
48
- let selectedDate = today
49
- </script>
50
-
51
- <Calendar
52
- value={selectedDate}
53
- minDate={minDate}
54
- maxDate={maxDate}
55
- onChange={(date) => selectedDate = date}
56
- />
57
- ```
58
-
59
- ### With Disabled Dates
60
-
61
- ```stx
62
- <script>
63
- import { Calendar } from '@stacksjs/components'
64
-
65
- const disabledDates = [
66
- new Date(2024, 11, 25), // Christmas
67
- new Date(2024, 0, 1), // New Year's Day
68
- ]
69
-
70
- let selectedDate = new Date()
71
- </script>
72
-
73
- <Calendar
74
- value={selectedDate}
75
- disabledDates={disabledDates}
76
- onChange={(date) => selectedDate = date}
77
- />
78
- ```
79
-
80
- ### Localized Calendar
81
-
82
- ```stx
83
- <script>
84
- import { Calendar } from '@stacksjs/components'
85
-
86
- let selectedDate = new Date()
87
- </script>
88
-
89
- <!-- Spanish calendar starting on Monday -->
90
- <Calendar
91
- value={selectedDate}
92
- locale="es-ES"
93
- firstDayOfWeek={1}
94
- onChange={(date) => selectedDate = date}
95
- />
96
- ```
97
-
98
- ### Without Today Button
99
-
100
- ```stx
101
- <script>
102
- import { Calendar } from '@stacksjs/components'
103
-
104
- let selectedDate = new Date()
105
- </script>
106
-
107
- <Calendar
108
- value={selectedDate}
109
- showToday={false}
110
- highlightToday={false}
111
- onChange={(date) => selectedDate = date}
112
- />
113
- ```
114
-
115
- ## Props
116
-
117
- | Prop | Type | Default | Description |
118
- |------|------|---------|-------------|
119
- | `value` | `Date` | `new Date()` | Currently selected date |
120
- | `onChange` | `(date: Date) => void` | - | Callback when a date is selected |
121
- | `minDate` | `Date` | - | Minimum selectable date |
122
- | `maxDate` | `Date` | - | Maximum selectable date |
123
- | `disabledDates` | `Date[]` | `[]` | Array of dates that cannot be selected |
124
- | `locale` | `string` | `'en-US'` | Locale for month/day names (e.g., 'en-US', 'es-ES', 'fr-FR') |
125
- | `firstDayOfWeek` | `number` | `0` | First day of week (0 = Sunday, 1 = Monday, etc.) |
126
- | `showToday` | `boolean` | `true` | Show "Today" button |
127
- | `highlightToday` | `boolean` | `true` | Highlight today's date with a border |
128
- | `className` | `string` | `''` | Additional CSS classes |
129
-
130
- ## Examples
131
-
132
- ### Date Range Selector (Start Date)
133
-
134
- ```stx
135
- <script>
136
- import { Calendar } from '@stacksjs/components'
137
-
138
- let startDate = null
139
- let endDate = null
140
-
141
- function handleStartDateChange(date) {
142
- startDate = date
143
- if (endDate && date > endDate) {
144
- endDate = null
145
- }
146
- }
147
- </script>
148
-
149
- <div>
150
- <h3>Select Start Date</h3>
151
- <Calendar
152
- value={startDate}
153
- maxDate={endDate}
154
- onChange={handleStartDateChange}
155
- />
156
- </div>
157
- ```
158
-
159
- ### Meeting Scheduler (Exclude Weekends)
160
-
161
- ```stx
162
- <script>
163
- import { Calendar } from '@stacksjs/components'
164
-
165
- function getNextNDays(n) {
166
- const dates = []
167
- const today = new Date()
168
- for (let i = 0; i < n; i++) {
169
- const date = new Date(today)
170
- date.setDate(today.getDate() + i)
171
- dates.push(date)
172
- }
173
- return dates
174
- }
175
-
176
- function getWeekends(days) {
177
- return days.filter(date => date.getDay() === 0 || date.getDay() === 6)
178
- }
179
-
180
- const next60Days = getNextNDays(60)
181
- const weekends = getWeekends(next60Days)
182
-
183
- let meetingDate = null
184
- </script>
185
-
186
- <Calendar
187
- value={meetingDate}
188
- minDate={new Date()}
189
- disabledDates={weekends}
190
- onChange={(date) => meetingDate = date}
191
- />
192
- ```
193
-
194
- ### Birthday Picker
195
-
196
- ```stx
197
- <script>
198
- import { Calendar } from '@stacksjs/components'
199
-
200
- const today = new Date()
201
- const minDate = new Date(today.getFullYear() - 120, 0, 1) // 120 years ago
202
- const maxDate = new Date(today.getFullYear() - 18, today.getMonth(), today.getDate()) // 18+ only
203
-
204
- let birthday = null
205
- </script>
206
-
207
- <Calendar
208
- value={birthday}
209
- minDate={minDate}
210
- maxDate={maxDate}
211
- onChange={(date) => birthday = date}
212
- />
213
- ```
214
-
215
- ## Styling
216
-
217
- The calendar uses utility-first CSS classes and supports dark mode out of the box. You can customize the appearance by passing additional classes:
218
-
219
- ```stx
220
- <Calendar
221
- className="border-2 border-gray-300 shadow-xl"
222
- value={selectedDate}
223
- onChange={handleChange}
224
- />
225
- ```
226
-
227
- ### Key Classes
228
-
229
- - Container: `bg-white dark:bg-gray-800 rounded-lg shadow-lg p-4`
230
- - Selected date: `bg-blue-600 text-white`
231
- - Today: `border-2 border-blue-600` (when not selected)
232
- - Disabled: `opacity-50 cursor-not-allowed`
233
- - Hover: `hover:bg-gray-100 dark:hover:bg-gray-700`
234
-
235
- ## Accessibility
236
-
237
- - Semantic HTML with proper ARIA labels
238
- - Keyboard navigation support (ready for enhancement)
239
- - Disabled dates are properly marked with `disabled` attribute
240
- - Clear visual indicators for selected and current dates
241
-
242
- ## Browser Support
243
-
244
- Works in all modern browsers that support:
245
- - ES6+ JavaScript features
246
- - CSS Grid
247
- - CSS custom properties (for dark mode)
248
-
249
- ## Related Components
250
-
251
- - **DatePicker**: Combines Calendar with an input field
252
- - **DateRangePicker**: Select start and end dates
253
- - **TimePicker**: Select time values
254
- - **DateTimePicker**: Combines date and time selection
@@ -1,14 +0,0 @@
1
- export { default as Calendar } from './Calendar.stx'
2
-
3
- export interface CalendarProps {
4
- value?: Date
5
- onChange?: (date: Date) => void
6
- minDate?: Date
7
- maxDate?: Date
8
- disabledDates?: Date[]
9
- locale?: string
10
- firstDayOfWeek?: number // 0 = Sunday, 1 = Monday, etc.
11
- showToday?: boolean
12
- highlightToday?: boolean
13
- className?: string
14
- }
@@ -1,68 +0,0 @@
1
- <script server>
2
- export const variant = $props.variant || 'default'
3
- export const padding = $props.padding || 'default'
4
- export const hover = $props.hover || false
5
- export const clickable = $props.clickable || false
6
- export const image = $props.image || ''
7
- export const imageAlt = $props.imageAlt || ''
8
- export const className = $props.className || ''
9
-
10
- const variantClasses = {
11
- default: 'bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700',
12
- outlined: 'bg-transparent border-2 border-gray-300 dark:border-gray-600',
13
- elevated: 'bg-white dark:bg-gray-800 shadow-lg border-0',
14
- flat: 'bg-gray-50 dark:bg-gray-900 border-0',
15
- }
16
-
17
- const paddingClasses = { none: 'p-0', sm: 'p-3', default: 'p-6', lg: 'p-8' }
18
- const hoverClasses = hover ? 'transition-all duration-200 hover:shadow-lg hover:-translate-y-0.5' : ''
19
- const clickableClasses = clickable ? 'cursor-pointer' : ''
20
-
21
- export const cardClasses = `rounded-lg overflow-hidden ${variantClasses[variant]} ${paddingClasses[image ? 'none' : padding]} ${hoverClasses} ${clickableClasses} ${className}`.trim()
22
- export const imageClasses = `w-full h-48 object-cover`.trim()
23
- export const contentClasses = `${image ? paddingClasses[padding] : ''}`.trim()
24
- </script>
25
-
26
- <script client>
27
- const emit = defineEmits()
28
- const isClickable = {{ clickable }}
29
-
30
- function onClick(event) {
31
- if (!isClickable) return
32
- emit('click', event)
33
- }
34
-
35
- function onKey(event) {
36
- if (!isClickable) return
37
- if (event.key === 'Enter' || event.key === ' ') {
38
- event.preventDefault()
39
- emit('click', event)
40
- }
41
- }
42
- </script>
43
-
44
- @if(clickable)
45
- <div
46
- class="{{ cardClasses }}"
47
- @click="onClick($event)"
48
- @keydown="onKey($event)"
49
- role="button"
50
- tabindex="0"
51
- >
52
- @if(image)
53
- <img src="{{ image }}" alt="{{ imageAlt }}" class="{{ imageClasses }}" />
54
- @endif
55
- <div class="{{ contentClasses }}">
56
- <slot />
57
- </div>
58
- </div>
59
- @else
60
- <div class="{{ cardClasses }}">
61
- @if(image)
62
- <img src="{{ image }}" alt="{{ imageAlt }}" class="{{ imageClasses }}" />
63
- @endif
64
- <div class="{{ contentClasses }}">
65
- <slot />
66
- </div>
67
- </div>
68
- @endif
@@ -1,13 +0,0 @@
1
- export { default as Card } from './Card.stx'
2
-
3
- export interface CardProps {
4
- variant?: 'default' | 'outlined' | 'elevated' | 'flat'
5
- padding?: 'none' | 'sm' | 'default' | 'lg'
6
- hover?: boolean
7
- clickable?: boolean
8
- image?: string
9
- imageAlt?: string
10
- imagePosition?: 'top' | 'bottom'
11
- onClick?: (event: Event) => void
12
- className?: string
13
- }