@assistant-ui/react-generative-ui 0.0.22 → 0.0.23
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/a2ui/convert.d.ts.map +1 -1
- package/dist/a2ui/convert.js +21 -4
- package/dist/a2ui/convert.js.map +1 -1
- package/dist/constants.d.ts +1 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +2 -1
- package/dist/constants.js.map +1 -1
- package/dist/slack/decodeBlockAction.d.ts.map +1 -1
- package/dist/slack/decodeBlockAction.js +64 -26
- package/dist/slack/decodeBlockAction.js.map +1 -1
- package/dist/slack/fromSlackBlocks.d.ts.map +1 -1
- package/dist/slack/fromSlackBlocks.js +23 -0
- package/dist/slack/fromSlackBlocks.js.map +1 -1
- package/dist/slack/toSlackBlocks.d.ts.map +1 -1
- package/dist/slack/toSlackBlocks.js +74 -18
- package/dist/slack/toSlackBlocks.js.map +1 -1
- package/dist/slack/types.d.ts +20 -1
- package/dist/slack/types.d.ts.map +1 -1
- package/dist/slack.d.ts +1 -1
- package/dist/slack.d.ts.map +1 -1
- package/dist/teams/decodeSubmitData.d.ts.map +1 -1
- package/dist/teams/decodeSubmitData.js +24 -3
- package/dist/teams/decodeSubmitData.js.map +1 -1
- package/dist/teams/temporalId.d.ts +5 -0
- package/dist/teams/temporalId.d.ts.map +1 -0
- package/dist/teams/temporalId.js +28 -0
- package/dist/teams/temporalId.js.map +1 -0
- package/dist/teams/toAdaptiveCard.d.ts.map +1 -1
- package/dist/teams/toAdaptiveCard.js +80 -1
- package/dist/teams/toAdaptiveCard.js.map +1 -1
- package/dist/teams/toTeamsAttachments.d.ts.map +1 -1
- package/dist/teams/toTeamsAttachments.js.map +1 -1
- package/dist/teams/types.d.ts +19 -1
- package/dist/teams/types.d.ts.map +1 -1
- package/dist/teams.d.ts +1 -1
- package/dist/teams.d.ts.map +1 -1
- package/dist/temporal.d.ts +33 -0
- package/dist/temporal.d.ts.map +1 -0
- package/dist/temporal.js +152 -0
- package/dist/temporal.js.map +1 -0
- package/dist/vocabulary/collectFormValues.d.ts +1 -1
- package/dist/vocabulary/collectFormValues.d.ts.map +1 -1
- package/dist/vocabulary/collectFormValues.js +7 -3
- package/dist/vocabulary/collectFormValues.js.map +1 -1
- package/dist/vocabulary/data.d.ts +1 -1
- package/dist/vocabulary/interactive.d.ts +7 -1
- package/dist/vocabulary/interactive.d.ts.map +1 -1
- package/dist/vocabulary/interactive.js +62 -12
- package/dist/vocabulary/interactive.js.map +1 -1
- package/package.json +5 -5
- package/src/a2ui/convert.test.ts +223 -14
- package/src/a2ui/convert.ts +41 -7
- package/src/constants.ts +1 -0
- package/src/slack/datePicker.test.ts +612 -0
- package/src/slack/decodeBlockAction.ts +114 -41
- package/src/slack/fromSlackBlocks.ts +29 -0
- package/src/slack/toSlackBlocks.ts +123 -36
- package/src/slack/types.ts +24 -0
- package/src/slack.ts +2 -0
- package/src/teams/decodeSubmitData.test.ts +216 -0
- package/src/teams/decodeSubmitData.ts +49 -4
- package/src/teams/temporal.test.ts +766 -0
- package/src/teams/temporalId.ts +56 -0
- package/src/teams/toAdaptiveCard.ts +166 -2
- package/src/teams/toTeamsAttachments.ts +4 -1
- package/src/teams/types.ts +17 -0
- package/src/teams.ts +1 -0
- package/src/temporal.test.ts +319 -0
- package/src/temporal.ts +259 -0
- package/src/vocabulary/collectFormValues.test.ts +198 -1
- package/src/vocabulary/collectFormValues.ts +31 -2
- package/src/vocabulary/datepicker.dom.test.tsx +1148 -0
- package/src/vocabulary/interactive.dom.test.tsx +59 -11
- package/src/vocabulary/interactive.tsx +151 -15
package/dist/temporal.js
ADDED
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
//#region src/temporal.ts
|
|
2
|
+
const DATE_PATTERN = /^\d{4}-\d{2}-\d{2}$/;
|
|
3
|
+
const TIME_PATTERN = /^([01]\d|2[0-3]):([0-5]\d)(?::([0-5]\d)(?:\.(\d{1,9}))?)?$/;
|
|
4
|
+
const DATETIME_PATTERN = /^(\d{4}-\d{2}-\d{2})T([01]\d|2[0-3]):([0-5]\d)(?::([0-5]\d)(?:\.(\d+))?)?(Z|[+-](?:[01]\d|2[0-3]):[0-5]\d)?$/;
|
|
5
|
+
const INPUT_PATTERN = /^((?:\d{4}-\d{2}-\d{2}T)?(?:[01]\d|2[0-3]):[0-5]\d)(?::([0-5]\d)(?:\.(\d{1,9}))?)?$/;
|
|
6
|
+
const normalizeTemporalInputValue = (value) => {
|
|
7
|
+
const match = INPUT_PATTERN.exec(value);
|
|
8
|
+
if (!match || match[2] === void 0) return value;
|
|
9
|
+
const digits = match[3]?.slice(0, 3) ?? "";
|
|
10
|
+
let end = digits.length;
|
|
11
|
+
while (end > 0 && digits[end - 1] === "0") end--;
|
|
12
|
+
const fraction = digits.slice(0, end);
|
|
13
|
+
if (match[2] === "00" && !fraction) return match[1];
|
|
14
|
+
return `${match[1]}:${match[2]}${fraction ? `.${fraction}` : ""}`;
|
|
15
|
+
};
|
|
16
|
+
const isCalendarDate = (value) => {
|
|
17
|
+
const date = /* @__PURE__ */ new Date(`${value}T00:00:00Z`);
|
|
18
|
+
return Number.isFinite(date.getTime()) && date.toISOString().slice(0, 10) === value;
|
|
19
|
+
};
|
|
20
|
+
const classifyTemporal = (value) => {
|
|
21
|
+
if (DATE_PATTERN.test(value) && isCalendarDate(value)) return {
|
|
22
|
+
kind: "date",
|
|
23
|
+
value
|
|
24
|
+
};
|
|
25
|
+
const time = TIME_PATTERN.exec(value);
|
|
26
|
+
if (time) return {
|
|
27
|
+
kind: "time",
|
|
28
|
+
value,
|
|
29
|
+
precision: time[4]?.length ?? (time[3] === void 0 ? "minutes" : "seconds")
|
|
30
|
+
};
|
|
31
|
+
const datetime = DATETIME_PATTERN.exec(value);
|
|
32
|
+
if (!datetime || !isCalendarDate(datetime[1])) return {
|
|
33
|
+
kind: "unparseable",
|
|
34
|
+
value
|
|
35
|
+
};
|
|
36
|
+
const precision = datetime[5]?.length ?? (datetime[4] === void 0 ? "minutes" : "seconds");
|
|
37
|
+
const offset = datetime[6];
|
|
38
|
+
if (offset === void 0) return {
|
|
39
|
+
kind: "floating",
|
|
40
|
+
value,
|
|
41
|
+
precision
|
|
42
|
+
};
|
|
43
|
+
return {
|
|
44
|
+
kind: "instant",
|
|
45
|
+
epochMs: Date.parse(value),
|
|
46
|
+
offset,
|
|
47
|
+
precision,
|
|
48
|
+
...datetime[5] && datetime[5].length > 3 ? { subMillisecondDigits: datetime[5].slice(3) } : {}
|
|
49
|
+
};
|
|
50
|
+
};
|
|
51
|
+
const getTemporalInputStep = (...values) => {
|
|
52
|
+
let step;
|
|
53
|
+
for (const value of values) {
|
|
54
|
+
const temporal = classifyTemporal(value ?? "");
|
|
55
|
+
const precision = "precision" in temporal ? temporal.precision : INPUT_PATTERN.exec(value ?? "")?.[3]?.length;
|
|
56
|
+
if (typeof precision === "number") return "any";
|
|
57
|
+
if (precision === "seconds") step = 1;
|
|
58
|
+
}
|
|
59
|
+
return step;
|
|
60
|
+
};
|
|
61
|
+
const splitTemporalMinutes = (value, offset) => {
|
|
62
|
+
const temporal = classifyTemporal(value);
|
|
63
|
+
if (temporal.kind === "date" || temporal.kind === "unparseable") return void 0;
|
|
64
|
+
const wallTime = temporal.kind === "instant" ? formatTemporalInstant(temporal, offset).slice(0, -(offset ?? temporal.offset).length) : temporal.value;
|
|
65
|
+
const end = temporal.kind === "time" ? 5 : 16;
|
|
66
|
+
return {
|
|
67
|
+
...temporal.kind === "time" ? {} : { date: wallTime.slice(0, 10) },
|
|
68
|
+
time: wallTime.slice(end - 5, end),
|
|
69
|
+
droppedPrecision: /[1-9]/.test(wallTime.slice(end))
|
|
70
|
+
};
|
|
71
|
+
};
|
|
72
|
+
const mergeTemporalMinutes = (date, time) => {
|
|
73
|
+
if (classifyTemporal(date).kind !== "date" || classifyTemporal(time).kind !== "time") return "";
|
|
74
|
+
return `${date}T${time.slice(0, 5)}`;
|
|
75
|
+
};
|
|
76
|
+
const pad = (value, digits = 2) => String(value).padStart(digits, "0");
|
|
77
|
+
const offsetMinutes = (offset) => offset === "Z" ? 0 : (offset.startsWith("-") ? -1 : 1) * (Number(offset.slice(1, 3)) * 60 + Number(offset.slice(4, 6)));
|
|
78
|
+
const formatTemporalInstant = (instant, offset = instant.offset, precision = instant.precision) => {
|
|
79
|
+
const date = new Date(instant.epochMs + offsetMinutes(offset) * 6e4);
|
|
80
|
+
const iso = date.toISOString();
|
|
81
|
+
return `${precision === "minutes" ? iso.slice(0, 16) : precision === "seconds" ? iso.slice(0, 19) : `${iso.slice(0, 19)}.${(pad(date.getUTCMilliseconds(), 3) + (instant.subMillisecondDigits ?? "")).padEnd(precision, "0").slice(0, precision)}`}${offset}`;
|
|
82
|
+
};
|
|
83
|
+
const formatTemporalUnixSeconds = (seconds, offset = "Z") => {
|
|
84
|
+
if (!Number.isInteger(seconds)) return void 0;
|
|
85
|
+
try {
|
|
86
|
+
const value = formatTemporalInstant({
|
|
87
|
+
kind: "instant",
|
|
88
|
+
epochMs: seconds * 1e3,
|
|
89
|
+
offset,
|
|
90
|
+
precision: "seconds"
|
|
91
|
+
});
|
|
92
|
+
return classifyTemporal(value).kind === "instant" ? value : void 0;
|
|
93
|
+
} catch {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
const temporalOffsetLabel = (value) => {
|
|
98
|
+
const temporal = classifyTemporal(value);
|
|
99
|
+
if (temporal.kind !== "instant") return void 0;
|
|
100
|
+
return temporal.offset === "Z" ? "UTC" : `UTC${temporal.offset}`;
|
|
101
|
+
};
|
|
102
|
+
const fromOffsetDateTime = (value, previousValue) => {
|
|
103
|
+
if (value === "") return "";
|
|
104
|
+
if (classifyTemporal(value).kind !== "floating") return value;
|
|
105
|
+
const previous = classifyTemporal(previousValue ?? "");
|
|
106
|
+
if (previous.kind !== "instant") return value;
|
|
107
|
+
const epochMs = Date.parse(`${value}${previous.offset}`);
|
|
108
|
+
const minuteRemainder = previous.precision === "minutes" ? 0 : (previous.epochMs % 6e4 + 6e4) % 6e4;
|
|
109
|
+
return formatTemporalInstant({
|
|
110
|
+
...previous,
|
|
111
|
+
epochMs: epochMs + minuteRemainder
|
|
112
|
+
});
|
|
113
|
+
};
|
|
114
|
+
const toLocalDateTime = (value, precision) => {
|
|
115
|
+
const temporal = classifyTemporal(value);
|
|
116
|
+
if (temporal.kind !== "instant") return value;
|
|
117
|
+
const date = new Date(temporal.epochMs);
|
|
118
|
+
const wallTime = `${pad(date.getFullYear(), 4)}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}T${pad(date.getHours())}:${pad(date.getMinutes())}`;
|
|
119
|
+
return (precision ?? temporal.precision) === "minutes" ? wallTime : `${wallTime}:${pad(date.getSeconds())}${typeof precision === "number" ? formatTemporalInstant(temporal, "Z", precision).slice(19, -1) : ""}`;
|
|
120
|
+
};
|
|
121
|
+
const toPickerLocalDateTime = (value) => {
|
|
122
|
+
const temporal = classifyTemporal(value);
|
|
123
|
+
if (temporal.kind !== "instant") return normalizeTemporalInputValue(value);
|
|
124
|
+
const local = toLocalDateTime(value, typeof temporal.precision === "number" ? 3 : temporal.precision);
|
|
125
|
+
return typeof temporal.precision !== "number" || local.endsWith(".000") ? normalizeTemporalInputValue(local) : local;
|
|
126
|
+
};
|
|
127
|
+
const fromLocalDateTime = (value, previousValue) => {
|
|
128
|
+
const temporal = classifyTemporal(value);
|
|
129
|
+
const previous = classifyTemporal(previousValue ?? "");
|
|
130
|
+
if (temporal.kind !== "floating" || previous.kind === "floating") return value;
|
|
131
|
+
const date = new Date(value.replace(/\.(\d{1,2})$/, (_, digits) => `.${digits.padEnd(3, "0")}`));
|
|
132
|
+
const minutes = -date.getTimezoneOffset();
|
|
133
|
+
const offset = `${minutes < 0 ? "-" : "+"}${pad(Math.floor(Math.abs(minutes) / 60))}:${pad(Math.abs(minutes) % 60)}`;
|
|
134
|
+
if (previous.kind !== "instant") return formatTemporalInstant({
|
|
135
|
+
kind: "instant",
|
|
136
|
+
epochMs: date.getTime(),
|
|
137
|
+
offset,
|
|
138
|
+
precision: "seconds"
|
|
139
|
+
});
|
|
140
|
+
return formatTemporalInstant({
|
|
141
|
+
...previous,
|
|
142
|
+
epochMs: date.getTime(),
|
|
143
|
+
...date.getMilliseconds() === new Date(previous.epochMs).getUTCMilliseconds() ? {} : typeof temporal.precision === "number" ? {
|
|
144
|
+
precision: Math.max(temporal.precision, typeof previous.precision === "number" ? previous.precision : 0),
|
|
145
|
+
subMillisecondDigits: value.slice(value.indexOf(".") + 4)
|
|
146
|
+
} : { subMillisecondDigits: "" }
|
|
147
|
+
});
|
|
148
|
+
};
|
|
149
|
+
//#endregion
|
|
150
|
+
export { classifyTemporal, formatTemporalInstant, formatTemporalUnixSeconds, fromLocalDateTime, fromOffsetDateTime, getTemporalInputStep, mergeTemporalMinutes, normalizeTemporalInputValue, splitTemporalMinutes, temporalOffsetLabel, toLocalDateTime, toPickerLocalDateTime };
|
|
151
|
+
|
|
152
|
+
//# sourceMappingURL=temporal.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"temporal.js","names":[],"sources":["../src/temporal.ts"],"sourcesContent":["export type TemporalPrecision = \"minutes\" | \"seconds\" | number;\n\nexport type TemporalInstant = {\n kind: \"instant\";\n epochMs: number;\n offset: string;\n precision: TemporalPrecision;\n subMillisecondDigits?: string;\n};\n\nexport type TemporalValue =\n | { kind: \"date\" | \"unparseable\"; value: string }\n | {\n kind: \"time\" | \"floating\";\n value: string;\n precision: TemporalPrecision;\n }\n | TemporalInstant;\n\nconst DATE_PATTERN = /^\\d{4}-\\d{2}-\\d{2}$/;\nconst TIME_PATTERN =\n /^([01]\\d|2[0-3]):([0-5]\\d)(?::([0-5]\\d)(?:\\.(\\d{1,9}))?)?$/;\nconst DATETIME_PATTERN =\n /^(\\d{4}-\\d{2}-\\d{2})T([01]\\d|2[0-3]):([0-5]\\d)(?::([0-5]\\d)(?:\\.(\\d+))?)?(Z|[+-](?:[01]\\d|2[0-3]):[0-5]\\d)?$/;\nconst INPUT_PATTERN =\n /^((?:\\d{4}-\\d{2}-\\d{2}T)?(?:[01]\\d|2[0-3]):[0-5]\\d)(?::([0-5]\\d)(?:\\.(\\d{1,9}))?)?$/;\n\nexport const normalizeTemporalInputValue = (value: string): string => {\n const match = INPUT_PATTERN.exec(value);\n if (!match || match[2] === undefined) return value;\n const digits = match[3]?.slice(0, 3) ?? \"\";\n let end = digits.length;\n while (end > 0 && digits[end - 1] === \"0\") end--;\n const fraction = digits.slice(0, end);\n if (match[2] === \"00\" && !fraction) return match[1]!;\n return `${match[1]}:${match[2]}${fraction ? `.${fraction}` : \"\"}`;\n};\n\nconst isCalendarDate = (value: string): boolean => {\n const date = new Date(`${value}T00:00:00Z`);\n return (\n Number.isFinite(date.getTime()) && date.toISOString().slice(0, 10) === value\n );\n};\n\nexport const classifyTemporal = (value: string): TemporalValue => {\n if (DATE_PATTERN.test(value) && isCalendarDate(value)) {\n return { kind: \"date\", value };\n }\n const time = TIME_PATTERN.exec(value);\n if (time) {\n return {\n kind: \"time\",\n value,\n precision:\n time[4]?.length ?? (time[3] === undefined ? \"minutes\" : \"seconds\"),\n };\n }\n const datetime = DATETIME_PATTERN.exec(value);\n if (!datetime || !isCalendarDate(datetime[1]!)) {\n return { kind: \"unparseable\", value };\n }\n const precision =\n datetime[5]?.length ?? (datetime[4] === undefined ? \"minutes\" : \"seconds\");\n const offset = datetime[6];\n if (offset === undefined) return { kind: \"floating\", value, precision };\n return {\n kind: \"instant\",\n epochMs: Date.parse(value),\n offset,\n precision,\n ...(datetime[5] && datetime[5].length > 3\n ? { subMillisecondDigits: datetime[5].slice(3) }\n : {}),\n };\n};\n\nexport const getTemporalInputStep = (\n ...values: (string | undefined)[]\n): \"any\" | 1 | undefined => {\n let step: 1 | undefined;\n for (const value of values) {\n const temporal = classifyTemporal(value ?? \"\");\n const precision =\n \"precision\" in temporal\n ? temporal.precision\n : INPUT_PATTERN.exec(value ?? \"\")?.[3]?.length;\n if (typeof precision === \"number\") return \"any\";\n if (precision === \"seconds\") step = 1;\n }\n return step;\n};\n\nexport const splitTemporalMinutes = (\n value: string,\n offset?: string,\n): { date?: string; time: string; droppedPrecision: boolean } | undefined => {\n const temporal = classifyTemporal(value);\n if (temporal.kind === \"date\" || temporal.kind === \"unparseable\")\n return undefined;\n const wallTime =\n temporal.kind === \"instant\"\n ? formatTemporalInstant(temporal, offset).slice(\n 0,\n -(offset ?? temporal.offset).length,\n )\n : temporal.value;\n const end = temporal.kind === \"time\" ? 5 : 16;\n return {\n ...(temporal.kind === \"time\" ? {} : { date: wallTime.slice(0, 10) }),\n time: wallTime.slice(end - 5, end),\n droppedPrecision: /[1-9]/.test(wallTime.slice(end)),\n };\n};\n\nexport const mergeTemporalMinutes = (date: string, time: string): string => {\n if (\n classifyTemporal(date).kind !== \"date\" ||\n classifyTemporal(time).kind !== \"time\"\n )\n return \"\";\n return `${date}T${time.slice(0, 5)}`;\n};\n\nconst pad = (value: number, digits = 2): string =>\n String(value).padStart(digits, \"0\");\n\nconst offsetMinutes = (offset: string): number =>\n offset === \"Z\"\n ? 0\n : (offset.startsWith(\"-\") ? -1 : 1) *\n (Number(offset.slice(1, 3)) * 60 + Number(offset.slice(4, 6)));\n\nexport const formatTemporalInstant = (\n instant: TemporalInstant,\n offset = instant.offset,\n precision = instant.precision,\n): string => {\n const date = new Date(instant.epochMs + offsetMinutes(offset) * 60_000);\n const iso = date.toISOString();\n const wallTime =\n precision === \"minutes\"\n ? iso.slice(0, 16)\n : precision === \"seconds\"\n ? iso.slice(0, 19)\n : `${iso.slice(0, 19)}.${(pad(date.getUTCMilliseconds(), 3) + (instant.subMillisecondDigits ?? \"\")).padEnd(precision, \"0\").slice(0, precision)}`;\n return `${wallTime}${offset}`;\n};\n\nexport const formatTemporalUnixSeconds = (\n seconds: number,\n offset = \"Z\",\n): string | undefined => {\n if (!Number.isInteger(seconds)) return undefined;\n try {\n const value = formatTemporalInstant({\n kind: \"instant\",\n epochMs: seconds * 1000,\n offset,\n precision: \"seconds\",\n });\n return classifyTemporal(value).kind === \"instant\" ? value : undefined;\n } catch {\n return undefined;\n }\n};\n\nexport const temporalOffsetLabel = (value: string): string | undefined => {\n const temporal = classifyTemporal(value);\n if (temporal.kind !== \"instant\") return undefined;\n return temporal.offset === \"Z\" ? \"UTC\" : `UTC${temporal.offset}`;\n};\n\nexport const fromOffsetDateTime = (\n value: string,\n previousValue?: string,\n): string => {\n if (value === \"\") return \"\";\n if (classifyTemporal(value).kind !== \"floating\") return value;\n const previous = classifyTemporal(previousValue ?? \"\");\n if (previous.kind !== \"instant\") return value;\n const epochMs = Date.parse(`${value}${previous.offset}`);\n const minuteRemainder =\n previous.precision === \"minutes\"\n ? 0\n : ((previous.epochMs % 60_000) + 60_000) % 60_000;\n return formatTemporalInstant({\n ...previous,\n epochMs: epochMs + minuteRemainder,\n });\n};\n\nexport const toLocalDateTime = (\n value: string,\n precision?: TemporalPrecision,\n): string => {\n const temporal = classifyTemporal(value);\n if (temporal.kind !== \"instant\") return value;\n const date = new Date(temporal.epochMs);\n const wallTime = `${pad(date.getFullYear(), 4)}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}T${pad(date.getHours())}:${pad(date.getMinutes())}`;\n return (precision ?? temporal.precision) === \"minutes\"\n ? wallTime\n : `${wallTime}:${pad(date.getSeconds())}${typeof precision === \"number\" ? formatTemporalInstant(temporal, \"Z\", precision).slice(19, -1) : \"\"}`;\n};\n\nexport const toPickerLocalDateTime = (value: string): string => {\n const temporal = classifyTemporal(value);\n if (temporal.kind !== \"instant\") return normalizeTemporalInputValue(value);\n const local = toLocalDateTime(\n value,\n typeof temporal.precision === \"number\" ? 3 : temporal.precision,\n );\n return typeof temporal.precision !== \"number\" || local.endsWith(\".000\")\n ? normalizeTemporalInputValue(local)\n : local;\n};\n\nexport const fromLocalDateTime = (\n value: string,\n previousValue?: string,\n): string => {\n const temporal = classifyTemporal(value);\n const previous = classifyTemporal(previousValue ?? \"\");\n if (temporal.kind !== \"floating\" || previous.kind === \"floating\") {\n return value;\n }\n const date = new Date(\n value.replace(\n /\\.(\\d{1,2})$/,\n (_, digits: string) => `.${digits.padEnd(3, \"0\")}`,\n ),\n );\n const minutes = -date.getTimezoneOffset();\n const offset = `${minutes < 0 ? \"-\" : \"+\"}${pad(Math.floor(Math.abs(minutes) / 60))}:${pad(Math.abs(minutes) % 60)}`;\n if (previous.kind !== \"instant\") {\n return formatTemporalInstant({\n kind: \"instant\",\n epochMs: date.getTime(),\n offset,\n precision: \"seconds\",\n });\n }\n return formatTemporalInstant({\n ...previous,\n epochMs: date.getTime(),\n ...(date.getMilliseconds() ===\n new Date(previous.epochMs).getUTCMilliseconds()\n ? {}\n : typeof temporal.precision === \"number\"\n ? {\n precision: Math.max(\n temporal.precision,\n typeof previous.precision === \"number\" ? previous.precision : 0,\n ),\n subMillisecondDigits: value.slice(value.indexOf(\".\") + 4),\n }\n : { subMillisecondDigits: \"\" }),\n });\n};\n"],"mappings":";AAmBA,MAAM,eAAe;AACrB,MAAM,eACJ;AACF,MAAM,mBACJ;AACF,MAAM,gBACJ;AAEF,MAAa,+BAA+B,UAA0B;CACpE,MAAM,QAAQ,cAAc,KAAK,KAAK;CACtC,IAAI,CAAC,SAAS,MAAM,OAAO,KAAA,GAAW,OAAO;CAC7C,MAAM,SAAS,MAAM,EAAE,EAAE,MAAM,GAAG,CAAC,KAAK;CACxC,IAAI,MAAM,OAAO;CACjB,OAAO,MAAM,KAAK,OAAO,MAAM,OAAO,KAAK;CAC3C,MAAM,WAAW,OAAO,MAAM,GAAG,GAAG;CACpC,IAAI,MAAM,OAAO,QAAQ,CAAC,UAAU,OAAO,MAAM;CACjD,OAAO,GAAG,MAAM,GAAG,GAAG,MAAM,KAAK,WAAW,IAAI,aAAa;AAC/D;AAEA,MAAM,kBAAkB,UAA2B;CACjD,MAAM,uBAAO,IAAI,KAAK,GAAG,MAAM,WAAW;CAC1C,OACE,OAAO,SAAS,KAAK,QAAQ,CAAC,KAAK,KAAK,YAAY,CAAC,CAAC,MAAM,GAAG,EAAE,MAAM;AAE3E;AAEA,MAAa,oBAAoB,UAAiC;CAChE,IAAI,aAAa,KAAK,KAAK,KAAK,eAAe,KAAK,GAClD,OAAO;EAAE,MAAM;EAAQ;CAAM;CAE/B,MAAM,OAAO,aAAa,KAAK,KAAK;CACpC,IAAI,MACF,OAAO;EACL,MAAM;EACN;EACA,WACE,KAAK,EAAE,EAAE,WAAW,KAAK,OAAO,KAAA,IAAY,YAAY;CAC5D;CAEF,MAAM,WAAW,iBAAiB,KAAK,KAAK;CAC5C,IAAI,CAAC,YAAY,CAAC,eAAe,SAAS,EAAG,GAC3C,OAAO;EAAE,MAAM;EAAe;CAAM;CAEtC,MAAM,YACJ,SAAS,EAAE,EAAE,WAAW,SAAS,OAAO,KAAA,IAAY,YAAY;CAClE,MAAM,SAAS,SAAS;CACxB,IAAI,WAAW,KAAA,GAAW,OAAO;EAAE,MAAM;EAAY;EAAO;CAAU;CACtE,OAAO;EACL,MAAM;EACN,SAAS,KAAK,MAAM,KAAK;EACzB;EACA;EACA,GAAI,SAAS,MAAM,SAAS,EAAE,CAAC,SAAS,IACpC,EAAE,sBAAsB,SAAS,EAAE,CAAC,MAAM,CAAC,EAAE,IAC7C,CAAC;CACP;AACF;AAEA,MAAa,wBACX,GAAG,WACuB;CAC1B,IAAI;CACJ,KAAK,MAAM,SAAS,QAAQ;EAC1B,MAAM,WAAW,iBAAiB,SAAS,EAAE;EAC7C,MAAM,YACJ,eAAe,WACX,SAAS,YACT,cAAc,KAAK,SAAS,EAAE,CAAC,GAAG,EAAE,EAAE;EAC5C,IAAI,OAAO,cAAc,UAAU,OAAO;EAC1C,IAAI,cAAc,WAAW,OAAO;CACtC;CACA,OAAO;AACT;AAEA,MAAa,wBACX,OACA,WAC2E;CAC3E,MAAM,WAAW,iBAAiB,KAAK;CACvC,IAAI,SAAS,SAAS,UAAU,SAAS,SAAS,eAChD,OAAO,KAAA;CACT,MAAM,WACJ,SAAS,SAAS,YACd,sBAAsB,UAAU,MAAM,CAAC,CAAC,MACtC,GACA,EAAE,UAAU,SAAS,OAAA,CAAQ,MAC/B,IACA,SAAS;CACf,MAAM,MAAM,SAAS,SAAS,SAAS,IAAI;CAC3C,OAAO;EACL,GAAI,SAAS,SAAS,SAAS,CAAC,IAAI,EAAE,MAAM,SAAS,MAAM,GAAG,EAAE,EAAE;EAClE,MAAM,SAAS,MAAM,MAAM,GAAG,GAAG;EACjC,kBAAkB,QAAQ,KAAK,SAAS,MAAM,GAAG,CAAC;CACpD;AACF;AAEA,MAAa,wBAAwB,MAAc,SAAyB;CAC1E,IACE,iBAAiB,IAAI,CAAC,CAAC,SAAS,UAChC,iBAAiB,IAAI,CAAC,CAAC,SAAS,QAEhC,OAAO;CACT,OAAO,GAAG,KAAK,GAAG,KAAK,MAAM,GAAG,CAAC;AACnC;AAEA,MAAM,OAAO,OAAe,SAAS,MACnC,OAAO,KAAK,CAAC,CAAC,SAAS,QAAQ,GAAG;AAEpC,MAAM,iBAAiB,WACrB,WAAW,MACP,KACC,OAAO,WAAW,GAAG,IAAI,KAAK,MAC9B,OAAO,OAAO,MAAM,GAAG,CAAC,CAAC,IAAI,KAAK,OAAO,OAAO,MAAM,GAAG,CAAC,CAAC;AAElE,MAAa,yBACX,SACA,SAAS,QAAQ,QACjB,YAAY,QAAQ,cACT;CACX,MAAM,OAAO,IAAI,KAAK,QAAQ,UAAU,cAAc,MAAM,IAAI,GAAM;CACtE,MAAM,MAAM,KAAK,YAAY;CAO7B,OAAO,GALL,cAAc,YACV,IAAI,MAAM,GAAG,EAAE,IACf,cAAc,YACZ,IAAI,MAAM,GAAG,EAAE,IACf,GAAG,IAAI,MAAM,GAAG,EAAE,EAAE,IAAI,IAAI,KAAK,mBAAmB,GAAG,CAAC,KAAK,QAAQ,wBAAwB,IAAA,CAAK,OAAO,WAAW,GAAG,CAAC,CAAC,MAAM,GAAG,SAAS,MAC9H;AACvB;AAEA,MAAa,6BACX,SACA,SAAS,QACc;CACvB,IAAI,CAAC,OAAO,UAAU,OAAO,GAAG,OAAO,KAAA;CACvC,IAAI;EACF,MAAM,QAAQ,sBAAsB;GAClC,MAAM;GACN,SAAS,UAAU;GACnB;GACA,WAAW;EACb,CAAC;EACD,OAAO,iBAAiB,KAAK,CAAC,CAAC,SAAS,YAAY,QAAQ,KAAA;CAC9D,QAAQ;EACN;CACF;AACF;AAEA,MAAa,uBAAuB,UAAsC;CACxE,MAAM,WAAW,iBAAiB,KAAK;CACvC,IAAI,SAAS,SAAS,WAAW,OAAO,KAAA;CACxC,OAAO,SAAS,WAAW,MAAM,QAAQ,MAAM,SAAS;AAC1D;AAEA,MAAa,sBACX,OACA,kBACW;CACX,IAAI,UAAU,IAAI,OAAO;CACzB,IAAI,iBAAiB,KAAK,CAAC,CAAC,SAAS,YAAY,OAAO;CACxD,MAAM,WAAW,iBAAiB,iBAAiB,EAAE;CACrD,IAAI,SAAS,SAAS,WAAW,OAAO;CACxC,MAAM,UAAU,KAAK,MAAM,GAAG,QAAQ,SAAS,QAAQ;CACvD,MAAM,kBACJ,SAAS,cAAc,YACnB,KACE,SAAS,UAAU,MAAU,OAAU;CAC/C,OAAO,sBAAsB;EAC3B,GAAG;EACH,SAAS,UAAU;CACrB,CAAC;AACH;AAEA,MAAa,mBACX,OACA,cACW;CACX,MAAM,WAAW,iBAAiB,KAAK;CACvC,IAAI,SAAS,SAAS,WAAW,OAAO;CACxC,MAAM,OAAO,IAAI,KAAK,SAAS,OAAO;CACtC,MAAM,WAAW,GAAG,IAAI,KAAK,YAAY,GAAG,CAAC,EAAE,GAAG,IAAI,KAAK,SAAS,IAAI,CAAC,EAAE,GAAG,IAAI,KAAK,QAAQ,CAAC,EAAE,GAAG,IAAI,KAAK,SAAS,CAAC,EAAE,GAAG,IAAI,KAAK,WAAW,CAAC;CAClJ,QAAQ,aAAa,SAAS,eAAe,YACzC,WACA,GAAG,SAAS,GAAG,IAAI,KAAK,WAAW,CAAC,IAAI,OAAO,cAAc,WAAW,sBAAsB,UAAU,KAAK,SAAS,CAAC,CAAC,MAAM,IAAI,EAAE,IAAI;AAC9I;AAEA,MAAa,yBAAyB,UAA0B;CAC9D,MAAM,WAAW,iBAAiB,KAAK;CACvC,IAAI,SAAS,SAAS,WAAW,OAAO,4BAA4B,KAAK;CACzE,MAAM,QAAQ,gBACZ,OACA,OAAO,SAAS,cAAc,WAAW,IAAI,SAAS,SACxD;CACA,OAAO,OAAO,SAAS,cAAc,YAAY,MAAM,SAAS,MAAM,IAClE,4BAA4B,KAAK,IACjC;AACN;AAEA,MAAa,qBACX,OACA,kBACW;CACX,MAAM,WAAW,iBAAiB,KAAK;CACvC,MAAM,WAAW,iBAAiB,iBAAiB,EAAE;CACrD,IAAI,SAAS,SAAS,cAAc,SAAS,SAAS,YACpD,OAAO;CAET,MAAM,OAAO,IAAI,KACf,MAAM,QACJ,iBACC,GAAG,WAAmB,IAAI,OAAO,OAAO,GAAG,GAAG,GACjD,CACF;CACA,MAAM,UAAU,CAAC,KAAK,kBAAkB;CACxC,MAAM,SAAS,GAAG,UAAU,IAAI,MAAM,MAAM,IAAI,KAAK,MAAM,KAAK,IAAI,OAAO,IAAI,EAAE,CAAC,EAAE,GAAG,IAAI,KAAK,IAAI,OAAO,IAAI,EAAE;CACjH,IAAI,SAAS,SAAS,WACpB,OAAO,sBAAsB;EAC3B,MAAM;EACN,SAAS,KAAK,QAAQ;EACtB;EACA,WAAW;CACb,CAAC;CAEH,OAAO,sBAAsB;EAC3B,GAAG;EACH,SAAS,KAAK,QAAQ;EACtB,GAAI,KAAK,gBAAgB,MACzB,IAAI,KAAK,SAAS,OAAO,CAAC,CAAC,mBAAmB,IAC1C,CAAC,IACD,OAAO,SAAS,cAAc,WAC5B;GACE,WAAW,KAAK,IACd,SAAS,WACT,OAAO,SAAS,cAAc,WAAW,SAAS,YAAY,CAChE;GACA,sBAAsB,MAAM,MAAM,MAAM,QAAQ,GAAG,IAAI,CAAC;EAC1D,IACA,EAAE,sBAAsB,GAAG;CACnC,CAAC;AACH"}
|
|
@@ -13,7 +13,7 @@ export type FormControlElementLike = {
|
|
|
13
13
|
readonly matches?: ((selector: string) => boolean) | undefined;
|
|
14
14
|
};
|
|
15
15
|
/**
|
|
16
|
-
* Collects a submitted form's named control values into a plain object, keyed by `name`, in document order. Reads each control's live DOM state rather than `FormData`, so a checkbox resolves to its `checked` boolean instead of an on/off string. A radio group resolves to its checked option's `value`, or `undefined` if none is checked. A checkbox group resolves to its checked options' values in document order, or an empty array if none is checked. Any other repeated `name` resolves to an array of its controls' values, in document order. Controls without a `name`, that carry `data-aui-generated-name`, or that are effectively disabled, including through an ancestor disabled fieldset outside its first legend, are skipped entirely.
|
|
16
|
+
* Collects a submitted form's named control values into a plain object, keyed by `name`, in document order. Reads each control's live DOM state rather than `FormData`, so a checkbox resolves to its `checked` boolean instead of an on/off string. A radio group resolves to its checked option's `value`, or `undefined` if none is checked. A checkbox group resolves to its checked options' values in document order, or an empty array if none is checked. Any other repeated `name` resolves to an array of its controls' values, in document order. A time or datetime-local control's `data-aui-field-value` preserves the canonical string when its local projection is unchanged; an edited instant retains its original offset and precision. Controls without a `name`, that carry `data-aui-generated-name`, or that are effectively disabled, including through an ancestor disabled fieldset outside its first legend, are skipped entirely.
|
|
17
17
|
*/
|
|
18
18
|
export declare function collectFormValues(elements: ArrayLike<FormControlElementLike>): Record<string, unknown>;
|
|
19
19
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"collectFormValues.d.ts","sourceRoot":"","sources":["../../src/vocabulary/collectFormValues.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"collectFormValues.d.ts","sourceRoot":"","sources":["../../src/vocabulary/collectFormValues.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAavC;;GAEG;AACH,MAAM,MAAM,sBAAsB,GAAG;IACnC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;IACjD,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC,GAAG,SAAS,CAAC;IACtE,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,GAAG,SAAS,CAAC;CAChE,CAAC;AAEF;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,SAAS,CAAC,sBAAsB,CAAC,GAC1C,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAuEzB;AAED;;GAEG;AACH,wBAAgB,0BAA0B,CACxC,KAAK,EAAE,SAAS,CAAC,eAAe,CAAC,GAChC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAKzB"}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import "../constants.js";
|
|
1
|
+
import { FIELD_VALUE_ATTR } from "../constants.js";
|
|
2
|
+
import { fromLocalDateTime, normalizeTemporalInputValue, toPickerLocalDateTime } from "../temporal.js";
|
|
2
3
|
//#region src/vocabulary/collectFormValues.ts
|
|
3
4
|
/**
|
|
4
|
-
* Collects a submitted form's named control values into a plain object, keyed by `name`, in document order. Reads each control's live DOM state rather than `FormData`, so a checkbox resolves to its `checked` boolean instead of an on/off string. A radio group resolves to its checked option's `value`, or `undefined` if none is checked. A checkbox group resolves to its checked options' values in document order, or an empty array if none is checked. Any other repeated `name` resolves to an array of its controls' values, in document order. Controls without a `name`, that carry `data-aui-generated-name`, or that are effectively disabled, including through an ancestor disabled fieldset outside its first legend, are skipped entirely.
|
|
5
|
+
* Collects a submitted form's named control values into a plain object, keyed by `name`, in document order. Reads each control's live DOM state rather than `FormData`, so a checkbox resolves to its `checked` boolean instead of an on/off string. A radio group resolves to its checked option's `value`, or `undefined` if none is checked. A checkbox group resolves to its checked options' values in document order, or an empty array if none is checked. Any other repeated `name` resolves to an array of its controls' values, in document order. A time or datetime-local control's `data-aui-field-value` preserves the canonical string when its local projection is unchanged; an edited instant retains its original offset and precision. Controls without a `name`, that carry `data-aui-generated-name`, or that are effectively disabled, including through an ancestor disabled fieldset outside its first legend, are skipped entirely.
|
|
5
6
|
*/
|
|
6
7
|
function collectFormValues(elements) {
|
|
7
8
|
const values = Object.create(null);
|
|
@@ -20,7 +21,10 @@ function collectFormValues(elements) {
|
|
|
20
21
|
values[name] = element.checked ? [...checked, element.value] : checked;
|
|
21
22
|
continue;
|
|
22
23
|
}
|
|
23
|
-
const
|
|
24
|
+
const temporalType = element.type === "datetime-local" || element.type === "time" ? element.type : element.getAttribute?.("type");
|
|
25
|
+
const inputValue = temporalType === "datetime-local" || temporalType === "time" ? normalizeTemporalInputValue(element.value) : element.value;
|
|
26
|
+
const fieldValue = temporalType === "datetime-local" || temporalType === "time" ? element.getAttribute?.(FIELD_VALUE_ATTR) : void 0;
|
|
27
|
+
const value = element.type === "checkbox" ? element.checked ?? false : element.type === "range" ? Number(element.value) : fieldValue && inputValue !== "" ? normalizeTemporalInputValue(inputValue) === normalizeTemporalInputValue(temporalType === "time" ? fieldValue : toPickerLocalDateTime(fieldValue)) ? fieldValue : temporalType === "datetime-local" ? fromLocalDateTime(inputValue, fieldValue) : inputValue : inputValue;
|
|
24
28
|
if (Object.hasOwn(values, name)) {
|
|
25
29
|
const existing = values[name];
|
|
26
30
|
values[name] = Array.isArray(existing) ? [...existing, value] : [existing, value];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"collectFormValues.js","names":[],"sources":["../../src/vocabulary/collectFormValues.ts"],"sourcesContent":["import type { FormEvent } from \"react\";\nimport {\n CHECKBOX_GROUP_ATTR,\n FIELD_NAME_ATTR,\n GENERATED_NAME_ATTR,\n} from \"../constants\";\n\n/**\n * The subset of `HTMLInputElement`/`HTMLSelectElement`/`HTMLTextAreaElement` that {@link collectFormValues} reads. A structural type rather than the DOM interfaces themselves, so a plain object can stand in for a form control in tests.\n */\nexport type FormControlElementLike = {\n readonly name: string;\n readonly type: string;\n readonly value: string;\n readonly checked?: boolean;\n readonly disabled: boolean;\n readonly hasAttribute: (name: string) => boolean;\n readonly getAttribute?: ((name: string) => string | null) | undefined;\n readonly matches?: ((selector: string) => boolean) | undefined;\n};\n\n/**\n * Collects a submitted form's named control values into a plain object, keyed by `name`, in document order. Reads each control's live DOM state rather than `FormData`, so a checkbox resolves to its `checked` boolean instead of an on/off string. A radio group resolves to its checked option's `value`, or `undefined` if none is checked. A checkbox group resolves to its checked options' values in document order, or an empty array if none is checked. Any other repeated `name` resolves to an array of its controls' values, in document order. Controls without a `name`, that carry `data-aui-generated-name`, or that are effectively disabled, including through an ancestor disabled fieldset outside its first legend, are skipped entirely.\n */\nexport function collectFormValues(\n elements: ArrayLike<FormControlElementLike>,\n): Record<string, unknown> {\n const values: Record<string, unknown> = Object.create(null);\n\n for (const element of Array.from(elements)) {\n const { disabled } = element;\n const name = element.getAttribute?.(FIELD_NAME_ATTR) ?? element.name;\n if (\n !name ||\n disabled ||\n element.hasAttribute(GENERATED_NAME_ATTR) ||\n element.matches?.(\":disabled\")\n )\n continue;\n\n if (element.type === \"radio\") {\n if (element.checked) values[name] = element.value;\n else if (!Object.hasOwn(values, name)) values[name] = undefined;\n continue;\n }\n\n if (\n element.type === \"checkbox\" &&\n element.hasAttribute(CHECKBOX_GROUP_ATTR)\n ) {\n const existing = values[name];\n const checked = Array.isArray(existing) ? existing : [];\n values[name] = element.checked ? [...checked, element.value] : checked;\n continue;\n }\n\n const value: string | number | boolean =\n element.type === \"checkbox\"\n ? (element.checked ?? false)\n : element.type === \"range\"\n ? Number(element.value)\n :
|
|
1
|
+
{"version":3,"file":"collectFormValues.js","names":[],"sources":["../../src/vocabulary/collectFormValues.ts"],"sourcesContent":["import type { FormEvent } from \"react\";\nimport {\n CHECKBOX_GROUP_ATTR,\n FIELD_NAME_ATTR,\n FIELD_VALUE_ATTR,\n GENERATED_NAME_ATTR,\n} from \"../constants\";\nimport {\n fromLocalDateTime,\n normalizeTemporalInputValue,\n toPickerLocalDateTime,\n} from \"../temporal\";\n\n/**\n * The subset of `HTMLInputElement`/`HTMLSelectElement`/`HTMLTextAreaElement` that {@link collectFormValues} reads. A structural type rather than the DOM interfaces themselves, so a plain object can stand in for a form control in tests.\n */\nexport type FormControlElementLike = {\n readonly name: string;\n readonly type: string;\n readonly value: string;\n readonly checked?: boolean;\n readonly disabled: boolean;\n readonly hasAttribute: (name: string) => boolean;\n readonly getAttribute?: ((name: string) => string | null) | undefined;\n readonly matches?: ((selector: string) => boolean) | undefined;\n};\n\n/**\n * Collects a submitted form's named control values into a plain object, keyed by `name`, in document order. Reads each control's live DOM state rather than `FormData`, so a checkbox resolves to its `checked` boolean instead of an on/off string. A radio group resolves to its checked option's `value`, or `undefined` if none is checked. A checkbox group resolves to its checked options' values in document order, or an empty array if none is checked. Any other repeated `name` resolves to an array of its controls' values, in document order. A time or datetime-local control's `data-aui-field-value` preserves the canonical string when its local projection is unchanged; an edited instant retains its original offset and precision. Controls without a `name`, that carry `data-aui-generated-name`, or that are effectively disabled, including through an ancestor disabled fieldset outside its first legend, are skipped entirely.\n */\nexport function collectFormValues(\n elements: ArrayLike<FormControlElementLike>,\n): Record<string, unknown> {\n const values: Record<string, unknown> = Object.create(null);\n\n for (const element of Array.from(elements)) {\n const { disabled } = element;\n const name = element.getAttribute?.(FIELD_NAME_ATTR) ?? element.name;\n if (\n !name ||\n disabled ||\n element.hasAttribute(GENERATED_NAME_ATTR) ||\n element.matches?.(\":disabled\")\n )\n continue;\n\n if (element.type === \"radio\") {\n if (element.checked) values[name] = element.value;\n else if (!Object.hasOwn(values, name)) values[name] = undefined;\n continue;\n }\n\n if (\n element.type === \"checkbox\" &&\n element.hasAttribute(CHECKBOX_GROUP_ATTR)\n ) {\n const existing = values[name];\n const checked = Array.isArray(existing) ? existing : [];\n values[name] = element.checked ? [...checked, element.value] : checked;\n continue;\n }\n\n const temporalType =\n element.type === \"datetime-local\" || element.type === \"time\"\n ? element.type\n : element.getAttribute?.(\"type\");\n const inputValue =\n temporalType === \"datetime-local\" || temporalType === \"time\"\n ? normalizeTemporalInputValue(element.value)\n : element.value;\n const fieldValue =\n temporalType === \"datetime-local\" || temporalType === \"time\"\n ? element.getAttribute?.(FIELD_VALUE_ATTR)\n : undefined;\n const value: string | number | boolean =\n element.type === \"checkbox\"\n ? (element.checked ?? false)\n : element.type === \"range\"\n ? Number(element.value)\n : fieldValue && inputValue !== \"\"\n ? normalizeTemporalInputValue(inputValue) ===\n normalizeTemporalInputValue(\n temporalType === \"time\"\n ? fieldValue\n : toPickerLocalDateTime(fieldValue),\n )\n ? fieldValue\n : temporalType === \"datetime-local\"\n ? fromLocalDateTime(inputValue, fieldValue)\n : inputValue\n : inputValue;\n\n if (Object.hasOwn(values, name)) {\n const existing = values[name];\n values[name] = Array.isArray(existing)\n ? [...existing, value]\n : [existing, value];\n } else {\n values[name] = value;\n }\n }\n\n return values;\n}\n\n/**\n * Convenience wrapper around {@link collectFormValues} for a native form submit event; the cast from `HTMLFormControlsCollection` to `ArrayLike<FormControlElementLike>` lives here once instead of at every call site.\n */\nexport function collectFormValuesFromEvent(\n event: FormEvent<HTMLFormElement>,\n): Record<string, unknown> {\n return collectFormValues(\n event.currentTarget\n .elements as unknown as ArrayLike<FormControlElementLike>,\n );\n}\n"],"mappings":";;;;;;AA8BA,SAAgB,kBACd,UACyB;CACzB,MAAM,SAAkC,OAAO,OAAO,IAAI;CAE1D,KAAK,MAAM,WAAW,MAAM,KAAK,QAAQ,GAAG;EAC1C,MAAM,EAAE,aAAa;EACrB,MAAM,OAAO,QAAQ,eAAA,qBAA8B,KAAK,QAAQ;EAChE,IACE,CAAC,QACD,YACA,QAAQ,aAAA,yBAAgC,KACxC,QAAQ,UAAU,WAAW,GAE7B;EAEF,IAAI,QAAQ,SAAS,SAAS;GAC5B,IAAI,QAAQ,SAAS,OAAO,QAAQ,QAAQ;QACvC,IAAI,CAAC,OAAO,OAAO,QAAQ,IAAI,GAAG,OAAO,QAAQ,KAAA;GACtD;EACF;EAEA,IACE,QAAQ,SAAS,cACjB,QAAQ,aAAA,yBAAgC,GACxC;GACA,MAAM,WAAW,OAAO;GACxB,MAAM,UAAU,MAAM,QAAQ,QAAQ,IAAI,WAAW,CAAC;GACtD,OAAO,QAAQ,QAAQ,UAAU,CAAC,GAAG,SAAS,QAAQ,KAAK,IAAI;GAC/D;EACF;EAEA,MAAM,eACJ,QAAQ,SAAS,oBAAoB,QAAQ,SAAS,SAClD,QAAQ,OACR,QAAQ,eAAe,MAAM;EACnC,MAAM,aACJ,iBAAiB,oBAAoB,iBAAiB,SAClD,4BAA4B,QAAQ,KAAK,IACzC,QAAQ;EACd,MAAM,aACJ,iBAAiB,oBAAoB,iBAAiB,SAClD,QAAQ,eAAe,gBAAgB,IACvC,KAAA;EACN,MAAM,QACJ,QAAQ,SAAS,aACZ,QAAQ,WAAW,QACpB,QAAQ,SAAS,UACf,OAAO,QAAQ,KAAK,IACpB,cAAc,eAAe,KAC3B,4BAA4B,UAAU,MACtC,4BACE,iBAAiB,SACb,aACA,sBAAsB,UAAU,CACtC,IACE,aACA,iBAAiB,mBACf,kBAAkB,YAAY,UAAU,IACxC,aACJ;EAEV,IAAI,OAAO,OAAO,QAAQ,IAAI,GAAG;GAC/B,MAAM,WAAW,OAAO;GACxB,OAAO,QAAQ,MAAM,QAAQ,QAAQ,IACjC,CAAC,GAAG,UAAU,KAAK,IACnB,CAAC,UAAU,KAAK;EACtB,OACE,OAAO,QAAQ;CAEnB;CAEA,OAAO;AACT;;;;AAKA,SAAgB,2BACd,OACyB;CACzB,OAAO,kBACL,MAAM,cACH,QACL;AACF"}
|
|
@@ -13,9 +13,9 @@ export declare const dataVocabulary: {
|
|
|
13
13
|
format: z.ZodOptional<z.ZodObject<{
|
|
14
14
|
kind: z.ZodEnum<{
|
|
15
15
|
number: "number";
|
|
16
|
+
date: "date";
|
|
16
17
|
currency: "currency";
|
|
17
18
|
percent: "percent";
|
|
18
|
-
date: "date";
|
|
19
19
|
}>;
|
|
20
20
|
currency: z.ZodOptional<z.ZodString>;
|
|
21
21
|
decimals: z.ZodOptional<z.ZodNumber>;
|
|
@@ -59,6 +59,7 @@ type InputRenderProps = {
|
|
|
59
59
|
};
|
|
60
60
|
declare function InputRender({ value, inputType, placeholder, multiline, label, name, defaultValue, $action, $dispatch, }: InputRenderProps): React.JSX.Element;
|
|
61
61
|
type DatePickerRenderProps = {
|
|
62
|
+
inputType?: "date" | "datetime" | "time";
|
|
62
63
|
value?: string;
|
|
63
64
|
min?: string;
|
|
64
65
|
max?: string;
|
|
@@ -68,7 +69,7 @@ type DatePickerRenderProps = {
|
|
|
68
69
|
$action?: Action;
|
|
69
70
|
$dispatch?: GenerativeUIDispatch;
|
|
70
71
|
};
|
|
71
|
-
declare function DatePickerRender({ value, min, max, label, name, $action, $dispatch, }: DatePickerRenderProps): React.JSX.Element;
|
|
72
|
+
declare function DatePickerRender({ inputType, value, min, max, label, name, $action, $dispatch, }: DatePickerRenderProps): React.JSX.Element;
|
|
72
73
|
type CheckboxRenderProps = {
|
|
73
74
|
checked?: boolean;
|
|
74
75
|
label: string;
|
|
@@ -157,6 +158,11 @@ export declare const interactiveVocabulary: {
|
|
|
157
158
|
DatePicker: {
|
|
158
159
|
description: string;
|
|
159
160
|
properties: z.ZodObject<{
|
|
161
|
+
inputType: z.ZodOptional<z.ZodEnum<{
|
|
162
|
+
date: "date";
|
|
163
|
+
time: "time";
|
|
164
|
+
datetime: "datetime";
|
|
165
|
+
}>>;
|
|
160
166
|
value: z.ZodOptional<z.ZodString>;
|
|
161
167
|
min: z.ZodOptional<z.ZodString>;
|
|
162
168
|
max: z.ZodOptional<z.ZodString>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"interactive.d.ts","sourceRoot":"","sources":["../../src/vocabulary/interactive.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"interactive.d.ts","sourceRoot":"","sources":["../../src/vocabulary/interactive.tsx"],"names":[],"mappings":"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"}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { useRadioGroupName } from "../RadioGroupScope.js";
|
|
2
|
-
import { CHECKBOX_GROUP_ATTR, FIELD_NAME_ATTR, GENERATED_NAME_ATTR } from "../constants.js";
|
|
2
|
+
import { CHECKBOX_GROUP_ATTR, FIELD_NAME_ATTR, FIELD_VALUE_ATTR, GENERATED_NAME_ATTR } from "../constants.js";
|
|
3
3
|
import { BUTTON_STYLES } from "../ir.js";
|
|
4
4
|
import { A2uiBindingContext, useA2uiBinding } from "../a2ui/BindingContext.js";
|
|
5
|
+
import { classifyTemporal, fromLocalDateTime, getTemporalInputStep, normalizeTemporalInputValue, toLocalDateTime, toPickerLocalDateTime } from "../temporal.js";
|
|
5
6
|
import { useAnsweredValue } from "../answeredValues.js";
|
|
6
7
|
import { toTextContent } from "./toTextContent.js";
|
|
7
8
|
import { actionAttr, fire } from "./dispatch.js";
|
|
@@ -166,23 +167,67 @@ function InputRender({ value, inputType, placeholder, multiline, label, name, de
|
|
|
166
167
|
}
|
|
167
168
|
}, initialValue);
|
|
168
169
|
}
|
|
169
|
-
|
|
170
|
+
const subscribeToHydration = () => () => {};
|
|
171
|
+
const clientHydrationSnapshot = () => true;
|
|
172
|
+
const serverHydrationSnapshot = () => false;
|
|
173
|
+
function DatePickerRender({ inputType = "date", value, min, max, label, name, $action, $dispatch }) {
|
|
170
174
|
const answeredValue = useAnsweredValue(name);
|
|
171
175
|
const updateBinding = useA2uiBinding(name);
|
|
172
176
|
const isBound = updateBinding !== void 0;
|
|
173
177
|
const initialValue = typeof answeredValue === "string" ? answeredValue : value;
|
|
178
|
+
const [selection, setSelection] = React.useState({
|
|
179
|
+
initialValue,
|
|
180
|
+
value: initialValue,
|
|
181
|
+
anchor: initialValue
|
|
182
|
+
});
|
|
183
|
+
if (selection.initialValue !== initialValue) setSelection({
|
|
184
|
+
initialValue,
|
|
185
|
+
value: initialValue,
|
|
186
|
+
anchor: isBound && initialValue === selection.value ? selection.anchor : initialValue
|
|
187
|
+
});
|
|
188
|
+
const currentValue = isBound ? initialValue : selection.value;
|
|
189
|
+
const temporal = classifyTemporal(currentValue ?? "");
|
|
190
|
+
const anchor = classifyTemporal(selection.anchor ?? "");
|
|
191
|
+
const hasInstantAnchor = inputType === "datetime" && anchor.kind === "instant";
|
|
192
|
+
const canonicalFieldValue = (value) => {
|
|
193
|
+
const current = value ?? "";
|
|
194
|
+
const kind = classifyTemporal(current).kind;
|
|
195
|
+
if (inputType === "time") return kind === "time" && normalizeTemporalInputValue(current) !== current ? value : void 0;
|
|
196
|
+
if (inputType !== "datetime") return void 0;
|
|
197
|
+
if (kind === "instant") return value;
|
|
198
|
+
if (hasInstantAnchor) return selection.anchor;
|
|
199
|
+
return kind === "floating" && normalizeTemporalInputValue(current) !== current ? value : void 0;
|
|
200
|
+
};
|
|
201
|
+
const minimum = classifyTemporal(min ?? "");
|
|
202
|
+
const maximum = classifyTemporal(max ?? "");
|
|
203
|
+
const hydrated = React.useSyncExternalStore(subscribeToHydration, clientHydrationSnapshot, serverHydrationSnapshot);
|
|
204
|
+
const showRawValue = inputType === "datetime" && temporal.kind === "instant" && !hydrated;
|
|
205
|
+
const displayValue = currentValue === void 0 ? void 0 : inputType === "datetime" && hydrated ? toPickerLocalDateTime(currentValue) : normalizeTemporalInputValue(currentValue);
|
|
174
206
|
return /* @__PURE__ */ jsx("input", {
|
|
175
|
-
type: "
|
|
207
|
+
type: showRawValue ? "text" : inputType === "datetime" ? "datetime-local" : inputType,
|
|
208
|
+
readOnly: showRawValue || void 0,
|
|
176
209
|
"data-aui": "datepicker",
|
|
177
210
|
"data-aui-action": actionAttr($action),
|
|
211
|
+
[FIELD_VALUE_ATTR]: canonicalFieldValue(currentValue),
|
|
178
212
|
name,
|
|
179
213
|
"aria-label": label,
|
|
180
|
-
...isBound
|
|
181
|
-
min,
|
|
182
|
-
max,
|
|
214
|
+
...isBound || inputType === "datetime" ? { value: displayValue ?? "" } : { defaultValue: displayValue },
|
|
215
|
+
min: inputType === "datetime" && hydrated && min !== void 0 ? normalizeTemporalInputValue(toLocalDateTime(min, minimum.kind === "instant" ? minimum.precision : void 0)) : min === void 0 ? void 0 : normalizeTemporalInputValue(min),
|
|
216
|
+
max: inputType === "datetime" && hydrated && max !== void 0 ? normalizeTemporalInputValue(toLocalDateTime(max, maximum.kind === "instant" ? maximum.precision : void 0)) : max === void 0 ? void 0 : normalizeTemporalInputValue(max),
|
|
217
|
+
step: inputType !== "date" ? getTemporalInputStep(selection.anchor, currentValue, min, max) : void 0,
|
|
183
218
|
onChange: (e) => {
|
|
184
|
-
|
|
185
|
-
|
|
219
|
+
const inputValue = normalizeTemporalInputValue(e.currentTarget.value);
|
|
220
|
+
const nextValue = inputType === "datetime" ? fromLocalDateTime(inputValue, selection.anchor) : inputValue;
|
|
221
|
+
const canonical = canonicalFieldValue(nextValue);
|
|
222
|
+
if (canonical !== void 0) e.currentTarget.setAttribute(FIELD_VALUE_ATTR, canonical);
|
|
223
|
+
else e.currentTarget.removeAttribute(FIELD_VALUE_ATTR);
|
|
224
|
+
setSelection({
|
|
225
|
+
initialValue,
|
|
226
|
+
value: nextValue,
|
|
227
|
+
anchor: selection.anchor
|
|
228
|
+
});
|
|
229
|
+
updateBinding?.(nextValue);
|
|
230
|
+
fire($action, $dispatch, nextValue, e.currentTarget);
|
|
186
231
|
}
|
|
187
232
|
}, isBound ? void 0 : initialValue);
|
|
188
233
|
}
|
|
@@ -420,11 +465,16 @@ const interactiveVocabulary = {
|
|
|
420
465
|
render: InputRender
|
|
421
466
|
},
|
|
422
467
|
DatePicker: {
|
|
423
|
-
description: "A date input. Carries `$action` describing the on-select behavior.",
|
|
468
|
+
description: "A date, datetime, or time input. Carries `$action` describing the on-select behavior.",
|
|
424
469
|
properties: z.object({
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
470
|
+
inputType: z.enum([
|
|
471
|
+
"date",
|
|
472
|
+
"datetime",
|
|
473
|
+
"time"
|
|
474
|
+
]).optional().describe("Temporal input type. Defaults to \"date\". Values remain strings."),
|
|
475
|
+
value: z.string().optional().describe("Initial value: YYYY-MM-DD for date, HH:mm or HH:mm:ss with optional fraction of at most 9 digits for time, YYYY-MM-DDTHH:mm with optional :ss and fraction of at most 9 digits for datetime. A datetime with Z or ±HH:mm is an instant, displayed in the viewer's time zone and submitted with the same offset and precision. A datetime without an offset is local and submitted unchanged. An empty datetime submits with the viewer's offset and seconds."),
|
|
476
|
+
min: z.string().optional().describe("Minimum value: YYYY-MM-DD for date, HH:mm or HH:mm:ss with optional fraction of at most 9 digits for time, YYYY-MM-DDTHH:mm with optional :ss and fraction of at most 9 digits for datetime. Datetimes with Z or ±HH:mm are converted to the viewer's time zone."),
|
|
477
|
+
max: z.string().optional().describe("Maximum value: YYYY-MM-DD for date, HH:mm or HH:mm:ss with optional fraction of at most 9 digits for time, YYYY-MM-DDTHH:mm with optional :ss and fraction of at most 9 digits for datetime. Datetimes with Z or ±HH:mm are converted to the viewer's time zone."),
|
|
428
478
|
label: z.string().optional().describe("Accessible label for the control."),
|
|
429
479
|
name: z.string().optional().describe("Field name used inside a Form.")
|
|
430
480
|
}),
|