@arcfusionz/arc-primitive-ui 0.1.0 → 0.2.1
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/dist/components/AILoader/AILoader.d.ts +32 -0
- package/dist/components/AILoader/AILoader.js +157 -0
- package/dist/components/AILoader/index.d.ts +2 -0
- package/dist/components/AILoader/index.js +2 -0
- package/dist/components/Accordion/Accordion.d.ts +96 -0
- package/dist/components/Accordion/Accordion.js +149 -0
- package/dist/components/Accordion/index.d.ts +2 -0
- package/dist/components/Accordion/index.js +2 -0
- package/dist/components/Avatar/Avatar.d.ts +152 -0
- package/dist/components/Avatar/Avatar.js +216 -0
- package/dist/components/Avatar/index.d.ts +2 -0
- package/dist/components/Avatar/index.js +2 -0
- package/dist/components/Badge/Badge.d.ts +87 -0
- package/dist/components/Badge/Badge.js +118 -0
- package/dist/components/Badge/index.d.ts +2 -0
- package/dist/components/Badge/index.js +2 -0
- package/dist/components/Breadcrumb/Breadcrumb.d.ts +109 -0
- package/dist/components/Breadcrumb/Breadcrumb.js +182 -0
- package/dist/components/Breadcrumb/index.d.ts +2 -0
- package/dist/components/Breadcrumb/index.js +2 -0
- package/dist/components/Button/Button.d.ts +57 -0
- package/dist/components/Button/Button.js +177 -0
- package/dist/components/Button/index.d.ts +2 -0
- package/dist/components/Button/index.js +2 -0
- package/dist/components/Calendar/Calendar.d.ts +140 -0
- package/dist/components/Calendar/Calendar.js +468 -0
- package/dist/components/Calendar/index.d.ts +2 -0
- package/dist/components/Calendar/index.js +2 -0
- package/dist/components/Checkbox/Checkbox.d.ts +60 -0
- package/dist/components/Checkbox/Checkbox.js +129 -0
- package/dist/components/Checkbox/index.d.ts +2 -0
- package/dist/components/Checkbox/index.js +2 -0
- package/dist/components/Combobox/Combobox.d.ts +251 -0
- package/dist/components/Combobox/Combobox.js +354 -0
- package/dist/components/Combobox/index.d.ts +2 -0
- package/dist/components/Combobox/index.js +2 -0
- package/dist/components/ContextMenu/ContextMenu.d.ts +129 -0
- package/dist/components/ContextMenu/ContextMenu.js +93 -0
- package/dist/components/ContextMenu/index.d.ts +2 -0
- package/dist/components/ContextMenu/index.js +2 -0
- package/dist/components/DatePicker/DatePicker.d.ts +109 -0
- package/dist/components/DatePicker/DatePicker.js +145 -0
- package/dist/components/DatePicker/index.d.ts +2 -0
- package/dist/components/DatePicker/index.js +2 -0
- package/dist/components/DateRangePicker/DateRangePicker.d.ts +107 -0
- package/dist/components/DateRangePicker/DateRangePicker.js +161 -0
- package/dist/components/DateRangePicker/index.d.ts +2 -0
- package/dist/components/DateRangePicker/index.js +2 -0
- package/dist/components/Dialog/Dialog.d.ts +112 -0
- package/dist/components/Dialog/Dialog.js +141 -0
- package/dist/components/Dialog/index.d.ts +2 -0
- package/dist/components/Dialog/index.js +2 -0
- package/dist/components/Drawer/Drawer.d.ts +188 -0
- package/dist/components/Drawer/Drawer.js +268 -0
- package/dist/components/Drawer/index.d.ts +2 -0
- package/dist/components/Drawer/index.js +2 -0
- package/dist/components/Field/Field.d.ts +123 -0
- package/dist/components/Field/Field.js +241 -0
- package/dist/components/Field/FieldContext.d.ts +43 -0
- package/dist/components/Field/FieldContext.js +28 -0
- package/dist/components/Field/index.d.ts +3 -0
- package/dist/components/Field/index.js +3 -0
- package/dist/components/Fieldset/Fieldset.d.ts +43 -0
- package/dist/components/Fieldset/Fieldset.js +48 -0
- package/dist/components/Fieldset/index.d.ts +2 -0
- package/dist/components/Fieldset/index.js +2 -0
- package/dist/components/Form/Form.d.ts +54 -0
- package/dist/components/Form/Form.js +57 -0
- package/dist/components/Form/index.d.ts +2 -0
- package/dist/components/Form/index.js +2 -0
- package/dist/components/Input/Input.d.ts +64 -0
- package/dist/components/Input/Input.js +111 -0
- package/dist/components/Input/index.d.ts +2 -0
- package/dist/components/Input/index.js +2 -0
- package/dist/components/Menu/Menu.d.ts +212 -0
- package/dist/components/Menu/Menu.js +255 -0
- package/dist/components/Menu/index.d.ts +2 -0
- package/dist/components/Menu/index.js +2 -0
- package/dist/components/Popover/Popover.d.ts +122 -0
- package/dist/components/Popover/Popover.js +116 -0
- package/dist/components/Popover/index.d.ts +2 -0
- package/dist/components/Popover/index.js +2 -0
- package/dist/components/Progress/Progress.d.ts +87 -0
- package/dist/components/Progress/Progress.js +73 -0
- package/dist/components/Progress/index.d.ts +2 -0
- package/dist/components/Progress/index.js +2 -0
- package/dist/components/Radio/Radio.d.ts +65 -0
- package/dist/components/Radio/Radio.js +93 -0
- package/dist/components/Radio/index.d.ts +2 -0
- package/dist/components/Radio/index.js +2 -0
- package/dist/components/Select/Select.d.ts +136 -0
- package/dist/components/Select/Select.js +219 -0
- package/dist/components/Select/index.d.ts +2 -0
- package/dist/components/Select/index.js +2 -0
- package/dist/components/Skeleton/Skeleton.d.ts +39 -0
- package/dist/components/Skeleton/Skeleton.js +44 -0
- package/dist/components/Skeleton/index.d.ts +2 -0
- package/dist/components/Skeleton/index.js +2 -0
- package/dist/components/Stepper/Stepper.d.ts +161 -0
- package/dist/components/Stepper/Stepper.js +344 -0
- package/dist/components/Stepper/index.d.ts +2 -0
- package/dist/components/Stepper/index.js +2 -0
- package/dist/components/Switch/Switch.d.ts +56 -0
- package/dist/components/Switch/Switch.js +87 -0
- package/dist/components/Switch/index.d.ts +2 -0
- package/dist/components/Switch/index.js +2 -0
- package/dist/components/Table/Table.d.ts +116 -0
- package/dist/components/Table/Table.js +143 -0
- package/dist/components/Table/index.d.ts +2 -0
- package/dist/components/Table/index.js +2 -0
- package/dist/components/Tabs/Tabs.d.ts +116 -0
- package/dist/components/Tabs/Tabs.js +158 -0
- package/dist/components/Tabs/index.d.ts +2 -0
- package/dist/components/Tabs/index.js +2 -0
- package/dist/components/Timeline/Timeline.d.ts +137 -0
- package/dist/components/Timeline/Timeline.js +243 -0
- package/dist/components/Timeline/index.d.ts +2 -0
- package/dist/components/Timeline/index.js +2 -0
- package/dist/components/Toast/Toast.d.ts +135 -0
- package/dist/components/Toast/Toast.js +314 -0
- package/dist/components/Toast/index.d.ts +2 -0
- package/dist/components/Toast/index.js +2 -0
- package/dist/components/Tooltip/Tooltip.d.ts +104 -0
- package/dist/components/Tooltip/Tooltip.js +95 -0
- package/dist/components/Tooltip/index.d.ts +2 -0
- package/dist/components/Tooltip/index.js +2 -0
- package/dist/components/Typography/Typography.d.ts +38 -0
- package/dist/components/Typography/Typography.js +53 -0
- package/dist/components/Typography/index.d.ts +2 -0
- package/dist/components/Typography/index.js +2 -0
- package/dist/index.d.ts +66 -3398
- package/dist/index.js +34 -5343
- package/dist/lib/cn.d.ts +6 -0
- package/dist/lib/cn.js +9 -0
- package/package.json +6 -2
|
@@ -0,0 +1,468 @@
|
|
|
1
|
+
import { cn } from "../../lib/cn.js";
|
|
2
|
+
import { forwardRef, useEffect, useMemo, useRef, useState } from "react";
|
|
3
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
4
|
+
import { useRender } from "@base-ui/react/use-render";
|
|
5
|
+
import { mergeProps } from "@base-ui/react/merge-props";
|
|
6
|
+
//#region src/components/Calendar/Calendar.tsx
|
|
7
|
+
function isSameDay(a, b) {
|
|
8
|
+
return !!a && !!b && a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();
|
|
9
|
+
}
|
|
10
|
+
/** Day-precision comparator; ignores time-of-day. */
|
|
11
|
+
function compareDays(a, b) {
|
|
12
|
+
return a.getFullYear() - b.getFullYear() || a.getMonth() - b.getMonth() || a.getDate() - b.getDate();
|
|
13
|
+
}
|
|
14
|
+
function isSameMonth(a, b) {
|
|
15
|
+
return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth();
|
|
16
|
+
}
|
|
17
|
+
function toDayStart(date) {
|
|
18
|
+
return new Date(date.getFullYear(), date.getMonth(), date.getDate());
|
|
19
|
+
}
|
|
20
|
+
function startOfMonth(date) {
|
|
21
|
+
return new Date(date.getFullYear(), date.getMonth(), 1);
|
|
22
|
+
}
|
|
23
|
+
function addDays(date, amount) {
|
|
24
|
+
return new Date(date.getFullYear(), date.getMonth(), date.getDate() + amount);
|
|
25
|
+
}
|
|
26
|
+
function daysInMonth(year, monthIndex) {
|
|
27
|
+
return new Date(year, monthIndex + 1, 0).getDate();
|
|
28
|
+
}
|
|
29
|
+
/** Month arithmetic that clamps the day-of-month (Jan 31 + 1 month = Feb 28/29). */
|
|
30
|
+
function addMonths(date, amount) {
|
|
31
|
+
const year = date.getFullYear();
|
|
32
|
+
const month = date.getMonth() + amount;
|
|
33
|
+
const target = new Date(year, month, 1);
|
|
34
|
+
return new Date(target.getFullYear(), target.getMonth(), Math.min(date.getDate(), daysInMonth(target.getFullYear(), target.getMonth())));
|
|
35
|
+
}
|
|
36
|
+
function dayKey(date) {
|
|
37
|
+
return `${date.getFullYear()}-${date.getMonth()}-${date.getDate()}`;
|
|
38
|
+
}
|
|
39
|
+
function orderRange(a, b) {
|
|
40
|
+
return compareDays(a, b) <= 0 ? {
|
|
41
|
+
start: a,
|
|
42
|
+
end: b
|
|
43
|
+
} : {
|
|
44
|
+
start: b,
|
|
45
|
+
end: a
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
/** A Sunday, used to render weekday names for any `weekStartsOn`. */
|
|
49
|
+
const REFERENCE_SUNDAY = new Date(2026, 0, 4);
|
|
50
|
+
function buildWeeks(month, weekStartsOn, fixedWeeks) {
|
|
51
|
+
const first = startOfMonth(month);
|
|
52
|
+
const lead = (first.getDay() - weekStartsOn + 7) % 7;
|
|
53
|
+
const gridStart = addDays(first, -lead);
|
|
54
|
+
const total = lead + daysInMonth(month.getFullYear(), month.getMonth());
|
|
55
|
+
const weekCount = fixedWeeks ? 6 : Math.ceil(total / 7);
|
|
56
|
+
return Array.from({ length: weekCount }, (_, week) => Array.from({ length: 7 }, (_, day) => addDays(gridStart, week * 7 + day)));
|
|
57
|
+
}
|
|
58
|
+
/** First day of week for a BCP-47 locale (0 = Sunday), when the runtime knows it. */
|
|
59
|
+
function localeWeekStart(locale) {
|
|
60
|
+
try {
|
|
61
|
+
const asAny = new Intl.Locale(locale ?? new Intl.DateTimeFormat().resolvedOptions().locale);
|
|
62
|
+
const firstDay = (asAny.getWeekInfo?.() ?? asAny.weekInfo)?.firstDay;
|
|
63
|
+
if (typeof firstDay === "number") return firstDay % 7;
|
|
64
|
+
} catch {}
|
|
65
|
+
return 0;
|
|
66
|
+
}
|
|
67
|
+
function createFormatter(locale, options) {
|
|
68
|
+
try {
|
|
69
|
+
return new Intl.DateTimeFormat(locale, options);
|
|
70
|
+
} catch {
|
|
71
|
+
return new Intl.DateTimeFormat(void 0, options);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
/** Minimal controllable-state pair: `undefined` = uncontrolled, `null` = controlled-empty. */
|
|
75
|
+
function useControlled(controlled, initial) {
|
|
76
|
+
const [internal, setInternal] = useState(initial);
|
|
77
|
+
return [controlled !== void 0 ? controlled : internal, setInternal];
|
|
78
|
+
}
|
|
79
|
+
const dayButtonClasses = "relative inline-flex size-9 cursor-pointer select-none items-center justify-center rounded-full font-sans text-sm text-foreground duration-150 hover:bg-muted active:bg-slate-200 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring disabled:pointer-events-none disabled:opacity-50 data-today:border data-today:border-primary-500 data-outside:text-muted-foreground data-hidden:invisible data-unavailable:cursor-default data-unavailable:text-muted-foreground data-unavailable:line-through data-unavailable:hover:bg-transparent data-unavailable:active:bg-transparent data-selected:bg-primary data-selected:text-primary-foreground data-selected:hover:bg-primary-700 data-selected:active:bg-primary-800 data-range-middle:rounded-none data-range-middle:bg-primary-100 data-range-middle:text-foreground data-range-middle:data-today:rounded-full data-range-middle:hover:bg-primary-200 data-range-middle:active:bg-primary-200";
|
|
80
|
+
const navButtonClasses = "inline-flex size-9 cursor-pointer items-center justify-center rounded-md text-foreground transition-colors duration-150 hover:bg-muted active:bg-slate-200 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4";
|
|
81
|
+
const captionClasses = "font-sans text-sm font-semibold text-foreground";
|
|
82
|
+
const weekdayClasses = "size-9 p-0 text-center align-middle font-sans text-xs font-medium text-muted-foreground";
|
|
83
|
+
function ChevronLeftIcon(props) {
|
|
84
|
+
return /* @__PURE__ */ jsx("svg", {
|
|
85
|
+
viewBox: "0 0 24 24",
|
|
86
|
+
fill: "none",
|
|
87
|
+
stroke: "currentColor",
|
|
88
|
+
strokeWidth: 2,
|
|
89
|
+
strokeLinecap: "round",
|
|
90
|
+
strokeLinejoin: "round",
|
|
91
|
+
"aria-hidden": "true",
|
|
92
|
+
...props,
|
|
93
|
+
children: /* @__PURE__ */ jsx("path", { d: "m15 18-6-6 6-6" })
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
function ChevronRightIcon(props) {
|
|
97
|
+
return /* @__PURE__ */ jsx("svg", {
|
|
98
|
+
viewBox: "0 0 24 24",
|
|
99
|
+
fill: "none",
|
|
100
|
+
stroke: "currentColor",
|
|
101
|
+
strokeWidth: 2,
|
|
102
|
+
strokeLinecap: "round",
|
|
103
|
+
strokeLinejoin: "round",
|
|
104
|
+
"aria-hidden": "true",
|
|
105
|
+
...props,
|
|
106
|
+
children: /* @__PURE__ */ jsx("path", { d: "m9 18 6-6-6-6" })
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
const Calendar = forwardRef((props, forwardedRef) => {
|
|
110
|
+
const { mode = "single", value: valueProp, defaultValue, onValueChange, allowDeselect = false, month: monthProp, defaultMonth, onMonthChange, numberOfMonths: numberOfMonthsProp = 1, minDate, maxDate, isDateUnavailable, disabled = false, readOnly = false, locale, weekStartsOn: weekStartsOnProp, showOutsideDays = true, fixedWeeks = false, today: todayProp, autoFocus = false, previousMonthLabel = "Previous month", nextMonthLabel = "Next month", "aria-label": ariaLabel, className, render, ...rest } = props;
|
|
111
|
+
const numberOfMonths = Math.max(1, Math.floor(numberOfMonthsProp));
|
|
112
|
+
const weekStartsOn = weekStartsOnProp ?? localeWeekStart(locale);
|
|
113
|
+
const [fallbackToday] = useState(() => toDayStart(/* @__PURE__ */ new Date()));
|
|
114
|
+
const today = todayProp ? toDayStart(todayProp) : fallbackToday;
|
|
115
|
+
const minDay = minDate ? toDayStart(minDate) : null;
|
|
116
|
+
const maxDay = maxDate ? toDayStart(maxDate) : null;
|
|
117
|
+
const [rawValue, setRawValue] = useControlled(valueProp, defaultValue ?? (mode === "multiple" ? [] : null));
|
|
118
|
+
const singleValue = mode === "single" && rawValue ? rawValue : null;
|
|
119
|
+
const multipleValue = useMemo(() => mode === "multiple" && Array.isArray(rawValue) ? rawValue : [], [mode, rawValue]);
|
|
120
|
+
const committedRange = mode === "range" && rawValue ? rawValue : null;
|
|
121
|
+
const [anchor, setAnchor] = useState(null);
|
|
122
|
+
const [previewDate, setPreviewDate] = useState(null);
|
|
123
|
+
const displayRange = anchor ? orderRange(anchor, previewDate ?? anchor) : committedRange ? orderRange(committedRange.start, committedRange.end) : null;
|
|
124
|
+
const firstSelected = mode === "single" ? singleValue : mode === "multiple" ? multipleValue[0] ?? null : committedRange?.start ?? null;
|
|
125
|
+
const initialMonth = () => startOfMonth(defaultMonth ?? firstSelected ?? today);
|
|
126
|
+
const [firstMonthRaw, setFirstMonthState] = useControlled(monthProp ? startOfMonth(monthProp) : void 0, initialMonth());
|
|
127
|
+
const firstMonth = startOfMonth(firstMonthRaw);
|
|
128
|
+
const visibleMonths = useMemo(() => Array.from({ length: numberOfMonths }, (_, i) => addMonths(firstMonth, i)), [firstMonth, numberOfMonths]);
|
|
129
|
+
const lastMonth = visibleMonths[visibleMonths.length - 1];
|
|
130
|
+
const [focusedDate, setFocusedDate] = useState(null);
|
|
131
|
+
const [announcement, setAnnouncement] = useState("");
|
|
132
|
+
const dayRefs = useRef(/* @__PURE__ */ new Map());
|
|
133
|
+
const shouldFocusRef = useRef(false);
|
|
134
|
+
const pagedDayRef = useRef(null);
|
|
135
|
+
const navRescueRef = useRef(null);
|
|
136
|
+
const formatters = useMemo(() => ({
|
|
137
|
+
caption: createFormatter(locale, {
|
|
138
|
+
month: "long",
|
|
139
|
+
year: "numeric"
|
|
140
|
+
}),
|
|
141
|
+
weekday: createFormatter(locale, { weekday: "short" }),
|
|
142
|
+
day: createFormatter(locale, { day: "numeric" }),
|
|
143
|
+
dayLabel: createFormatter(locale, {
|
|
144
|
+
weekday: "long",
|
|
145
|
+
day: "numeric",
|
|
146
|
+
month: "long",
|
|
147
|
+
year: "numeric"
|
|
148
|
+
})
|
|
149
|
+
}), [locale]);
|
|
150
|
+
const weekdayLabels = useMemo(() => Array.from({ length: 7 }, (_, i) => formatters.weekday.format(addDays(REFERENCE_SUNDAY, weekStartsOn + i))), [formatters, weekStartsOn]);
|
|
151
|
+
const isOutOfBounds = (day) => minDay !== null && compareDays(day, minDay) < 0 || maxDay !== null && compareDays(day, maxDay) > 0;
|
|
152
|
+
const clampToBounds = (day) => {
|
|
153
|
+
if (minDay && compareDays(day, minDay) < 0) return minDay;
|
|
154
|
+
if (maxDay && compareDays(day, maxDay) > 0) return maxDay;
|
|
155
|
+
return day;
|
|
156
|
+
};
|
|
157
|
+
const contiguousBounds = useMemo(() => {
|
|
158
|
+
if (mode !== "range" || !anchor || !isDateUnavailable) return null;
|
|
159
|
+
const SCAN_LIMIT = 400;
|
|
160
|
+
let low = anchor;
|
|
161
|
+
for (let i = 0; i < SCAN_LIMIT; i++) {
|
|
162
|
+
const previous = addDays(low, -1);
|
|
163
|
+
if (minDay && compareDays(previous, minDay) < 0 || isDateUnavailable(previous)) break;
|
|
164
|
+
low = previous;
|
|
165
|
+
}
|
|
166
|
+
let high = anchor;
|
|
167
|
+
for (let i = 0; i < SCAN_LIMIT; i++) {
|
|
168
|
+
const next = addDays(high, 1);
|
|
169
|
+
if (maxDay && compareDays(next, maxDay) > 0 || isDateUnavailable(next)) break;
|
|
170
|
+
high = next;
|
|
171
|
+
}
|
|
172
|
+
return {
|
|
173
|
+
low,
|
|
174
|
+
high
|
|
175
|
+
};
|
|
176
|
+
}, [
|
|
177
|
+
mode,
|
|
178
|
+
anchor,
|
|
179
|
+
isDateUnavailable,
|
|
180
|
+
minDay,
|
|
181
|
+
maxDay
|
|
182
|
+
]);
|
|
183
|
+
const isUnavailable = (day) => isDateUnavailable?.(day) === true || contiguousBounds !== null && (compareDays(day, contiguousBounds.low) < 0 || compareDays(day, contiguousBounds.high) > 0);
|
|
184
|
+
const focusTarget = useMemo(() => {
|
|
185
|
+
const visible = (day) => day !== null && visibleMonths.some((m) => isSameMonth(m, day)) && !isOutOfBounds(day);
|
|
186
|
+
if (visible(focusedDate)) return focusedDate;
|
|
187
|
+
if (mode === "range" && visible(anchor)) return anchor;
|
|
188
|
+
if (visible(firstSelected)) return firstSelected;
|
|
189
|
+
if (visible(today)) return today;
|
|
190
|
+
const first = visibleMonths[0];
|
|
191
|
+
return minDay && compareDays(minDay, first) > 0 ? minDay : first;
|
|
192
|
+
}, [
|
|
193
|
+
focusedDate,
|
|
194
|
+
anchor,
|
|
195
|
+
firstSelected,
|
|
196
|
+
today,
|
|
197
|
+
visibleMonths,
|
|
198
|
+
minDay,
|
|
199
|
+
maxDay,
|
|
200
|
+
mode
|
|
201
|
+
]);
|
|
202
|
+
const commitValue = (next) => {
|
|
203
|
+
setRawValue(next);
|
|
204
|
+
onValueChange?.(next);
|
|
205
|
+
};
|
|
206
|
+
const setMonthWindow = (next) => {
|
|
207
|
+
let clamped = startOfMonth(next);
|
|
208
|
+
if (maxDay) {
|
|
209
|
+
const maxMonth = startOfMonth(maxDay);
|
|
210
|
+
if (compareDays(addMonths(clamped, numberOfMonths - 1), maxMonth) > 0) clamped = addMonths(maxMonth, -(numberOfMonths - 1));
|
|
211
|
+
}
|
|
212
|
+
if (minDay) {
|
|
213
|
+
const minMonth = startOfMonth(minDay);
|
|
214
|
+
if (compareDays(clamped, minMonth) < 0) clamped = minMonth;
|
|
215
|
+
}
|
|
216
|
+
if (!isSameMonth(clamped, firstMonth)) {
|
|
217
|
+
setFirstMonthState(clamped);
|
|
218
|
+
onMonthChange?.(clamped);
|
|
219
|
+
}
|
|
220
|
+
return clamped;
|
|
221
|
+
};
|
|
222
|
+
/** Move the roving focus to a day, shifting the visible window if needed. */
|
|
223
|
+
const focusDay = (target) => {
|
|
224
|
+
const day = clampToBounds(target);
|
|
225
|
+
const monthsFromFirst = (day.getFullYear() - firstMonth.getFullYear()) * 12 + (day.getMonth() - firstMonth.getMonth());
|
|
226
|
+
if (monthsFromFirst < 0) setMonthWindow(day);
|
|
227
|
+
else if (monthsFromFirst >= numberOfMonths) setMonthWindow(addMonths(startOfMonth(day), -(numberOfMonths - 1)));
|
|
228
|
+
shouldFocusRef.current = true;
|
|
229
|
+
setFocusedDate(day);
|
|
230
|
+
if (anchor) setPreviewDate(day);
|
|
231
|
+
};
|
|
232
|
+
const handleDaySelect = (day) => {
|
|
233
|
+
if (disabled || readOnly || isUnavailable(day)) return;
|
|
234
|
+
pagedDayRef.current = null;
|
|
235
|
+
if (mode === "single") {
|
|
236
|
+
if (allowDeselect && isSameDay(singleValue, day)) commitValue(null);
|
|
237
|
+
else commitValue(day);
|
|
238
|
+
setFocusedDate(day);
|
|
239
|
+
} else if (mode === "multiple") {
|
|
240
|
+
const next = multipleValue.some((d) => isSameDay(d, day)) ? multipleValue.filter((d) => !isSameDay(d, day)) : [...multipleValue, day].sort(compareDays);
|
|
241
|
+
commitValue(next);
|
|
242
|
+
setFocusedDate(day);
|
|
243
|
+
} else if (!anchor) {
|
|
244
|
+
setAnchor(day);
|
|
245
|
+
setPreviewDate(day);
|
|
246
|
+
focusDay(addDays(day, 1));
|
|
247
|
+
} else {
|
|
248
|
+
commitValue(orderRange(anchor, day));
|
|
249
|
+
setAnchor(null);
|
|
250
|
+
setPreviewDate(null);
|
|
251
|
+
setFocusedDate(day);
|
|
252
|
+
}
|
|
253
|
+
};
|
|
254
|
+
const handleGridKeyDown = (event) => {
|
|
255
|
+
if (disabled) return;
|
|
256
|
+
if (event.key === "Escape") {
|
|
257
|
+
if (mode === "range" && anchor) {
|
|
258
|
+
setAnchor(null);
|
|
259
|
+
setPreviewDate(null);
|
|
260
|
+
event.preventDefault();
|
|
261
|
+
event.stopPropagation();
|
|
262
|
+
}
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
const focused = focusTarget;
|
|
266
|
+
const weekOffset = (focused.getDay() - weekStartsOn + 7) % 7;
|
|
267
|
+
let next = null;
|
|
268
|
+
let paging = false;
|
|
269
|
+
switch (event.key) {
|
|
270
|
+
case "ArrowRight":
|
|
271
|
+
case "ArrowLeft": {
|
|
272
|
+
const rtl = getComputedStyle(event.currentTarget).direction === "rtl";
|
|
273
|
+
next = addDays(focused, event.key === "ArrowRight" !== rtl ? 1 : -1);
|
|
274
|
+
break;
|
|
275
|
+
}
|
|
276
|
+
case "ArrowDown":
|
|
277
|
+
next = addDays(focused, 7);
|
|
278
|
+
break;
|
|
279
|
+
case "ArrowUp":
|
|
280
|
+
next = addDays(focused, -7);
|
|
281
|
+
break;
|
|
282
|
+
case "Home":
|
|
283
|
+
next = addDays(focused, -weekOffset);
|
|
284
|
+
break;
|
|
285
|
+
case "End":
|
|
286
|
+
next = addDays(focused, 6 - weekOffset);
|
|
287
|
+
break;
|
|
288
|
+
case "PageUp":
|
|
289
|
+
case "PageDown": {
|
|
290
|
+
const monthDelta = (event.key === "PageDown" ? 1 : -1) * (event.shiftKey ? 12 : numberOfMonths);
|
|
291
|
+
pagedDayRef.current ??= focused.getDate();
|
|
292
|
+
const targetMonth = addMonths(startOfMonth(focused), monthDelta);
|
|
293
|
+
next = new Date(targetMonth.getFullYear(), targetMonth.getMonth(), Math.min(pagedDayRef.current, daysInMonth(targetMonth.getFullYear(), targetMonth.getMonth())));
|
|
294
|
+
paging = true;
|
|
295
|
+
break;
|
|
296
|
+
}
|
|
297
|
+
default: return;
|
|
298
|
+
}
|
|
299
|
+
event.preventDefault();
|
|
300
|
+
if (!paging) pagedDayRef.current = null;
|
|
301
|
+
focusDay(next);
|
|
302
|
+
};
|
|
303
|
+
const previousDisabled = disabled || minDay !== null && compareDays(firstMonth, startOfMonth(minDay)) <= 0;
|
|
304
|
+
const nextDisabled = disabled || maxDay !== null && compareDays(lastMonth, startOfMonth(maxDay)) >= 0;
|
|
305
|
+
const handleNavigate = (direction) => {
|
|
306
|
+
navRescueRef.current = direction === -1 ? "previous" : "next";
|
|
307
|
+
const landed = setMonthWindow(addMonths(firstMonth, direction * numberOfMonths));
|
|
308
|
+
const from = formatters.caption.format(landed);
|
|
309
|
+
const to = formatters.caption.format(addMonths(landed, numberOfMonths - 1));
|
|
310
|
+
setAnnouncement(numberOfMonths > 1 ? `${from} – ${to}` : from);
|
|
311
|
+
};
|
|
312
|
+
useEffect(() => {
|
|
313
|
+
if (shouldFocusRef.current && focusedDate) {
|
|
314
|
+
shouldFocusRef.current = false;
|
|
315
|
+
dayRefs.current.get(dayKey(focusedDate))?.focus();
|
|
316
|
+
}
|
|
317
|
+
}, [focusedDate]);
|
|
318
|
+
useEffect(() => {
|
|
319
|
+
if (!navRescueRef.current) return;
|
|
320
|
+
const which = navRescueRef.current;
|
|
321
|
+
navRescueRef.current = null;
|
|
322
|
+
if (which === "previous" && previousDisabled || which === "next" && nextDisabled) dayRefs.current.get(dayKey(focusTarget))?.focus();
|
|
323
|
+
});
|
|
324
|
+
useEffect(() => {
|
|
325
|
+
if (autoFocus) dayRefs.current.get(dayKey(focusTarget))?.focus();
|
|
326
|
+
}, []);
|
|
327
|
+
const renderDay = (day, month) => {
|
|
328
|
+
const key = dayKey(day);
|
|
329
|
+
const outside = !isSameMonth(day, month);
|
|
330
|
+
const duplicate = outside && visibleMonths.some((m) => isSameMonth(m, day));
|
|
331
|
+
const hidden = outside && (!showOutsideDays || duplicate);
|
|
332
|
+
const hardDisabled = disabled || outside || isOutOfBounds(day);
|
|
333
|
+
const unavailable = !outside && !hardDisabled && isUnavailable(day);
|
|
334
|
+
const inRange = displayRange !== null && compareDays(day, displayRange.start) >= 0 && compareDays(day, displayRange.end) <= 0;
|
|
335
|
+
const rangeStart = mode === "range" && inRange && isSameDay(day, displayRange.start);
|
|
336
|
+
const rangeEnd = mode === "range" && inRange && isSameDay(day, displayRange.end);
|
|
337
|
+
const rangeMiddle = mode === "range" && inRange && !rangeStart && !rangeEnd;
|
|
338
|
+
const columnIndex = (day.getDay() - weekStartsOn + 7) % 7;
|
|
339
|
+
const rangeConnectorClass = !outside && rangeStart && !rangeEnd && columnIndex < 6 ? "end-0" : !outside && rangeEnd && !rangeStart && columnIndex > 0 ? "start-0" : null;
|
|
340
|
+
const selected = mode === "single" ? isSameDay(singleValue, day) : mode === "multiple" ? multipleValue.some((d) => isSameDay(d, day)) : rangeStart || rangeEnd;
|
|
341
|
+
const ariaSelected = mode === "range" ? inRange : selected;
|
|
342
|
+
const dataAttributes = {};
|
|
343
|
+
if (selected) dataAttributes["data-selected"] = "";
|
|
344
|
+
if (rangeMiddle) dataAttributes["data-range-middle"] = "";
|
|
345
|
+
if (rangeStart) dataAttributes["data-range-start"] = "";
|
|
346
|
+
if (rangeEnd) dataAttributes["data-range-end"] = "";
|
|
347
|
+
if (isSameDay(today, day)) dataAttributes["data-today"] = "";
|
|
348
|
+
if (outside) dataAttributes["data-outside"] = "";
|
|
349
|
+
if (hidden) dataAttributes["data-hidden"] = "";
|
|
350
|
+
if (unavailable) dataAttributes["data-unavailable"] = "";
|
|
351
|
+
if (hardDisabled) dataAttributes["data-disabled"] = "";
|
|
352
|
+
return /* @__PURE__ */ jsxs("td", {
|
|
353
|
+
role: "gridcell",
|
|
354
|
+
"aria-selected": !outside && ariaSelected ? true : void 0,
|
|
355
|
+
"aria-hidden": outside || void 0,
|
|
356
|
+
className: cn("relative p-0", !outside && rangeMiddle && "bg-primary-100"),
|
|
357
|
+
children: [rangeConnectorClass && /* @__PURE__ */ jsx("span", {
|
|
358
|
+
"aria-hidden": "true",
|
|
359
|
+
className: cn("pointer-events-none absolute inset-y-0 w-1/2 bg-primary-100", rangeConnectorClass)
|
|
360
|
+
}), /* @__PURE__ */ jsx("button", {
|
|
361
|
+
ref: (node) => {
|
|
362
|
+
if (node) dayRefs.current.set(key, node);
|
|
363
|
+
else dayRefs.current.delete(key);
|
|
364
|
+
},
|
|
365
|
+
type: "button",
|
|
366
|
+
tabIndex: !outside && isSameDay(day, focusTarget) ? 0 : -1,
|
|
367
|
+
disabled: hardDisabled || void 0,
|
|
368
|
+
"aria-disabled": unavailable || void 0,
|
|
369
|
+
"aria-label": formatters.dayLabel.format(day),
|
|
370
|
+
"aria-current": isSameDay(today, day) ? "date" : void 0,
|
|
371
|
+
onClick: () => handleDaySelect(day),
|
|
372
|
+
onFocus: () => {
|
|
373
|
+
if (!isSameDay(focusedDate, day)) setFocusedDate(day);
|
|
374
|
+
if (anchor) setPreviewDate(day);
|
|
375
|
+
},
|
|
376
|
+
onPointerEnter: anchor ? () => setPreviewDate(day) : void 0,
|
|
377
|
+
className: cn(dayButtonClasses, mode === "range" ? "transition-[color,border-color]" : "transition-colors", readOnly && "pointer-events-none"),
|
|
378
|
+
...dataAttributes,
|
|
379
|
+
children: formatters.day.format(day)
|
|
380
|
+
})]
|
|
381
|
+
}, key);
|
|
382
|
+
};
|
|
383
|
+
const renderMonth = (month, index) => {
|
|
384
|
+
const caption = formatters.caption.format(month);
|
|
385
|
+
const spacer = /* @__PURE__ */ jsx("span", {
|
|
386
|
+
"aria-hidden": "true",
|
|
387
|
+
className: "size-9"
|
|
388
|
+
});
|
|
389
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
390
|
+
className: "flex flex-col gap-3",
|
|
391
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
392
|
+
className: "flex items-center justify-between gap-2",
|
|
393
|
+
children: [
|
|
394
|
+
index === 0 ? /* @__PURE__ */ jsx("button", {
|
|
395
|
+
type: "button",
|
|
396
|
+
"aria-label": previousMonthLabel,
|
|
397
|
+
disabled: previousDisabled || void 0,
|
|
398
|
+
onClick: () => handleNavigate(-1),
|
|
399
|
+
className: navButtonClasses,
|
|
400
|
+
children: /* @__PURE__ */ jsx(ChevronLeftIcon, { className: "rtl:-scale-x-100" })
|
|
401
|
+
}) : spacer,
|
|
402
|
+
/* @__PURE__ */ jsx("span", {
|
|
403
|
+
"aria-hidden": "true",
|
|
404
|
+
className: captionClasses,
|
|
405
|
+
children: caption
|
|
406
|
+
}),
|
|
407
|
+
index === numberOfMonths - 1 ? /* @__PURE__ */ jsx("button", {
|
|
408
|
+
type: "button",
|
|
409
|
+
"aria-label": nextMonthLabel,
|
|
410
|
+
disabled: nextDisabled || void 0,
|
|
411
|
+
onClick: () => handleNavigate(1),
|
|
412
|
+
className: navButtonClasses,
|
|
413
|
+
children: /* @__PURE__ */ jsx(ChevronRightIcon, { className: "rtl:-scale-x-100" })
|
|
414
|
+
}) : spacer
|
|
415
|
+
]
|
|
416
|
+
}), /* @__PURE__ */ jsxs("table", {
|
|
417
|
+
role: "grid",
|
|
418
|
+
"aria-label": ariaLabel ? `${ariaLabel}, ${caption}` : caption,
|
|
419
|
+
"aria-multiselectable": mode !== "single" || void 0,
|
|
420
|
+
"aria-readonly": readOnly || void 0,
|
|
421
|
+
"aria-disabled": disabled || void 0,
|
|
422
|
+
onKeyDown: handleGridKeyDown,
|
|
423
|
+
className: "border-collapse",
|
|
424
|
+
children: [/* @__PURE__ */ jsx("thead", {
|
|
425
|
+
"aria-hidden": "true",
|
|
426
|
+
children: /* @__PURE__ */ jsx("tr", { children: weekdayLabels.map((label, i) => /* @__PURE__ */ jsx("th", {
|
|
427
|
+
scope: "col",
|
|
428
|
+
className: weekdayClasses,
|
|
429
|
+
children: label
|
|
430
|
+
}, i)) })
|
|
431
|
+
}), /* @__PURE__ */ jsx("tbody", { children: buildWeeks(month, weekStartsOn, fixedWeeks).map((week, w) => /* @__PURE__ */ jsx("tr", { children: week.map((day) => renderDay(day, month)) }, w)) })]
|
|
432
|
+
})]
|
|
433
|
+
}, dayKey(month));
|
|
434
|
+
};
|
|
435
|
+
const state = {
|
|
436
|
+
mode,
|
|
437
|
+
disabled,
|
|
438
|
+
readOnly
|
|
439
|
+
};
|
|
440
|
+
const defaultProps = {
|
|
441
|
+
role: "group",
|
|
442
|
+
"aria-label": ariaLabel,
|
|
443
|
+
className: cn("inline-flex flex-col p-3 font-sans", className),
|
|
444
|
+
children: /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("span", {
|
|
445
|
+
role: "status",
|
|
446
|
+
className: "sr-only",
|
|
447
|
+
children: announcement
|
|
448
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
449
|
+
className: "flex flex-wrap items-start gap-8",
|
|
450
|
+
children: visibleMonths.map(renderMonth)
|
|
451
|
+
})] })
|
|
452
|
+
};
|
|
453
|
+
return useRender({
|
|
454
|
+
defaultTagName: "div",
|
|
455
|
+
render,
|
|
456
|
+
state,
|
|
457
|
+
stateAttributesMapping: {
|
|
458
|
+
mode: (value) => ({ "data-mode": value }),
|
|
459
|
+
disabled: (value) => value ? { "data-disabled": "" } : null,
|
|
460
|
+
readOnly: (value) => value ? { "data-readonly": "" } : null
|
|
461
|
+
},
|
|
462
|
+
ref: [forwardedRef],
|
|
463
|
+
props: mergeProps(defaultProps, rest)
|
|
464
|
+
});
|
|
465
|
+
});
|
|
466
|
+
Calendar.displayName = "Calendar";
|
|
467
|
+
//#endregion
|
|
468
|
+
export { Calendar };
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { ComponentPropsWithoutRef, ReactNode } from "react";
|
|
2
|
+
import { Checkbox } from "@base-ui/react/checkbox";
|
|
3
|
+
import { CheckboxGroup } from "@base-ui/react/checkbox-group";
|
|
4
|
+
//#region src/components/Checkbox/Checkbox.d.ts
|
|
5
|
+
type CheckboxSize = "sm" | "md" | "lg";
|
|
6
|
+
interface CheckboxVariantsOptions {
|
|
7
|
+
size?: CheckboxSize;
|
|
8
|
+
className?: string;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Class list for the checkbox box itself. State styling hangs off Base UI's
|
|
12
|
+
* data-attributes (`data-checked`, `data-indeterminate`, `data-disabled`,
|
|
13
|
+
* `data-readonly`, `data-invalid`) plus `aria-invalid`.
|
|
14
|
+
*/
|
|
15
|
+
declare function checkboxVariants({ size, className }?: CheckboxVariantsOptions): string;
|
|
16
|
+
interface CheckboxProps extends Omit<ComponentPropsWithoutRef<typeof Checkbox.Root>, "className"> {
|
|
17
|
+
/**
|
|
18
|
+
* Box size. The 24px `lg` box meets the WCAG 2.5.8 target-size floor on its
|
|
19
|
+
* own; `sm`/`md` rely on the clickable `label` (or surrounding spacing) to
|
|
20
|
+
* extend the target. Prefer `md`+ with a label on touch-first surfaces.
|
|
21
|
+
*/
|
|
22
|
+
size?: CheckboxSize;
|
|
23
|
+
/**
|
|
24
|
+
* Visible label rendered in an enclosing `<label>`, so clicking it toggles
|
|
25
|
+
* the checkbox and it names the control. Without it, provide an accessible
|
|
26
|
+
* name another way: `aria-label`, `aria-labelledby`, or an external
|
|
27
|
+
* `<label>`. When `required` is set, the label shows a decorative asterisk.
|
|
28
|
+
*/
|
|
29
|
+
label?: ReactNode;
|
|
30
|
+
/**
|
|
31
|
+
* Supporting copy below the label, linked via `aria-describedby`. Rendered
|
|
32
|
+
* outside the `<label>` element so screen readers announce it as the
|
|
33
|
+
* description instead of reading it into the accessible name.
|
|
34
|
+
*/
|
|
35
|
+
description?: ReactNode;
|
|
36
|
+
/** Applied to the checkbox box itself, also when `label`/`description` wrap it. */
|
|
37
|
+
className?: string;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Binary/mixed-state control built on Base UI's Checkbox. The indicator is
|
|
41
|
+
* built in: a check mark, or a minus while `indeterminate` — so a `parent`
|
|
42
|
+
* checkbox inside a controlled `CheckboxGroup` with `allValues` needs no
|
|
43
|
+
* extra wiring. `ref` and `className` always target the box element, whether
|
|
44
|
+
* or not the labelled layout wraps it.
|
|
45
|
+
*/
|
|
46
|
+
declare const Checkbox$1: import("react").ForwardRefExoticComponent<CheckboxProps & import("react").RefAttributes<HTMLSpanElement>>;
|
|
47
|
+
interface CheckboxGroupProps extends Omit<ComponentPropsWithoutRef<typeof CheckboxGroup>, "className"> {
|
|
48
|
+
className?: string;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Shares ticked-value state (`value`/`defaultValue`/`onValueChange`) across
|
|
52
|
+
* child checkboxes matched by their `value` prop, and drives a `parent`
|
|
53
|
+
* checkbox's indeterminate state when `allValues` is set. Lays the items out
|
|
54
|
+
* as a vertical stack — pass `className="flex-row"` for a horizontal row.
|
|
55
|
+
* The group needs an accessible name: `aria-labelledby` pointing at a caption,
|
|
56
|
+
* or `aria-label`.
|
|
57
|
+
*/
|
|
58
|
+
declare const CheckboxGroup$1: import("react").ForwardRefExoticComponent<CheckboxGroupProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
59
|
+
//#endregion
|
|
60
|
+
export { Checkbox$1 as Checkbox, CheckboxGroup$1 as CheckboxGroup, CheckboxGroupProps, CheckboxProps, CheckboxSize, CheckboxVariantsOptions, checkboxVariants };
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { cn } from "../../lib/cn.js";
|
|
2
|
+
import { forwardRef, useId } from "react";
|
|
3
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
4
|
+
import { Checkbox } from "@base-ui/react/checkbox";
|
|
5
|
+
import { CheckboxGroup } from "@base-ui/react/checkbox-group";
|
|
6
|
+
//#region src/components/Checkbox/Checkbox.tsx
|
|
7
|
+
const boxClasses = "inline-flex shrink-0 cursor-pointer select-none items-center justify-center rounded-md border border-border bg-background text-primary-foreground transition-colors duration-150 hover:border-slate-300 data-checked:border-primary data-checked:bg-primary data-indeterminate:border-primary data-indeterminate:bg-primary hover:data-checked:border-primary-700 hover:data-checked:bg-primary-700 hover:data-indeterminate:border-primary-700 hover:data-indeterminate:bg-primary-700 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring aria-invalid:border-destructive data-invalid:border-destructive aria-invalid:focus-visible:outline-destructive data-invalid:focus-visible:outline-destructive data-readonly:cursor-default disabled:pointer-events-none disabled:opacity-50 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0";
|
|
8
|
+
const boxSizeClasses = {
|
|
9
|
+
sm: "size-4 [&_svg]:size-3",
|
|
10
|
+
md: "size-5 [&_svg]:size-3.5",
|
|
11
|
+
lg: "size-6 [&_svg]:size-4"
|
|
12
|
+
};
|
|
13
|
+
const boxOffsetClasses = {
|
|
14
|
+
sm: "mt-0.5",
|
|
15
|
+
md: "",
|
|
16
|
+
lg: ""
|
|
17
|
+
};
|
|
18
|
+
const labelTextClasses = {
|
|
19
|
+
sm: "text-sm",
|
|
20
|
+
md: "text-sm",
|
|
21
|
+
lg: "text-base"
|
|
22
|
+
};
|
|
23
|
+
const descriptionTextClasses = {
|
|
24
|
+
sm: "text-xs ps-6",
|
|
25
|
+
md: "text-xs ps-7",
|
|
26
|
+
lg: "text-sm ps-8"
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Class list for the checkbox box itself. State styling hangs off Base UI's
|
|
30
|
+
* data-attributes (`data-checked`, `data-indeterminate`, `data-disabled`,
|
|
31
|
+
* `data-readonly`, `data-invalid`) plus `aria-invalid`.
|
|
32
|
+
*/
|
|
33
|
+
function checkboxVariants({ size = "md", className } = {}) {
|
|
34
|
+
return cn(boxClasses, boxSizeClasses[size], className);
|
|
35
|
+
}
|
|
36
|
+
const glyphDrawClasses = "[stroke-dasharray:1] motion-safe:transition-[stroke-dashoffset,opacity] motion-safe:duration-200 motion-safe:ease-out motion-safe:in-data-starting-style:[stroke-dashoffset:1] motion-safe:in-data-starting-style:opacity-0";
|
|
37
|
+
function CheckIcon() {
|
|
38
|
+
return /* @__PURE__ */ jsx("svg", {
|
|
39
|
+
viewBox: "0 0 24 24",
|
|
40
|
+
fill: "none",
|
|
41
|
+
stroke: "currentColor",
|
|
42
|
+
strokeWidth: 3,
|
|
43
|
+
strokeLinecap: "round",
|
|
44
|
+
strokeLinejoin: "round",
|
|
45
|
+
"aria-hidden": "true",
|
|
46
|
+
children: /* @__PURE__ */ jsx("path", {
|
|
47
|
+
d: "m5 13 4 4L19 7",
|
|
48
|
+
pathLength: 1,
|
|
49
|
+
className: glyphDrawClasses
|
|
50
|
+
})
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
function MinusIcon() {
|
|
54
|
+
return /* @__PURE__ */ jsx("svg", {
|
|
55
|
+
viewBox: "0 0 24 24",
|
|
56
|
+
fill: "none",
|
|
57
|
+
stroke: "currentColor",
|
|
58
|
+
strokeWidth: 3,
|
|
59
|
+
strokeLinecap: "round",
|
|
60
|
+
"aria-hidden": "true",
|
|
61
|
+
children: /* @__PURE__ */ jsx("path", {
|
|
62
|
+
d: "M6 12h12",
|
|
63
|
+
pathLength: 1,
|
|
64
|
+
className: glyphDrawClasses
|
|
65
|
+
})
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Binary/mixed-state control built on Base UI's Checkbox. The indicator is
|
|
70
|
+
* built in: a check mark, or a minus while `indeterminate` — so a `parent`
|
|
71
|
+
* checkbox inside a controlled `CheckboxGroup` with `allValues` needs no
|
|
72
|
+
* extra wiring. `ref` and `className` always target the box element, whether
|
|
73
|
+
* or not the labelled layout wraps it.
|
|
74
|
+
*/
|
|
75
|
+
const Checkbox$1 = forwardRef(({ size = "md", label, description, required, className, "aria-describedby": ariaDescribedBy, ...rest }, ref) => {
|
|
76
|
+
const descriptionId = useId();
|
|
77
|
+
const hasLabel = label != null;
|
|
78
|
+
const hasText = hasLabel || description != null;
|
|
79
|
+
const control = /* @__PURE__ */ jsx(Checkbox.Root, {
|
|
80
|
+
ref,
|
|
81
|
+
required,
|
|
82
|
+
"aria-describedby": [ariaDescribedBy, description != null ? descriptionId : void 0].filter(Boolean).join(" ") || void 0,
|
|
83
|
+
className: cn(checkboxVariants({ size }), hasText && "data-disabled:opacity-100", hasLabel && boxOffsetClasses[size], className),
|
|
84
|
+
...rest,
|
|
85
|
+
children: /* @__PURE__ */ jsx(Checkbox.Indicator, {
|
|
86
|
+
className: cn("flex", "motion-safe:transition-[scale,opacity] motion-safe:duration-200 motion-safe:ease-out", "motion-safe:data-ending-style:scale-75 motion-safe:data-ending-style:opacity-0", "motion-safe:data-ending-style:duration-100 motion-safe:data-ending-style:ease-in"),
|
|
87
|
+
render: (props, state) => /* @__PURE__ */ jsx("span", {
|
|
88
|
+
...props,
|
|
89
|
+
children: state.indeterminate ? /* @__PURE__ */ jsx(MinusIcon, {}) : /* @__PURE__ */ jsx(CheckIcon, {})
|
|
90
|
+
})
|
|
91
|
+
})
|
|
92
|
+
});
|
|
93
|
+
if (!hasText) return control;
|
|
94
|
+
return /* @__PURE__ */ jsxs("span", {
|
|
95
|
+
className: cn("inline-flex max-w-full flex-col gap-1 font-sans", "has-data-disabled:pointer-events-none has-data-disabled:opacity-50"),
|
|
96
|
+
children: [hasLabel ? /* @__PURE__ */ jsxs("label", {
|
|
97
|
+
className: cn("inline-flex cursor-pointer items-start gap-2", "has-data-readonly:cursor-default"),
|
|
98
|
+
children: [control, /* @__PURE__ */ jsxs("span", {
|
|
99
|
+
className: cn("font-medium text-foreground select-none", labelTextClasses[size]),
|
|
100
|
+
children: [label, required && /* @__PURE__ */ jsx("span", {
|
|
101
|
+
"aria-hidden": "true",
|
|
102
|
+
className: "ms-0.5 text-destructive",
|
|
103
|
+
children: "*"
|
|
104
|
+
})]
|
|
105
|
+
})]
|
|
106
|
+
}) : control, description != null && /* @__PURE__ */ jsx("span", {
|
|
107
|
+
id: descriptionId,
|
|
108
|
+
className: cn("text-muted-foreground", descriptionTextClasses[size]),
|
|
109
|
+
children: description
|
|
110
|
+
})]
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
Checkbox$1.displayName = "Checkbox";
|
|
114
|
+
/**
|
|
115
|
+
* Shares ticked-value state (`value`/`defaultValue`/`onValueChange`) across
|
|
116
|
+
* child checkboxes matched by their `value` prop, and drives a `parent`
|
|
117
|
+
* checkbox's indeterminate state when `allValues` is set. Lays the items out
|
|
118
|
+
* as a vertical stack — pass `className="flex-row"` for a horizontal row.
|
|
119
|
+
* The group needs an accessible name: `aria-labelledby` pointing at a caption,
|
|
120
|
+
* or `aria-label`.
|
|
121
|
+
*/
|
|
122
|
+
const CheckboxGroup$1 = forwardRef(({ className, ...rest }, ref) => /* @__PURE__ */ jsx(CheckboxGroup, {
|
|
123
|
+
ref,
|
|
124
|
+
className: cn("flex flex-col items-start gap-3", className),
|
|
125
|
+
...rest
|
|
126
|
+
}));
|
|
127
|
+
CheckboxGroup$1.displayName = "CheckboxGroup";
|
|
128
|
+
//#endregion
|
|
129
|
+
export { Checkbox$1 as Checkbox, CheckboxGroup$1 as CheckboxGroup, checkboxVariants };
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { Checkbox, CheckboxGroup, CheckboxGroupProps, CheckboxProps, CheckboxSize, CheckboxVariantsOptions, checkboxVariants } from "./Checkbox.js";
|
|
2
|
+
export { Checkbox, CheckboxGroup, type CheckboxGroupProps, type CheckboxProps, type CheckboxSize, type CheckboxVariantsOptions, checkboxVariants };
|