@santi020k/lumen-astro 0.3.0 → 1.0.0

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 (158) hide show
  1. package/README.md +100 -2
  2. package/components/Accordion.astro +4 -4
  3. package/components/Affix.astro +2 -2
  4. package/components/Agenda.astro +3 -2
  5. package/components/Alert.astro +9 -9
  6. package/components/AlertDialog.astro +7 -13
  7. package/components/Anchor.astro +29 -3
  8. package/components/AnimatedLogo.astro +2 -1
  9. package/components/AnimatedNumber.astro +5 -2
  10. package/components/AnimatedPortrait.astro +46 -36
  11. package/components/AspectRatio.astro +10 -8
  12. package/components/Attachment.astro +24 -24
  13. package/components/Autocomplete.astro +3 -2
  14. package/components/Avatar.astro +4 -3
  15. package/components/BackToTop.astro +2 -2
  16. package/components/Badge.astro +9 -9
  17. package/components/BarChart.astro +211 -0
  18. package/components/Breadcrumb.astro +3 -3
  19. package/components/Bubble.astro +7 -7
  20. package/components/Button.astro +18 -16
  21. package/components/ButtonGroup.astro +3 -3
  22. package/components/ButtonLink.astro +9 -3
  23. package/components/Calendar.astro +43 -31
  24. package/components/Callout.astro +2 -2
  25. package/components/Card.astro +12 -10
  26. package/components/CardContent.astro +26 -0
  27. package/components/CardDescription.astro +26 -0
  28. package/components/CardFooter.astro +26 -0
  29. package/components/CardHeader.astro +26 -0
  30. package/components/CardTitle.astro +26 -0
  31. package/components/Carousel.astro +6 -6
  32. package/components/Cascader.astro +10 -4
  33. package/components/Chart.astro +32 -6
  34. package/components/Checkbox.astro +3 -2
  35. package/components/CheckboxGroup.astro +39 -0
  36. package/components/Code.astro +55 -52
  37. package/components/CodeTabs.astro +6 -6
  38. package/components/Collapsible.astro +3 -3
  39. package/components/ColorPicker.astro +3 -2
  40. package/components/Combobox.astro +4 -5
  41. package/components/Command.astro +6 -6
  42. package/components/Container.astro +29 -0
  43. package/components/ContextMenu.astro +7 -13
  44. package/components/CopyButton.astro +55 -0
  45. package/components/CoverImage.astro +19 -9
  46. package/components/DataTable.astro +50 -49
  47. package/components/DatePicker.astro +20 -17
  48. package/components/DateRangePicker.astro +3 -2
  49. package/components/Descriptions.astro +3 -3
  50. package/components/Dialog.astro +8 -14
  51. package/components/Direction.astro +3 -3
  52. package/components/Drawer.astro +7 -13
  53. package/components/DropdownMenu.astro +7 -13
  54. package/components/Empty.astro +6 -6
  55. package/components/ErrorSummary.astro +54 -0
  56. package/components/Eyebrow.astro +2 -2
  57. package/components/Field.astro +7 -6
  58. package/components/FieldError.astro +29 -0
  59. package/components/FileUpload.astro +2 -2
  60. package/components/FloatingBadge.astro +2 -2
  61. package/components/Form.astro +33 -0
  62. package/components/FormattedDate.astro +2 -2
  63. package/components/GradientDivider.astro +2 -2
  64. package/components/Grid.astro +46 -0
  65. package/components/HoverCard.astro +7 -13
  66. package/components/Icon.astro +8 -6
  67. package/components/Image.astro +2 -1
  68. package/components/Input.astro +6 -5
  69. package/components/InputGroup.astro +3 -3
  70. package/components/InputOTP.astro +5 -3
  71. package/components/Item.astro +11 -8
  72. package/components/Kbd.astro +3 -3
  73. package/components/Label.astro +3 -2
  74. package/components/LanguageToggle.astro +2 -2
  75. package/components/LineChart.astro +244 -0
  76. package/components/Link.astro +6 -5
  77. package/components/ListBox.astro +154 -0
  78. package/components/Marker.astro +6 -6
  79. package/components/Mentions.astro +30 -10
  80. package/components/Menubar.astro +7 -13
  81. package/components/Message.astro +5 -5
  82. package/components/MessageScroller.astro +6 -6
  83. package/components/Meter.astro +1 -0
  84. package/components/NativeSelect.astro +4 -5
  85. package/components/NavigationMenu.astro +9 -14
  86. package/components/Note.astro +1 -1
  87. package/components/NumberField.astro +3 -2
  88. package/components/Pagination.astro +3 -3
  89. package/components/Particles.astro +58 -2
  90. package/components/PasswordField.astro +73 -0
  91. package/components/PhoneInput.astro +5 -7
  92. package/components/PieChart.astro +141 -0
  93. package/components/Pill.astro +15 -9
  94. package/components/Popconfirm.astro +8 -3
  95. package/components/Popover.astro +7 -13
  96. package/components/Progress.astro +12 -4
  97. package/components/Prose.astro +2 -2
  98. package/components/QRCode.astro +13 -5
  99. package/components/RadioGroup.astro +3 -3
  100. package/components/Rating.astro +3 -1
  101. package/components/Resizable.astro +8 -7
  102. package/components/RevealGroup.astro +4 -2
  103. package/components/RichTextEditor.astro +3 -2
  104. package/components/Schedule.astro +3 -2
  105. package/components/ScrollArea.astro +6 -6
  106. package/components/ScrollProgress.astro +38 -0
  107. package/components/ScrollReveal.astro +4 -2
  108. package/components/SearchField.astro +3 -2
  109. package/components/Segmented.astro +4 -6
  110. package/components/Select.astro +23 -14
  111. package/components/Separator.astro +5 -5
  112. package/components/Sheet.astro +7 -13
  113. package/components/Sidebar.astro +9 -14
  114. package/components/Skeleton.astro +4 -3
  115. package/components/SkipLink.astro +2 -2
  116. package/components/Slider.astro +3 -2
  117. package/components/Sonner.astro +3 -3
  118. package/components/Sparkline.astro +72 -0
  119. package/components/SpeedDial.astro +3 -3
  120. package/components/Spinner.astro +4 -3
  121. package/components/Stack.astro +46 -0
  122. package/components/Stat.astro +14 -8
  123. package/components/StatDescription.astro +16 -0
  124. package/components/StatIcon.astro +15 -0
  125. package/components/StatLabel.astro +16 -0
  126. package/components/StatTrend.astro +28 -0
  127. package/components/StatValue.astro +16 -0
  128. package/components/Stepper.astro +11 -8
  129. package/components/Switch.astro +3 -2
  130. package/components/Table.astro +7 -6
  131. package/components/Tabs.astro +6 -6
  132. package/components/TagGroup.astro +3 -2
  133. package/components/Textarea.astro +3 -2
  134. package/components/ThemeBuilder.astro +3 -2
  135. package/components/ThemeToggle.astro +5 -3
  136. package/components/TimeField.astro +3 -2
  137. package/components/Timeline.astro +2 -1
  138. package/components/TimelineItem.astro +2 -1
  139. package/components/Toast.astro +10 -16
  140. package/components/Toggle.astro +3 -2
  141. package/components/ToggleGroup.astro +3 -3
  142. package/components/Toolbar.astro +2 -2
  143. package/components/Tooltip.astro +3 -3
  144. package/components/Tour.astro +3 -3
  145. package/components/Transfer.astro +16 -5
  146. package/components/Tree.astro +3 -2
  147. package/components/TreeGrid.astro +3 -2
  148. package/components/TreeSelect.astro +10 -4
  149. package/components/Typography.astro +3 -3
  150. package/components/VirtualList.astro +3 -2
  151. package/components/VisuallyHidden.astro +27 -0
  152. package/components/Watermark.astro +11 -7
  153. package/forms.ts +46 -0
  154. package/index.ts +31 -0
  155. package/package.json +12 -8
  156. package/runtime/UIPrimitives.astro +3764 -3142
  157. package/runtime/controllers/motion.ts +13 -16
  158. package/index.d.ts +0 -126
@@ -0,0 +1,211 @@
1
+ ---
2
+ import type { HTMLAttributes } from 'astro/types'
3
+
4
+ import {
5
+ createLumenBarGeometry,
6
+ getLumenChartTicks,
7
+ getLumenChartToneClassName,
8
+ hasLumenChartData,
9
+ type LumenBarChartLayout,
10
+ type LumenChartOrientation,
11
+ type LumenChartSeries,
12
+ scaleLumenChartValue
13
+ } from '@santi020k/lumen-core'
14
+
15
+ import Chart from './Chart.astro'
16
+
17
+ interface Props extends HTMLAttributes<'figure'> {
18
+ caption?: string
19
+ categoryWidth?: number
20
+ class?: string | null
21
+ className?: string
22
+ description?: string
23
+ emptyLabel?: string
24
+ formatCategory?: (category: number | string) => string
25
+ formatValue?: (value: number) => string
26
+ glass?: boolean | 'subtle' | 'strong'
27
+ heading?: string
28
+ layout?: LumenBarChartLayout
29
+ orientation?: LumenChartOrientation
30
+ presentation?: 'bare' | 'default'
31
+ series: readonly LumenChartSeries[]
32
+ showLegend?: boolean
33
+ showTable?: boolean
34
+ }
35
+
36
+ const {
37
+ caption,
38
+ categoryWidth,
39
+ class: classProp = '',
40
+ className = '',
41
+ description,
42
+ emptyLabel = 'No chart data available.',
43
+ formatCategory = String,
44
+ formatValue = String,
45
+ glass = false,
46
+ heading,
47
+ layout = 'grouped',
48
+ orientation = 'vertical',
49
+ series,
50
+ showLegend = series.length > 1,
51
+ showTable = true,
52
+ ...rest
53
+ } = Astro.props
54
+
55
+ const geometry = createLumenBarGeometry(series, { categoryWidth, layout, orientation })
56
+ const hasData = hasLumenChartData(series)
57
+ const ticks = getLumenChartTicks(geometry.domain)
58
+ const categories = geometry.categories.map(category => category.category)
59
+
60
+ const datumFor = (item: LumenChartSeries, category: number | string) => (
61
+ item.data.find(datum => datum.x === category)
62
+ )
63
+
64
+ const valueFor = (item: LumenChartSeries, category: number | string) => (
65
+ datumFor(item, category)?.y ?? null
66
+ )
67
+
68
+ const labelFor = (item: LumenChartSeries, category: number | string) => (
69
+ datumFor(item, category)?.label
70
+ )
71
+
72
+ const formattedValueFor = (item: LumenChartSeries, category: number | string) => {
73
+ const value = valueFor(item, category)
74
+
75
+ return value === null ? 'Not available' : formatValue(value)
76
+ }
77
+
78
+ const categoryLabelFor = (category: number | string) => {
79
+ const label = series.flatMap(item => item.data).find(datum => datum.x === category)?.xLabel
80
+
81
+ return label ?? formatCategory(category)
82
+ }
83
+
84
+ const margin = orientation === 'horizontal' ?
85
+ { bottom: 24, left: Math.max(64, Math.min(240, categoryWidth ?? 112)), right: 20, top: 16 } :
86
+ { bottom: 52, left: 52, right: 16, top: 16 }
87
+ ---
88
+
89
+ <Chart
90
+ class:list={['ui-bar-chart', classProp, className]}
91
+ {caption}
92
+ {description}
93
+ {glass}
94
+ {heading}
95
+ {...rest}
96
+ >
97
+ {
98
+ showLegend && hasData && (
99
+ <ul class="ui-chart__legend" aria-label="Chart legend">
100
+ {series.map((item, index) => (
101
+ <li class={getLumenChartToneClassName(item.tone, index)}>
102
+ <span aria-hidden="true" />
103
+ {item.label}
104
+ </li>
105
+ ))}
106
+ </ul>
107
+ )
108
+ }
109
+ {!hasData && <p class="ui-chart__empty" role="status">{emptyLabel}</p>}
110
+ <div class="ui-chart__plot" hidden={!hasData}>
111
+ <svg
112
+ aria-hidden="true"
113
+ preserveAspectRatio="xMidYMid meet"
114
+ viewBox={`0 0 ${geometry.width} ${geometry.height}`}
115
+ >
116
+ <g class="ui-chart__grid">
117
+ {
118
+ ticks.map(tick => {
119
+ const coordinate =
120
+ orientation === 'horizontal' ?
121
+ scaleLumenChartValue(
122
+ tick, geometry.domain, margin.left, geometry.width - margin.right
123
+ ) :
124
+ scaleLumenChartValue(
125
+ tick, geometry.domain, geometry.height - margin.bottom, margin.top
126
+ )
127
+
128
+ return orientation === 'horizontal' ?
129
+ (
130
+ <line
131
+ x1={coordinate}
132
+ x2={coordinate}
133
+ y1={margin.top}
134
+ y2={geometry.height - margin.bottom}
135
+ />
136
+ ) :
137
+ (
138
+ <line
139
+ x1={margin.left}
140
+ x2={geometry.width - margin.right}
141
+ y1={coordinate}
142
+ y2={coordinate}
143
+ />
144
+ )
145
+ })
146
+ }
147
+ </g>
148
+ <g class="ui-chart__axis-labels">
149
+ {
150
+ geometry.categories.map(category => (
151
+ <text
152
+ dominant-baseline={orientation === 'horizontal' ? 'middle' : undefined}
153
+ text-anchor={orientation === 'horizontal' ? 'end' : 'middle'}
154
+ x={category.x}
155
+ y={category.y}
156
+ >
157
+ {String(category.label)}
158
+ </text>
159
+ ))
160
+ }
161
+ </g>
162
+ <g class="ui-bar-chart__marks">
163
+ {
164
+ geometry.marks.map(mark => (
165
+ <rect
166
+ class={getLumenChartToneClassName(mark.tone)}
167
+ height={mark.height}
168
+ rx="4"
169
+ width={mark.width}
170
+ x={mark.x}
171
+ y={mark.y}
172
+ >
173
+ <title>
174
+ {`${categoryLabelFor(mark.category)} · ${mark.seriesLabel}: ${formatValue(mark.value)}`}
175
+ </title>
176
+ </rect>
177
+ ))
178
+ }
179
+ </g>
180
+ </svg>
181
+ </div>
182
+ {
183
+ showTable && hasData && (
184
+ <details class="ui-chart__data">
185
+ <summary>View chart data</summary>
186
+ <div>
187
+ <table>
188
+ <thead>
189
+ <tr>
190
+ <th scope="col">Category</th>
191
+ {series.map(item => <th scope="col">{item.label}</th>)}
192
+ </tr>
193
+ </thead>
194
+ <tbody>
195
+ {categories.map(category => (
196
+ <tr>
197
+ <th scope="row">{categoryLabelFor(category)}</th>
198
+ {series.map(item => (
199
+ <td>
200
+ {labelFor(item, category) ?? formattedValueFor(item, category)}
201
+ </td>
202
+ ))}
203
+ </tr>
204
+ ))}
205
+ </tbody>
206
+ </table>
207
+ </div>
208
+ </details>
209
+ )
210
+ }
211
+ </Chart>
@@ -1,8 +1,8 @@
1
1
  ---
2
- import { resolveLumenAstroProps } from '@santi020k/lumen-core'
3
-
4
2
  import type { HTMLAttributes } from 'astro/types'
5
3
 
4
+ import { resolveLumenAstroProps } from '@santi020k/lumen-core'
5
+
6
6
  interface Props extends HTMLAttributes<'nav'> {
7
7
  class?: string | null
8
8
  className?: string
@@ -15,7 +15,7 @@ const {
15
15
  } = Astro.props
16
16
 
17
17
  const { classList, passthrough } = resolveLumenAstroProps(rest, [
18
- 'ui-breadcrumb'
18
+ 'ui-breadcrumb'
19
19
  ], classProp, className)
20
20
  ---
21
21
 
@@ -1,8 +1,8 @@
1
1
  ---
2
- import { resolveLumenAstroProps } from '@santi020k/lumen-core'
3
-
4
2
  import type { HTMLAttributes } from 'astro/types'
5
3
 
4
+ import { resolveLumenAstroProps } from '@santi020k/lumen-core'
5
+
6
6
  interface Props extends HTMLAttributes<'article'> {
7
7
  class?: string | null
8
8
  className?: string
@@ -19,11 +19,11 @@ const {
19
19
  } = Astro.props
20
20
 
21
21
  const { classList, passthrough } = resolveLumenAstroProps(rest, [
22
- 'ui-bubble',
23
- from === 'user' && 'ui-bubble--user',
24
- glass && 'ui-bubble--glass',
25
- glass === 'subtle' && 'ui-glass-subtle',
26
- glass === 'strong' && 'ui-glass-strong'
22
+ 'ui-bubble',
23
+ from === 'user' && 'ui-bubble--user',
24
+ glass && 'ui-bubble--glass',
25
+ glass === 'subtle' && 'ui-glass-subtle',
26
+ glass === 'strong' && 'ui-glass-strong'
27
27
  ], classProp, className)
28
28
  ---
29
29
 
@@ -1,8 +1,8 @@
1
1
  ---
2
- import { resolveLumenAstroProps } from '@santi020k/lumen-core'
3
-
4
2
  import type { HTMLAttributes } from 'astro/types'
5
3
 
4
+ import { resolveLumenAstroProps } from '@santi020k/lumen-core'
5
+
6
6
  interface Props extends HTMLAttributes<'button'> {
7
7
  class?: string | null
8
8
  className?: string
@@ -23,26 +23,28 @@ const {
23
23
  } = Astro.props
24
24
 
25
25
  const isDisabled = Boolean(disabled) || loading
26
+
26
27
  const { classList, passthrough } = resolveLumenAstroProps(rest, [
27
- 'ui-button',
28
- variant === 'default' && 'ui-button--default',
29
- variant === 'destructive' && 'ui-button--destructive',
30
- variant === 'ghost' && 'ui-button--ghost',
31
- variant === 'link' && 'ui-button--link',
32
- variant === 'outline' && 'ui-button--outline',
33
- variant === 'secondary' && 'ui-button--secondary',
34
- size === 'default' && 'ui-button--default-size',
35
- size === 'sm' && 'ui-button--sm',
36
- size === 'lg' && 'ui-button--lg',
37
- size === 'icon' && 'ui-button--icon',
38
- isDisabled && 'ui-button--disabled',
39
- loading && 'ui-button--loading'
28
+ 'ui-button',
29
+ variant === 'default' && 'ui-button--default',
30
+ variant === 'destructive' && 'ui-button--destructive',
31
+ variant === 'ghost' && 'ui-button--ghost',
32
+ variant === 'link' && 'ui-button--link',
33
+ variant === 'outline' && 'ui-button--outline',
34
+ variant === 'secondary' && 'ui-button--secondary',
35
+ size === 'default' && 'ui-button--default-size',
36
+ size === 'sm' && 'ui-button--sm',
37
+ size === 'lg' && 'ui-button--lg',
38
+ size === 'icon' && 'ui-button--icon',
39
+ isDisabled && 'ui-button--disabled',
40
+ loading && 'ui-button--loading'
40
41
  ], classProp, className)
41
42
  ---
42
43
 
43
44
  <button
44
- class:list={classList}
45
45
  aria-busy={loading || undefined}
46
+ class:list={classList}
47
+ data-slot="button"
46
48
  disabled={isDisabled || undefined}
47
49
  type={type}
48
50
  {...passthrough}
@@ -1,8 +1,8 @@
1
1
  ---
2
- import { resolveLumenAstroProps } from '@santi020k/lumen-core'
3
-
4
2
  import type { HTMLAttributes } from 'astro/types'
5
3
 
4
+ import { resolveLumenAstroProps } from '@santi020k/lumen-core'
5
+
6
6
  interface Props extends HTMLAttributes<'div'> {
7
7
  class?: string | null
8
8
  className?: string
@@ -15,7 +15,7 @@ const {
15
15
  } = Astro.props
16
16
 
17
17
  const { classList, passthrough } = resolveLumenAstroProps(rest, [
18
- 'ui-button-group'
18
+ 'ui-button-group'
19
19
  ], classProp, className)
20
20
  ---
21
21
 
@@ -1,8 +1,9 @@
1
1
  ---
2
+ import type { HTMLAttributes } from 'astro/types'
3
+
2
4
  import { resolveLumenAstroProps } from '@santi020k/lumen-core'
3
- import Icon from './Icon.astro'
4
5
 
5
- import type { HTMLAttributes } from 'astro/types'
6
+ import Icon from './Icon.astro'
6
7
 
7
8
  interface Props extends HTMLAttributes<'a'> {
8
9
  ariaLabel?: string
@@ -43,6 +44,7 @@ const { classList, passthrough } = resolveLumenAstroProps(rest, [
43
44
  <a
44
45
  aria-label={ariaLabel}
45
46
  class:list={classList}
47
+ data-slot="button-link"
46
48
  href={href}
47
49
  rel={newTab ? 'noreferrer noopener' : undefined}
48
50
  target={newTab ? '_blank' : undefined}
@@ -52,7 +54,11 @@ const { classList, passthrough } = resolveLumenAstroProps(rest, [
52
54
  {showArrow && (
53
55
  <Icon
54
56
  aria-hidden="true"
55
- class="size-4 shrink-0 transition-transform duration-200 motion-safe:group-hover:translate-x-0.5 motion-reduce:transition-none"
57
+ class="
58
+ size-4 shrink-0 transition-transform duration-200
59
+ motion-safe:group-hover:translate-x-0.5
60
+ motion-reduce:transition-none
61
+ "
56
62
  name={newTab ? 'arrow-up-right' : 'arrow-right'}
57
63
  />
58
64
  )}
@@ -1,8 +1,8 @@
1
1
  ---
2
- import { resolveLumenAstroProps } from '@santi020k/lumen-core'
3
-
4
2
  import type { HTMLAttributes } from 'astro/types'
5
3
 
4
+ import { resolveLumenAstroProps } from '@santi020k/lumen-core'
5
+
6
6
  interface Props extends Omit<HTMLAttributes<'div'>, 'value'> {
7
7
  class?: string | null
8
8
  className?: string
@@ -19,6 +19,7 @@ const isoDatePattern = /^\d{4}-\d{2}-\d{2}$/
19
19
  const isoMonthPattern = /^\d{4}-\d{2}$/
20
20
  const weekdayFormatter = new Intl.DateTimeFormat('en', { timeZone: 'UTC', weekday: 'short' })
21
21
  const monthFormatter = new Intl.DateTimeFormat('en', { month: 'long', timeZone: 'UTC', year: 'numeric' })
22
+
22
23
  const dayFormatter = new Intl.DateTimeFormat('en', {
23
24
  day: 'numeric',
24
25
  month: 'long',
@@ -35,9 +36,9 @@ const parseIsoDate = (date: string | undefined): Date | undefined => {
35
36
 
36
37
  return parsed.getUTCFullYear() === year &&
37
38
  parsed.getUTCMonth() === month - 1 &&
38
- parsed.getUTCDate() === day
39
- ? parsed
40
- : undefined
39
+ parsed.getUTCDate() === day ?
40
+ parsed :
41
+ undefined
41
42
  }
42
43
 
43
44
  const parseIsoMonth = (date: string | undefined): Date | undefined => {
@@ -46,21 +47,27 @@ const parseIsoMonth = (date: string | undefined): Date | undefined => {
46
47
  const [year, month] = date.split('-').map(Number)
47
48
  const parsed = new Date(Date.UTC(year, month - 1, 1))
48
49
 
49
- return parsed.getUTCFullYear() === year && parsed.getUTCMonth() === month - 1
50
- ? parsed
51
- : undefined
50
+ return parsed.getUTCFullYear() === year && parsed.getUTCMonth() === month - 1 ?
51
+ parsed :
52
+ undefined
52
53
  }
53
54
 
54
55
  const formatIsoDate = (date: Date): string => date.toISOString().slice(0, 10)
55
56
  const formatIsoMonth = (date: Date): string => date.toISOString().slice(0, 7)
56
- const addDays = (date: Date, days: number): Date =>
57
- new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate() + days))
58
- const getDaysInMonth = (date: Date): number =>
59
- new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth() + 1, 0)).getUTCDate()
60
- const isBefore = (date: Date, limit: Date | undefined): boolean =>
57
+
58
+ const addDays = (date: Date, days: number): Date => {
59
+ const utc = Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate() + days)
60
+
61
+ return new Date(utc)
62
+ }
63
+
64
+ const isBefore = (date: Date, limit: Date | undefined): boolean => (
61
65
  Boolean(limit && formatIsoDate(date) < formatIsoDate(limit))
62
- const isAfter = (date: Date, limit: Date | undefined): boolean =>
66
+ )
67
+
68
+ const isAfter = (date: Date, limit: Date | undefined): boolean => (
63
69
  Boolean(limit && formatIsoDate(date) > formatIsoDate(limit))
70
+ )
64
71
 
65
72
  const {
66
73
  class: classProp = '',
@@ -82,9 +89,11 @@ const selectedDate = parseIsoDate(value)
82
89
  const minDate = parseIsoDate(min)
83
90
  const maxDate = parseIsoDate(max)
84
91
  const selectedIso = selectedDate ? formatIsoDate(selectedDate) : ''
92
+
85
93
  const monthDate = parseIsoMonth(month) ??
86
94
  (selectedDate ? new Date(Date.UTC(selectedDate.getUTCFullYear(), selectedDate.getUTCMonth(), 1)) : undefined) ??
87
95
  new Date(Date.UTC(todayUtc.getUTCFullYear(), todayUtc.getUTCMonth(), 1))
96
+
88
97
  const calendarId = id ?? `ui-calendar-${Math.random().toString(36).slice(2)}`
89
98
  const labelId = `${calendarId}-label`
90
99
  const monthIso = formatIsoMonth(monthDate)
@@ -92,26 +101,29 @@ const todayIso = formatIsoDate(todayUtc)
92
101
  const firstWeekday = (monthDate.getUTCDay() + 6) % 7
93
102
  const firstCell = addDays(monthDate, -firstWeekday)
94
103
  const visibleDates = Array.from({ length: 42 }, (_, index) => addDays(firstCell, index))
95
- const firstSelectableDate = visibleDates.find(date =>
96
- date.getUTCMonth() === monthDate.getUTCMonth() &&
104
+
105
+ const firstSelectableDate = visibleDates.find(date => date.getUTCMonth() === monthDate.getUTCMonth() &&
97
106
  !isBefore(date, minDate) &&
98
- !isAfter(date, maxDate)
99
- )
100
- const focusIso = selectedDate && formatIsoMonth(selectedDate) === monthIso
101
- ? selectedIso
102
- : todayUtc.getUTCMonth() === monthDate.getUTCMonth() && todayUtc.getUTCFullYear() === monthDate.getUTCFullYear()
103
- ? todayIso
104
- : firstSelectableDate
105
- ? formatIsoDate(firstSelectableDate)
106
- : formatIsoDate(monthDate)
107
- const weekdays = Array.from({ length: 7 }, (_, index) =>
108
- weekdayFormatter.format(new Date(Date.UTC(2026, 0, 5 + index)))
107
+ !isAfter(date, maxDate))
108
+
109
+ let focusIso = formatIsoDate(monthDate)
110
+
111
+ if (selectedDate && formatIsoMonth(selectedDate) === monthIso) focusIso = selectedIso
112
+ else if (
113
+ todayUtc.getUTCMonth() === monthDate.getUTCMonth() &&
114
+ todayUtc.getUTCFullYear() === monthDate.getUTCFullYear()
115
+ ) focusIso = todayIso
116
+ else if (firstSelectableDate) focusIso = formatIsoDate(firstSelectableDate)
117
+
118
+ const weekdays = Array.from(
119
+ { length: 7 }, (_, index) => weekdayFormatter.format(new Date(Date.UTC(2026, 0, 5 + index)))
109
120
  )
121
+
110
122
  const { classList, passthrough } = resolveLumenAstroProps(rest, [
111
- 'ui-calendar',
112
- glass && 'ui-calendar--glass',
113
- glass === 'subtle' && 'ui-glass-subtle',
114
- glass === 'strong' && 'ui-glass-strong'
123
+ 'ui-calendar',
124
+ glass && 'ui-calendar--glass',
125
+ glass === 'subtle' && 'ui-glass-subtle',
126
+ glass === 'strong' && 'ui-glass-strong'
115
127
  ], classProp, className)
116
128
  ---
117
129
 
@@ -1,8 +1,8 @@
1
1
  ---
2
- import { resolveLumenAstroProps } from '@santi020k/lumen-core'
3
-
4
2
  import type { HTMLAttributes } from 'astro/types'
5
3
 
4
+ import { resolveLumenAstroProps } from '@santi020k/lumen-core'
5
+
6
6
  interface Props extends HTMLAttributes<'aside'> {
7
7
  class?: string | null
8
8
  className?: string
@@ -1,8 +1,8 @@
1
1
  ---
2
- import { resolveLumenAstroProps } from '@santi020k/lumen-core'
3
-
4
2
  import type { HTMLAttributes } from 'astro/types'
5
3
 
4
+ import { resolveLumenAstroProps } from '@santi020k/lumen-core'
5
+
6
6
  interface Props extends HTMLAttributes<'div'> {
7
7
  as?: 'article' | 'div' | 'section'
8
8
  class?: string | null
@@ -21,20 +21,22 @@ const {
21
21
  } = Astro.props
22
22
 
23
23
  const isGlass = glass || variant === 'glass'
24
+
24
25
  const { classList, passthrough } = resolveLumenAstroProps(rest, [
25
- 'ui-card',
26
- variant === 'unstyled' && 'ui-card--unstyled',
27
- variant === 'muted' && 'ui-card--muted',
28
- variant === 'interactive' && 'ui-card--interactive',
29
- isGlass && 'ui-card--glass',
30
- glass === 'subtle' && 'ui-glass-subtle',
31
- glass === 'strong' && 'ui-glass-strong'
26
+ 'ui-card',
27
+ variant === 'unstyled' && 'ui-card--unstyled',
28
+ variant === 'muted' && 'ui-card--muted',
29
+ variant === 'interactive' && 'ui-card--interactive',
30
+ isGlass && 'ui-card--glass',
31
+ glass === 'subtle' && 'ui-glass-subtle',
32
+ glass === 'strong' && 'ui-glass-strong'
32
33
  ], classProp, className)
33
34
  ---
34
35
 
35
36
  <Tag
36
- data-variant={variant}
37
37
  class:list={classList}
38
+ data-slot="card"
39
+ data-variant={variant}
38
40
  {...passthrough}
39
41
  >
40
42
  <slot />
@@ -0,0 +1,26 @@
1
+ ---
2
+ import type { HTMLAttributes } from 'astro/types'
3
+
4
+ import { resolveLumenAstroProps } from '@santi020k/lumen-core'
5
+
6
+ interface Props extends HTMLAttributes<'div'> {
7
+ as?: 'div' | 'section'
8
+ class?: string | null
9
+ className?: string
10
+ }
11
+
12
+ const {
13
+ as: Tag = 'div',
14
+ class: classProp = '',
15
+ className = '',
16
+ ...rest
17
+ } = Astro.props
18
+
19
+ const { classList, passthrough } = resolveLumenAstroProps(
20
+ rest, ['ui-card__content'], classProp, className
21
+ )
22
+ ---
23
+
24
+ <Tag class:list={classList} data-slot="card-content" {...passthrough}>
25
+ <slot />
26
+ </Tag>
@@ -0,0 +1,26 @@
1
+ ---
2
+ import type { HTMLAttributes } from 'astro/types'
3
+
4
+ import { resolveLumenAstroProps } from '@santi020k/lumen-core'
5
+
6
+ interface Props extends HTMLAttributes<'div'> {
7
+ as?: 'div' | 'p'
8
+ class?: string | null
9
+ className?: string
10
+ }
11
+
12
+ const {
13
+ as: Tag = 'div',
14
+ class: classProp = '',
15
+ className = '',
16
+ ...rest
17
+ } = Astro.props
18
+
19
+ const { classList, passthrough } = resolveLumenAstroProps(
20
+ rest, ['ui-card__description'], classProp, className
21
+ )
22
+ ---
23
+
24
+ <Tag class:list={classList} data-slot="card-description" {...passthrough}>
25
+ <slot />
26
+ </Tag>
@@ -0,0 +1,26 @@
1
+ ---
2
+ import type { HTMLAttributes } from 'astro/types'
3
+
4
+ import { resolveLumenAstroProps } from '@santi020k/lumen-core'
5
+
6
+ interface Props extends HTMLAttributes<'div'> {
7
+ as?: 'div' | 'footer'
8
+ class?: string | null
9
+ className?: string
10
+ }
11
+
12
+ const {
13
+ as: Tag = 'div',
14
+ class: classProp = '',
15
+ className = '',
16
+ ...rest
17
+ } = Astro.props
18
+
19
+ const { classList, passthrough } = resolveLumenAstroProps(
20
+ rest, ['ui-card__footer'], classProp, className
21
+ )
22
+ ---
23
+
24
+ <Tag class:list={classList} data-slot="card-footer" {...passthrough}>
25
+ <slot />
26
+ </Tag>
@@ -0,0 +1,26 @@
1
+ ---
2
+ import type { HTMLAttributes } from 'astro/types'
3
+
4
+ import { resolveLumenAstroProps } from '@santi020k/lumen-core'
5
+
6
+ interface Props extends HTMLAttributes<'div'> {
7
+ as?: 'div' | 'header'
8
+ class?: string | null
9
+ className?: string
10
+ }
11
+
12
+ const {
13
+ as: Tag = 'div',
14
+ class: classProp = '',
15
+ className = '',
16
+ ...rest
17
+ } = Astro.props
18
+
19
+ const { classList, passthrough } = resolveLumenAstroProps(
20
+ rest, ['ui-card__header'], classProp, className
21
+ )
22
+ ---
23
+
24
+ <Tag class:list={classList} data-slot="card-header" {...passthrough}>
25
+ <slot />
26
+ </Tag>
@@ -0,0 +1,26 @@
1
+ ---
2
+ import type { HTMLAttributes } from 'astro/types'
3
+
4
+ import { resolveLumenAstroProps } from '@santi020k/lumen-core'
5
+
6
+ interface Props extends HTMLAttributes<'div'> {
7
+ as?: 'div' | 'h2' | 'h3' | 'h4'
8
+ class?: string | null
9
+ className?: string
10
+ }
11
+
12
+ const {
13
+ as: Tag = 'div',
14
+ class: classProp = '',
15
+ className = '',
16
+ ...rest
17
+ } = Astro.props
18
+
19
+ const { classList, passthrough } = resolveLumenAstroProps(
20
+ rest, ['ui-card__title'], classProp, className
21
+ )
22
+ ---
23
+
24
+ <Tag class:list={classList} data-slot="card-title" {...passthrough}>
25
+ <slot />
26
+ </Tag>