@lattice-php/lattice 0.9.0 → 0.11.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.
Files changed (91) hide show
  1. package/dist/action/components/action-form.js +1 -1
  2. package/dist/action/components/action-form.js.map +1 -1
  3. package/dist/chat/components/chat-box.js +1 -1
  4. package/dist/chat/components/chat-box.js.map +1 -1
  5. package/dist/chat/components/prompt-input.js +2 -2
  6. package/dist/chat/components/prompt-input.js.map +1 -1
  7. package/dist/core/components/combobox.js +1 -1
  8. package/dist/core/components/combobox.js.map +1 -1
  9. package/dist/core/components/fragment.js +4 -1
  10. package/dist/core/components/fragment.js.map +1 -1
  11. package/dist/core/components/icon.js +4 -1
  12. package/dist/core/components/icon.js.map +1 -1
  13. package/dist/core/components/info-tooltip.js +1 -1
  14. package/dist/core/components/info-tooltip.js.map +1 -1
  15. package/dist/core/components/spinner.js +1 -1
  16. package/dist/core/components/spinner.js.map +1 -1
  17. package/dist/core/components/tabs.js +1 -1
  18. package/dist/core/components/tabs.js.map +1 -1
  19. package/dist/core/components/text.js +4 -1
  20. package/dist/core/components/text.js.map +1 -1
  21. package/dist/form/components/fields/date-input.js +7 -6
  22. package/dist/form/components/fields/date-input.js.map +1 -1
  23. package/dist/form/components/fields/date-picker-control.d.ts +18 -0
  24. package/dist/form/components/fields/date-picker-control.js +199 -0
  25. package/dist/form/components/fields/date-picker-control.js.map +1 -0
  26. package/dist/form/components/fields/date-picker-value.d.ts +10 -0
  27. package/dist/form/components/fields/date-picker-value.js +125 -0
  28. package/dist/form/components/fields/date-picker-value.js.map +1 -0
  29. package/dist/form/components/fields/date-time-input.d.ts +2 -0
  30. package/dist/form/components/fields/date-time-input.js +34 -0
  31. package/dist/form/components/fields/date-time-input.js.map +1 -0
  32. package/dist/form/components/fields/file-upload.js +3 -3
  33. package/dist/form/components/fields/file-upload.js.map +1 -1
  34. package/dist/form/components/fields/lazy-date-picker-control.d.ts +2 -0
  35. package/dist/form/components/fields/lazy-date-picker-control.js +17 -0
  36. package/dist/form/components/fields/lazy-date-picker-control.js.map +1 -0
  37. package/dist/form/components/fields/number-input.js +1 -1
  38. package/dist/form/components/fields/rich-editor.js +3 -3
  39. package/dist/form/components/fields/rich-editor.js.map +1 -1
  40. package/dist/form/components/fields/row-action-menu.js +2 -2
  41. package/dist/form/components/fields/row-action-menu.js.map +1 -1
  42. package/dist/form/components/fields/select.js +1 -1
  43. package/dist/form/components/fields/select.js.map +1 -1
  44. package/dist/form/components/fields/table-rows.js +2 -2
  45. package/dist/form/components/fields/table-rows.js.map +1 -1
  46. package/dist/form/components/fields/text-input.js +1 -1
  47. package/dist/form/components/fields/time-input.d.ts +2 -0
  48. package/dist/form/components/fields/time-input.js +30 -0
  49. package/dist/form/components/fields/time-input.js.map +1 -0
  50. package/dist/form/components/fields/toggle.d.ts +2 -0
  51. package/dist/form/components/fields/toggle.js +65 -0
  52. package/dist/form/components/fields/toggle.js.map +1 -0
  53. package/dist/form/components/index.d.ts +3 -0
  54. package/dist/form/components/index.js +4 -1
  55. package/dist/form/components/types.d.ts +1 -1
  56. package/dist/form/components/use-controlled-field.d.ts +2 -0
  57. package/dist/form/components/use-controlled-field.js +6 -2
  58. package/dist/form/components/use-controlled-field.js.map +1 -1
  59. package/dist/form/index.js +4 -1
  60. package/dist/form/index.js.map +1 -1
  61. package/dist/lattice.css +6 -0
  62. package/dist/layout/callouts.js +1 -1
  63. package/dist/layout/callouts.js.map +1 -1
  64. package/dist/lib/utils.js +11 -1
  65. package/dist/lib/utils.js.map +1 -1
  66. package/dist/remote/components/data-list.js +3 -3
  67. package/dist/remote/components/data-list.js.map +1 -1
  68. package/dist/table/components/bulk-bar.js +2 -2
  69. package/dist/table/components/bulk-bar.js.map +1 -1
  70. package/dist/table/components/column-filter-control.js +5 -5
  71. package/dist/table/components/column-filter-control.js.map +1 -1
  72. package/dist/table/components/filter-bar.js +3 -3
  73. package/dist/table/components/filter-bar.js.map +1 -1
  74. package/dist/table/components/filter-controls.js +9 -9
  75. package/dist/table/components/filter-controls.js.map +1 -1
  76. package/dist/table/components/filter-stack-bar.js +1 -1
  77. package/dist/table/components/filter-stack-bar.js.map +1 -1
  78. package/dist/table/components/filter-value-input.js +5 -5
  79. package/dist/table/components/filter-value-input.js.map +1 -1
  80. package/dist/table/components/pagination.js +8 -8
  81. package/dist/table/components/pagination.js.map +1 -1
  82. package/dist/table/components/table.js +4 -4
  83. package/dist/table/components/table.js.map +1 -1
  84. package/dist/table/query.js +1 -1
  85. package/dist/table/query.js.map +1 -1
  86. package/dist/toast/toaster.js +1 -1
  87. package/dist/toast/toaster.js.map +1 -1
  88. package/dist/types/generated.d.ts +97 -2
  89. package/package.json +8 -2
  90. package/resources/icons/calendar.svg +18 -0
  91. package/resources/icons/chevron-left.svg +15 -0
@@ -0,0 +1,199 @@
1
+ import { useLocale } from "../../../i18n/locale.js";
2
+ import { cn } from "../../../lib/utils.js";
3
+ import { Icon } from "../../../icons/sprite.js";
4
+ import { Button } from "../../../core/components/button.js";
5
+ import { Input } from "../base/input.js";
6
+ import { formatDateDisplayValue, formatDateTimeDisplayValue, formatDateTimeValue, formatDateValue, formatTimeInputValue, parseDateDisplayValue, parseDateTimeDisplayValue, parseDateTimeValue, parseDateValue } from "./date-picker-value.js";
7
+ import { createElement, useId, useMemo } from "react";
8
+ import { jsx, jsxs } from "react/jsx-runtime";
9
+ import * as datePicker from "@zag-js/date-picker";
10
+ import { normalizeProps, useMachine } from "@zag-js/react";
11
+ //#region resources/js/form/components/fields/date-picker-control.tsx
12
+ function DatePickerControl({ mode, label, name, testId, value, min, max, step, disabled, readOnly, autoFocus = false, tabIndex, timezone = "UTC", onChange, onBlur }) {
13
+ const id = useId();
14
+ const { locale } = useLocale();
15
+ const selected = useMemo(() => [mode === "date" ? parseDateValue(value) : parseDateTimeValue(value, timezone)].filter(Boolean), [
16
+ mode,
17
+ timezone,
18
+ value
19
+ ]);
20
+ const service = useMachine(datePicker.machine, {
21
+ id,
22
+ name,
23
+ value: selected.length > 0 ? selected : void 0,
24
+ min: min ? parseDateValue(min) : void 0,
25
+ max: max ? parseDateValue(max) : void 0,
26
+ disabled,
27
+ readOnly,
28
+ locale,
29
+ selectionMode: "single",
30
+ timeZone: timezone,
31
+ closeOnSelect: mode === "date",
32
+ format(date) {
33
+ return mode === "date" ? formatDateDisplayValue(date, locale) : formatDateTimeDisplayValue(date, locale, timezone);
34
+ },
35
+ parse(text) {
36
+ return mode === "date" ? parseDateDisplayValue(text, locale) : parseDateTimeDisplayValue(text, locale, timezone);
37
+ },
38
+ onValueChange(details) {
39
+ const next = details.value[0];
40
+ onChange(mode === "date" ? formatDateValue(next) : formatDateTimeValue(next, timezone));
41
+ },
42
+ onOpenChange(details) {
43
+ if (!details.open) onBlur?.();
44
+ }
45
+ });
46
+ const api = datePicker.connect(service, normalizeProps);
47
+ const { name: _inputName, onInput, ...inputProps } = api.getInputProps();
48
+ const submittedValue = mode === "date" ? formatDateValue(selected[0]) : formatDateTimeValue(selected[0], timezone);
49
+ return /* @__PURE__ */ jsxs("div", {
50
+ ...api.getRootProps(),
51
+ className: cn("relative", api.open && "z-[var(--lt-z-popover)]"),
52
+ children: [
53
+ /* @__PURE__ */ jsx("input", {
54
+ type: "hidden",
55
+ name,
56
+ value: submittedValue,
57
+ "data-test": `${testId}-value`
58
+ }),
59
+ /* @__PURE__ */ jsxs("div", {
60
+ ...api.getControlProps(),
61
+ className: "flex gap-2",
62
+ children: [/* @__PURE__ */ jsx(Input, {
63
+ ...inputProps,
64
+ "aria-label": label,
65
+ autoFocus,
66
+ "data-test": testId,
67
+ disabled,
68
+ id: name,
69
+ onInput: (event) => {
70
+ onInput?.(event);
71
+ if (mode !== "date") return;
72
+ const normalized = normalizeDateInputValue(event.currentTarget.value);
73
+ if (!normalized) return;
74
+ const next = parseDateValue(normalized);
75
+ if (!next) return;
76
+ event.currentTarget.value = normalized;
77
+ api.setValue([next]);
78
+ event.currentTarget.value = formatDateDisplayValue(next, locale);
79
+ onChange(formatDateValue(next));
80
+ },
81
+ readOnly,
82
+ tabIndex: tabIndex ?? void 0
83
+ }), /* @__PURE__ */ jsx(Button, {
84
+ ...api.getTriggerProps(),
85
+ "aria-label": `Open ${label || name} calendar`,
86
+ disabled: disabled || readOnly,
87
+ size: "icon",
88
+ type: "button",
89
+ variant: "secondary",
90
+ children: /* @__PURE__ */ jsx(Icon, {
91
+ name: "calendar",
92
+ className: "size-lt-icon-md",
93
+ "aria-hidden": "true"
94
+ })
95
+ })]
96
+ }),
97
+ api.open ? /* @__PURE__ */ jsx("div", {
98
+ ...api.getPositionerProps(),
99
+ className: "absolute z-[var(--lt-z-popover)] mt-2 rounded-lt-sm border border-lt-border bg-lt-popover p-3 text-lt-popover-fg shadow-lt-md",
100
+ children: /* @__PURE__ */ jsxs("div", {
101
+ ...api.getContentProps(),
102
+ className: "grid gap-3",
103
+ children: [
104
+ /* @__PURE__ */ jsxs("div", {
105
+ className: "flex items-center justify-between gap-2",
106
+ children: [
107
+ /* @__PURE__ */ jsx(Button, {
108
+ ...api.getPrevTriggerProps(),
109
+ size: "icon",
110
+ type: "button",
111
+ variant: "ghost",
112
+ children: /* @__PURE__ */ jsx(Icon, {
113
+ name: "chevron-left",
114
+ className: "size-lt-icon-md",
115
+ "aria-hidden": "true"
116
+ })
117
+ }),
118
+ /* @__PURE__ */ jsx("div", {
119
+ ...api.getRangeTextProps(),
120
+ className: "text-sm font-medium text-lt-fg"
121
+ }),
122
+ /* @__PURE__ */ jsx(Button, {
123
+ ...api.getNextTriggerProps(),
124
+ size: "icon",
125
+ type: "button",
126
+ variant: "ghost",
127
+ children: /* @__PURE__ */ jsx(Icon, {
128
+ name: "chevron-right",
129
+ className: "size-lt-icon-md",
130
+ "aria-hidden": "true"
131
+ })
132
+ })
133
+ ]
134
+ }),
135
+ /* @__PURE__ */ jsxs("table", {
136
+ ...api.getTableProps(),
137
+ className: "w-full border-collapse text-sm",
138
+ children: [/* @__PURE__ */ jsx("thead", {
139
+ ...api.getTableHeadProps(),
140
+ children: /* @__PURE__ */ jsx("tr", {
141
+ ...api.getTableRowProps(),
142
+ children: api.weekDays.map((day) => /* @__PURE__ */ createElement("th", {
143
+ ...api.getTableHeaderProps(),
144
+ "aria-label": day.long,
145
+ key: day.value.toString(),
146
+ className: "size-8 text-center text-xs font-medium text-lt-muted-fg"
147
+ }, day.narrow))
148
+ })
149
+ }), /* @__PURE__ */ jsx("tbody", {
150
+ ...api.getTableBodyProps(),
151
+ children: api.weeks.map((week, weekIndex) => /* @__PURE__ */ createElement("tr", {
152
+ ...api.getTableRowProps(),
153
+ key: weekIndex
154
+ }, week.map((day) => {
155
+ const state = api.getDayTableCellState({ value: day });
156
+ return /* @__PURE__ */ createElement("td", {
157
+ ...api.getDayTableCellProps({ value: day }),
158
+ key: day.toString(),
159
+ className: "p-0 text-center"
160
+ }, /* @__PURE__ */ jsx("button", {
161
+ ...api.getDayTableCellTriggerProps({ value: day }),
162
+ type: "button",
163
+ className: cn("size-8 rounded-lt-sm text-sm text-lt-fg hover:bg-lt-muted", state.selected && "bg-lt-primary text-lt-primary-fg", state.outsideRange && "text-lt-muted-fg", state.disabled && "cursor-not-allowed opacity-40"),
164
+ children: day.day
165
+ }));
166
+ })))
167
+ })]
168
+ }),
169
+ mode === "date-time" ? /* @__PURE__ */ jsx(Input, {
170
+ "aria-label": `${label || name} time`,
171
+ disabled,
172
+ onChange: (event) => {
173
+ const [hour = "0", minute = "0", second = "0"] = event.target.value.split(":");
174
+ api.setTime({
175
+ hour: Number(hour),
176
+ minute: Number(minute),
177
+ second: Number(second)
178
+ });
179
+ },
180
+ readOnly,
181
+ step: step ?? void 0,
182
+ type: "time",
183
+ value: formatTimeInputValue(selected[0], timezone)
184
+ }) : null
185
+ ]
186
+ })
187
+ }) : null
188
+ ]
189
+ });
190
+ }
191
+ function normalizeDateInputValue(value) {
192
+ const compact = value.replace(/\D/g, "");
193
+ if (compact.length !== 8) return;
194
+ return `${compact.slice(0, 4)}-${compact.slice(4, 6)}-${compact.slice(6, 8)}`;
195
+ }
196
+ //#endregion
197
+ export { DatePickerControl };
198
+
199
+ //# sourceMappingURL=date-picker-control.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"date-picker-control.js","names":[],"sources":["../../../../resources/js/form/components/fields/date-picker-control.tsx"],"sourcesContent":["import type { DateValue } from \"@internationalized/date\";\nimport * as datePicker from \"@zag-js/date-picker\";\nimport { normalizeProps, useMachine } from \"@zag-js/react\";\nimport { useId, useMemo } from \"react\";\nimport { Button } from \"@lattice-php/lattice/core/components/button\";\nimport { Icon } from \"@lattice-php/lattice/icons\";\nimport { useLocale } from \"@lattice-php/lattice/i18n\";\nimport { cn } from \"@lattice-php/lattice/lib/utils\";\nimport { Input } from \"../base/input\";\nimport {\n formatDateDisplayValue,\n formatDateTimeDisplayValue,\n formatDateTimeValue,\n formatDateValue,\n formatTimeInputValue,\n parseDateDisplayValue,\n parseDateTimeDisplayValue,\n parseDateTimeValue,\n parseDateValue,\n} from \"./date-picker-value\";\n\nexport type DatePickerControlProps = {\n mode: \"date\" | \"date-time\";\n label: string;\n name: string;\n testId: string;\n value: unknown;\n min?: string | null;\n max?: string | null;\n step?: number | null;\n disabled: boolean;\n readOnly: boolean;\n autoFocus?: boolean;\n tabIndex?: number | null;\n timezone?: string;\n onChange: (value: string) => void;\n onBlur?: () => void;\n};\n\nexport function DatePickerControl({\n mode,\n label,\n name,\n testId,\n value,\n min,\n max,\n step,\n disabled,\n readOnly,\n autoFocus = false,\n tabIndex,\n timezone = \"UTC\",\n onChange,\n onBlur,\n}: DatePickerControlProps) {\n const id = useId();\n const { locale } = useLocale();\n const selected = useMemo(\n () =>\n [mode === \"date\" ? parseDateValue(value) : parseDateTimeValue(value, timezone)].filter(\n Boolean,\n ) as DateValue[],\n [mode, timezone, value],\n );\n const service = useMachine(datePicker.machine, {\n id,\n name,\n value: selected.length > 0 ? selected : undefined,\n min: min ? parseDateValue(min) : undefined,\n max: max ? parseDateValue(max) : undefined,\n disabled,\n readOnly,\n locale,\n selectionMode: \"single\",\n timeZone: timezone,\n closeOnSelect: mode === \"date\",\n format(date) {\n return mode === \"date\"\n ? formatDateDisplayValue(date, locale)\n : formatDateTimeDisplayValue(date, locale, timezone);\n },\n parse(text) {\n return mode === \"date\"\n ? parseDateDisplayValue(text, locale)\n : parseDateTimeDisplayValue(text, locale, timezone);\n },\n onValueChange(details) {\n const next = details.value[0];\n\n onChange(mode === \"date\" ? formatDateValue(next) : formatDateTimeValue(next, timezone));\n },\n onOpenChange(details) {\n if (!details.open) {\n onBlur?.();\n }\n },\n });\n const api = datePicker.connect(service, normalizeProps);\n const { name: _inputName, onInput, ...inputProps } = api.getInputProps();\n const submittedValue =\n mode === \"date\" ? formatDateValue(selected[0]) : formatDateTimeValue(selected[0], timezone);\n\n return (\n <div {...api.getRootProps()} className={cn(\"relative\", api.open && \"z-[var(--lt-z-popover)]\")}>\n <input type=\"hidden\" name={name} value={submittedValue} data-test={`${testId}-value`} />\n <div {...api.getControlProps()} className=\"flex gap-2\">\n <Input\n {...inputProps}\n aria-label={label}\n autoFocus={autoFocus}\n data-test={testId}\n disabled={disabled}\n id={name}\n onInput={(event) => {\n onInput?.(event);\n\n if (mode !== \"date\") {\n return;\n }\n\n const normalized = normalizeDateInputValue(event.currentTarget.value);\n\n if (!normalized) {\n return;\n }\n\n const next = parseDateValue(normalized);\n\n if (!next) {\n return;\n }\n\n event.currentTarget.value = normalized;\n api.setValue([next]);\n event.currentTarget.value = formatDateDisplayValue(next, locale);\n onChange(formatDateValue(next));\n }}\n readOnly={readOnly}\n tabIndex={tabIndex ?? undefined}\n />\n <Button\n {...api.getTriggerProps()}\n aria-label={`Open ${label || name} calendar`}\n disabled={disabled || readOnly}\n size=\"icon\"\n type=\"button\"\n variant=\"secondary\"\n >\n <Icon name=\"calendar\" className=\"size-lt-icon-md\" aria-hidden=\"true\" />\n </Button>\n </div>\n {api.open ? (\n <div\n {...api.getPositionerProps()}\n className=\"absolute z-[var(--lt-z-popover)] mt-2 rounded-lt-sm border border-lt-border bg-lt-popover p-3 text-lt-popover-fg shadow-lt-md\"\n >\n <div {...api.getContentProps()} className=\"grid gap-3\">\n <div className=\"flex items-center justify-between gap-2\">\n <Button {...api.getPrevTriggerProps()} size=\"icon\" type=\"button\" variant=\"ghost\">\n <Icon name=\"chevron-left\" className=\"size-lt-icon-md\" aria-hidden=\"true\" />\n </Button>\n <div {...api.getRangeTextProps()} className=\"text-sm font-medium text-lt-fg\" />\n <Button {...api.getNextTriggerProps()} size=\"icon\" type=\"button\" variant=\"ghost\">\n <Icon name=\"chevron-right\" className=\"size-lt-icon-md\" aria-hidden=\"true\" />\n </Button>\n </div>\n <table {...api.getTableProps()} className=\"w-full border-collapse text-sm\">\n <thead {...api.getTableHeadProps()}>\n <tr {...api.getTableRowProps()}>\n {api.weekDays.map((day) => (\n <th\n {...api.getTableHeaderProps()}\n aria-label={day.long}\n key={day.value.toString()}\n className=\"size-8 text-center text-xs font-medium text-lt-muted-fg\"\n >\n {day.narrow}\n </th>\n ))}\n </tr>\n </thead>\n <tbody {...api.getTableBodyProps()}>\n {api.weeks.map((week, weekIndex) => (\n <tr {...api.getTableRowProps()} key={weekIndex}>\n {week.map((day) => {\n const state = api.getDayTableCellState({ value: day });\n\n return (\n <td\n {...api.getDayTableCellProps({ value: day })}\n key={day.toString()}\n className=\"p-0 text-center\"\n >\n <button\n {...api.getDayTableCellTriggerProps({ value: day })}\n type=\"button\"\n className={cn(\n \"size-8 rounded-lt-sm text-sm text-lt-fg hover:bg-lt-muted\",\n state.selected && \"bg-lt-primary text-lt-primary-fg\",\n state.outsideRange && \"text-lt-muted-fg\",\n state.disabled && \"cursor-not-allowed opacity-40\",\n )}\n >\n {day.day}\n </button>\n </td>\n );\n })}\n </tr>\n ))}\n </tbody>\n </table>\n {mode === \"date-time\" ? (\n <Input\n aria-label={`${label || name} time`}\n disabled={disabled}\n onChange={(event) => {\n const [hour = \"0\", minute = \"0\", second = \"0\"] = event.target.value.split(\":\");\n\n api.setTime({\n hour: Number(hour),\n minute: Number(minute),\n second: Number(second),\n });\n }}\n readOnly={readOnly}\n step={step ?? undefined}\n type=\"time\"\n value={formatTimeInputValue(selected[0], timezone)}\n />\n ) : null}\n </div>\n </div>\n ) : null}\n </div>\n );\n}\n\nfunction normalizeDateInputValue(value: string): string | undefined {\n const compact = value.replace(/\\D/g, \"\");\n\n if (compact.length !== 8) {\n return undefined;\n }\n\n return `${compact.slice(0, 4)}-${compact.slice(4, 6)}-${compact.slice(6, 8)}`;\n}\n"],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import { DateValue } from '@internationalized/date';
2
+ export declare function parseDateValue(value: unknown): DateValue | undefined;
3
+ export declare function parseDateTimeValue(value: unknown, timezone: string): DateValue | undefined;
4
+ export declare function parseDateDisplayValue(value: unknown, locale: string): DateValue | undefined;
5
+ export declare function parseDateTimeDisplayValue(value: unknown, locale: string, timezone: string): DateValue | undefined;
6
+ export declare function formatDateValue(value: DateValue | undefined): string;
7
+ export declare function formatDateDisplayValue(value: DateValue | undefined, locale: string): string;
8
+ export declare function formatDateTimeValue(value: DateValue | undefined, timezone: string): string;
9
+ export declare function formatDateTimeDisplayValue(value: DateValue | undefined, locale: string, timezone: string): string;
10
+ export declare function formatTimeInputValue(value: DateValue | undefined, timezone: string): string;
@@ -0,0 +1,125 @@
1
+ import { DateFormatter, parseAbsolute, parseDate, parseDateTime, parseZonedDateTime, toTimeZone, toZoned } from "@internationalized/date";
2
+ //#region resources/js/form/components/fields/date-picker-value.ts
3
+ var dateTimeWithZone = /^(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}(?::\d{2})?)\s+(.+)$/;
4
+ var bareDateTime = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}(?::\d{2})?$/;
5
+ var dateTimeFormatOptions = {
6
+ day: "2-digit",
7
+ hour: "2-digit",
8
+ hourCycle: "h23",
9
+ minute: "2-digit",
10
+ month: "2-digit",
11
+ year: "numeric"
12
+ };
13
+ var dateFormatOptions = {
14
+ day: "2-digit",
15
+ month: "2-digit",
16
+ year: "numeric"
17
+ };
18
+ function parseDateValue(value) {
19
+ if (typeof value !== "string" || value === "") return;
20
+ try {
21
+ return parseDate(value.slice(0, 10));
22
+ } catch {
23
+ return;
24
+ }
25
+ }
26
+ function parseDateTimeValue(value, timezone) {
27
+ if (typeof value !== "string" || value === "") return;
28
+ const zoned = dateTimeWithZone.exec(value);
29
+ try {
30
+ if (zoned) return parseZonedDateTime(`${normalizeSeconds(zoned[1])}[${zoned[2]}]`);
31
+ if (bareDateTime.test(value)) return toZoned(parseDateTime(normalizeSeconds(value)), timezone);
32
+ return parseAbsolute(value, timezone);
33
+ } catch {
34
+ return;
35
+ }
36
+ }
37
+ function parseDateDisplayValue(value, locale) {
38
+ return parseDateValue(value) ?? parseLocalizedDate(value, locale);
39
+ }
40
+ function parseDateTimeDisplayValue(value, locale, timezone) {
41
+ return parseDateTimeValue(value, timezone) ?? parseLocalizedDateTime(value, locale, timezone);
42
+ }
43
+ function formatDateValue(value) {
44
+ return value?.toString().slice(0, 10) ?? "";
45
+ }
46
+ function formatDateDisplayValue(value, locale) {
47
+ if (!value) return "";
48
+ return new DateFormatter(locale, {
49
+ ...dateFormatOptions,
50
+ timeZone: "UTC"
51
+ }).format(value.toDate("UTC"));
52
+ }
53
+ function formatDateTimeValue(value, timezone) {
54
+ if (!value) return "";
55
+ return `${normalizeSeconds(("timeZone" in value ? toTimeZone(value, timezone) : toZoned(value, timezone)).toString().replace(/\[.+\]$/, "")).slice(0, 19)} ${timezone}`;
56
+ }
57
+ function formatDateTimeDisplayValue(value, locale, timezone) {
58
+ if (!value) return "";
59
+ const zoned = "timeZone" in value ? toTimeZone(value, timezone) : toZoned(value, timezone);
60
+ return new DateFormatter(locale, {
61
+ ...dateTimeFormatOptions,
62
+ timeZone: timezone
63
+ }).format(zoned.toDate());
64
+ }
65
+ function formatTimeInputValue(value, timezone) {
66
+ if (!value) return "";
67
+ const zoned = "timeZone" in value ? toTimeZone(value, timezone) : toZoned(value, timezone);
68
+ return [
69
+ String(zoned.hour).padStart(2, "0"),
70
+ String(zoned.minute).padStart(2, "0"),
71
+ String(zoned.second).padStart(2, "0")
72
+ ].join(":");
73
+ }
74
+ function normalizeSeconds(value) {
75
+ return /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}$/.test(value) ? `${value}:00` : value;
76
+ }
77
+ function parseLocalizedDate(value, locale) {
78
+ const parts = localizedParts(value, locale, "date");
79
+ if (!parts) return;
80
+ try {
81
+ return parseDate(`${parts.year.padStart(4, "0")}-${parts.month.padStart(2, "0")}-${parts.day.padStart(2, "0")}`);
82
+ } catch {
83
+ return;
84
+ }
85
+ }
86
+ function parseLocalizedDateTime(value, locale, timezone) {
87
+ const parts = localizedParts(value, locale, "date-time");
88
+ if (!parts || !parts.hour || !parts.minute) return;
89
+ try {
90
+ return toZoned(parseDateTime(`${parts.year.padStart(4, "0")}-${parts.month.padStart(2, "0")}-${parts.day.padStart(2, "0")}T${parts.hour.padStart(2, "0")}:${parts.minute.padStart(2, "0")}:00`), timezone);
91
+ } catch {
92
+ return;
93
+ }
94
+ }
95
+ function localizedParts(value, locale, mode) {
96
+ if (typeof value !== "string" || value.trim() === "") return;
97
+ const formatter = new DateFormatter(locale, mode === "date" ? dateFormatOptions : dateTimeFormatOptions);
98
+ const sample = new Date(Date.UTC(2006, 10, 22, 14, 30, 0));
99
+ const pattern = formatter.formatToParts(sample).map((part) => {
100
+ if ([
101
+ "day",
102
+ "hour",
103
+ "minute",
104
+ "month",
105
+ "year"
106
+ ].includes(part.type)) return `(?<${part.type}>\\d{1,4})`;
107
+ return escapeRegExp(part.value).replace(/\s+/g, "\\s*");
108
+ }).join("");
109
+ const groups = new RegExp(`^\\s*${pattern}\\s*$`).exec(value)?.groups;
110
+ if (!groups?.day || !groups.month || !groups.year) return;
111
+ return {
112
+ day: groups.day,
113
+ hour: groups.hour,
114
+ minute: groups.minute,
115
+ month: groups.month,
116
+ year: groups.year
117
+ };
118
+ }
119
+ function escapeRegExp(value) {
120
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
121
+ }
122
+ //#endregion
123
+ export { formatDateDisplayValue, formatDateTimeDisplayValue, formatDateTimeValue, formatDateValue, formatTimeInputValue, parseDateDisplayValue, parseDateTimeDisplayValue, parseDateTimeValue, parseDateValue };
124
+
125
+ //# sourceMappingURL=date-picker-value.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"date-picker-value.js","names":[],"sources":["../../../../resources/js/form/components/fields/date-picker-value.ts"],"sourcesContent":["import {\n DateFormatter,\n type DateValue,\n parseAbsolute,\n parseDate,\n parseDateTime,\n parseZonedDateTime,\n toTimeZone,\n toZoned,\n} from \"@internationalized/date\";\n\nconst dateTimeWithZone = /^(\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}(?::\\d{2})?)\\s+(.+)$/;\nconst bareDateTime = /^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}(?::\\d{2})?$/;\nconst dateTimeFormatOptions = {\n day: \"2-digit\",\n hour: \"2-digit\",\n hourCycle: \"h23\",\n minute: \"2-digit\",\n month: \"2-digit\",\n year: \"numeric\",\n} as const;\nconst dateFormatOptions = {\n day: \"2-digit\",\n month: \"2-digit\",\n year: \"numeric\",\n} as const;\n\nexport function parseDateValue(value: unknown): DateValue | undefined {\n if (typeof value !== \"string\" || value === \"\") {\n return undefined;\n }\n\n try {\n return parseDate(value.slice(0, 10));\n } catch {\n return undefined;\n }\n}\n\nexport function parseDateTimeValue(value: unknown, timezone: string): DateValue | undefined {\n if (typeof value !== \"string\" || value === \"\") {\n return undefined;\n }\n\n const zoned = dateTimeWithZone.exec(value);\n\n try {\n if (zoned) {\n return parseZonedDateTime(`${normalizeSeconds(zoned[1])}[${zoned[2]}]`);\n }\n\n if (bareDateTime.test(value)) {\n return toZoned(parseDateTime(normalizeSeconds(value)), timezone);\n }\n\n return parseAbsolute(value, timezone);\n } catch {\n return undefined;\n }\n}\n\nexport function parseDateDisplayValue(value: unknown, locale: string): DateValue | undefined {\n return parseDateValue(value) ?? parseLocalizedDate(value, locale);\n}\n\nexport function parseDateTimeDisplayValue(\n value: unknown,\n locale: string,\n timezone: string,\n): DateValue | undefined {\n return parseDateTimeValue(value, timezone) ?? parseLocalizedDateTime(value, locale, timezone);\n}\n\nexport function formatDateValue(value: DateValue | undefined): string {\n return value?.toString().slice(0, 10) ?? \"\";\n}\n\nexport function formatDateDisplayValue(value: DateValue | undefined, locale: string): string {\n if (!value) {\n return \"\";\n }\n\n return new DateFormatter(locale, { ...dateFormatOptions, timeZone: \"UTC\" }).format(\n value.toDate(\"UTC\"),\n );\n}\n\nexport function formatDateTimeValue(value: DateValue | undefined, timezone: string): string {\n if (!value) {\n return \"\";\n }\n\n const zoned = \"timeZone\" in value ? toTimeZone(value, timezone) : toZoned(value, timezone);\n const text = zoned.toString().replace(/\\[.+\\]$/, \"\");\n\n return `${normalizeSeconds(text).slice(0, 19)} ${timezone}`;\n}\n\nexport function formatDateTimeDisplayValue(\n value: DateValue | undefined,\n locale: string,\n timezone: string,\n): string {\n if (!value) {\n return \"\";\n }\n\n const zoned = \"timeZone\" in value ? toTimeZone(value, timezone) : toZoned(value, timezone);\n\n return new DateFormatter(locale, { ...dateTimeFormatOptions, timeZone: timezone }).format(\n zoned.toDate(),\n );\n}\n\nexport function formatTimeInputValue(value: DateValue | undefined, timezone: string): string {\n if (!value) {\n return \"\";\n }\n\n const zoned = \"timeZone\" in value ? toTimeZone(value, timezone) : toZoned(value, timezone);\n\n return [\n String(zoned.hour).padStart(2, \"0\"),\n String(zoned.minute).padStart(2, \"0\"),\n String(zoned.second).padStart(2, \"0\"),\n ].join(\":\");\n}\n\nfunction normalizeSeconds(value: string): string {\n return /^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}$/.test(value) ? `${value}:00` : value;\n}\n\nfunction parseLocalizedDate(value: unknown, locale: string): DateValue | undefined {\n const parts = localizedParts(value, locale, \"date\");\n\n if (!parts) {\n return undefined;\n }\n\n try {\n return parseDate(\n `${parts.year.padStart(4, \"0\")}-${parts.month.padStart(2, \"0\")}-${parts.day.padStart(2, \"0\")}`,\n );\n } catch {\n return undefined;\n }\n}\n\nfunction parseLocalizedDateTime(\n value: unknown,\n locale: string,\n timezone: string,\n): DateValue | undefined {\n const parts = localizedParts(value, locale, \"date-time\");\n\n if (!parts || !parts.hour || !parts.minute) {\n return undefined;\n }\n\n try {\n return toZoned(\n parseDateTime(\n `${parts.year.padStart(4, \"0\")}-${parts.month.padStart(2, \"0\")}-${parts.day.padStart(2, \"0\")}T${parts.hour.padStart(2, \"0\")}:${parts.minute.padStart(2, \"0\")}:00`,\n ),\n timezone,\n );\n } catch {\n return undefined;\n }\n}\n\nfunction localizedParts(\n value: unknown,\n locale: string,\n mode: \"date\" | \"date-time\",\n):\n | {\n day: string;\n hour?: string;\n minute?: string;\n month: string;\n year: string;\n }\n | undefined {\n if (typeof value !== \"string\" || value.trim() === \"\") {\n return undefined;\n }\n\n const formatter = new DateFormatter(\n locale,\n mode === \"date\" ? dateFormatOptions : dateTimeFormatOptions,\n );\n const sample = new Date(Date.UTC(2006, 10, 22, 14, 30, 0));\n const pattern = formatter\n .formatToParts(sample)\n .map((part) => {\n if ([\"day\", \"hour\", \"minute\", \"month\", \"year\"].includes(part.type)) {\n return `(?<${part.type}>\\\\d{1,4})`;\n }\n\n return escapeRegExp(part.value).replace(/\\s+/g, \"\\\\s*\");\n })\n .join(\"\");\n const match = new RegExp(`^\\\\s*${pattern}\\\\s*$`).exec(value);\n const groups = match?.groups;\n\n if (!groups?.day || !groups.month || !groups.year) {\n return undefined;\n }\n\n return {\n day: groups.day,\n hour: groups.hour,\n minute: groups.minute,\n month: groups.month,\n year: groups.year,\n };\n}\n\nfunction escapeRegExp(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import { RendererComponent } from '../../../core/types';
2
+ export declare const DateTimeInputComponent: RendererComponent<"field.date-time-input">;
@@ -0,0 +1,34 @@
1
+ import { useTimezone } from "../../../i18n/timezone.js";
2
+ import { LazyDatePickerControl } from "./lazy-date-picker-control.js";
3
+ import { SimpleField } from "./simple-field.js";
4
+ import { jsx } from "react/jsx-runtime";
5
+ //#region resources/js/form/components/fields/date-time-input.tsx
6
+ var DateTimeInputComponent = ({ node }) => {
7
+ const props = node.props;
8
+ const { timezone } = useTimezone();
9
+ return /* @__PURE__ */ jsx(SimpleField, {
10
+ node,
11
+ label: props.label ?? "",
12
+ children: ({ name, testId, value, readOnly, disabled, change, blur }) => /* @__PURE__ */ jsx(LazyDatePickerControl, {
13
+ autoFocus: props.autoFocus ?? false,
14
+ disabled,
15
+ label: props.label ?? props.name,
16
+ max: props.max,
17
+ min: props.min,
18
+ mode: "date-time",
19
+ name,
20
+ onBlur: blur,
21
+ onChange: change,
22
+ readOnly,
23
+ step: props.step,
24
+ tabIndex: props.tabIndex ?? void 0,
25
+ testId: testId ?? props.name,
26
+ timezone,
27
+ value
28
+ })
29
+ });
30
+ };
31
+ //#endregion
32
+ export { DateTimeInputComponent };
33
+
34
+ //# sourceMappingURL=date-time-input.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"date-time-input.js","names":[],"sources":["../../../../resources/js/form/components/fields/date-time-input.tsx"],"sourcesContent":["import type { RendererComponent } from \"@lattice-php/lattice/core/types\";\nimport { useTimezone } from \"@lattice-php/lattice/i18n\";\nimport { LazyDatePickerControl } from \"./lazy-date-picker-control\";\nimport { SimpleField } from \"./simple-field\";\n\nexport const DateTimeInputComponent: RendererComponent<\"field.date-time-input\"> = ({ node }) => {\n const props = node.props;\n const { timezone } = useTimezone();\n\n return (\n <SimpleField node={node} label={props.label ?? \"\"}>\n {({ name, testId, value, readOnly, disabled, change, blur }) => (\n <LazyDatePickerControl\n autoFocus={props.autoFocus ?? false}\n disabled={disabled}\n label={props.label ?? props.name}\n max={props.max}\n min={props.min}\n mode=\"date-time\"\n name={name}\n onBlur={blur}\n onChange={change}\n readOnly={readOnly}\n step={props.step}\n tabIndex={props.tabIndex ?? undefined}\n testId={testId ?? props.name}\n timezone={timezone}\n value={value}\n />\n )}\n </SimpleField>\n );\n};\n"],"mappings":";;;;;AAKA,IAAa,0BAAsE,EAAE,WAAW;CAC9F,MAAM,QAAQ,KAAK;CACnB,MAAM,EAAE,aAAa,YAAY;CAEjC,OACE,oBAAC,aAAD;EAAmB;EAAM,OAAO,MAAM,SAAS;aAC3C,EAAE,MAAM,QAAQ,OAAO,UAAU,UAAU,QAAQ,WACnD,oBAAC,uBAAD;GACE,WAAW,MAAM,aAAa;GACpB;GACV,OAAO,MAAM,SAAS,MAAM;GAC5B,KAAK,MAAM;GACX,KAAK,MAAM;GACX,MAAK;GACC;GACN,QAAQ;GACR,UAAU;GACA;GACV,MAAM,MAAM;GACZ,UAAU,MAAM,YAAY,KAAA;GAC5B,QAAQ,UAAU,MAAM;GACd;GACH;EACR,CAAA;CAEQ,CAAA;AAEjB"}
@@ -199,7 +199,7 @@ var FileUploadComponent = ({ node }) => {
199
199
  disabled: locked,
200
200
  onClick: () => fileInputRef.current?.click(),
201
201
  type: "button",
202
- children: t("file-upload.dropzone", "Drop files here or click to browse")
202
+ children: t("form.file-upload.dropzone", "Drop files here or click to browse")
203
203
  }),
204
204
  /* @__PURE__ */ jsx("ul", {
205
205
  className: props.image ? "grid grid-cols-1 gap-3 sm:grid-cols-2" : "flex flex-col gap-2",
@@ -226,12 +226,12 @@ var FileUploadComponent = ({ node }) => {
226
226
  }),
227
227
  item.status === "error" && /* @__PURE__ */ jsx("span", {
228
228
  className: "text-xs text-lt-danger",
229
- children: t("file-upload.failed", "Failed")
229
+ children: t("form.file-upload.failed", "Failed")
230
230
  })
231
231
  ]
232
232
  }),
233
233
  (!item.existing || !scope) && /* @__PURE__ */ jsx("button", {
234
- "aria-label": t("file-upload.remove", "Remove {{name}}", { name: item.name }),
234
+ "aria-label": t("form.file-upload.remove", "Remove {{name}}", { name: item.name }),
235
235
  className: "inline-flex size-7 shrink-0 items-center justify-center rounded-lt-sm text-lt-muted-fg transition-colors hover:bg-lt-accent hover:text-lt-accent-fg disabled:pointer-events-none disabled:opacity-50",
236
236
  "data-test": testIdentity(item.existing ? `${name}-remove-existing` : `${name}-remove`),
237
237
  disabled: locked,
@@ -1 +1 @@
1
- {"version":3,"file":"file-upload.js","names":[],"sources":["../../../../resources/js/form/components/fields/file-upload.tsx"],"sourcesContent":["import { apiFetch } from \"@lattice-php/lattice/core/api\";\nimport { testIdentity } from \"@lattice-php/lattice/core/test-id\";\nimport type { RendererComponent } from \"@lattice-php/lattice/core/types\";\nimport { Icon } from \"@lattice-php/lattice/icons\";\nimport { useT } from \"@lattice-php/lattice/i18n\";\nimport { useEffect, useId, useMemo, useRef, useState } from \"react\";\nimport { FormFieldFrame } from \"../base/field\";\nimport { useFormContext } from \"../context\";\nimport { useDependentField } from \"../use-dependent-field\";\nimport { useFieldScope } from \"../field-scope\";\nimport { useFormValues, useSetFormValue } from \"../values\";\n\ntype Item = {\n id: string;\n name: string;\n size: number | null;\n status: \"ready\" | \"uploading\" | \"error\";\n progress: number;\n file?: File;\n key?: string;\n url?: string | null;\n token?: string;\n existing: boolean;\n};\n\ntype SignResponse = {\n key: string;\n url: string;\n headers: Record<string, string>;\n method: string;\n};\n\nfunction uploadValueEquals(current: unknown, next: string[] | string): boolean {\n if (Array.isArray(next)) {\n return (\n Array.isArray(current) &&\n current.length === next.length &&\n current.every((value, index) => value === next[index])\n );\n }\n\n return current === next;\n}\n\nexport const FileUploadComponent: RendererComponent<\"field.file-upload\"> = ({ node }) => {\n const { t } = useT(\"lattice\");\n const props = node.props;\n const { hidden, required, readOnly, disabled } = useDependentField(node);\n const { action, componentRef, errors } = useFormContext();\n const name = props.name;\n const scope = useFieldScope();\n const domName = scope ? scope.scopedName(name) : name;\n const errorKey = scope ? scope.errorKey(name) : name;\n const uploadKey = errorKey;\n const values = useFormValues();\n const setValue = useSetFormValue();\n const inputId = useId();\n const fileInputRef = useRef<HTMLInputElement>(null);\n const previewUrlsRef = useRef<Set<string>>(new Set());\n const locked = readOnly || disabled;\n const signed = props.signed;\n const multiple = props.multiple;\n const fieldName = multiple ? `${domName}[]` : domName;\n\n const initial = useMemo<Item[]>(\n () =>\n (props.files ?? []).map((file) => ({\n id: crypto.randomUUID(),\n name: file.name,\n size: file.size,\n status: \"ready\" as const,\n progress: 100,\n key: file.key,\n url: file.url,\n token: file.token,\n existing: true,\n })),\n [props.files],\n );\n const [items, setItems] = useState<Item[]>(initial);\n const [removedTokens, setRemovedTokens] = useState<string[]>([]);\n\n useEffect(() => {\n if (!signed) {\n return;\n }\n\n const keys = items\n .filter((item) => !item.existing && item.key && item.status === \"ready\")\n .map((item) => item.key as string);\n const next = multiple ? keys : (keys[0] ?? \"\");\n\n if (scope) {\n if (!uploadValueEquals(scope.getValue(name), next)) {\n scope.setValue(name, next);\n }\n\n return;\n }\n\n setValue(name, next);\n }, [items, multiple, name, scope, setValue, signed]);\n\n useEffect(() => {\n if (!signed || scope) {\n return;\n }\n\n setValue(`${name}__removed`, removedTokens);\n }, [name, removedTokens, scope, setValue, signed]);\n\n useEffect(\n () => () => {\n previewUrlsRef.current.forEach((url) => URL.revokeObjectURL(url));\n previewUrlsRef.current.clear();\n },\n [],\n );\n\n const multipartFiles = items\n .filter((item) => item.file && !item.existing)\n .map((item) => item.file as File);\n useEffect(() => {\n if (signed || !fileInputRef.current) {\n return;\n }\n\n const transfer = new DataTransfer();\n multipartFiles.forEach((file) => transfer.items.add(file));\n fileInputRef.current.files = transfer.files;\n });\n\n function createPreviewUrl(file: File): string | undefined {\n if (!props.image) {\n return undefined;\n }\n\n const url = URL.createObjectURL(file);\n previewUrlsRef.current.add(url);\n\n return url;\n }\n\n function revokePreviewUrl(item: Item): void {\n if (!item.url || !previewUrlsRef.current.has(item.url)) {\n return;\n }\n\n URL.revokeObjectURL(item.url);\n previewUrlsRef.current.delete(item.url);\n }\n\n async function signAndUpload(item: Item, file: File): Promise<void> {\n const response = await apiFetch(action, {\n method: \"POST\",\n ref: componentRef,\n body: JSON.stringify({\n ...values,\n _upload: uploadKey,\n filename: file.name,\n contentType: file.type,\n }),\n throwOnError: false,\n });\n\n if (!response.ok) {\n setItems((prev) =>\n prev.map((entry) => (entry.id === item.id ? { ...entry, status: \"error\" } : entry)),\n );\n\n return;\n }\n\n const sign = (await response.json()) as SignResponse;\n\n await new Promise<void>((resolve) => {\n const request = new XMLHttpRequest();\n request.open(sign.method, sign.url, true);\n Object.entries(sign.headers).forEach(([key, value]) =>\n request.setRequestHeader(key, String(value)),\n );\n request.upload.onprogress = (event) => {\n if (event.lengthComputable) {\n const progress = Math.round((event.loaded / event.total) * 100);\n setItems((prev) =>\n prev.map((entry) => (entry.id === item.id ? { ...entry, progress } : entry)),\n );\n }\n };\n request.onload = () => {\n setItems((prev) =>\n prev.map((entry) =>\n entry.id === item.id\n ? {\n ...entry,\n status: request.status < 300 ? \"ready\" : \"error\",\n key: sign.key,\n progress: 100,\n }\n : entry,\n ),\n );\n resolve();\n };\n request.onerror = () => {\n setItems((prev) =>\n prev.map((entry) => (entry.id === item.id ? { ...entry, status: \"error\" } : entry)),\n );\n resolve();\n };\n request.send(file);\n });\n }\n\n function addFiles(fileList: FileList | null): void {\n if (!fileList || locked) {\n return;\n }\n\n const incoming = Array.from(fileList);\n const next = incoming.map<Item>((file) => ({\n id: crypto.randomUUID(),\n name: file.name,\n size: file.size,\n status: signed ? \"uploading\" : \"ready\",\n progress: 0,\n file,\n url: createPreviewUrl(file),\n existing: false,\n }));\n\n if (!multiple) {\n items.forEach(revokePreviewUrl);\n\n if (!scope) {\n const replacedTokens = items\n .filter((item) => item.existing && item.token)\n .map((item) => item.token as string);\n\n if (replacedTokens.length > 0) {\n setRemovedTokens((tokens) => [...tokens, ...replacedTokens]);\n }\n }\n }\n\n setItems((prev) => (multiple ? [...prev, ...next] : next));\n\n if (signed) {\n next.forEach((item, index) => void signAndUpload(item, incoming[index]));\n }\n }\n\n function removeItem(id: string): void {\n const target = items.find((item) => item.id === id);\n\n if (target) {\n revokePreviewUrl(target);\n }\n\n setItems((prev) => {\n if (target?.existing && target.token && !scope) {\n setRemovedTokens((tokens) => [...tokens, target.token as string]);\n }\n return prev.filter((i) => i.id !== id);\n });\n }\n\n if (hidden) {\n return null;\n }\n\n return (\n <FormFieldFrame\n error={errors[errorKey]}\n helperText={props.helperText ?? undefined}\n tooltip={props.tooltip ?? undefined}\n label={props.label ?? \"\"}\n name={name}\n required={required}\n >\n <div\n className=\"flex flex-col gap-3 rounded-lt-sm border border-dashed border-lt-border bg-lt-surface px-4 py-6\"\n data-test={testIdentity(name)}\n onDragOver={(event) => event.preventDefault()}\n onDrop={(event) => {\n event.preventDefault();\n addFiles(event.dataTransfer.files);\n }}\n >\n <button\n className=\"text-sm text-lt-muted-fg\"\n disabled={locked}\n onClick={() => fileInputRef.current?.click()}\n type=\"button\"\n >\n {t(\"file-upload.dropzone\", \"Drop files here or click to browse\")}\n </button>\n\n <ul\n className={props.image ? \"grid grid-cols-1 gap-3 sm:grid-cols-2\" : \"flex flex-col gap-2\"}\n >\n {items.map((item) => (\n <li\n className={\n props.image\n ? \"flex min-w-0 items-center gap-3 rounded-lt-sm border border-lt-border bg-lt-bg p-2 text-sm\"\n : \"flex items-center justify-between gap-3 text-sm\"\n }\n key={item.id}\n >\n {props.image && item.url ? (\n <img\n alt={item.name}\n className=\"size-16 shrink-0 rounded-lt-sm border border-lt-border object-cover\"\n data-test={testIdentity(`${name}-preview`)}\n src={item.url}\n />\n ) : null}\n <div className=\"min-w-0 flex-1\">\n <span className=\"block truncate\" data-test={testIdentity(`${name}-item`)}>\n {item.name}\n </span>\n {item.status === \"uploading\" && (\n <span className=\"text-xs text-lt-muted-fg\">{item.progress}%</span>\n )}\n {item.status === \"error\" && (\n <span className=\"text-xs text-lt-danger\">\n {t(\"file-upload.failed\", \"Failed\")}\n </span>\n )}\n </div>\n {(!item.existing || !scope) && (\n <button\n aria-label={t(\"file-upload.remove\", \"Remove {{name}}\", { name: item.name })}\n className=\"inline-flex size-7 shrink-0 items-center justify-center rounded-lt-sm text-lt-muted-fg transition-colors hover:bg-lt-accent hover:text-lt-accent-fg disabled:pointer-events-none disabled:opacity-50\"\n data-test={testIdentity(\n item.existing ? `${name}-remove-existing` : `${name}-remove`,\n )}\n disabled={locked}\n onClick={() => removeItem(item.id)}\n type=\"button\"\n >\n <Icon name=\"x\" aria-hidden=\"true\" className=\"size-lt-icon-sm\" />\n </button>\n )}\n {signed && !item.existing && item.key && item.status === \"ready\" && (\n <input\n data-test={testIdentity(`${name}-uploaded`)}\n name={fieldName}\n type=\"hidden\"\n value={item.key}\n />\n )}\n </li>\n ))}\n </ul>\n\n {!scope &&\n removedTokens.map((token) => (\n <input key={token} name={`${name}__removed[]`} type=\"hidden\" value={token} />\n ))}\n\n <input\n accept={props.accept ?? undefined}\n aria-label={props.label ?? name}\n className=\"sr-only\"\n data-test={testIdentity(`${name}-input`)}\n id={inputId}\n multiple={multiple}\n name={signed ? undefined : fieldName}\n onChange={(event) => {\n addFiles(event.target.files);\n if (signed) {\n event.target.value = \"\";\n }\n }}\n ref={fileInputRef}\n type=\"file\"\n />\n </div>\n </FormFieldFrame>\n );\n};\n"],"mappings":";;;;;;;;;;;;AAgCA,SAAS,kBAAkB,SAAkB,MAAkC;CAC7E,IAAI,MAAM,QAAQ,IAAI,GACpB,OACE,MAAM,QAAQ,OAAO,KACrB,QAAQ,WAAW,KAAK,UACxB,QAAQ,OAAO,OAAO,UAAU,UAAU,KAAK,MAAM;CAIzD,OAAO,YAAY;AACrB;AAEA,IAAa,uBAA+D,EAAE,WAAW;CACvF,MAAM,EAAE,MAAM,KAAK,SAAS;CAC5B,MAAM,QAAQ,KAAK;CACnB,MAAM,EAAE,QAAQ,UAAU,UAAU,aAAa,kBAAkB,IAAI;CACvE,MAAM,EAAE,QAAQ,cAAc,WAAW,eAAe;CACxD,MAAM,OAAO,MAAM;CACnB,MAAM,QAAQ,cAAc;CAC5B,MAAM,UAAU,QAAQ,MAAM,WAAW,IAAI,IAAI;CACjD,MAAM,WAAW,QAAQ,MAAM,SAAS,IAAI,IAAI;CAChD,MAAM,YAAY;CAClB,MAAM,SAAS,cAAc;CAC7B,MAAM,WAAW,gBAAgB;CACjC,MAAM,UAAU,MAAM;CACtB,MAAM,eAAe,OAAyB,IAAI;CAClD,MAAM,iBAAiB,uBAAoB,IAAI,IAAI,CAAC;CACpD,MAAM,SAAS,YAAY;CAC3B,MAAM,SAAS,MAAM;CACrB,MAAM,WAAW,MAAM;CACvB,MAAM,YAAY,WAAW,GAAG,QAAQ,MAAM;CAiB9C,MAAM,CAAC,OAAO,YAAY,SAfV,eAEX,MAAM,SAAS,CAAC,GAAG,KAAK,UAAU;EACjC,IAAI,OAAO,WAAW;EACtB,MAAM,KAAK;EACX,MAAM,KAAK;EACX,QAAQ;EACR,UAAU;EACV,KAAK,KAAK;EACV,KAAK,KAAK;EACV,OAAO,KAAK;EACZ,UAAU;CACZ,EAAE,GACJ,CAAC,MAAM,KAAK,CAE6B,CAAO;CAClD,MAAM,CAAC,eAAe,oBAAoB,SAAmB,CAAC,CAAC;CAE/D,gBAAgB;EACd,IAAI,CAAC,QACH;EAGF,MAAM,OAAO,MACV,QAAQ,SAAS,CAAC,KAAK,YAAY,KAAK,OAAO,KAAK,WAAW,OAAO,EACtE,KAAK,SAAS,KAAK,GAAa;EACnC,MAAM,OAAO,WAAW,OAAQ,KAAK,MAAM;EAE3C,IAAI,OAAO;GACT,IAAI,CAAC,kBAAkB,MAAM,SAAS,IAAI,GAAG,IAAI,GAC/C,MAAM,SAAS,MAAM,IAAI;GAG3B;EACF;EAEA,SAAS,MAAM,IAAI;CACrB,GAAG;EAAC;EAAO;EAAU;EAAM;EAAO;EAAU;CAAM,CAAC;CAEnD,gBAAgB;EACd,IAAI,CAAC,UAAU,OACb;EAGF,SAAS,GAAG,KAAK,YAAY,aAAa;CAC5C,GAAG;EAAC;EAAM;EAAe;EAAO;EAAU;CAAM,CAAC;CAEjD,sBACc;EACV,eAAe,QAAQ,SAAS,QAAQ,IAAI,gBAAgB,GAAG,CAAC;EAChE,eAAe,QAAQ,MAAM;CAC/B,GACA,CAAC,CACH;CAEA,MAAM,iBAAiB,MACpB,QAAQ,SAAS,KAAK,QAAQ,CAAC,KAAK,QAAQ,EAC5C,KAAK,SAAS,KAAK,IAAY;CAClC,gBAAgB;EACd,IAAI,UAAU,CAAC,aAAa,SAC1B;EAGF,MAAM,WAAW,IAAI,aAAa;EAClC,eAAe,SAAS,SAAS,SAAS,MAAM,IAAI,IAAI,CAAC;EACzD,aAAa,QAAQ,QAAQ,SAAS;CACxC,CAAC;CAED,SAAS,iBAAiB,MAAgC;EACxD,IAAI,CAAC,MAAM,OACT;EAGF,MAAM,MAAM,IAAI,gBAAgB,IAAI;EACpC,eAAe,QAAQ,IAAI,GAAG;EAE9B,OAAO;CACT;CAEA,SAAS,iBAAiB,MAAkB;EAC1C,IAAI,CAAC,KAAK,OAAO,CAAC,eAAe,QAAQ,IAAI,KAAK,GAAG,GACnD;EAGF,IAAI,gBAAgB,KAAK,GAAG;EAC5B,eAAe,QAAQ,OAAO,KAAK,GAAG;CACxC;CAEA,eAAe,cAAc,MAAY,MAA2B;EAClE,MAAM,WAAW,MAAM,SAAS,QAAQ;GACtC,QAAQ;GACR,KAAK;GACL,MAAM,KAAK,UAAU;IACnB,GAAG;IACH,SAAS;IACT,UAAU,KAAK;IACf,aAAa,KAAK;GACpB,CAAC;GACD,cAAc;EAChB,CAAC;EAED,IAAI,CAAC,SAAS,IAAI;GAChB,UAAU,SACR,KAAK,KAAK,UAAW,MAAM,OAAO,KAAK,KAAK;IAAE,GAAG;IAAO,QAAQ;GAAQ,IAAI,KAAM,CACpF;GAEA;EACF;EAEA,MAAM,OAAQ,MAAM,SAAS,KAAK;EAElC,MAAM,IAAI,SAAe,YAAY;GACnC,MAAM,UAAU,IAAI,eAAe;GACnC,QAAQ,KAAK,KAAK,QAAQ,KAAK,KAAK,IAAI;GACxC,OAAO,QAAQ,KAAK,OAAO,EAAE,SAAS,CAAC,KAAK,WAC1C,QAAQ,iBAAiB,KAAK,OAAO,KAAK,CAAC,CAC7C;GACA,QAAQ,OAAO,cAAc,UAAU;IACrC,IAAI,MAAM,kBAAkB;KAC1B,MAAM,WAAW,KAAK,MAAO,MAAM,SAAS,MAAM,QAAS,GAAG;KAC9D,UAAU,SACR,KAAK,KAAK,UAAW,MAAM,OAAO,KAAK,KAAK;MAAE,GAAG;MAAO;KAAS,IAAI,KAAM,CAC7E;IACF;GACF;GACA,QAAQ,eAAe;IACrB,UAAU,SACR,KAAK,KAAK,UACR,MAAM,OAAO,KAAK,KACd;KACE,GAAG;KACH,QAAQ,QAAQ,SAAS,MAAM,UAAU;KACzC,KAAK,KAAK;KACV,UAAU;IACZ,IACA,KACN,CACF;IACA,QAAQ;GACV;GACA,QAAQ,gBAAgB;IACtB,UAAU,SACR,KAAK,KAAK,UAAW,MAAM,OAAO,KAAK,KAAK;KAAE,GAAG;KAAO,QAAQ;IAAQ,IAAI,KAAM,CACpF;IACA,QAAQ;GACV;GACA,QAAQ,KAAK,IAAI;EACnB,CAAC;CACH;CAEA,SAAS,SAAS,UAAiC;EACjD,IAAI,CAAC,YAAY,QACf;EAGF,MAAM,WAAW,MAAM,KAAK,QAAQ;EACpC,MAAM,OAAO,SAAS,KAAW,UAAU;GACzC,IAAI,OAAO,WAAW;GACtB,MAAM,KAAK;GACX,MAAM,KAAK;GACX,QAAQ,SAAS,cAAc;GAC/B,UAAU;GACV;GACA,KAAK,iBAAiB,IAAI;GAC1B,UAAU;EACZ,EAAE;EAEF,IAAI,CAAC,UAAU;GACb,MAAM,QAAQ,gBAAgB;GAE9B,IAAI,CAAC,OAAO;IACV,MAAM,iBAAiB,MACpB,QAAQ,SAAS,KAAK,YAAY,KAAK,KAAK,EAC5C,KAAK,SAAS,KAAK,KAAe;IAErC,IAAI,eAAe,SAAS,GAC1B,kBAAkB,WAAW,CAAC,GAAG,QAAQ,GAAG,cAAc,CAAC;GAE/D;EACF;EAEA,UAAU,SAAU,WAAW,CAAC,GAAG,MAAM,GAAG,IAAI,IAAI,IAAK;EAEzD,IAAI,QACF,KAAK,SAAS,MAAM,UAAU,KAAK,cAAc,MAAM,SAAS,MAAM,CAAC;CAE3E;CAEA,SAAS,WAAW,IAAkB;EACpC,MAAM,SAAS,MAAM,MAAM,SAAS,KAAK,OAAO,EAAE;EAElD,IAAI,QACF,iBAAiB,MAAM;EAGzB,UAAU,SAAS;GACjB,IAAI,QAAQ,YAAY,OAAO,SAAS,CAAC,OACvC,kBAAkB,WAAW,CAAC,GAAG,QAAQ,OAAO,KAAe,CAAC;GAElE,OAAO,KAAK,QAAQ,MAAM,EAAE,OAAO,EAAE;EACvC,CAAC;CACH;CAEA,IAAI,QACF,OAAO;CAGT,OACE,oBAAC,gBAAD;EACE,OAAO,OAAO;EACd,YAAY,MAAM,cAAc,KAAA;EAChC,SAAS,MAAM,WAAW,KAAA;EAC1B,OAAO,MAAM,SAAS;EAChB;EACI;YAEV,qBAAC,OAAD;GACE,WAAU;GACV,aAAW,aAAa,IAAI;GAC5B,aAAa,UAAU,MAAM,eAAe;GAC5C,SAAS,UAAU;IACjB,MAAM,eAAe;IACrB,SAAS,MAAM,aAAa,KAAK;GACnC;aAPF;IASE,oBAAC,UAAD;KACE,WAAU;KACV,UAAU;KACV,eAAe,aAAa,SAAS,MAAM;KAC3C,MAAK;eAEJ,EAAE,wBAAwB,oCAAoC;IACzD,CAAA;IAER,oBAAC,MAAD;KACE,WAAW,MAAM,QAAQ,0CAA0C;eAElE,MAAM,KAAK,SACV,qBAAC,MAAD;MACE,WACE,MAAM,QACF,+FACA;gBAJR;OAQG,MAAM,SAAS,KAAK,MACnB,oBAAC,OAAD;QACE,KAAK,KAAK;QACV,WAAU;QACV,aAAW,aAAa,GAAG,KAAK,SAAS;QACzC,KAAK,KAAK;OACX,CAAA,IACC;OACJ,qBAAC,OAAD;QAAK,WAAU;kBAAf;SACE,oBAAC,QAAD;UAAM,WAAU;UAAiB,aAAW,aAAa,GAAG,KAAK,MAAM;oBACpE,KAAK;SACF,CAAA;SACL,KAAK,WAAW,eACf,qBAAC,QAAD;UAAM,WAAU;oBAAhB,CAA4C,KAAK,UAAS,GAAO;;SAElE,KAAK,WAAW,WACf,oBAAC,QAAD;UAAM,WAAU;oBACb,EAAE,sBAAsB,QAAQ;SAC7B,CAAA;QAEL;;QACH,CAAC,KAAK,YAAY,CAAC,UACnB,oBAAC,UAAD;QACE,cAAY,EAAE,sBAAsB,mBAAmB,EAAE,MAAM,KAAK,KAAK,CAAC;QAC1E,WAAU;QACV,aAAW,aACT,KAAK,WAAW,GAAG,KAAK,oBAAoB,GAAG,KAAK,QACtD;QACA,UAAU;QACV,eAAe,WAAW,KAAK,EAAE;QACjC,MAAK;kBAEL,oBAAC,MAAD;SAAM,MAAK;SAAI,eAAY;SAAO,WAAU;QAAmB,CAAA;OACzD,CAAA;OAET,UAAU,CAAC,KAAK,YAAY,KAAK,OAAO,KAAK,WAAW,WACvD,oBAAC,SAAD;QACE,aAAW,aAAa,GAAG,KAAK,UAAU;QAC1C,MAAM;QACN,MAAK;QACL,OAAO,KAAK;OACb,CAAA;MAED;QA7CG,KAAK,EA6CR,CACL;IACC,CAAA;IAEH,CAAC,SACA,cAAc,KAAK,UACjB,oBAAC,SAAD;KAAmB,MAAM,GAAG,KAAK;KAAc,MAAK;KAAS,OAAO;IAAQ,GAAhE,KAAgE,CAC7E;IAEH,oBAAC,SAAD;KACE,QAAQ,MAAM,UAAU,KAAA;KACxB,cAAY,MAAM,SAAS;KAC3B,WAAU;KACV,aAAW,aAAa,GAAG,KAAK,OAAO;KACvC,IAAI;KACM;KACV,MAAM,SAAS,KAAA,IAAY;KAC3B,WAAW,UAAU;MACnB,SAAS,MAAM,OAAO,KAAK;MAC3B,IAAI,QACF,MAAM,OAAO,QAAQ;KAEzB;KACA,KAAK;KACL,MAAK;IACN,CAAA;GACE;;CACS,CAAA;AAEpB"}
1
+ {"version":3,"file":"file-upload.js","names":[],"sources":["../../../../resources/js/form/components/fields/file-upload.tsx"],"sourcesContent":["import { apiFetch } from \"@lattice-php/lattice/core/api\";\nimport { testIdentity } from \"@lattice-php/lattice/core/test-id\";\nimport type { RendererComponent } from \"@lattice-php/lattice/core/types\";\nimport { Icon } from \"@lattice-php/lattice/icons\";\nimport { useT } from \"@lattice-php/lattice/i18n\";\nimport { useEffect, useId, useMemo, useRef, useState } from \"react\";\nimport { FormFieldFrame } from \"../base/field\";\nimport { useFormContext } from \"../context\";\nimport { useDependentField } from \"../use-dependent-field\";\nimport { useFieldScope } from \"../field-scope\";\nimport { useFormValues, useSetFormValue } from \"../values\";\n\ntype Item = {\n id: string;\n name: string;\n size: number | null;\n status: \"ready\" | \"uploading\" | \"error\";\n progress: number;\n file?: File;\n key?: string;\n url?: string | null;\n token?: string;\n existing: boolean;\n};\n\ntype SignResponse = {\n key: string;\n url: string;\n headers: Record<string, string>;\n method: string;\n};\n\nfunction uploadValueEquals(current: unknown, next: string[] | string): boolean {\n if (Array.isArray(next)) {\n return (\n Array.isArray(current) &&\n current.length === next.length &&\n current.every((value, index) => value === next[index])\n );\n }\n\n return current === next;\n}\n\nexport const FileUploadComponent: RendererComponent<\"field.file-upload\"> = ({ node }) => {\n const { t } = useT(\"lattice\");\n const props = node.props;\n const { hidden, required, readOnly, disabled } = useDependentField(node);\n const { action, componentRef, errors } = useFormContext();\n const name = props.name;\n const scope = useFieldScope();\n const domName = scope ? scope.scopedName(name) : name;\n const errorKey = scope ? scope.errorKey(name) : name;\n const uploadKey = errorKey;\n const values = useFormValues();\n const setValue = useSetFormValue();\n const inputId = useId();\n const fileInputRef = useRef<HTMLInputElement>(null);\n const previewUrlsRef = useRef<Set<string>>(new Set());\n const locked = readOnly || disabled;\n const signed = props.signed;\n const multiple = props.multiple;\n const fieldName = multiple ? `${domName}[]` : domName;\n\n const initial = useMemo<Item[]>(\n () =>\n (props.files ?? []).map((file) => ({\n id: crypto.randomUUID(),\n name: file.name,\n size: file.size,\n status: \"ready\" as const,\n progress: 100,\n key: file.key,\n url: file.url,\n token: file.token,\n existing: true,\n })),\n [props.files],\n );\n const [items, setItems] = useState<Item[]>(initial);\n const [removedTokens, setRemovedTokens] = useState<string[]>([]);\n\n useEffect(() => {\n if (!signed) {\n return;\n }\n\n const keys = items\n .filter((item) => !item.existing && item.key && item.status === \"ready\")\n .map((item) => item.key as string);\n const next = multiple ? keys : (keys[0] ?? \"\");\n\n if (scope) {\n if (!uploadValueEquals(scope.getValue(name), next)) {\n scope.setValue(name, next);\n }\n\n return;\n }\n\n setValue(name, next);\n }, [items, multiple, name, scope, setValue, signed]);\n\n useEffect(() => {\n if (!signed || scope) {\n return;\n }\n\n setValue(`${name}__removed`, removedTokens);\n }, [name, removedTokens, scope, setValue, signed]);\n\n useEffect(\n () => () => {\n previewUrlsRef.current.forEach((url) => URL.revokeObjectURL(url));\n previewUrlsRef.current.clear();\n },\n [],\n );\n\n const multipartFiles = items\n .filter((item) => item.file && !item.existing)\n .map((item) => item.file as File);\n useEffect(() => {\n if (signed || !fileInputRef.current) {\n return;\n }\n\n const transfer = new DataTransfer();\n multipartFiles.forEach((file) => transfer.items.add(file));\n fileInputRef.current.files = transfer.files;\n });\n\n function createPreviewUrl(file: File): string | undefined {\n if (!props.image) {\n return undefined;\n }\n\n const url = URL.createObjectURL(file);\n previewUrlsRef.current.add(url);\n\n return url;\n }\n\n function revokePreviewUrl(item: Item): void {\n if (!item.url || !previewUrlsRef.current.has(item.url)) {\n return;\n }\n\n URL.revokeObjectURL(item.url);\n previewUrlsRef.current.delete(item.url);\n }\n\n async function signAndUpload(item: Item, file: File): Promise<void> {\n const response = await apiFetch(action, {\n method: \"POST\",\n ref: componentRef,\n body: JSON.stringify({\n ...values,\n _upload: uploadKey,\n filename: file.name,\n contentType: file.type,\n }),\n throwOnError: false,\n });\n\n if (!response.ok) {\n setItems((prev) =>\n prev.map((entry) => (entry.id === item.id ? { ...entry, status: \"error\" } : entry)),\n );\n\n return;\n }\n\n const sign = (await response.json()) as SignResponse;\n\n await new Promise<void>((resolve) => {\n const request = new XMLHttpRequest();\n request.open(sign.method, sign.url, true);\n Object.entries(sign.headers).forEach(([key, value]) =>\n request.setRequestHeader(key, String(value)),\n );\n request.upload.onprogress = (event) => {\n if (event.lengthComputable) {\n const progress = Math.round((event.loaded / event.total) * 100);\n setItems((prev) =>\n prev.map((entry) => (entry.id === item.id ? { ...entry, progress } : entry)),\n );\n }\n };\n request.onload = () => {\n setItems((prev) =>\n prev.map((entry) =>\n entry.id === item.id\n ? {\n ...entry,\n status: request.status < 300 ? \"ready\" : \"error\",\n key: sign.key,\n progress: 100,\n }\n : entry,\n ),\n );\n resolve();\n };\n request.onerror = () => {\n setItems((prev) =>\n prev.map((entry) => (entry.id === item.id ? { ...entry, status: \"error\" } : entry)),\n );\n resolve();\n };\n request.send(file);\n });\n }\n\n function addFiles(fileList: FileList | null): void {\n if (!fileList || locked) {\n return;\n }\n\n const incoming = Array.from(fileList);\n const next = incoming.map<Item>((file) => ({\n id: crypto.randomUUID(),\n name: file.name,\n size: file.size,\n status: signed ? \"uploading\" : \"ready\",\n progress: 0,\n file,\n url: createPreviewUrl(file),\n existing: false,\n }));\n\n if (!multiple) {\n items.forEach(revokePreviewUrl);\n\n if (!scope) {\n const replacedTokens = items\n .filter((item) => item.existing && item.token)\n .map((item) => item.token as string);\n\n if (replacedTokens.length > 0) {\n setRemovedTokens((tokens) => [...tokens, ...replacedTokens]);\n }\n }\n }\n\n setItems((prev) => (multiple ? [...prev, ...next] : next));\n\n if (signed) {\n next.forEach((item, index) => void signAndUpload(item, incoming[index]));\n }\n }\n\n function removeItem(id: string): void {\n const target = items.find((item) => item.id === id);\n\n if (target) {\n revokePreviewUrl(target);\n }\n\n setItems((prev) => {\n if (target?.existing && target.token && !scope) {\n setRemovedTokens((tokens) => [...tokens, target.token as string]);\n }\n return prev.filter((i) => i.id !== id);\n });\n }\n\n if (hidden) {\n return null;\n }\n\n return (\n <FormFieldFrame\n error={errors[errorKey]}\n helperText={props.helperText ?? undefined}\n tooltip={props.tooltip ?? undefined}\n label={props.label ?? \"\"}\n name={name}\n required={required}\n >\n <div\n className=\"flex flex-col gap-3 rounded-lt-sm border border-dashed border-lt-border bg-lt-surface px-4 py-6\"\n data-test={testIdentity(name)}\n onDragOver={(event) => event.preventDefault()}\n onDrop={(event) => {\n event.preventDefault();\n addFiles(event.dataTransfer.files);\n }}\n >\n <button\n className=\"text-sm text-lt-muted-fg\"\n disabled={locked}\n onClick={() => fileInputRef.current?.click()}\n type=\"button\"\n >\n {t(\"form.file-upload.dropzone\", \"Drop files here or click to browse\")}\n </button>\n\n <ul\n className={props.image ? \"grid grid-cols-1 gap-3 sm:grid-cols-2\" : \"flex flex-col gap-2\"}\n >\n {items.map((item) => (\n <li\n className={\n props.image\n ? \"flex min-w-0 items-center gap-3 rounded-lt-sm border border-lt-border bg-lt-bg p-2 text-sm\"\n : \"flex items-center justify-between gap-3 text-sm\"\n }\n key={item.id}\n >\n {props.image && item.url ? (\n <img\n alt={item.name}\n className=\"size-16 shrink-0 rounded-lt-sm border border-lt-border object-cover\"\n data-test={testIdentity(`${name}-preview`)}\n src={item.url}\n />\n ) : null}\n <div className=\"min-w-0 flex-1\">\n <span className=\"block truncate\" data-test={testIdentity(`${name}-item`)}>\n {item.name}\n </span>\n {item.status === \"uploading\" && (\n <span className=\"text-xs text-lt-muted-fg\">{item.progress}%</span>\n )}\n {item.status === \"error\" && (\n <span className=\"text-xs text-lt-danger\">\n {t(\"form.file-upload.failed\", \"Failed\")}\n </span>\n )}\n </div>\n {(!item.existing || !scope) && (\n <button\n aria-label={t(\"form.file-upload.remove\", \"Remove {{name}}\", { name: item.name })}\n className=\"inline-flex size-7 shrink-0 items-center justify-center rounded-lt-sm text-lt-muted-fg transition-colors hover:bg-lt-accent hover:text-lt-accent-fg disabled:pointer-events-none disabled:opacity-50\"\n data-test={testIdentity(\n item.existing ? `${name}-remove-existing` : `${name}-remove`,\n )}\n disabled={locked}\n onClick={() => removeItem(item.id)}\n type=\"button\"\n >\n <Icon name=\"x\" aria-hidden=\"true\" className=\"size-lt-icon-sm\" />\n </button>\n )}\n {signed && !item.existing && item.key && item.status === \"ready\" && (\n <input\n data-test={testIdentity(`${name}-uploaded`)}\n name={fieldName}\n type=\"hidden\"\n value={item.key}\n />\n )}\n </li>\n ))}\n </ul>\n\n {!scope &&\n removedTokens.map((token) => (\n <input key={token} name={`${name}__removed[]`} type=\"hidden\" value={token} />\n ))}\n\n <input\n accept={props.accept ?? undefined}\n aria-label={props.label ?? name}\n className=\"sr-only\"\n data-test={testIdentity(`${name}-input`)}\n id={inputId}\n multiple={multiple}\n name={signed ? undefined : fieldName}\n onChange={(event) => {\n addFiles(event.target.files);\n if (signed) {\n event.target.value = \"\";\n }\n }}\n ref={fileInputRef}\n type=\"file\"\n />\n </div>\n </FormFieldFrame>\n );\n};\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import { DatePickerControlProps } from './date-picker-control';
2
+ export declare function LazyDatePickerControl(props: DatePickerControlProps): import("react").JSX.Element;
@@ -0,0 +1,17 @@
1
+ import { Suspense, lazy } from "react";
2
+ import { jsx } from "react/jsx-runtime";
3
+ //#region resources/js/form/components/fields/lazy-date-picker-control.tsx
4
+ var DatePickerControl = lazy(async () => {
5
+ const { DatePickerControl } = await import("./date-picker-control.js");
6
+ return { default: DatePickerControl };
7
+ });
8
+ function LazyDatePickerControl(props) {
9
+ return /* @__PURE__ */ jsx(Suspense, {
10
+ fallback: null,
11
+ children: /* @__PURE__ */ jsx(DatePickerControl, { ...props })
12
+ });
13
+ }
14
+ //#endregion
15
+ export { LazyDatePickerControl };
16
+
17
+ //# sourceMappingURL=lazy-date-picker-control.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lazy-date-picker-control.js","names":[],"sources":["../../../../resources/js/form/components/fields/lazy-date-picker-control.tsx"],"sourcesContent":["import { lazy, Suspense } from \"react\";\nimport type { DatePickerControlProps } from \"./date-picker-control\";\n\nconst DatePickerControl = lazy(async () => {\n const { DatePickerControl } = await import(\"./date-picker-control\");\n\n return { default: DatePickerControl };\n});\n\nexport function LazyDatePickerControl(props: DatePickerControlProps) {\n return (\n <Suspense fallback={null}>\n <DatePickerControl {...props} />\n </Suspense>\n );\n}\n"],"mappings":";;;AAGA,IAAM,oBAAoB,KAAK,YAAY;CACzC,MAAM,EAAE,sBAAsB,MAAM,OAAO;CAE3C,OAAO,EAAE,SAAS,kBAAkB;AACtC,CAAC;AAED,SAAgB,sBAAsB,OAA+B;CACnE,OACE,oBAAC,UAAD;EAAU,UAAU;YAClB,oBAAC,mBAAD,EAAmB,GAAI,MAAQ,CAAA;CACvB,CAAA;AAEd"}
@@ -1,6 +1,6 @@
1
- import { Input } from "../base/input.js";
2
1
  import { SimpleField } from "./simple-field.js";
3
2
  import { AffixGroup } from "../base/affix-group.js";
3
+ import { Input } from "../base/input.js";
4
4
  import { jsx, jsxs } from "react/jsx-runtime";
5
5
  //#region resources/js/form/components/fields/number-input.tsx
6
6
  var NumberInputComponent = ({ node }) => {
@@ -229,12 +229,12 @@ function EmojiPicker({ editor }) {
229
229
  return /* @__PURE__ */ jsxs("div", {
230
230
  className: "relative",
231
231
  children: [/* @__PURE__ */ jsx("button", {
232
- "aria-label": t("editor.insert-emoji", "Insert emoji"),
232
+ "aria-label": t("form.editor.insert-emoji", "Insert emoji"),
233
233
  "data-test": "editor-emoji",
234
234
  className: "inline-flex size-7 items-center justify-center rounded-lt-sm text-lt-muted-fg transition-colors hover:bg-lt-accent hover:text-lt-accent-fg [&_svg]:size-lt-icon-md",
235
235
  onClick: () => setOpen((value) => !value),
236
236
  onMouseDown: (event) => event.preventDefault(),
237
- title: t("editor.insert-emoji", "Insert emoji"),
237
+ title: t("form.editor.insert-emoji", "Insert emoji"),
238
238
  type: "button",
239
239
  children: /* @__PURE__ */ jsx(Icon, { name: "smile" })
240
240
  }), open && /* @__PURE__ */ jsx("div", {
@@ -259,7 +259,7 @@ function Toolbar({ editor }) {
259
259
  children: [
260
260
  toolbar.map((item, index) => {
261
261
  if (item === "separator") return /* @__PURE__ */ jsx("span", { className: "mx-1 h-5 w-px bg-lt-border" }, `sep-${index}`);
262
- const label = t(`editor.${item.key}`, item.label);
262
+ const label = t(`form.editor.${item.key}`, item.label);
263
263
  return /* @__PURE__ */ jsx("button", {
264
264
  "aria-label": label,
265
265
  "aria-pressed": item.isActive(editor),