@ukiahinsure/a2ui-react-adapter 0.1.14 → 0.1.16
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/index.js +151 -41
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -19,48 +19,153 @@ import {
|
|
|
19
19
|
} from "@a2ui/web_core/v0_9";
|
|
20
20
|
|
|
21
21
|
// src/DateTimeInput.tsx
|
|
22
|
-
import { useId, useLayoutEffect, useRef } from "react";
|
|
22
|
+
import { useId, useLayoutEffect, useRef, useState } from "react";
|
|
23
23
|
import { createComponentImplementation } from "@a2ui/react/v0_9";
|
|
24
24
|
import { DateTimeInputApi } from "@a2ui/web_core/v0_9/basic_catalog";
|
|
25
25
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
26
|
-
var
|
|
27
|
-
|
|
28
|
-
(
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
26
|
+
var inputStyle = {
|
|
27
|
+
backgroundColor: "var(--a2ui-datetimeinput-background, var(--a2ui-color-input, #fff))",
|
|
28
|
+
color: "var(--a2ui-datetimeinput-color, var(--a2ui-color-on-input, #333))",
|
|
29
|
+
border: "var(--a2ui-datetimeinput-border, var(--a2ui-border))",
|
|
30
|
+
borderRadius: "var(--a2ui-datetimeinput-border-radius, var(--a2ui-border-radius))",
|
|
31
|
+
padding: "var(--a2ui-datetimeinput-padding, var(--a2ui-spacing-s))",
|
|
32
|
+
boxSizing: "border-box"
|
|
33
|
+
};
|
|
34
|
+
var labelStyle = { fontSize: "var(--a2ui-label-font-size, var(--a2ui-font-size-s))", fontWeight: "bold" };
|
|
35
|
+
function parseDateDraft(raw) {
|
|
36
|
+
const value = raw.trim();
|
|
37
|
+
const iso = /^(\d{4})-(\d{2})-(\d{2})$/.exec(value);
|
|
38
|
+
const us = /^(\d{1,2})\/(\d{1,2})\/(\d{4})$/.exec(value);
|
|
39
|
+
if (!iso && !us) return null;
|
|
40
|
+
const year = Number(iso ? iso[1] : us[3]);
|
|
41
|
+
const month = Number(iso ? iso[2] : us[1]);
|
|
42
|
+
const day = Number(iso ? iso[3] : us[2]);
|
|
43
|
+
const leap = year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0);
|
|
44
|
+
const days = [31, leap ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
|
|
45
|
+
if (year < 1 || month < 1 || month > 12 || day < 1 || day > days[month - 1]) return null;
|
|
46
|
+
return `${String(year).padStart(4, "0")}-${String(month).padStart(2, "0")}-${String(day).padStart(2, "0")}`;
|
|
47
|
+
}
|
|
48
|
+
function displayDate(value) {
|
|
49
|
+
const iso = parseDateDraft(value);
|
|
50
|
+
return iso ? `${iso.slice(5, 7)}/${iso.slice(8, 10)}/${iso.slice(0, 4)}` : value;
|
|
51
|
+
}
|
|
52
|
+
function DateOnlyInput(props) {
|
|
53
|
+
const id = useId();
|
|
54
|
+
const [draft, setDraft] = useState(() => displayDate(props.value || ""));
|
|
55
|
+
const [pickerOpen, setPickerOpen] = useState(false);
|
|
56
|
+
const published = useRef(props.value || "");
|
|
57
|
+
const inputRef = useRef(null);
|
|
58
|
+
const pickerRef = useRef(null);
|
|
59
|
+
const min = typeof props.min === "string" ? props.min : void 0;
|
|
60
|
+
const max = typeof props.max === "string" ? props.max : void 0;
|
|
61
|
+
const parsed = parseDateDraft(draft);
|
|
62
|
+
useLayoutEffect(() => {
|
|
63
|
+
const incoming = props.value || "";
|
|
64
|
+
if (incoming !== published.current) {
|
|
65
|
+
published.current = incoming;
|
|
66
|
+
setDraft(displayDate(incoming));
|
|
67
|
+
}
|
|
68
|
+
}, [props.value]);
|
|
69
|
+
useLayoutEffect(() => {
|
|
70
|
+
const message = draft.trim() && !parsed ? "Enter a valid date in MM/DD/YYYY format." : parsed && min && parsed < min ? `Enter a date on or after ${displayDate(min)}.` : parsed && max && parsed > max ? `Enter a date on or before ${displayDate(max)}.` : "";
|
|
71
|
+
inputRef.current?.setCustomValidity(message);
|
|
72
|
+
}, [draft, parsed, min, max]);
|
|
73
|
+
const update = (raw) => {
|
|
74
|
+
setDraft(raw);
|
|
75
|
+
const value = parseDateDraft(raw) || "";
|
|
76
|
+
published.current = value;
|
|
77
|
+
props.setValue(value);
|
|
78
|
+
};
|
|
79
|
+
return /* @__PURE__ */ jsxs("div", { "data-a2ui-date-editor": "true", style: { display: "flex", flexDirection: "column", gap: "var(--a2ui-spacing-xs, 0.25rem)" }, children: [
|
|
80
|
+
props.label && /* @__PURE__ */ jsx("label", { htmlFor: id, style: labelStyle, children: props.label }),
|
|
81
|
+
/* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: "0.25rem", position: "relative" }, children: [
|
|
41
82
|
/* @__PURE__ */ jsx(
|
|
42
83
|
"input",
|
|
43
84
|
{
|
|
44
85
|
ref: inputRef,
|
|
45
86
|
id,
|
|
46
|
-
type,
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
87
|
+
type: "text",
|
|
88
|
+
inputMode: "numeric",
|
|
89
|
+
autoComplete: "off",
|
|
90
|
+
"data-a2ui-date-text-draft": "true",
|
|
91
|
+
placeholder: "MM/DD/YYYY",
|
|
92
|
+
value: draft,
|
|
93
|
+
onChange: (event) => update(event.currentTarget.value),
|
|
94
|
+
onBlur: () => {
|
|
95
|
+
if (parsed) setDraft(displayDate(parsed));
|
|
96
|
+
},
|
|
97
|
+
style: { ...inputStyle, minWidth: 0, flex: 1 }
|
|
98
|
+
}
|
|
99
|
+
),
|
|
100
|
+
/* @__PURE__ */ jsx(
|
|
101
|
+
"button",
|
|
102
|
+
{
|
|
103
|
+
type: "button",
|
|
104
|
+
"aria-label": `Choose ${props.label || "date"} from calendar`,
|
|
105
|
+
style: inputStyle,
|
|
106
|
+
onClick: () => {
|
|
107
|
+
const picker = pickerRef.current;
|
|
108
|
+
if (picker && typeof picker.showPicker === "function") {
|
|
109
|
+
try {
|
|
110
|
+
picker.showPicker();
|
|
111
|
+
return;
|
|
112
|
+
} catch {
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
setPickerOpen(true);
|
|
116
|
+
},
|
|
117
|
+
children: "\u25A6"
|
|
118
|
+
}
|
|
119
|
+
),
|
|
120
|
+
/* @__PURE__ */ jsx(
|
|
121
|
+
"input",
|
|
122
|
+
{
|
|
123
|
+
ref: pickerRef,
|
|
124
|
+
type: "date",
|
|
125
|
+
"aria-label": `${props.label || "Date"} calendar`,
|
|
126
|
+
tabIndex: pickerOpen ? 0 : -1,
|
|
127
|
+
"aria-hidden": !pickerOpen,
|
|
128
|
+
"data-a2ui-calendar-input": "true",
|
|
129
|
+
value: parsed || "",
|
|
130
|
+
min,
|
|
131
|
+
max,
|
|
132
|
+
onChange: (event) => {
|
|
133
|
+
update(displayDate(event.currentTarget.value));
|
|
134
|
+
setPickerOpen(false);
|
|
135
|
+
},
|
|
136
|
+
style: pickerOpen ? inputStyle : { position: "absolute", opacity: 0, pointerEvents: "none", width: 1, height: 1, bottom: 0, right: 0 }
|
|
60
137
|
}
|
|
61
138
|
)
|
|
62
|
-
] })
|
|
63
|
-
}
|
|
139
|
+
] })
|
|
140
|
+
] });
|
|
141
|
+
}
|
|
142
|
+
function NativeTimeInput(props) {
|
|
143
|
+
const id = useId();
|
|
144
|
+
const inputRef = useRef(null);
|
|
145
|
+
const initialValue = useRef(props.value || "");
|
|
146
|
+
useLayoutEffect(() => {
|
|
147
|
+
if (inputRef.current && inputRef.current.value !== (props.value || "")) inputRef.current.value = props.value || "";
|
|
148
|
+
}, [props.value]);
|
|
149
|
+
return /* @__PURE__ */ jsxs("div", { children: [
|
|
150
|
+
props.label && /* @__PURE__ */ jsx("label", { htmlFor: id, style: labelStyle, children: props.label }),
|
|
151
|
+
/* @__PURE__ */ jsx(
|
|
152
|
+
"input",
|
|
153
|
+
{
|
|
154
|
+
ref: inputRef,
|
|
155
|
+
id,
|
|
156
|
+
type: !props.enableDate && props.enableTime ? "time" : "datetime-local",
|
|
157
|
+
defaultValue: initialValue.current,
|
|
158
|
+
onChange: (event) => props.setValue(event.currentTarget.value),
|
|
159
|
+
min: typeof props.min === "string" ? props.min : void 0,
|
|
160
|
+
max: typeof props.max === "string" ? props.max : void 0,
|
|
161
|
+
style: inputStyle
|
|
162
|
+
}
|
|
163
|
+
)
|
|
164
|
+
] });
|
|
165
|
+
}
|
|
166
|
+
var DateTimeInput = createComponentImplementation(
|
|
167
|
+
DateTimeInputApi,
|
|
168
|
+
({ props }) => props.enableDate && !props.enableTime ? /* @__PURE__ */ jsx(DateOnlyInput, { ...props }) : /* @__PURE__ */ jsx(NativeTimeInput, { ...props })
|
|
64
169
|
);
|
|
65
170
|
|
|
66
171
|
// src/adapter.ts
|
|
@@ -1859,14 +1964,18 @@ function bindFieldInteractionGroups(root, groups, editing, controller) {
|
|
|
1859
1964
|
const field = control.dataset.a2uiField;
|
|
1860
1965
|
const group = field === void 0 ? void 0 : groupByField.get(field);
|
|
1861
1966
|
if (group !== void 0) {
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1967
|
+
const dateEditor = control.closest("[data-a2ui-date-editor]");
|
|
1968
|
+
const targets = dateEditor ? [control, ...dateEditor.querySelectorAll("button, input[data-a2ui-calendar-input]")] : [control];
|
|
1969
|
+
for (const target of targets) {
|
|
1970
|
+
originalGroupAttributes.set(target, {
|
|
1971
|
+
groupId: target.dataset.a2uiGroupId,
|
|
1972
|
+
groupMode: target.dataset.a2uiGroupMode,
|
|
1973
|
+
editState: target.dataset.a2uiEditState
|
|
1974
|
+
});
|
|
1975
|
+
target.dataset.a2uiGroupId = group.groupId;
|
|
1976
|
+
target.dataset.a2uiGroupMode = group.mode;
|
|
1977
|
+
target.dataset.a2uiEditState = groupEditState(group.groupId, editing);
|
|
1978
|
+
}
|
|
1870
1979
|
}
|
|
1871
1980
|
}
|
|
1872
1981
|
if (controller === void 0) {
|
|
@@ -1899,7 +2008,8 @@ function bindFieldInteractionGroups(root, groups, editing, controller) {
|
|
|
1899
2008
|
}
|
|
1900
2009
|
queueMicrotask(() => {
|
|
1901
2010
|
if (interactionGroupId(root, root.ownerDocument.activeElement) !== groupId) {
|
|
1902
|
-
|
|
2011
|
+
const invalidDate = [...root.querySelectorAll("input[data-a2ui-date-text-draft]")].some((input) => input.dataset.a2uiGroupId === groupId && !input.checkValidity());
|
|
2012
|
+
if (!invalidDate) controller.commitFieldGroup(groupId);
|
|
1903
2013
|
}
|
|
1904
2014
|
});
|
|
1905
2015
|
};
|