@ukiahinsure/a2ui-react-adapter 0.1.19 → 0.1.21

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 CHANGED
@@ -78,10 +78,41 @@ function parseDateDraft(raw) {
78
78
  if (year < 1 || month < 1 || month > 12 || day < 1 || day > days[month - 1]) return null;
79
79
  return `${String(year).padStart(4, "0")}-${String(month).padStart(2, "0")}-${String(day).padStart(2, "0")}`;
80
80
  }
81
+ function formatDateDigits(raw) {
82
+ if (!/^(\d*|\d{2}\/\d*|\d{2}\/\d{2}\/\d*)$/.test(raw)) return raw;
83
+ const digits = raw.replace(/\D/g, "").slice(0, 8);
84
+ const typedSlash = raw.endsWith("/") && (digits.length === 2 || digits.length === 4) ? "/" : "";
85
+ if (digits.length <= 2) return digits + typedSlash;
86
+ if (digits.length <= 4) return `${digits.slice(0, 2)}/${digits.slice(2)}${typedSlash}`;
87
+ return `${digits.slice(0, 2)}/${digits.slice(2, 4)}/${digits.slice(4)}`;
88
+ }
81
89
  function displayDate(value) {
82
90
  const iso = parseDateDraft(value);
83
91
  return iso ? `${iso.slice(5, 7)}/${iso.slice(8, 10)}/${iso.slice(0, 4)}` : value;
84
92
  }
93
+ var calendarOverlayStyle = {
94
+ position: "absolute",
95
+ inset: 0,
96
+ width: "100%",
97
+ height: "100%",
98
+ margin: 0,
99
+ padding: 0,
100
+ border: 0,
101
+ opacity: 0,
102
+ cursor: "pointer",
103
+ fontSize: 16,
104
+ boxSizing: "border-box"
105
+ };
106
+ function openPicker(picker, fallback) {
107
+ if (picker && typeof picker.showPicker === "function") {
108
+ try {
109
+ picker.showPicker();
110
+ return;
111
+ } catch {
112
+ }
113
+ }
114
+ fallback?.();
115
+ }
85
116
  function DateOnlyInput(props) {
86
117
  const id = useId2();
87
118
  const [draft, setDraft] = useState(() => displayDate(props.value || ""));
@@ -103,7 +134,8 @@ function DateOnlyInput(props) {
103
134
  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)}.` : "";
104
135
  inputRef.current?.setCustomValidity(message);
105
136
  }, [draft, parsed, min, max]);
106
- const update = (raw) => {
137
+ const update = (typed) => {
138
+ const raw = formatDateDigits(typed);
107
139
  setDraft(raw);
108
140
  const value = parseDateDraft(raw) || "";
109
141
  published.current = value;
@@ -130,45 +162,38 @@ function DateOnlyInput(props) {
130
162
  style: { ...inputStyle, minWidth: 0, flex: 1 }
131
163
  }
132
164
  ),
133
- /* @__PURE__ */ jsx2(
134
- "button",
135
- {
136
- type: "button",
137
- "aria-label": `Choose ${props.label || "date"} from calendar`,
138
- style: inputStyle,
139
- onClick: () => {
140
- const picker = pickerRef.current;
141
- if (picker && typeof picker.showPicker === "function") {
142
- try {
143
- picker.showPicker();
144
- return;
145
- } catch {
146
- }
147
- }
148
- setPickerOpen(true);
149
- },
150
- children: "\u25A6"
151
- }
152
- ),
153
- /* @__PURE__ */ jsx2(
154
- "input",
155
- {
156
- ref: pickerRef,
157
- type: "date",
158
- "aria-label": `${props.label || "Date"} calendar`,
159
- tabIndex: pickerOpen ? 0 : -1,
160
- "aria-hidden": !pickerOpen,
161
- "data-a2ui-calendar-input": "true",
162
- value: parsed || "",
163
- min,
164
- max,
165
- onChange: (event) => {
166
- update(displayDate(event.currentTarget.value));
167
- setPickerOpen(false);
168
- },
169
- style: pickerOpen ? inputStyle : { position: "absolute", opacity: 0, pointerEvents: "none", width: 1, height: 1, bottom: 0, right: 0 }
170
- }
171
- )
165
+ /* @__PURE__ */ jsxs2("span", { style: { position: "relative", display: "flex" }, children: [
166
+ /* @__PURE__ */ jsx2(
167
+ "button",
168
+ {
169
+ type: "button",
170
+ "aria-label": `Choose ${props.label || "date"} from calendar`,
171
+ style: inputStyle,
172
+ onClick: () => openPicker(pickerRef.current, () => setPickerOpen(true)),
173
+ children: "\u25A6"
174
+ }
175
+ ),
176
+ /* @__PURE__ */ jsx2(
177
+ "input",
178
+ {
179
+ ref: pickerRef,
180
+ type: "date",
181
+ "aria-label": `${props.label || "Date"} calendar`,
182
+ tabIndex: pickerOpen ? 0 : -1,
183
+ "aria-hidden": !pickerOpen,
184
+ "data-a2ui-calendar-input": "true",
185
+ value: parsed || "",
186
+ min,
187
+ max,
188
+ onClick: (event) => openPicker(event.currentTarget),
189
+ onChange: (event) => {
190
+ update(displayDate(event.currentTarget.value));
191
+ setPickerOpen(false);
192
+ },
193
+ style: pickerOpen ? inputStyle : calendarOverlayStyle
194
+ }
195
+ )
196
+ ] })
172
197
  ] })
173
198
  ] });
174
199
  }
@@ -1831,7 +1856,7 @@ function A2UISurfaceHost({
1831
1856
  const lastViewedSection = useRef2(void 0);
1832
1857
  const lastValidationKey = useRef2("");
1833
1858
  const pendingFieldUpdates = useRef2(/* @__PURE__ */ new Map());
1834
- const lastCurrentGroupId = useRef2(void 0);
1859
+ const lastQuestionKey = useRef2(void 0);
1835
1860
  const onAgentUpdateRef = useRef2(onAgentUpdate);
1836
1861
  onAgentUpdateRef.current = onAgentUpdate;
1837
1862
  const resolvedSurfaceMetadata = surfaceMetadata ?? controllerSnapshot?.surface ?? null;
@@ -1902,9 +1927,11 @@ function A2UISurfaceHost({
1902
1927
  const currentGroup = resolvedSurfaceMetadata?.fieldInteractions.find(
1903
1928
  (group) => group.mode === "current"
1904
1929
  );
1905
- const previousGroupId = lastCurrentGroupId.current;
1906
- if (currentGroup !== void 0) {
1907
- lastCurrentGroupId.current = currentGroup.groupId;
1930
+ const activeStateId = resolvedSurfaceMetadata?.activeStateId;
1931
+ const questionKey = currentGroup?.groupId ?? (activeStateId == null ? void 0 : `state:${activeStateId}`);
1932
+ const previousQuestionKey = lastQuestionKey.current;
1933
+ if (questionKey !== void 0) {
1934
+ lastQuestionKey.current = questionKey;
1908
1935
  }
1909
1936
  const report = onAgentUpdateRef.current;
1910
1937
  if (report === void 0) {
@@ -1918,14 +1945,14 @@ function A2UISurfaceHost({
1918
1945
  element: agentUpdateElement(root, changedFields, structure.fields)
1919
1946
  });
1920
1947
  }
1921
- if (currentGroup !== void 0 && previousGroupId !== void 0 && currentGroup.groupId !== previousGroupId) {
1922
- const fields = currentGroup.fields.map((binding) => binding.field);
1948
+ if (questionKey !== void 0 && previousQuestionKey !== void 0 && questionKey !== previousQuestionKey) {
1949
+ const fields = currentGroup?.fields.map((binding) => binding.field) ?? [];
1923
1950
  report({
1924
1951
  reason: "current-group",
1925
1952
  surfaceId: surface.id,
1926
1953
  fields,
1927
- groupId: currentGroup.groupId,
1928
- element: agentUpdateElement(root, fields, structure.fields)
1954
+ ...currentGroup === void 0 ? {} : { groupId: currentGroup.groupId },
1955
+ element: agentUpdateElement(root, fields, structure.fields) ?? currentQuestionElement(root)
1929
1956
  });
1930
1957
  }
1931
1958
  };
@@ -2070,15 +2097,33 @@ function agentUpdateElement(root, fields, descriptors) {
2070
2097
  if (descriptor !== void 0) {
2071
2098
  labels.add(descriptor.label);
2072
2099
  }
2073
- const label = [
2074
- ...root.querySelectorAll("label, strong, legend")
2075
- ].find((candidate) => labels.has(candidate.textContent?.trim() ?? ""));
2100
+ const label = [...root.querySelectorAll("*")].find(
2101
+ (candidate) => candidate.childElementCount === 0 && labels.has(candidate.textContent?.trim() ?? "")
2102
+ );
2076
2103
  if (label?.parentElement != null && root.contains(label.parentElement)) {
2077
2104
  return label.parentElement;
2078
2105
  }
2079
2106
  }
2080
2107
  return void 0;
2081
2108
  }
2109
+ function currentQuestionElement(root) {
2110
+ const action = [
2111
+ ...root.querySelectorAll("[data-a2ui-action='true']")
2112
+ ].find(
2113
+ (candidate) => candidate.dataset.a2uiActionLabel !== "skip" && candidate.closest("[data-a2ui-loop-row]") === null
2114
+ );
2115
+ if (action === void 0) {
2116
+ return void 0;
2117
+ }
2118
+ let container = action.parentElement;
2119
+ if (container !== null && textOf(container) === [...container.querySelectorAll("button")].map(textOf).join("")) {
2120
+ container = container.parentElement;
2121
+ }
2122
+ return container !== null && container !== root && root.contains(container) ? container : action;
2123
+ }
2124
+ function textOf(element) {
2125
+ return (element.textContent ?? "").replace(/\s+/g, "");
2126
+ }
2082
2127
  function isControlDisabled(control) {
2083
2128
  return control.getAttribute("aria-disabled") === "true" || "disabled" in control && control.disabled === true;
2084
2129
  }