@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.
- package/dist/action/components/action-form.js +1 -1
- package/dist/action/components/action-form.js.map +1 -1
- package/dist/chat/components/chat-box.js +1 -1
- package/dist/chat/components/chat-box.js.map +1 -1
- package/dist/chat/components/prompt-input.js +2 -2
- package/dist/chat/components/prompt-input.js.map +1 -1
- package/dist/core/components/combobox.js +1 -1
- package/dist/core/components/combobox.js.map +1 -1
- package/dist/core/components/fragment.js +4 -1
- package/dist/core/components/fragment.js.map +1 -1
- package/dist/core/components/icon.js +4 -1
- package/dist/core/components/icon.js.map +1 -1
- package/dist/core/components/info-tooltip.js +1 -1
- package/dist/core/components/info-tooltip.js.map +1 -1
- package/dist/core/components/spinner.js +1 -1
- package/dist/core/components/spinner.js.map +1 -1
- package/dist/core/components/tabs.js +1 -1
- package/dist/core/components/tabs.js.map +1 -1
- package/dist/core/components/text.js +4 -1
- package/dist/core/components/text.js.map +1 -1
- package/dist/form/components/fields/date-input.js +7 -6
- package/dist/form/components/fields/date-input.js.map +1 -1
- package/dist/form/components/fields/date-picker-control.d.ts +18 -0
- package/dist/form/components/fields/date-picker-control.js +199 -0
- package/dist/form/components/fields/date-picker-control.js.map +1 -0
- package/dist/form/components/fields/date-picker-value.d.ts +10 -0
- package/dist/form/components/fields/date-picker-value.js +125 -0
- package/dist/form/components/fields/date-picker-value.js.map +1 -0
- package/dist/form/components/fields/date-time-input.d.ts +2 -0
- package/dist/form/components/fields/date-time-input.js +34 -0
- package/dist/form/components/fields/date-time-input.js.map +1 -0
- package/dist/form/components/fields/file-upload.js +3 -3
- package/dist/form/components/fields/file-upload.js.map +1 -1
- package/dist/form/components/fields/lazy-date-picker-control.d.ts +2 -0
- package/dist/form/components/fields/lazy-date-picker-control.js +17 -0
- package/dist/form/components/fields/lazy-date-picker-control.js.map +1 -0
- package/dist/form/components/fields/number-input.js +1 -1
- package/dist/form/components/fields/rich-editor.js +3 -3
- package/dist/form/components/fields/rich-editor.js.map +1 -1
- package/dist/form/components/fields/row-action-menu.js +2 -2
- package/dist/form/components/fields/row-action-menu.js.map +1 -1
- package/dist/form/components/fields/select.js +1 -1
- package/dist/form/components/fields/select.js.map +1 -1
- package/dist/form/components/fields/table-rows.js +2 -2
- package/dist/form/components/fields/table-rows.js.map +1 -1
- package/dist/form/components/fields/text-input.js +1 -1
- package/dist/form/components/fields/time-input.d.ts +2 -0
- package/dist/form/components/fields/time-input.js +30 -0
- package/dist/form/components/fields/time-input.js.map +1 -0
- package/dist/form/components/fields/toggle.d.ts +2 -0
- package/dist/form/components/fields/toggle.js +65 -0
- package/dist/form/components/fields/toggle.js.map +1 -0
- package/dist/form/components/index.d.ts +3 -0
- package/dist/form/components/index.js +4 -1
- package/dist/form/components/types.d.ts +1 -1
- package/dist/form/components/use-controlled-field.d.ts +2 -0
- package/dist/form/components/use-controlled-field.js +6 -2
- package/dist/form/components/use-controlled-field.js.map +1 -1
- package/dist/form/index.js +4 -1
- package/dist/form/index.js.map +1 -1
- package/dist/lattice.css +6 -0
- package/dist/layout/callouts.js +1 -1
- package/dist/layout/callouts.js.map +1 -1
- package/dist/lib/utils.js +11 -1
- package/dist/lib/utils.js.map +1 -1
- package/dist/remote/components/data-list.js +3 -3
- package/dist/remote/components/data-list.js.map +1 -1
- package/dist/table/components/bulk-bar.js +2 -2
- package/dist/table/components/bulk-bar.js.map +1 -1
- package/dist/table/components/column-filter-control.js +5 -5
- package/dist/table/components/column-filter-control.js.map +1 -1
- package/dist/table/components/filter-bar.js +3 -3
- package/dist/table/components/filter-bar.js.map +1 -1
- package/dist/table/components/filter-controls.js +9 -9
- package/dist/table/components/filter-controls.js.map +1 -1
- package/dist/table/components/filter-stack-bar.js +1 -1
- package/dist/table/components/filter-stack-bar.js.map +1 -1
- package/dist/table/components/filter-value-input.js +5 -5
- package/dist/table/components/filter-value-input.js.map +1 -1
- package/dist/table/components/pagination.js +8 -8
- package/dist/table/components/pagination.js.map +1 -1
- package/dist/table/components/table.js +4 -4
- package/dist/table/components/table.js.map +1 -1
- package/dist/table/query.js +1 -1
- package/dist/table/query.js.map +1 -1
- package/dist/toast/toaster.js +1 -1
- package/dist/toast/toaster.js.map +1 -1
- package/dist/types/generated.d.ts +97 -2
- package/package.json +8 -2
- package/resources/icons/calendar.svg +18 -0
- 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,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":"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"}
|
|
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,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),
|