chrona-react 0.1.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/LICENSE +21 -0
- package/README.md +132 -0
- package/dist/calendar.d.ts +126 -0
- package/dist/calendar.js +14 -0
- package/dist/calendar.js.map +1 -0
- package/dist/chunk-5426MN2K.js +211 -0
- package/dist/chunk-5426MN2K.js.map +1 -0
- package/dist/chunk-6QRNDYNF.js +16 -0
- package/dist/chunk-6QRNDYNF.js.map +1 -0
- package/dist/chunk-EFN32TNK.js +159 -0
- package/dist/chunk-EFN32TNK.js.map +1 -0
- package/dist/chunk-GN2YCKFZ.js +98 -0
- package/dist/chunk-GN2YCKFZ.js.map +1 -0
- package/dist/chunk-VSD2IX3U.js +183 -0
- package/dist/chunk-VSD2IX3U.js.map +1 -0
- package/dist/chunk-XNVORQQ5.js +112 -0
- package/dist/chunk-XNVORQQ5.js.map +1 -0
- package/dist/chunk-ZN4FZDUQ.js +16 -0
- package/dist/chunk-ZN4FZDUQ.js.map +1 -0
- package/dist/date-field.d.ts +74 -0
- package/dist/date-field.js +11 -0
- package/dist/date-field.js.map +1 -0
- package/dist/date-picker.d.ts +69 -0
- package/dist/date-picker.js +13 -0
- package/dist/date-picker.js.map +1 -0
- package/dist/field-CQjoX8QG.d.ts +11 -0
- package/dist/form-BCAGbNh-.d.ts +20 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +40 -0
- package/dist/index.js.map +1 -0
- package/dist/range-calendar.d.ts +194 -0
- package/dist/range-calendar.js +11 -0
- package/dist/range-calendar.js.map +1 -0
- package/dist/time-field.d.ts +74 -0
- package/dist/time-field.js +11 -0
- package/dist/time-field.js.map +1 -0
- package/package.json +75 -0
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Part,
|
|
3
|
+
composeEvent,
|
|
4
|
+
useChronaConfig,
|
|
5
|
+
useFormReset
|
|
6
|
+
} from "./chunk-GN2YCKFZ.js";
|
|
7
|
+
|
|
8
|
+
// src/calendar.tsx
|
|
9
|
+
import * as React from "react";
|
|
10
|
+
import { calendarKeys, connectCalendar, createCalendar, createStore, formatDate, getNumberFormatter, resolveWeekStart, sameDate, syncCalendar, temporal, transitionCalendar, translations, weeksInMonthView } from "chrona-core";
|
|
11
|
+
import { jsx } from "react/jsx-runtime";
|
|
12
|
+
function useCalendar(props = {}) {
|
|
13
|
+
const options = useChronaConfig(props);
|
|
14
|
+
const generatedId = React.useId();
|
|
15
|
+
const id = props.id ?? generatedId;
|
|
16
|
+
const [store] = React.useState(() => createStore(createCalendar({ ...options, value: props.value !== void 0 ? props.value : props.defaultValue, focusedValue: props.focusedValue ?? props.defaultFocusedValue })));
|
|
17
|
+
const snapshot = React.useSyncExternalStore(store.subscribe, store.getSnapshot, store.getServerSnapshot);
|
|
18
|
+
const state = syncCalendar(snapshot, { ...options, value: props.value, focusedValue: props.focusedValue });
|
|
19
|
+
React.useEffect(() => {
|
|
20
|
+
store.setState(state);
|
|
21
|
+
});
|
|
22
|
+
const rootRef = React.useRef(null);
|
|
23
|
+
const pendingFocus = React.useRef(false);
|
|
24
|
+
const [announcement, setAnnouncement] = React.useState("");
|
|
25
|
+
React.useEffect(() => {
|
|
26
|
+
if (pendingFocus.current) {
|
|
27
|
+
pendingFocus.current = false;
|
|
28
|
+
rootRef.current?.querySelector('[data-part="cell"][tabindex="0"]')?.focus();
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
function send(event) {
|
|
32
|
+
const dir = options.dir ?? (rootRef.current?.closest("[dir]")?.getAttribute("dir") === "rtl" ? "rtl" : "ltr");
|
|
33
|
+
const result = transitionCalendar(state, event, { ...options, dir });
|
|
34
|
+
store.setState(result.state);
|
|
35
|
+
for (const effect of result.effects) {
|
|
36
|
+
if (effect.type === "focus") {
|
|
37
|
+
pendingFocus.current = true;
|
|
38
|
+
if (!sameDate(effect.value, state.focusedValue)) props.onFocusedValueChange?.(effect.value);
|
|
39
|
+
} else if (effect.type === "change") {
|
|
40
|
+
props.onChange?.(effect.value);
|
|
41
|
+
setAnnouncement(effect.value ? (options.translations?.selected ?? translations.selected)(formatDate(effect.value, options.locale, { dateStyle: "full" })) : "");
|
|
42
|
+
} else {
|
|
43
|
+
props.onSelect?.(effect.value);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return {
|
|
48
|
+
state,
|
|
49
|
+
options,
|
|
50
|
+
send,
|
|
51
|
+
rootRef,
|
|
52
|
+
announcement,
|
|
53
|
+
api: connectCalendar(state, { ...options, id, today: temporal().Now.plainDateISO(options.timeZone) }),
|
|
54
|
+
months: Array.from({ length: options.numberOfMonths ?? 1 }, (_, index) => state.visibleMonth.add({ months: index }))
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
var Context = React.createContext(null);
|
|
58
|
+
var MonthContext = React.createContext(null);
|
|
59
|
+
function useContext2() {
|
|
60
|
+
const value = React.useContext(Context);
|
|
61
|
+
if (!value) throw new Error("Calendar parts must be inside Calendar.Root.");
|
|
62
|
+
return value;
|
|
63
|
+
}
|
|
64
|
+
function CalendarRoot({ children, asChild, className, style, ...props }) {
|
|
65
|
+
const calendar = useCalendar(props);
|
|
66
|
+
return /* @__PURE__ */ jsx(CalendarSurface, { calendar, id: props.id, asChild, className, style, children });
|
|
67
|
+
}
|
|
68
|
+
function CalendarSurface({ calendar, ...props }) {
|
|
69
|
+
return /* @__PURE__ */ jsx(Context.Provider, { value: calendar, children: /* @__PURE__ */ jsx(Part, { ...calendar.api.getRootProps(), ...props, ref: calendar.rootRef }) });
|
|
70
|
+
}
|
|
71
|
+
var Header = React.forwardRef(function Header2(props, ref) {
|
|
72
|
+
return /* @__PURE__ */ jsx(Part, { ...props, ref, "data-scope": "calendar", "data-part": "header" });
|
|
73
|
+
});
|
|
74
|
+
var Heading = React.forwardRef(function Heading2({ children, ...props }, ref) {
|
|
75
|
+
const { months, options } = useContext2();
|
|
76
|
+
const month = React.useContext(MonthContext);
|
|
77
|
+
return /* @__PURE__ */ jsx(Part, { as: "h2", ...props, ref, "data-scope": "calendar", "data-part": "heading", "aria-live": "polite", "aria-atomic": "true", children: children ?? (month ? [month] : months).map((date) => formatDate(date, options.locale, { month: "long", year: "numeric" })).join(options.translations?.rangeSeparator ?? translations.rangeSeparator) });
|
|
78
|
+
});
|
|
79
|
+
var PrevButton = React.forwardRef(function PrevButton2({ onClick, ...props }, ref) {
|
|
80
|
+
const { api, send } = useContext2();
|
|
81
|
+
return /* @__PURE__ */ jsx(Part, { as: "button", ...props, ...api.getPrevButtonProps(), ref, onClick: composeEvent(onClick, () => send({ type: "PAGE", direction: -1 })) });
|
|
82
|
+
});
|
|
83
|
+
var NextButton = React.forwardRef(function NextButton2({ onClick, ...props }, ref) {
|
|
84
|
+
const { api, send } = useContext2();
|
|
85
|
+
return /* @__PURE__ */ jsx(Part, { as: "button", ...props, ...api.getNextButtonProps(), ref, onClick: composeEvent(onClick, () => send({ type: "PAGE", direction: 1 })) });
|
|
86
|
+
});
|
|
87
|
+
var Grid = React.forwardRef(function Grid2({ monthIndex = 0, children, ...props }, ref) {
|
|
88
|
+
const { api, months } = useContext2();
|
|
89
|
+
const month = months[monthIndex];
|
|
90
|
+
if (!month) throw new Error("Calendar.Grid monthIndex is outside numberOfMonths.");
|
|
91
|
+
return /* @__PURE__ */ jsx(MonthContext.Provider, { value: month, children: /* @__PURE__ */ jsx(Part, { ...props, ...api.getGridProps(month), ref, children }) });
|
|
92
|
+
});
|
|
93
|
+
function useMonth() {
|
|
94
|
+
const context = useContext2();
|
|
95
|
+
const month = React.useContext(MonthContext) ?? context.state.visibleMonth;
|
|
96
|
+
return { ...context, month, weeks: weeksInMonthView(month.toPlainYearMonth(), resolveWeekStart(context.options.locale, context.options.firstDayOfWeek), context.options.fixedWeeks) };
|
|
97
|
+
}
|
|
98
|
+
var GridHeader = React.forwardRef(function GridHeader2({ children, ...props }, ref) {
|
|
99
|
+
const { weeks, options } = useMonth();
|
|
100
|
+
return /* @__PURE__ */ jsx(Part, { ...props, ref, role: "row", "data-scope": "calendar", "data-part": "grid-header", children: weeks[0].map((date) => {
|
|
101
|
+
const day = { date, label: formatDate(date, options.locale, { weekday: "short" }) };
|
|
102
|
+
return /* @__PURE__ */ jsx(React.Fragment, { children: children ? children(day) : /* @__PURE__ */ jsx(HeaderCell, { day }) }, date.toString());
|
|
103
|
+
}) });
|
|
104
|
+
});
|
|
105
|
+
var HeaderCell = React.forwardRef(function HeaderCell2({ day, children, ...props }, ref) {
|
|
106
|
+
const { options } = useContext2();
|
|
107
|
+
return /* @__PURE__ */ jsx(Part, { ...props, ref, role: "columnheader", "aria-label": formatDate(day.date, options.locale, { weekday: "long" }), "data-scope": "calendar", "data-part": "header-cell", children: children ?? day.label });
|
|
108
|
+
});
|
|
109
|
+
var GridBody = React.forwardRef(function GridBody2({ children, ...props }, ref) {
|
|
110
|
+
const { weeks } = useMonth();
|
|
111
|
+
return /* @__PURE__ */ jsx(Part, { ...props, ref, role: "rowgroup", "data-scope": "calendar", "data-part": "grid-body", children: weeks.map((week) => /* @__PURE__ */ jsx("div", { role: "row", "data-scope": "calendar", "data-part": "row", children: week.map((date) => /* @__PURE__ */ jsx(React.Fragment, { children: children ? children(date) : /* @__PURE__ */ jsx(Cell, { date }) }, date.toString())) }, week[0].toString())) });
|
|
112
|
+
});
|
|
113
|
+
var Cell = React.forwardRef(function Cell2({ date, children, onClick, onKeyDown, onFocus, ...props }, ref) {
|
|
114
|
+
const { api, send, month, options } = useMonth();
|
|
115
|
+
const cellProps = api.getCellProps(date, month);
|
|
116
|
+
return /* @__PURE__ */ jsx(
|
|
117
|
+
Part,
|
|
118
|
+
{
|
|
119
|
+
as: "button",
|
|
120
|
+
...props,
|
|
121
|
+
...cellProps,
|
|
122
|
+
type: "button",
|
|
123
|
+
ref,
|
|
124
|
+
onFocus: composeEvent(onFocus, () => {
|
|
125
|
+
if (!options.disabled) send({ type: "FOCUS", date });
|
|
126
|
+
}),
|
|
127
|
+
onClick: composeEvent(onClick, () => send({ type: "SELECT", date })),
|
|
128
|
+
onKeyDown: composeEvent(onKeyDown, (event) => {
|
|
129
|
+
if (!calendarKeys.has(event.key) || event.altKey || event.ctrlKey || event.metaKey) return;
|
|
130
|
+
event.preventDefault();
|
|
131
|
+
send({ type: "KEY_DOWN", key: event.key, shiftKey: event.shiftKey });
|
|
132
|
+
}),
|
|
133
|
+
children: children ?? getNumberFormatter(options.locale, { useGrouping: false }).format(date.day)
|
|
134
|
+
}
|
|
135
|
+
);
|
|
136
|
+
});
|
|
137
|
+
var LiveRegion = React.forwardRef(function LiveRegion2(props, ref) {
|
|
138
|
+
const { announcement } = useContext2();
|
|
139
|
+
return /* @__PURE__ */ jsx(Part, { ...props, ref, role: "status", "aria-live": "polite", "aria-atomic": "true", "data-scope": "calendar", "data-part": "live-region", children: announcement });
|
|
140
|
+
});
|
|
141
|
+
var ClearButton = React.forwardRef(function ClearButton2({ onClick, ...props }, ref) {
|
|
142
|
+
const { options, send, state } = useContext2();
|
|
143
|
+
return /* @__PURE__ */ jsx(Part, { as: "button", ...props, ref, type: "button", "data-scope": "calendar", "data-part": "clear-button", "aria-label": options.translations?.clear ?? translations.clear, disabled: options.disabled || options.readOnly || state.value === null, onClick: composeEvent(onClick, () => send({ type: "CLEAR" })) });
|
|
144
|
+
});
|
|
145
|
+
function HiddenInput(props) {
|
|
146
|
+
const { state, options, send } = useContext2();
|
|
147
|
+
const input = React.useRef(null);
|
|
148
|
+
useFormReset(input, props.form, () => send({ type: "RESET", value: options.defaultValue ?? null }));
|
|
149
|
+
return /* @__PURE__ */ jsx("input", { ...props, ref: input, type: "hidden", disabled: options.disabled || props.disabled, value: state.value?.toString() ?? "", "data-scope": "calendar", "data-part": "hidden-input" });
|
|
150
|
+
}
|
|
151
|
+
var Calendar = { Root: CalendarRoot, Header, Heading, PrevButton, NextButton, Grid, GridHeader, HeaderCell, GridBody, Cell, LiveRegion, ClearButton, HiddenInput };
|
|
152
|
+
|
|
153
|
+
export {
|
|
154
|
+
useCalendar,
|
|
155
|
+
CalendarRoot,
|
|
156
|
+
CalendarSurface,
|
|
157
|
+
Calendar
|
|
158
|
+
};
|
|
159
|
+
//# sourceMappingURL=chunk-EFN32TNK.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/calendar.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { calendarKeys, connectCalendar, createCalendar, createStore, formatDate, getNumberFormatter, resolveWeekStart, sameDate, syncCalendar, temporal, transitionCalendar, translations, weeksInMonthView, type CalendarEvent, type CalendarOptions, type PlainDate } from \"chrona-core\";\nimport { Part, composeEvent, type PartProps } from \"./part\";\nimport { useChronaConfig } from \"./provider\";\nimport { useFormReset, type HiddenInputProps } from \"./form\";\n\nexport interface CalendarProps extends CalendarOptions {\n defaultValue?: PlainDate | null;\n defaultFocusedValue?: PlainDate;\n onChange?: (value: PlainDate | null) => void;\n onSelect?: (value: PlainDate) => void;\n onFocusedValueChange?: (value: PlainDate) => void;\n id?: string;\n}\n\nexport function useCalendar(props: CalendarProps = {}) {\n const options = useChronaConfig(props);\n const generatedId = React.useId();\n const id = props.id ?? generatedId;\n const [store] = React.useState(() => createStore(createCalendar({ ...options, value: props.value !== undefined ? props.value : props.defaultValue, focusedValue: props.focusedValue ?? props.defaultFocusedValue })));\n const snapshot = React.useSyncExternalStore(store.subscribe, store.getSnapshot, store.getServerSnapshot);\n // The store is the single source of truth; controlled props are reconciled into it by syncCalendar.\n const state = syncCalendar(snapshot, { ...options, value: props.value, focusedValue: props.focusedValue });\n React.useEffect(() => { store.setState(state); });\n const rootRef = React.useRef<HTMLElement | null>(null);\n const pendingFocus = React.useRef(false);\n const [announcement, setAnnouncement] = React.useState(\"\");\n\n React.useEffect(() => {\n if (pendingFocus.current) {\n pendingFocus.current = false;\n rootRef.current?.querySelector<HTMLElement>('[data-part=\"cell\"][tabindex=\"0\"]')?.focus();\n }\n });\n\n function send(event: CalendarEvent) {\n const dir = options.dir ?? (rootRef.current?.closest(\"[dir]\")?.getAttribute(\"dir\") === \"rtl\" ? \"rtl\" : \"ltr\");\n const result = transitionCalendar(state, event, { ...options, dir });\n store.setState(result.state);\n for (const effect of result.effects) {\n if (effect.type === \"focus\") {\n pendingFocus.current = true;\n if (!sameDate(effect.value, state.focusedValue)) props.onFocusedValueChange?.(effect.value);\n } else if (effect.type === \"change\") {\n props.onChange?.(effect.value);\n setAnnouncement(effect.value ? (options.translations?.selected ?? translations.selected)(formatDate(effect.value, options.locale, { dateStyle: \"full\" })) : \"\");\n } else {\n props.onSelect?.(effect.value);\n }\n }\n }\n\n return {\n state, options, send, rootRef, announcement,\n api: connectCalendar(state, { ...options, id, today: temporal().Now.plainDateISO(options.timeZone) }),\n months: Array.from({ length: options.numberOfMonths ?? 1 }, (_, index) => state.visibleMonth.add({ months: index })),\n };\n}\n\ntype CalendarContextValue = ReturnType<typeof useCalendar>;\nconst Context = React.createContext<CalendarContextValue | null>(null);\nconst MonthContext = React.createContext<PlainDate | null>(null);\n\nfunction useContext() {\n const value = React.useContext(Context);\n if (!value) throw new Error(\"Calendar parts must be inside Calendar.Root.\");\n return value;\n}\n\nexport function CalendarRoot({ children, asChild, className, style, ...props }: CalendarProps & Pick<PartProps, \"children\" | \"asChild\" | \"className\" | \"style\">) {\n const calendar = useCalendar(props);\n return <CalendarSurface calendar={calendar} id={props.id} asChild={asChild} className={className} style={style}>{children}</CalendarSurface>;\n}\n\nexport function CalendarSurface({ calendar, ...props }: PartProps & { calendar: CalendarContextValue }) {\n return <Context.Provider value={calendar}><Part {...calendar.api.getRootProps()} {...props} ref={calendar.rootRef} /></Context.Provider>;\n}\n\nconst Header = React.forwardRef<HTMLElement, PartProps>(function Header(props, ref) {\n return <Part {...props} ref={ref} data-scope=\"calendar\" data-part=\"header\" />;\n});\n\nconst Heading = React.forwardRef<HTMLElement, PartProps>(function Heading({ children, ...props }, ref) {\n const { months, options } = useContext();\n const month = React.useContext(MonthContext);\n return <Part as=\"h2\" {...props} ref={ref} data-scope=\"calendar\" data-part=\"heading\" aria-live=\"polite\" aria-atomic=\"true\">{children ?? (month ? [month] : months).map((date) => formatDate(date, options.locale, { month: \"long\", year: \"numeric\" })).join(options.translations?.rangeSeparator ?? translations.rangeSeparator)}</Part>;\n});\n\ntype ButtonProps = React.ComponentPropsWithoutRef<\"button\"> & { asChild?: boolean };\n\nconst PrevButton = React.forwardRef<HTMLElement, ButtonProps>(function PrevButton({ onClick, ...props }, ref) {\n const { api, send } = useContext();\n return <Part as=\"button\" {...props} {...api.getPrevButtonProps()} ref={ref} onClick={composeEvent(onClick, () => send({ type: \"PAGE\", direction: -1 }))} />;\n});\n\nconst NextButton = React.forwardRef<HTMLElement, ButtonProps>(function NextButton({ onClick, ...props }, ref) {\n const { api, send } = useContext();\n return <Part as=\"button\" {...props} {...api.getNextButtonProps()} ref={ref} onClick={composeEvent(onClick, () => send({ type: \"PAGE\", direction: 1 }))} />;\n});\n\nconst Grid = React.forwardRef<HTMLElement, PartProps & { monthIndex?: number }>(function Grid({ monthIndex = 0, children, ...props }, ref) {\n const { api, months } = useContext();\n const month = months[monthIndex];\n if (!month) throw new Error(\"Calendar.Grid monthIndex is outside numberOfMonths.\");\n return <MonthContext.Provider value={month}><Part {...props} {...api.getGridProps(month)} ref={ref}>{children}</Part></MonthContext.Provider>;\n});\n\nfunction useMonth() {\n const context = useContext();\n const month = React.useContext(MonthContext) ?? context.state.visibleMonth;\n return { ...context, month, weeks: weeksInMonthView(month.toPlainYearMonth(), resolveWeekStart(context.options.locale, context.options.firstDayOfWeek), context.options.fixedWeeks) };\n}\n\nexport interface Weekday { date: PlainDate; label: string }\n\nconst GridHeader = React.forwardRef<HTMLElement, Omit<PartProps, \"children\"> & { children?: (day: Weekday) => React.ReactNode }>(function GridHeader({ children, ...props }, ref) {\n const { weeks, options } = useMonth();\n return <Part {...props} ref={ref} role=\"row\" data-scope=\"calendar\" data-part=\"grid-header\">{weeks[0]!.map((date) => {\n const day = { date, label: formatDate(date, options.locale, { weekday: \"short\" }) };\n return <React.Fragment key={date.toString()}>{children ? children(day) : <HeaderCell day={day} />}</React.Fragment>;\n })}</Part>;\n});\n\nconst HeaderCell = React.forwardRef<HTMLElement, PartProps & { day: Weekday }>(function HeaderCell({ day, children, ...props }, ref) {\n const { options } = useContext();\n return <Part {...props} ref={ref} role=\"columnheader\" aria-label={formatDate(day.date, options.locale, { weekday: \"long\" })} data-scope=\"calendar\" data-part=\"header-cell\">{children ?? day.label}</Part>;\n});\n\nconst GridBody = React.forwardRef<HTMLElement, Omit<PartProps, \"children\"> & { children?: (date: PlainDate) => React.ReactNode }>(function GridBody({ children, ...props }, ref) {\n const { weeks } = useMonth();\n return <Part {...props} ref={ref} role=\"rowgroup\" data-scope=\"calendar\" data-part=\"grid-body\">{weeks.map((week) => <div key={week[0]!.toString()} role=\"row\" data-scope=\"calendar\" data-part=\"row\">{week.map((date) => <React.Fragment key={date.toString()}>{children ? children(date) : <Cell date={date} />}</React.Fragment>)}</div>)}</Part>;\n});\n\nconst Cell = React.forwardRef<HTMLElement, ButtonProps & { date: PlainDate }>(function Cell({ date, children, onClick, onKeyDown, onFocus, ...props }, ref) {\n const { api, send, month, options } = useMonth();\n const cellProps = api.getCellProps(date, month);\n // aria-disabled instead of native disabled keeps out-of-range cells discoverable by screen readers.\n return <Part as=\"button\" {...props} {...cellProps} type=\"button\" ref={ref}\n onFocus={composeEvent(onFocus, () => { if (!options.disabled) send({ type: \"FOCUS\", date }); })}\n onClick={composeEvent(onClick, () => send({ type: \"SELECT\", date }))}\n onKeyDown={composeEvent(onKeyDown, (event) => {\n if (!calendarKeys.has(event.key) || event.altKey || event.ctrlKey || event.metaKey) return;\n event.preventDefault();\n send({ type: \"KEY_DOWN\", key: event.key, shiftKey: event.shiftKey });\n })}>{children ?? getNumberFormatter(options.locale, { useGrouping: false }).format(date.day)}</Part>;\n});\n\nconst LiveRegion = React.forwardRef<HTMLElement, PartProps>(function LiveRegion(props, ref) {\n const { announcement } = useContext();\n return <Part {...props} ref={ref} role=\"status\" aria-live=\"polite\" aria-atomic=\"true\" data-scope=\"calendar\" data-part=\"live-region\">{announcement}</Part>;\n});\n\nconst ClearButton = React.forwardRef<HTMLElement, ButtonProps>(function ClearButton({ onClick, ...props }, ref) {\n const { options, send, state } = useContext();\n return <Part as=\"button\" {...props} ref={ref} type=\"button\" data-scope=\"calendar\" data-part=\"clear-button\" aria-label={options.translations?.clear ?? translations.clear} disabled={options.disabled || options.readOnly || state.value === null} onClick={composeEvent(onClick, () => send({ type: \"CLEAR\" }))} />;\n});\n\nfunction HiddenInput(props: HiddenInputProps) {\n const { state, options, send } = useContext();\n const input = React.useRef<HTMLInputElement>(null);\n useFormReset(input, props.form, () => send({ type: \"RESET\", value: options.defaultValue ?? null }));\n return <input {...props} ref={input} type=\"hidden\" disabled={options.disabled || props.disabled} value={state.value?.toString() ?? \"\"} data-scope=\"calendar\" data-part=\"hidden-input\" />;\n}\n\nexport const Calendar = { Root: CalendarRoot, Header, Heading, PrevButton, NextButton, Grid, GridHeader, HeaderCell, GridBody, Cell, LiveRegion, ClearButton, HiddenInput };"],"mappings":"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","names":["useContext","Header","Heading","PrevButton","NextButton","Grid","GridHeader","HeaderCell","GridBody","Cell","LiveRegion","ClearButton"]}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
// src/part.tsx
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
function setRef(ref, value) {
|
|
4
|
+
if (typeof ref === "function") return ref(value);
|
|
5
|
+
if (ref) ref.current = value;
|
|
6
|
+
}
|
|
7
|
+
var Part = React.forwardRef(function Part2({ as: element = "div", asChild, children, ...props }, ref) {
|
|
8
|
+
if (!asChild) return React.createElement(element, { ...props, ref }, children);
|
|
9
|
+
const child = React.Children.only(children);
|
|
10
|
+
if (!React.isValidElement(child) || child.type === React.Fragment) throw new Error("Chrona asChild requires one non-Fragment element.");
|
|
11
|
+
const merged = { ...props, ...child.props };
|
|
12
|
+
for (const name of Object.keys(child.props)) {
|
|
13
|
+
const own = props[name];
|
|
14
|
+
const nested = child.props[name];
|
|
15
|
+
if (/^on[A-Z]/.test(name) && typeof own === "function" && typeof nested === "function") {
|
|
16
|
+
merged[name] = (event) => {
|
|
17
|
+
nested(event);
|
|
18
|
+
if (!event.defaultPrevented) own(event);
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
merged.className = [props.className, child.props.className].filter(Boolean).join(" ") || void 0;
|
|
23
|
+
merged.style = { ...props.style, ...child.props.style };
|
|
24
|
+
const childRef = Object.getOwnPropertyDescriptor(child.props, "ref")?.value ?? Object.getOwnPropertyDescriptor(child, "ref")?.value;
|
|
25
|
+
let cleanup;
|
|
26
|
+
merged.ref = (node) => {
|
|
27
|
+
cleanup?.();
|
|
28
|
+
cleanup = void 0;
|
|
29
|
+
if (node === null) return;
|
|
30
|
+
const ownCleanup = setRef(ref, node);
|
|
31
|
+
const childCleanup = setRef(childRef, node);
|
|
32
|
+
cleanup = () => {
|
|
33
|
+
if (typeof ownCleanup === "function") ownCleanup();
|
|
34
|
+
else setRef(ref, null);
|
|
35
|
+
if (typeof childCleanup === "function") childCleanup();
|
|
36
|
+
else setRef(childRef, null);
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
return React.cloneElement(child, merged);
|
|
40
|
+
});
|
|
41
|
+
function composeEvent(user, internal) {
|
|
42
|
+
return (event) => {
|
|
43
|
+
user?.(event);
|
|
44
|
+
if (!event.defaultPrevented) internal(event);
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// src/provider.tsx
|
|
49
|
+
import * as React2 from "react";
|
|
50
|
+
import { jsx } from "react/jsx-runtime";
|
|
51
|
+
var ConfigContext = React2.createContext({});
|
|
52
|
+
function ChronaProvider({ children, ...config }) {
|
|
53
|
+
const parent = React2.useContext(ConfigContext);
|
|
54
|
+
const { locale = parent.locale, timeZone = parent.timeZone, dir = parent.dir, translations } = config;
|
|
55
|
+
const value = React2.useMemo(() => ({ locale, timeZone, dir, translations: { ...parent.translations, ...translations } }), [locale, timeZone, dir, parent.translations, translations]);
|
|
56
|
+
return /* @__PURE__ */ jsx(ConfigContext.Provider, { value, children });
|
|
57
|
+
}
|
|
58
|
+
function useChronaConfig(options) {
|
|
59
|
+
const parent = React2.useContext(ConfigContext);
|
|
60
|
+
return {
|
|
61
|
+
...options,
|
|
62
|
+
locale: options.locale ?? parent.locale,
|
|
63
|
+
timeZone: options.timeZone ?? parent.timeZone,
|
|
64
|
+
dir: options.dir ?? parent.dir,
|
|
65
|
+
translations: { ...parent.translations, ...options.translations }
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// src/form.ts
|
|
70
|
+
import * as React3 from "react";
|
|
71
|
+
function useFormReset(input, form, reset) {
|
|
72
|
+
const latest = React3.useRef(reset);
|
|
73
|
+
React3.useEffect(() => {
|
|
74
|
+
latest.current = reset;
|
|
75
|
+
});
|
|
76
|
+
React3.useEffect(() => {
|
|
77
|
+
const owner = input.current?.form;
|
|
78
|
+
if (!owner) return;
|
|
79
|
+
let active = true;
|
|
80
|
+
const handler = (event) => queueMicrotask(() => {
|
|
81
|
+
if (active && !event.defaultPrevented) latest.current();
|
|
82
|
+
});
|
|
83
|
+
owner.addEventListener("reset", handler);
|
|
84
|
+
return () => {
|
|
85
|
+
active = false;
|
|
86
|
+
owner.removeEventListener("reset", handler);
|
|
87
|
+
};
|
|
88
|
+
}, [input, form]);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export {
|
|
92
|
+
Part,
|
|
93
|
+
composeEvent,
|
|
94
|
+
ChronaProvider,
|
|
95
|
+
useChronaConfig,
|
|
96
|
+
useFormReset
|
|
97
|
+
};
|
|
98
|
+
//# sourceMappingURL=chunk-GN2YCKFZ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/part.tsx","../src/provider.tsx","../src/form.ts"],"sourcesContent":["import * as React from \"react\";\n\nexport type PartProps = React.HTMLAttributes<HTMLElement> & { asChild?: boolean };\n\n// React 19 ref callbacks may return a cleanup function; React 18 types say void,\n// which would narrow that result to never at the call sites below.\nfunction setRef(ref: React.Ref<HTMLElement> | undefined, value: HTMLElement | null): (() => void) | void {\n if (typeof ref === \"function\") return ref(value);\n if (ref) (ref as React.MutableRefObject<HTMLElement | null>).current = value;\n}\n\nexport const Part = React.forwardRef<HTMLElement, PartProps & { as?: React.ElementType; type?: string; disabled?: boolean }>(function Part({ as: element = \"div\", asChild, children, ...props }, ref) {\n if (!asChild) return React.createElement(element, { ...props, ref }, children);\n const child = React.Children.only(children) as React.ReactElement<Record<string, unknown>>;\n if (!React.isValidElement(child) || child.type === React.Fragment) throw new Error(\"Chrona asChild requires one non-Fragment element.\");\n // Radix convention: the child's own props win over injected part props (events/className/style are merged).\n const merged: Record<string, unknown> = { ...props, ...child.props };\n for (const name of Object.keys(child.props)) {\n const own = (props as Record<string, unknown>)[name];\n const nested = child.props[name];\n if (/^on[A-Z]/.test(name) && typeof own === \"function\" && typeof nested === \"function\") {\n merged[name] = (event: React.SyntheticEvent) => {\n nested(event);\n if (!event.defaultPrevented) own(event);\n };\n }\n }\n merged.className = [props.className, child.props.className].filter(Boolean).join(\" \") || undefined;\n merged.style = { ...(props.style as React.CSSProperties), ...(child.props.style as React.CSSProperties) };\n const childRef = (Object.getOwnPropertyDescriptor(child.props, \"ref\")?.value ?? Object.getOwnPropertyDescriptor(child, \"ref\")?.value) as React.Ref<HTMLElement> | undefined;\n let cleanup: (() => void) | undefined;\n merged.ref = (node: HTMLElement | null) => {\n cleanup?.();\n cleanup = undefined;\n if (node === null) return;\n const ownCleanup = setRef(ref, node);\n const childCleanup = setRef(childRef, node);\n cleanup = () => {\n if (typeof ownCleanup === \"function\") ownCleanup(); else setRef(ref, null);\n if (typeof childCleanup === \"function\") childCleanup(); else setRef(childRef, null);\n };\n };\n return React.cloneElement(child, merged);\n});\n\nexport function composeEvent<Event extends React.SyntheticEvent>(user: ((event: Event) => void) | undefined, internal: (event: Event) => void) {\n return (event: Event) => {\n user?.(event);\n if (!event.defaultPrevented) internal(event);\n };\n}","import * as React from \"react\";\nimport type { Translations } from \"chrona-core\";\n\nexport interface ChronaConfig {\n locale?: string;\n timeZone?: string;\n dir?: \"ltr\" | \"rtl\";\n translations?: Partial<Translations>;\n}\n\nconst ConfigContext = React.createContext<ChronaConfig>({});\n\nexport function ChronaProvider({ children, ...config }: ChronaConfig & { children: React.ReactNode }) {\n const parent = React.useContext(ConfigContext);\n const { locale = parent.locale, timeZone = parent.timeZone, dir = parent.dir, translations } = config;\n const value = React.useMemo(() => ({ locale, timeZone, dir, translations: { ...parent.translations, ...translations } }), [locale, timeZone, dir, parent.translations, translations]);\n return <ConfigContext.Provider value={value}>{children}</ConfigContext.Provider>;\n}\n\nexport function useChronaConfig<Options extends ChronaConfig>(options: Options): Options & ChronaConfig {\n const parent = React.useContext(ConfigContext);\n return {\n ...options,\n locale: options.locale ?? parent.locale,\n timeZone: options.timeZone ?? parent.timeZone,\n dir: options.dir ?? parent.dir,\n translations: { ...parent.translations, ...options.translations },\n };\n}","import * as React from \"react\";\n\nexport type HiddenInputProps = Omit<React.ComponentPropsWithoutRef<\"input\">, \"type\" | \"value\" | \"defaultValue\" | \"onChange\">;\n\nexport function useFormReset(input: React.RefObject<HTMLInputElement | null>, form: string | undefined, reset: () => void) {\n const latest = React.useRef(reset);\n React.useEffect(() => { latest.current = reset; });\n React.useEffect(() => {\n const owner = input.current?.form;\n if (!owner) return;\n let active = true;\n const handler = (event: Event) => queueMicrotask(() => {\n if (active && !event.defaultPrevented) latest.current();\n });\n owner.addEventListener(\"reset\", handler);\n return () => {\n active = false;\n owner.removeEventListener(\"reset\", handler);\n };\n }, [input, form]);\n}"],"mappings":"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","names":["Part","React","React"]}
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Part,
|
|
3
|
+
composeEvent,
|
|
4
|
+
useChronaConfig,
|
|
5
|
+
useFormReset
|
|
6
|
+
} from "./chunk-GN2YCKFZ.js";
|
|
7
|
+
|
|
8
|
+
// src/field.tsx
|
|
9
|
+
import * as React from "react";
|
|
10
|
+
import { connectField, createField, createStore, digitValue, fieldHourCycle, transitionField, translations } from "chrona-core";
|
|
11
|
+
import { jsx } from "react/jsx-runtime";
|
|
12
|
+
function equalValues(first, second) {
|
|
13
|
+
return first === null || second === null ? first === second : first.equals(second);
|
|
14
|
+
}
|
|
15
|
+
function useField(kind, props) {
|
|
16
|
+
const options = useChronaConfig(props);
|
|
17
|
+
const generatedId = React.useId();
|
|
18
|
+
const id = props.id ?? generatedId;
|
|
19
|
+
const [store] = React.useState(() => createStore(createField(kind, { ...options, value: props.value !== void 0 ? props.value : props.defaultValue })));
|
|
20
|
+
const snapshot = React.useSyncExternalStore(store.subscribe, store.getSnapshot, store.getServerSnapshot);
|
|
21
|
+
const value = props.value !== void 0 ? props.value : snapshot.value;
|
|
22
|
+
const placeholderValue = options.placeholderValue ?? snapshot.reference;
|
|
23
|
+
const { minValue, maxValue, locale, hourCycle, granularity } = options;
|
|
24
|
+
const configured = React.useMemo(() => createField(kind, { value, placeholderValue, minValue, maxValue, locale, hourCycle, granularity }), [kind, value, placeholderValue, minValue, maxValue, locale, hourCycle, granularity]);
|
|
25
|
+
const cycle = fieldHourCycle(options);
|
|
26
|
+
const configuration = `${cycle}:${props.granularity ?? "minute"}`;
|
|
27
|
+
const previousConfiguration = React.useRef(configuration);
|
|
28
|
+
const state = props.value !== void 0 && !equalValues(snapshot.value, props.value) ? configured : kind === "time" && configuration !== previousConfiguration.current ? configured : snapshot;
|
|
29
|
+
React.useEffect(() => {
|
|
30
|
+
if (previousConfiguration.current !== configuration) {
|
|
31
|
+
previousConfiguration.current = configuration;
|
|
32
|
+
store.setState(state);
|
|
33
|
+
}
|
|
34
|
+
}, [configuration, state, store]);
|
|
35
|
+
const groupRef = React.useRef(null);
|
|
36
|
+
const [invalidReason, setInvalidReason] = React.useState(null);
|
|
37
|
+
const announcement = invalidReason === null ? "" : invalidReason === "range" ? options.translations?.invalidRange ?? translations.invalidRange : options.translations?.unavailable ?? translations.unavailable;
|
|
38
|
+
function moveFocus(segment, offset) {
|
|
39
|
+
const elements = Array.from(groupRef.current?.querySelectorAll("input[data-segment]") ?? []);
|
|
40
|
+
const index = elements.findIndex((element) => element.dataset.segment === segment);
|
|
41
|
+
elements[index + offset]?.focus();
|
|
42
|
+
}
|
|
43
|
+
function send(event) {
|
|
44
|
+
const result = transitionField(state, event, options);
|
|
45
|
+
store.setState(result.state);
|
|
46
|
+
if (!result.state.invalid) setInvalidReason(null);
|
|
47
|
+
for (const effect of result.effects) {
|
|
48
|
+
if (effect.type === "change") props.onChange?.(effect.value);
|
|
49
|
+
if (effect.type === "invalid") {
|
|
50
|
+
setInvalidReason(effect.reason);
|
|
51
|
+
props.onInvalid?.(effect.reason);
|
|
52
|
+
}
|
|
53
|
+
if (effect.type === "advance") queueMicrotask(() => moveFocus(effect.segment, 1));
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
function reset() {
|
|
57
|
+
setInvalidReason(null);
|
|
58
|
+
const value2 = props.defaultValue ?? null;
|
|
59
|
+
store.setState(createField(kind, { ...options, value: value2 }));
|
|
60
|
+
if (!equalValues(state.value, value2)) props.onChange?.(value2);
|
|
61
|
+
}
|
|
62
|
+
const [labelled, setLabelled] = React.useState(false);
|
|
63
|
+
return { id, state, options, send, reset, moveFocus, groupRef, announcement, registerLabel: setLabelled, api: connectField(state, { ...options, id, labelId: labelled ? `${id}-label` : void 0 }) };
|
|
64
|
+
}
|
|
65
|
+
function createFieldComponents(kind) {
|
|
66
|
+
const Context = React.createContext(null);
|
|
67
|
+
function useContext2() {
|
|
68
|
+
const context = React.useContext(Context);
|
|
69
|
+
if (!context) throw new Error(`${kind === "date" ? "DateField" : "TimeField"} parts must be inside their Root.`);
|
|
70
|
+
return context;
|
|
71
|
+
}
|
|
72
|
+
function Root({ children, asChild, className, style, ...props }) {
|
|
73
|
+
const context = useField(kind, props);
|
|
74
|
+
return /* @__PURE__ */ jsx(Context.Provider, { value: context, children: /* @__PURE__ */ jsx(Part, { asChild, className, style, id: props.id, dir: context.options.dir, "data-scope": `${kind}-field`, "data-part": "root", children }) });
|
|
75
|
+
}
|
|
76
|
+
const Label = React.forwardRef(function Label2(props, ref) {
|
|
77
|
+
const { id, registerLabel } = useContext2();
|
|
78
|
+
React.useEffect(() => {
|
|
79
|
+
registerLabel(true);
|
|
80
|
+
return () => registerLabel(false);
|
|
81
|
+
}, [registerLabel]);
|
|
82
|
+
return /* @__PURE__ */ jsx(Part, { as: "span", ...props, ref, id: `${id}-label`, "data-scope": `${kind}-field`, "data-part": "label" });
|
|
83
|
+
});
|
|
84
|
+
const Segment = React.forwardRef(function Segment2({ type, onKeyDown, onFocus, onBlur, onPaste, onDrop, ...props }, ref) {
|
|
85
|
+
const { state, api, options, send, moveFocus, groupRef } = useContext2();
|
|
86
|
+
if (!(type in state.parts)) throw new Error(`The ${type} segment is not enabled in this field.`);
|
|
87
|
+
const { display, ...segmentProps } = api.getSegmentProps(type);
|
|
88
|
+
return /* @__PURE__ */ jsx(
|
|
89
|
+
"input",
|
|
90
|
+
{
|
|
91
|
+
...props,
|
|
92
|
+
...segmentProps,
|
|
93
|
+
ref,
|
|
94
|
+
type: "text",
|
|
95
|
+
inputMode: type === "dayPeriod" ? "text" : "numeric",
|
|
96
|
+
autoComplete: "off",
|
|
97
|
+
spellCheck: false,
|
|
98
|
+
value: display,
|
|
99
|
+
disabled: options.disabled,
|
|
100
|
+
readOnly: options.readOnly,
|
|
101
|
+
onFocus: composeEvent(onFocus, (event) => {
|
|
102
|
+
event.currentTarget.select();
|
|
103
|
+
}),
|
|
104
|
+
onBlur: composeEvent(onBlur, () => send({ type: "BLUR" })),
|
|
105
|
+
onPaste: composeEvent(onPaste, (event) => event.preventDefault()),
|
|
106
|
+
onDrop: composeEvent(onDrop, (event) => event.preventDefault()),
|
|
107
|
+
onChange: (event) => {
|
|
108
|
+
const native = event.nativeEvent;
|
|
109
|
+
const digit = digitValue(native.data ?? "", options.locale);
|
|
110
|
+
event.currentTarget.value = display;
|
|
111
|
+
if (native.inputType === "insertText" && digit !== null) send({ type: "DIGIT", segment: type, digit });
|
|
112
|
+
else if (native.inputType === "deleteContentBackward" || native.inputType === "deleteContentForward") send({ type: "CLEAR", segment: type });
|
|
113
|
+
},
|
|
114
|
+
onKeyDown: composeEvent(onKeyDown, (event) => {
|
|
115
|
+
if (event.altKey || event.ctrlKey || event.metaKey || event.nativeEvent.isComposing) return;
|
|
116
|
+
const digit = digitValue(event.key, options.locale);
|
|
117
|
+
const dir = options.dir ?? (groupRef.current?.closest("[dir]")?.getAttribute("dir") === "rtl" ? "rtl" : "ltr");
|
|
118
|
+
if (digit !== null) {
|
|
119
|
+
event.preventDefault();
|
|
120
|
+
send({ type: "DIGIT", segment: type, digit });
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
switch (event.key) {
|
|
124
|
+
case "ArrowUp":
|
|
125
|
+
case "ArrowDown":
|
|
126
|
+
event.preventDefault();
|
|
127
|
+
send({ type: "STEP", segment: type, direction: event.key === "ArrowUp" ? 1 : -1 });
|
|
128
|
+
break;
|
|
129
|
+
case "Home":
|
|
130
|
+
case "End":
|
|
131
|
+
event.preventDefault();
|
|
132
|
+
send({ type: "EDGE", segment: type, edge: event.key === "Home" ? "min" : "max" });
|
|
133
|
+
break;
|
|
134
|
+
case "Backspace":
|
|
135
|
+
case "Delete":
|
|
136
|
+
event.preventDefault();
|
|
137
|
+
send({ type: "CLEAR", segment: type });
|
|
138
|
+
break;
|
|
139
|
+
case "ArrowLeft":
|
|
140
|
+
case "ArrowRight":
|
|
141
|
+
event.preventDefault();
|
|
142
|
+
moveFocus(type, (event.key === "ArrowRight" ? 1 : -1) * (dir === "rtl" ? -1 : 1));
|
|
143
|
+
break;
|
|
144
|
+
default:
|
|
145
|
+
if (type === "dayPeriod" && ["a", "p"].includes(event.key.toLowerCase())) {
|
|
146
|
+
event.preventDefault();
|
|
147
|
+
send({ type: "PERIOD", value: event.key.toLowerCase() === "a" ? 0 : 1 });
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
})
|
|
151
|
+
}
|
|
152
|
+
);
|
|
153
|
+
});
|
|
154
|
+
const Field = React.forwardRef(function Field2({ children, ...props }, ref) {
|
|
155
|
+
const { api, groupRef } = useContext2();
|
|
156
|
+
return /* @__PURE__ */ jsx(Part, { ...props, ...api.getGroupProps(), ref: (node) => {
|
|
157
|
+
groupRef.current = node;
|
|
158
|
+
if (typeof ref === "function") ref(node);
|
|
159
|
+
else if (ref) ref.current = node;
|
|
160
|
+
}, children: children ?? api.segments.map((segment, index) => segment.type === "literal" ? /* @__PURE__ */ jsx("span", { "aria-hidden": "true", "data-scope": `${kind}-field`, "data-part": "literal", children: segment.value }, index) : /* @__PURE__ */ jsx(Segment, { type: segment.type }, segment.type)) });
|
|
161
|
+
});
|
|
162
|
+
function HiddenInput(props) {
|
|
163
|
+
const { state, options, reset } = useContext2();
|
|
164
|
+
const input = React.useRef(null);
|
|
165
|
+
useFormReset(input, props.form, reset);
|
|
166
|
+
return /* @__PURE__ */ jsx("input", { ...props, ref: input, type: "hidden", value: state.value?.toString() ?? "", disabled: options.disabled || props.disabled, "data-scope": `${kind}-field`, "data-part": "hidden-input" });
|
|
167
|
+
}
|
|
168
|
+
const ClearButton = React.forwardRef(function ClearButton2({ onClick, ...props }, ref) {
|
|
169
|
+
const { options, send } = useContext2();
|
|
170
|
+
return /* @__PURE__ */ jsx(Part, { as: "button", ...props, ref, type: "button", "aria-label": options.translations?.clear ?? translations.clear, disabled: options.disabled || options.readOnly, "data-scope": `${kind}-field`, "data-part": "clear-button", onClick: composeEvent(onClick, () => send({ type: "CLEAR" })) });
|
|
171
|
+
});
|
|
172
|
+
const LiveRegion = React.forwardRef(function LiveRegion2(props, ref) {
|
|
173
|
+
const { announcement } = useContext2();
|
|
174
|
+
return /* @__PURE__ */ jsx(Part, { ...props, ref, role: "status", "aria-live": "polite", "aria-atomic": "true", "data-scope": `${kind}-field`, "data-part": "live-region", children: announcement });
|
|
175
|
+
});
|
|
176
|
+
return { Root, Label, Field, Segment, HiddenInput, ClearButton, LiveRegion };
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
export {
|
|
180
|
+
useField,
|
|
181
|
+
createFieldComponents
|
|
182
|
+
};
|
|
183
|
+
//# sourceMappingURL=chunk-VSD2IX3U.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/field.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { connectField, createField, createStore, digitValue, fieldHourCycle, transitionField, translations, type FieldEvent, type FieldKind, type FieldOptions, type FieldValue, type SegmentType } from \"chrona-core\";\nimport { Part, composeEvent, type PartProps } from \"./part\";\nimport { useChronaConfig } from \"./provider\";\nimport { useFormReset, type HiddenInputProps } from \"./form\";\n\nexport interface FieldProps<Kind extends FieldKind> extends FieldOptions<Kind> {\n defaultValue?: FieldValue<Kind> | null;\n onChange?: (value: FieldValue<Kind> | null) => void;\n onInvalid?: (reason: \"range\" | \"unavailable\") => void;\n id?: string;\n describedBy?: string;\n}\n\nfunction equalValues(first: { equals: (other: never) => boolean } | null, second: { equals: (other: never) => boolean } | null) {\n return first === null || second === null ? first === second : first.equals(second as never);\n}\n\nexport function useField<Kind extends FieldKind>(kind: Kind, props: FieldProps<Kind>) {\n const options = useChronaConfig(props);\n const generatedId = React.useId();\n const id = props.id ?? generatedId;\n const [store] = React.useState(() => createStore(createField(kind, { ...options, value: props.value !== undefined ? props.value : props.defaultValue })));\n const snapshot = React.useSyncExternalStore(store.subscribe, store.getSnapshot, store.getServerSnapshot);\n const value = props.value !== undefined ? props.value : snapshot.value;\n const placeholderValue = options.placeholderValue ?? snapshot.reference;\n const { minValue, maxValue, locale, hourCycle, granularity } = options;\n const configured = React.useMemo(() => createField(kind, { value, placeholderValue, minValue, maxValue, locale, hourCycle, granularity }), [kind, value, placeholderValue, minValue, maxValue, locale, hourCycle, granularity]);\n const cycle = fieldHourCycle(options);\n const configuration = `${cycle}:${props.granularity ?? \"minute\"}`;\n const previousConfiguration = React.useRef(configuration);\n const state = props.value !== undefined && !equalValues(snapshot.value, props.value)\n ? configured\n : kind === \"time\" && configuration !== previousConfiguration.current\n ? configured\n : snapshot;\n React.useEffect(() => {\n if (previousConfiguration.current !== configuration) {\n previousConfiguration.current = configuration;\n store.setState(state);\n }\n }, [configuration, state, store]);\n const groupRef = React.useRef<HTMLElement | null>(null);\n const [invalidReason, setInvalidReason] = React.useState<\"range\" | \"unavailable\" | null>(null);\n const announcement = invalidReason === null ? \"\" : invalidReason === \"range\"\n ? options.translations?.invalidRange ?? translations.invalidRange\n : options.translations?.unavailable ?? translations.unavailable;\n\n function moveFocus(segment: SegmentType, offset: number) {\n const elements = Array.from(groupRef.current?.querySelectorAll<HTMLInputElement>(\"input[data-segment]\") ?? []);\n const index = elements.findIndex((element) => element.dataset.segment === segment);\n elements[index + offset]?.focus();\n }\n\n function send(event: FieldEvent) {\n const result = transitionField(state, event, options);\n store.setState(result.state);\n if (!result.state.invalid) setInvalidReason(null);\n for (const effect of result.effects) {\n if (effect.type === \"change\") props.onChange?.(effect.value);\n if (effect.type === \"invalid\") { setInvalidReason(effect.reason); props.onInvalid?.(effect.reason); }\n if (effect.type === \"advance\") queueMicrotask(() => moveFocus(effect.segment, 1));\n }\n }\n\n function reset() {\n setInvalidReason(null);\n const value = props.defaultValue ?? null;\n store.setState(createField(kind, { ...options, value }));\n if (!equalValues(state.value, value)) props.onChange?.(value);\n }\n\n const [labelled, setLabelled] = React.useState(false);\n return { id, state, options, send, reset, moveFocus, groupRef, announcement, registerLabel: setLabelled, api: connectField(state, { ...options, id, labelId: labelled ? `${id}-label` : undefined }) };\n}\n\nexport function createFieldComponents<Kind extends FieldKind>(kind: Kind) {\n const Context = React.createContext<ReturnType<typeof useField<Kind>> | null>(null);\n function useContext() {\n const context = React.useContext(Context);\n if (!context) throw new Error(`${kind === \"date\" ? \"DateField\" : \"TimeField\"} parts must be inside their Root.`);\n return context;\n }\n\n function Root({ children, asChild, className, style, ...props }: FieldProps<Kind> & Pick<PartProps, \"children\" | \"asChild\" | \"className\" | \"style\">) {\n const context = useField(kind, props);\n return <Context.Provider value={context}><Part asChild={asChild} className={className} style={style} id={props.id} dir={context.options.dir} data-scope={`${kind}-field`} data-part=\"root\">{children}</Part></Context.Provider>;\n }\n\n const Label = React.forwardRef<HTMLElement, PartProps>(function Label(props, ref) {\n const { id, registerLabel } = useContext();\n React.useEffect(() => {\n registerLabel(true);\n return () => registerLabel(false);\n }, [registerLabel]);\n return <Part as=\"span\" {...props} ref={ref} id={`${id}-label`} data-scope={`${kind}-field`} data-part=\"label\" />;\n });\n\n const Segment = React.forwardRef<HTMLInputElement, Omit<React.ComponentPropsWithoutRef<\"input\">, \"type\" | \"value\" | \"defaultValue\" | \"onChange\" | \"children\"> & { type: SegmentType }>(function Segment({ type, onKeyDown, onFocus, onBlur, onPaste, onDrop, ...props }, ref) {\n const { state, api, options, send, moveFocus, groupRef } = useContext();\n if (!(type in state.parts)) throw new Error(`The ${type} segment is not enabled in this field.`);\n const { display, ...segmentProps } = api.getSegmentProps(type);\n return <input {...props} {...segmentProps} ref={ref} type=\"text\" inputMode={type === \"dayPeriod\" ? \"text\" : \"numeric\"} autoComplete=\"off\" spellCheck={false} value={display} disabled={options.disabled} readOnly={options.readOnly}\n onFocus={composeEvent(onFocus, (event) => { event.currentTarget.select(); })}\n onBlur={composeEvent(onBlur, () => send({ type: \"BLUR\" }))}\n onPaste={composeEvent(onPaste, (event) => event.preventDefault())}\n onDrop={composeEvent(onDrop, (event) => event.preventDefault())}\n onChange={(event) => {\n const native = event.nativeEvent as InputEvent;\n const digit = digitValue(native.data ?? \"\", options.locale);\n event.currentTarget.value = display;\n if (native.inputType === \"insertText\" && digit !== null) send({ type: \"DIGIT\", segment: type, digit });\n else if (native.inputType === \"deleteContentBackward\" || native.inputType === \"deleteContentForward\") send({ type: \"CLEAR\", segment: type });\n }}\n onKeyDown={composeEvent(onKeyDown, (event) => {\n if (event.altKey || event.ctrlKey || event.metaKey || event.nativeEvent.isComposing) return;\n const digit = digitValue(event.key, options.locale);\n const dir = options.dir ?? (groupRef.current?.closest(\"[dir]\")?.getAttribute(\"dir\") === \"rtl\" ? \"rtl\" : \"ltr\");\n if (digit !== null) { event.preventDefault(); send({ type: \"DIGIT\", segment: type, digit }); return; }\n switch (event.key) {\n case \"ArrowUp\": case \"ArrowDown\": event.preventDefault(); send({ type: \"STEP\", segment: type, direction: event.key === \"ArrowUp\" ? 1 : -1 }); break;\n case \"Home\": case \"End\": event.preventDefault(); send({ type: \"EDGE\", segment: type, edge: event.key === \"Home\" ? \"min\" : \"max\" }); break;\n case \"Backspace\": case \"Delete\": event.preventDefault(); send({ type: \"CLEAR\", segment: type }); break;\n case \"ArrowLeft\": case \"ArrowRight\": event.preventDefault(); moveFocus(type, (event.key === \"ArrowRight\" ? 1 : -1) * (dir === \"rtl\" ? -1 : 1)); break;\n default:\n if (type === \"dayPeriod\" && [\"a\", \"p\"].includes(event.key.toLowerCase())) {\n event.preventDefault(); send({ type: \"PERIOD\", value: event.key.toLowerCase() === \"a\" ? 0 : 1 });\n }\n }\n })} />;\n });\n\n const Field = React.forwardRef<HTMLElement, PartProps>(function Field({ children, ...props }, ref) {\n const { api, groupRef } = useContext();\n return <Part {...props} {...api.getGroupProps()} ref={(node) => {\n groupRef.current = node;\n if (typeof ref === \"function\") ref(node); else if (ref) ref.current = node;\n }}>{children ?? api.segments.map((segment, index) => segment.type === \"literal\" ? <span key={index} aria-hidden=\"true\" data-scope={`${kind}-field`} data-part=\"literal\">{segment.value}</span> : <Segment key={segment.type} type={segment.type} />)}</Part>;\n });\n\n function HiddenInput(props: HiddenInputProps) {\n const { state, options, reset } = useContext();\n const input = React.useRef<HTMLInputElement>(null);\n useFormReset(input, props.form, reset);\n return <input {...props} ref={input} type=\"hidden\" value={state.value?.toString() ?? \"\"} disabled={options.disabled || props.disabled} data-scope={`${kind}-field`} data-part=\"hidden-input\" />;\n }\n\n const ClearButton = React.forwardRef<HTMLElement, React.ComponentPropsWithoutRef<\"button\"> & { asChild?: boolean }>(function ClearButton({ onClick, ...props }, ref) {\n const { options, send } = useContext();\n return <Part as=\"button\" {...props} ref={ref} type=\"button\" aria-label={options.translations?.clear ?? translations.clear} disabled={options.disabled || options.readOnly} data-scope={`${kind}-field`} data-part=\"clear-button\" onClick={composeEvent(onClick, () => send({ type: \"CLEAR\" }))} />;\n });\n\n const LiveRegion = React.forwardRef<HTMLElement, PartProps>(function LiveRegion(props, ref) {\n const { announcement } = useContext();\n return <Part {...props} ref={ref} role=\"status\" aria-live=\"polite\" aria-atomic=\"true\" data-scope={`${kind}-field`} data-part=\"live-region\">{announcement}</Part>;\n });\n\n return { Root, Label, Field, Segment, HiddenInput, ClearButton, LiveRegion };\n}"],"mappings":"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","names":["value","useContext","Label","Segment","Field","ClearButton","LiveRegion"]}
|