@open-mercato/ui 0.8.1-develop.7296.1.2111d779db → 0.9.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.
- package/.turbo/turbo-build.log +1 -1
- package/dist/backend/CrudForm.js +19 -6
- package/dist/backend/CrudForm.js.map +2 -2
- package/dist/backend/DataTable.js +62 -10
- package/dist/backend/DataTable.js.map +2 -2
- package/dist/backend/RowActions.js +54 -5
- package/dist/backend/RowActions.js.map +2 -2
- package/dist/backend/charts/KpiCard.js +2 -1
- package/dist/backend/charts/KpiCard.js.map +2 -2
- package/dist/backend/detail/AttachmentsSection.js +17 -5
- package/dist/backend/detail/AttachmentsSection.js.map +2 -2
- package/dist/backend/detail/NotesSection.js +38 -20
- package/dist/backend/detail/NotesSection.js.map +2 -2
- package/dist/backend/dev/DevRuntimeDiagnosticsBanner.js +11 -1
- package/dist/backend/dev/DevRuntimeDiagnosticsBanner.js.map +2 -2
- package/dist/backend/icons/lucideRegistry.generated.js +26 -0
- package/dist/backend/icons/lucideRegistry.generated.js.map +2 -2
- package/dist/backend/injection/eventBridge.js +33 -0
- package/dist/backend/injection/eventBridge.js.map +2 -2
- package/dist/backend/inputs/LookupSelect.js +20 -3
- package/dist/backend/inputs/LookupSelect.js.map +2 -2
- package/dist/backend/inputs/PhoneNumberField.js +1 -1
- package/dist/backend/inputs/PhoneNumberField.js.map +2 -2
- package/dist/backend/inputs/TagsInput.js +20 -2
- package/dist/backend/inputs/TagsInput.js.map +2 -2
- package/dist/backend/messages/EmailThreadsPanel.js +2 -1
- package/dist/backend/messages/EmailThreadsPanel.js.map +2 -2
- package/dist/backend/messages/MessageComposer.js.map +2 -2
- package/dist/backend/messages/index.js.map +2 -2
- package/dist/backend/messages/message-compose-form-groups.js +24 -0
- package/dist/backend/messages/message-compose-form-groups.js.map +2 -2
- package/dist/backend/messages/useMessageCompose.js +27 -0
- package/dist/backend/messages/useMessageCompose.js.map +2 -2
- package/dist/backend/messages/useMessageComposeOperations.js +1 -0
- package/dist/backend/messages/useMessageComposeOperations.js.map +2 -2
- package/dist/backend/notifications/NotificationItem.js +8 -1
- package/dist/backend/notifications/NotificationItem.js.map +2 -2
- package/dist/portal/PortalShell.js +2 -2
- package/dist/portal/PortalShell.js.map +2 -2
- package/dist/primitives/calendar.js +69 -14
- package/dist/primitives/calendar.js.map +2 -2
- package/package.json +4 -5
- package/src/backend/CrudForm.tsx +30 -8
- package/src/backend/DataTable.tsx +95 -20
- package/src/backend/RowActions.tsx +114 -6
- package/src/backend/__tests__/AttachmentsSection.upload.test.tsx +183 -0
- package/src/backend/__tests__/CrudForm.fieldInjection.test.tsx +139 -2
- package/src/backend/__tests__/CrudForm.hiddenGroups.test.tsx +1 -1
- package/src/backend/__tests__/DataTable.extensions.test.tsx +30 -0
- package/src/backend/__tests__/DataTable.perspectiveReconcile.test.tsx +320 -2
- package/src/backend/__tests__/DataTable.stickyResponsive.test.tsx +19 -0
- package/src/backend/__tests__/DevRuntimeDiagnosticsBanner.test.tsx +117 -0
- package/src/backend/__tests__/NotesSection.test.tsx +138 -0
- package/src/backend/__tests__/RowActions.test.tsx +202 -0
- package/src/backend/charts/KpiCard.tsx +1 -0
- package/src/backend/charts/__tests__/KpiCard.test.tsx +20 -0
- package/src/backend/detail/AttachmentsSection.tsx +17 -5
- package/src/backend/detail/NotesSection.tsx +122 -66
- package/src/backend/dev/DevRuntimeDiagnosticsBanner.tsx +24 -1
- package/src/backend/icons/lucideRegistry.generated.tsx +26 -0
- package/src/backend/injection/__tests__/eventBridge.test.tsx +47 -1
- package/src/backend/injection/eventBridge.ts +35 -0
- package/src/backend/inputs/LookupSelect.tsx +32 -3
- package/src/backend/inputs/PhoneNumberField.tsx +1 -1
- package/src/backend/inputs/TagsInput.tsx +24 -3
- package/src/backend/inputs/__tests__/LookupSelect.test.tsx +166 -1
- package/src/backend/inputs/__tests__/PhoneNumberField.typeahead.test.tsx +43 -0
- package/src/backend/inputs/__tests__/TagsInput.test.tsx +81 -0
- package/src/backend/messages/EmailThreadsPanel.tsx +21 -1
- package/src/backend/messages/MessageComposer.tsx +1 -0
- package/src/backend/messages/__tests__/EmailThreadsPanel.senderLabel.test.tsx +99 -0
- package/src/backend/messages/__tests__/MessageComposer.test.tsx +44 -0
- package/src/backend/messages/__tests__/useMessageCompose.test.tsx +69 -0
- package/src/backend/messages/__tests__/useMessageComposeSender.test.tsx +208 -0
- package/src/backend/messages/index.ts +1 -0
- package/src/backend/messages/message-compose-form-groups.tsx +41 -0
- package/src/backend/messages/message-composer.types.ts +26 -0
- package/src/backend/messages/useMessageCompose.ts +46 -0
- package/src/backend/messages/useMessageComposeOperations.ts +8 -0
- package/src/backend/notifications/NotificationItem.tsx +7 -0
- package/src/backend/notifications/__tests__/NotificationItem.customRenderer.test.tsx +139 -0
- package/src/portal/PortalShell.tsx +7 -4
- package/src/portal/__tests__/PortalShell.test.tsx +29 -1
- package/src/primitives/__tests__/calendar.test.tsx +174 -1
- package/src/primitives/calendar.tsx +168 -96
|
@@ -7,7 +7,9 @@ import { ChevronLeft, ChevronRight } from 'lucide-react'
|
|
|
7
7
|
import { format } from 'date-fns/format'
|
|
8
8
|
import type { Locale } from 'date-fns/locale'
|
|
9
9
|
import { cn } from '@open-mercato/shared/lib/utils'
|
|
10
|
-
import { useT } from '@open-mercato/shared/lib/i18n/context'
|
|
10
|
+
import { useOptionalT, useT } from '@open-mercato/shared/lib/i18n/context'
|
|
11
|
+
import type { TranslateFn } from '@open-mercato/shared/lib/i18n/context'
|
|
12
|
+
import { createTranslator } from '@open-mercato/shared/lib/i18n/translate'
|
|
11
13
|
import { CompactButton } from './compact-button'
|
|
12
14
|
|
|
13
15
|
export type CalendarProps = DayPickerProps & { daySize?: 36 | 40 }
|
|
@@ -46,6 +48,16 @@ export function CalendarMonthSelector({
|
|
|
46
48
|
const STANDALONE_MONTH_YEAR = 'LLLL yyyy'
|
|
47
49
|
const STANDALONE_MONTH_SHORT = 'LLL'
|
|
48
50
|
|
|
51
|
+
const fallbackTranslate = createTranslator({})
|
|
52
|
+
|
|
53
|
+
function useCalendarT(): TranslateFn {
|
|
54
|
+
return useOptionalT() ?? fallbackTranslate
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
type CalendarLabels = DayPickerProps['labels']
|
|
58
|
+
|
|
59
|
+
const CalendarLabelsContext = React.createContext<CalendarLabels>(undefined)
|
|
60
|
+
|
|
49
61
|
const navButtonClassName = cn(
|
|
50
62
|
'h-9 w-9 inline-flex items-center justify-center rounded-md shrink-0',
|
|
51
63
|
'border border-border bg-background text-muted-foreground transition-colors',
|
|
@@ -61,6 +73,8 @@ function MonthNavButton({
|
|
|
61
73
|
direction: 'prev' | 'next'
|
|
62
74
|
locale?: Locale
|
|
63
75
|
}) {
|
|
76
|
+
const t = useCalendarT()
|
|
77
|
+
const labels = React.useContext(CalendarLabelsContext)
|
|
64
78
|
const dayPicker = useDayPicker() as unknown as {
|
|
65
79
|
previousMonth?: Date
|
|
66
80
|
nextMonth?: Date
|
|
@@ -69,7 +83,12 @@ function MonthNavButton({
|
|
|
69
83
|
const target = direction === 'prev' ? dayPicker.previousMonth : dayPicker.nextMonth
|
|
70
84
|
const Icon = direction === 'prev' ? ChevronLeft : ChevronRight
|
|
71
85
|
const targetLabel = format(target ?? new Date(), STANDALONE_MONTH_YEAR, locale ? { locale } : undefined)
|
|
72
|
-
const
|
|
86
|
+
const customLabel = direction === 'prev' ? labels?.labelPrevious : labels?.labelNext
|
|
87
|
+
const ariaLabel = customLabel
|
|
88
|
+
? customLabel(target)
|
|
89
|
+
: direction === 'prev'
|
|
90
|
+
? t('ui.calendar.goToPreviousMonth', 'Go to previous month: {month}', { month: targetLabel })
|
|
91
|
+
: t('ui.calendar.goToNextMonth', 'Go to next month: {month}', { month: targetLabel })
|
|
73
92
|
return (
|
|
74
93
|
<button
|
|
75
94
|
type="button"
|
|
@@ -89,6 +108,7 @@ function buildMonthCaption(
|
|
|
89
108
|
locale: Locale | undefined,
|
|
90
109
|
totalMonths: number,
|
|
91
110
|
onOpenMonthGrid: (() => void) | null,
|
|
111
|
+
monthGridTriggerRef: React.Ref<HTMLButtonElement>,
|
|
92
112
|
) {
|
|
93
113
|
return function MonthCaption({
|
|
94
114
|
calendarMonth,
|
|
@@ -97,6 +117,7 @@ function buildMonthCaption(
|
|
|
97
117
|
calendarMonth: CalendarMonth
|
|
98
118
|
displayIndex?: number
|
|
99
119
|
}) {
|
|
120
|
+
const t = useCalendarT()
|
|
100
121
|
const label = format(calendarMonth.date, STANDALONE_MONTH_YEAR, locale ? { locale } : undefined)
|
|
101
122
|
const index = typeof displayIndex === 'number' ? displayIndex : 0
|
|
102
123
|
// For multi-month layouts (e.g. range pickers) only the leftmost month
|
|
@@ -117,9 +138,10 @@ function buildMonthCaption(
|
|
|
117
138
|
)}
|
|
118
139
|
{labelInteractive ? (
|
|
119
140
|
<button
|
|
141
|
+
ref={monthGridTriggerRef}
|
|
120
142
|
type="button"
|
|
121
143
|
onClick={onOpenMonthGrid ?? undefined}
|
|
122
|
-
aria-label={
|
|
144
|
+
aria-label={t('ui.calendar.openMonthYearNavigation', '{month} – open month and year navigation', { month: label })}
|
|
123
145
|
className={cn(
|
|
124
146
|
'flex-1 flex items-center justify-center h-9 rounded-md bg-muted px-3 text-sm font-medium',
|
|
125
147
|
'transition-colors hover:bg-accent hover:text-accent-foreground',
|
|
@@ -152,14 +174,49 @@ function MonthGrid({
|
|
|
152
174
|
locale,
|
|
153
175
|
onSelectMonth,
|
|
154
176
|
onClose,
|
|
177
|
+
onRestoreFocus,
|
|
155
178
|
}: {
|
|
156
179
|
initialYear: number
|
|
157
180
|
selectedMonth: Date
|
|
158
181
|
locale?: Locale
|
|
159
182
|
onSelectMonth: (month: Date) => void
|
|
160
183
|
onClose: () => void
|
|
184
|
+
onRestoreFocus: () => void
|
|
161
185
|
}) {
|
|
186
|
+
const t = useCalendarT()
|
|
162
187
|
const [year, setYear] = React.useState(initialYear)
|
|
188
|
+
const gridRef = React.useRef<HTMLDivElement>(null)
|
|
189
|
+
const selectedMonthRef = React.useRef<HTMLButtonElement>(null)
|
|
190
|
+
React.useEffect(() => {
|
|
191
|
+
selectedMonthRef.current?.focus()
|
|
192
|
+
return onRestoreFocus
|
|
193
|
+
}, [onRestoreFocus])
|
|
194
|
+
|
|
195
|
+
React.useEffect(() => {
|
|
196
|
+
const handleEscape = (event: KeyboardEvent) => {
|
|
197
|
+
if (event.key !== 'Escape' || !(event.target instanceof Node) || !gridRef.current?.contains(event.target)) return
|
|
198
|
+
event.preventDefault()
|
|
199
|
+
event.stopPropagation()
|
|
200
|
+
onClose()
|
|
201
|
+
}
|
|
202
|
+
window.addEventListener('keydown', handleEscape, true)
|
|
203
|
+
return () => window.removeEventListener('keydown', handleEscape, true)
|
|
204
|
+
}, [onClose])
|
|
205
|
+
|
|
206
|
+
const handleKeyDown = (event: React.KeyboardEvent<HTMLDivElement>) => {
|
|
207
|
+
if (event.key !== 'Tab') return
|
|
208
|
+
|
|
209
|
+
const buttons = event.currentTarget.querySelectorAll<HTMLButtonElement>('button:not(:disabled)')
|
|
210
|
+
const firstButton = buttons[0]
|
|
211
|
+
const lastButton = buttons[buttons.length - 1]
|
|
212
|
+
if (event.shiftKey && document.activeElement === firstButton) {
|
|
213
|
+
event.preventDefault()
|
|
214
|
+
lastButton?.focus()
|
|
215
|
+
} else if (!event.shiftKey && document.activeElement === lastButton) {
|
|
216
|
+
event.preventDefault()
|
|
217
|
+
firstButton?.focus()
|
|
218
|
+
}
|
|
219
|
+
}
|
|
163
220
|
const today = new Date()
|
|
164
221
|
const monthLabels = React.useMemo(
|
|
165
222
|
() =>
|
|
@@ -171,14 +228,16 @@ function MonthGrid({
|
|
|
171
228
|
const yearLabel = format(new Date(year, 0, 1), 'yyyy', locale ? { locale } : undefined)
|
|
172
229
|
return (
|
|
173
230
|
<div
|
|
231
|
+
ref={gridRef}
|
|
174
232
|
className="absolute inset-0 z-10 flex flex-col rounded-md bg-popover p-3"
|
|
175
233
|
role="dialog"
|
|
176
|
-
aria-label=
|
|
234
|
+
aria-label={t('ui.calendar.selectMonthAndYear', 'Select month and year')}
|
|
235
|
+
onKeyDown={handleKeyDown}
|
|
177
236
|
>
|
|
178
237
|
<div className="flex items-center justify-between gap-2 mb-3">
|
|
179
238
|
<button
|
|
180
239
|
type="button"
|
|
181
|
-
aria-label={
|
|
240
|
+
aria-label={t('ui.calendar.goToPreviousYear', 'Go to previous year: {year}', { year: year - 1 })}
|
|
182
241
|
onClick={() => setYear((current) => current - 1)}
|
|
183
242
|
className={navButtonClassName}
|
|
184
243
|
>
|
|
@@ -187,7 +246,7 @@ function MonthGrid({
|
|
|
187
246
|
<button
|
|
188
247
|
type="button"
|
|
189
248
|
onClick={onClose}
|
|
190
|
-
aria-label={
|
|
249
|
+
aria-label={t('ui.calendar.backToDaySelection', '{year} – back to day selection', { year: yearLabel })}
|
|
191
250
|
className={cn(
|
|
192
251
|
'flex-1 flex items-center justify-center h-9 rounded-md bg-muted px-3 text-sm font-medium',
|
|
193
252
|
'transition-colors hover:bg-accent hover:text-accent-foreground',
|
|
@@ -198,7 +257,7 @@ function MonthGrid({
|
|
|
198
257
|
</button>
|
|
199
258
|
<button
|
|
200
259
|
type="button"
|
|
201
|
-
aria-label={
|
|
260
|
+
aria-label={t('ui.calendar.goToNextYear', 'Go to next year: {year}', { year: year + 1 })}
|
|
202
261
|
onClick={() => setYear((current) => current + 1)}
|
|
203
262
|
className={navButtonClassName}
|
|
204
263
|
>
|
|
@@ -214,6 +273,7 @@ function MonthGrid({
|
|
|
214
273
|
return (
|
|
215
274
|
<button
|
|
216
275
|
key={monthIndex}
|
|
276
|
+
ref={monthIndex === selectedMonth.getMonth() ? selectedMonthRef : undefined}
|
|
217
277
|
type="button"
|
|
218
278
|
aria-pressed={isSelected}
|
|
219
279
|
onClick={() => onSelectMonth(new Date(year, monthIndex, 1))}
|
|
@@ -248,6 +308,7 @@ export function Calendar({
|
|
|
248
308
|
month,
|
|
249
309
|
defaultMonth,
|
|
250
310
|
onMonthChange,
|
|
311
|
+
labels,
|
|
251
312
|
...props
|
|
252
313
|
}: CalendarProps) {
|
|
253
314
|
// The month/year grid (fast navigation) is only meaningful for single-month
|
|
@@ -257,6 +318,10 @@ export function Calendar({
|
|
|
257
318
|
() => month ?? defaultMonth ?? new Date(),
|
|
258
319
|
)
|
|
259
320
|
const [showMonthGrid, setShowMonthGrid] = React.useState(false)
|
|
321
|
+
const monthGridTriggerRef = React.useRef<HTMLButtonElement>(null)
|
|
322
|
+
const restoreDayViewFocus = React.useCallback(() => {
|
|
323
|
+
monthGridTriggerRef.current?.focus()
|
|
324
|
+
}, [])
|
|
260
325
|
|
|
261
326
|
// Honor a controlled `month` prop when consumers drive navigation externally.
|
|
262
327
|
React.useEffect(() => {
|
|
@@ -285,100 +350,107 @@ export function Calendar({
|
|
|
285
350
|
locale as Locale | undefined,
|
|
286
351
|
numberOfMonths,
|
|
287
352
|
monthGridEnabled ? () => setShowMonthGrid(true) : null,
|
|
353
|
+
monthGridTriggerRef,
|
|
288
354
|
),
|
|
289
355
|
[locale, numberOfMonths, monthGridEnabled],
|
|
290
356
|
)
|
|
291
357
|
|
|
292
358
|
return (
|
|
293
|
-
<
|
|
294
|
-
<div
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
'
|
|
321
|
-
|
|
322
|
-
'
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
'
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
359
|
+
<CalendarLabelsContext.Provider value={labels}>
|
|
360
|
+
<div className={monthGridEnabled ? 'relative' : 'contents'}>
|
|
361
|
+
<div
|
|
362
|
+
className={monthGridEnabled && showMonthGrid ? 'invisible pointer-events-none' : 'contents'}
|
|
363
|
+
aria-hidden={monthGridEnabled && showMonthGrid ? true : undefined}
|
|
364
|
+
inert={monthGridEnabled && showMonthGrid ? true : undefined}
|
|
365
|
+
>
|
|
366
|
+
<DayPicker
|
|
367
|
+
showOutsideDays={showOutsideDays}
|
|
368
|
+
fixedWeeks={fixedWeeks}
|
|
369
|
+
pagedNavigation={pagedNavigation}
|
|
370
|
+
hideNavigation
|
|
371
|
+
locale={locale}
|
|
372
|
+
labels={labels}
|
|
373
|
+
numberOfMonths={numberOfMonths}
|
|
374
|
+
month={displayMonth}
|
|
375
|
+
onMonthChange={handleMonthChange}
|
|
376
|
+
className={cn('p-3', className)}
|
|
377
|
+
classNames={{
|
|
378
|
+
months: 'flex flex-col sm:flex-row gap-4',
|
|
379
|
+
month: 'space-y-2',
|
|
380
|
+
month_caption: '',
|
|
381
|
+
caption_label: 'sr-only',
|
|
382
|
+
nav: 'sr-only',
|
|
383
|
+
month_grid: 'w-full border-collapse',
|
|
384
|
+
weekdays: 'flex',
|
|
385
|
+
weekday: cn('text-muted-foreground rounded-md font-normal text-xs', daySize === 40 ? 'w-10' : 'w-9'),
|
|
386
|
+
weeks: 'w-full border-collapse',
|
|
387
|
+
week: 'flex w-full mt-1',
|
|
388
|
+
day: cn('text-center text-sm p-0 relative focus-within:relative focus-within:z-20', daySize === 40 ? 'size-10' : 'size-9'),
|
|
389
|
+
day_button: cn(
|
|
390
|
+
'p-0 font-normal aria-selected:opacity-100',
|
|
391
|
+
daySize === 40 ? 'size-10' : 'size-9',
|
|
392
|
+
'inline-flex items-center justify-center rounded-md text-sm',
|
|
393
|
+
'transition-colors focus:outline-none focus-visible:outline-none disabled:pointer-events-none',
|
|
394
|
+
// Focus indicator is a soft accent fill instead of a ring overlay — keyboard
|
|
395
|
+
// users get a visible cue, but mouse-click focus does not leave a stuck ring
|
|
396
|
+
// on top of the selected cell.
|
|
397
|
+
'hover:bg-accent hover:text-accent-foreground',
|
|
398
|
+
'focus-visible:bg-accent focus-visible:text-accent-foreground',
|
|
399
|
+
),
|
|
400
|
+
// React-day-picker v9 applies `classNames.selected` / `range_*` to the day
|
|
401
|
+
// CELL (`<td>`) wrapper, not to the inner `<button>`. To keep the parent
|
|
402
|
+
// fill visible through interaction, we (a) paint the cell with the desired
|
|
403
|
+
// bg/text, and (b) force the inner button to render transparent — so the
|
|
404
|
+
// button's own hover/focus-visible bg overrides cannot cover the cell fill.
|
|
405
|
+
selected: cn(
|
|
406
|
+
'!bg-primary !text-primary-foreground rounded-md',
|
|
407
|
+
'[&_button]:!bg-transparent [&_button]:!text-primary-foreground',
|
|
408
|
+
'[&_button:hover]:!bg-transparent [&_button:hover]:!text-primary-foreground',
|
|
409
|
+
'[&_button:focus-visible]:!bg-transparent [&_button:focus-visible]:!text-primary-foreground',
|
|
410
|
+
),
|
|
411
|
+
range_start: cn(
|
|
412
|
+
'!bg-primary !text-primary-foreground rounded-l-md !rounded-r-none',
|
|
413
|
+
'[&_button]:!bg-transparent [&_button]:!text-primary-foreground',
|
|
414
|
+
'[&_button:hover]:!bg-transparent [&_button:hover]:!text-primary-foreground',
|
|
415
|
+
'[&_button:focus-visible]:!bg-transparent [&_button:focus-visible]:!text-primary-foreground',
|
|
416
|
+
),
|
|
417
|
+
range_end: cn(
|
|
418
|
+
'!bg-primary !text-primary-foreground rounded-r-md !rounded-l-none',
|
|
419
|
+
'[&_button]:!bg-transparent [&_button]:!text-primary-foreground',
|
|
420
|
+
'[&_button:hover]:!bg-transparent [&_button:hover]:!text-primary-foreground',
|
|
421
|
+
'[&_button:focus-visible]:!bg-transparent [&_button:focus-visible]:!text-primary-foreground',
|
|
422
|
+
),
|
|
423
|
+
range_middle: cn(
|
|
424
|
+
'!bg-accent !text-accent-foreground !rounded-none',
|
|
425
|
+
'[&_button]:!bg-transparent [&_button]:!text-accent-foreground',
|
|
426
|
+
'[&_button:hover]:!bg-transparent [&_button:hover]:!text-accent-foreground',
|
|
427
|
+
'[&_button:focus-visible]:!bg-transparent [&_button:focus-visible]:!text-accent-foreground',
|
|
428
|
+
),
|
|
429
|
+
today: 'font-semibold text-primary rounded-md',
|
|
430
|
+
outside:
|
|
431
|
+
'day-outside text-muted-foreground opacity-40 aria-selected:bg-accent/50 aria-selected:text-muted-foreground aria-selected:opacity-30',
|
|
432
|
+
disabled: 'text-muted-foreground opacity-50',
|
|
433
|
+
hidden: 'invisible',
|
|
434
|
+
...classNames,
|
|
435
|
+
}}
|
|
436
|
+
components={{
|
|
437
|
+
MonthCaption: monthCaption,
|
|
438
|
+
...components,
|
|
439
|
+
}}
|
|
440
|
+
{...props}
|
|
441
|
+
/>
|
|
442
|
+
</div>
|
|
443
|
+
{monthGridEnabled && showMonthGrid ? (
|
|
444
|
+
<MonthGrid
|
|
445
|
+
initialYear={displayMonth.getFullYear()}
|
|
446
|
+
selectedMonth={displayMonth}
|
|
447
|
+
locale={locale as Locale | undefined}
|
|
448
|
+
onSelectMonth={handleSelectMonth}
|
|
449
|
+
onClose={() => setShowMonthGrid(false)}
|
|
450
|
+
onRestoreFocus={restoreDayViewFocus}
|
|
451
|
+
/>
|
|
452
|
+
) : null}
|
|
372
453
|
</div>
|
|
373
|
-
|
|
374
|
-
<MonthGrid
|
|
375
|
-
initialYear={displayMonth.getFullYear()}
|
|
376
|
-
selectedMonth={displayMonth}
|
|
377
|
-
locale={locale as Locale | undefined}
|
|
378
|
-
onSelectMonth={handleSelectMonth}
|
|
379
|
-
onClose={() => setShowMonthGrid(false)}
|
|
380
|
-
/>
|
|
381
|
-
) : null}
|
|
382
|
-
</div>
|
|
454
|
+
</CalendarLabelsContext.Provider>
|
|
383
455
|
)
|
|
384
456
|
}
|