@dxos/react-ui-form 0.7.5-main.9d2a38b → 0.7.5-main.e94eead
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/lib/browser/index.mjs +1014 -571
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node/index.cjs +1031 -599
- package/dist/lib/node/index.cjs.map +4 -4
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node-esm/index.mjs +1014 -571
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/types/src/components/FieldEditor/FieldEditor.d.ts +1 -2
- package/dist/types/src/components/FieldEditor/FieldEditor.d.ts.map +1 -1
- package/dist/types/src/components/Form/ArrayField.d.ts +15 -0
- package/dist/types/src/components/Form/ArrayField.d.ts.map +1 -0
- package/dist/types/src/components/Form/Defaults.d.ts +6 -7
- package/dist/types/src/components/Form/Defaults.d.ts.map +1 -1
- package/dist/types/src/components/Form/Form.d.ts +12 -21
- package/dist/types/src/components/Form/Form.d.ts.map +1 -1
- package/dist/types/src/components/Form/Form.stories.d.ts +2 -1
- package/dist/types/src/components/Form/Form.stories.d.ts.map +1 -1
- package/dist/types/src/components/Form/FormActions.d.ts +6 -0
- package/dist/types/src/components/Form/FormActions.d.ts.map +1 -0
- package/dist/types/src/components/Form/FormContent.d.ts +25 -0
- package/dist/types/src/components/Form/FormContent.d.ts.map +1 -0
- package/dist/types/src/components/Form/FormContext.d.ts +23 -0
- package/dist/types/src/components/Form/FormContext.d.ts.map +1 -0
- package/dist/types/src/components/Form/Input.d.ts +7 -8
- package/dist/types/src/components/Form/Input.d.ts.map +1 -1
- package/dist/types/src/components/Form/custom/GeoPointInput.d.ts +1 -3
- package/dist/types/src/components/Form/custom/GeoPointInput.d.ts.map +1 -1
- package/dist/types/src/components/Form/custom/SelectOptionsInput.d.ts +3 -0
- package/dist/types/src/components/Form/custom/SelectOptionsInput.d.ts.map +1 -0
- package/dist/types/src/components/Form/custom/SelectOptionsInput.stories.d.ts +7 -0
- package/dist/types/src/components/Form/custom/SelectOptionsInput.stories.d.ts.map +1 -0
- package/dist/types/src/components/Form/custom/TupleInput.d.ts +2 -4
- package/dist/types/src/components/Form/custom/TupleInput.d.ts.map +1 -1
- package/dist/types/src/components/Form/custom/index.d.ts +1 -0
- package/dist/types/src/components/Form/custom/index.d.ts.map +1 -1
- package/dist/types/src/components/Form/factory.d.ts +2 -2
- package/dist/types/src/components/Form/factory.d.ts.map +1 -1
- package/dist/types/src/components/Form/index.d.ts +2 -0
- package/dist/types/src/components/Form/index.d.ts.map +1 -1
- package/dist/types/src/components/ViewEditor/Test.stories.d.ts +1 -2
- package/dist/types/src/components/ViewEditor/Test.stories.d.ts.map +1 -1
- package/dist/types/src/components/ViewEditor/ViewEditor.d.ts +1 -2
- package/dist/types/src/components/ViewEditor/ViewEditor.d.ts.map +1 -1
- package/dist/types/src/components/deprecated/Form.d.ts +1 -2
- package/dist/types/src/components/deprecated/Form.d.ts.map +1 -1
- package/dist/types/src/components/deprecated/Form.stories.d.ts +1 -2
- package/dist/types/src/components/deprecated/Form.stories.d.ts.map +1 -1
- package/dist/types/src/components/deprecated/FormInput.d.ts +6 -1
- package/dist/types/src/components/deprecated/FormInput.d.ts.map +1 -1
- package/dist/types/src/components/testing.d.ts +3 -3
- package/dist/types/src/components/testing.d.ts.map +1 -1
- package/dist/types/src/hooks/useForm.d.ts +11 -11
- package/dist/types/src/hooks/useForm.d.ts.map +1 -1
- package/dist/types/src/translations.d.ts +6 -0
- package/dist/types/src/translations.d.ts.map +1 -1
- package/dist/types/src/util/field.d.ts.map +1 -1
- package/dist/types/src/util/formatting.d.ts.map +1 -1
- package/package.json +29 -27
- package/src/components/FieldEditor/FieldEditor.stories.tsx +1 -1
- package/src/components/FieldEditor/FieldEditor.tsx +7 -6
- package/src/components/Form/ArrayField.tsx +111 -0
- package/src/components/Form/Defaults.tsx +78 -34
- package/src/components/Form/Form.stories.tsx +15 -5
- package/src/components/Form/Form.tsx +50 -355
- package/src/components/Form/FormActions.tsx +41 -0
- package/src/components/Form/FormContent.tsx +170 -0
- package/src/components/Form/FormContext.tsx +96 -0
- package/src/components/Form/Input.tsx +5 -6
- package/src/components/Form/custom/GeoPointInput.tsx +44 -23
- package/src/components/Form/custom/SelectOptionsInput.stories.tsx +58 -0
- package/src/components/Form/custom/SelectOptionsInput.tsx +190 -0
- package/src/components/Form/custom/TupleInput.tsx +5 -9
- package/src/components/Form/custom/index.ts +1 -0
- package/src/components/Form/factory.tsx +6 -7
- package/src/components/Form/index.ts +3 -0
- package/src/components/ViewEditor/ViewEditor.tsx +7 -4
- package/src/components/deprecated/FormInput.tsx +20 -7
- package/src/hooks/useForm.ts +116 -79
- package/src/translations.ts +9 -1
- package/src/util/field.ts +19 -1
- package/src/util/formatting.ts +29 -1
|
@@ -29,12 +29,13 @@ var translations_default = [
|
|
|
29
29
|
"format hostname": "Hostname",
|
|
30
30
|
"format integer": "Integer",
|
|
31
31
|
"format json": "JSON",
|
|
32
|
-
"format latlng": "
|
|
32
|
+
"format latlng": "Geopoint",
|
|
33
33
|
"format markdown": "Markdown",
|
|
34
34
|
"format percent": "Percent",
|
|
35
35
|
"format ref": "Reference",
|
|
36
36
|
"format regex": "RegExp",
|
|
37
37
|
"format string": "String",
|
|
38
|
+
"format single-select": "Select",
|
|
38
39
|
"format text": "Long text",
|
|
39
40
|
"format time": "Time",
|
|
40
41
|
"format timestamp": "Timestamp",
|
|
@@ -44,7 +45,13 @@ var translations_default = [
|
|
|
44
45
|
"format uuid": "UUID",
|
|
45
46
|
// Placeholders
|
|
46
47
|
"placeholder latitude": "Latitude",
|
|
47
|
-
"placeholder longitude": "Longitude"
|
|
48
|
+
"placeholder longitude": "Longitude",
|
|
49
|
+
// SelectOptionsInput
|
|
50
|
+
"select option label": "Label",
|
|
51
|
+
"select option label placeholder": "Option label",
|
|
52
|
+
"select option color": "Color",
|
|
53
|
+
"select option delete": "Delete",
|
|
54
|
+
"select option add": "Add option"
|
|
48
55
|
}
|
|
49
56
|
}
|
|
50
57
|
}
|
|
@@ -53,6 +60,16 @@ var translations_default = [
|
|
|
53
60
|
// packages/ui/react-ui-form/src/components/deprecated/FormInput.tsx
|
|
54
61
|
import React from "react";
|
|
55
62
|
import { Input } from "@dxos/react-ui";
|
|
63
|
+
import { mx, textBlockWidth } from "@dxos/react-ui-theme";
|
|
64
|
+
var DeprecatedFormContainer = ({ children, classNames }) => {
|
|
65
|
+
return /* @__PURE__ */ React.createElement("div", {
|
|
66
|
+
role: "none",
|
|
67
|
+
className: "w-full p-4 justify-center overflow-x-hidden overflow-y-auto"
|
|
68
|
+
}, /* @__PURE__ */ React.createElement("div", {
|
|
69
|
+
role: "form",
|
|
70
|
+
className: mx("flex flex-col", textBlockWidth, classNames)
|
|
71
|
+
}, children));
|
|
72
|
+
};
|
|
56
73
|
var DeprecatedFormInput = ({ label, description, secondary, children }) => {
|
|
57
74
|
const primary = /* @__PURE__ */ React.createElement("div", {
|
|
58
75
|
role: "none",
|
|
@@ -61,224 +78,57 @@ var DeprecatedFormInput = ({ label, description, secondary, children }) => {
|
|
|
61
78
|
role: "none",
|
|
62
79
|
className: "flex flex-col w-full"
|
|
63
80
|
}, /* @__PURE__ */ React.createElement(Input.Label, {
|
|
64
|
-
classNames: "flex min-
|
|
81
|
+
classNames: "flex min-bs-[--rail-action] items-center",
|
|
82
|
+
style: {
|
|
83
|
+
fontSize: "unset"
|
|
84
|
+
}
|
|
65
85
|
}, label), description && /* @__PURE__ */ React.createElement(Input.DescriptionAndValidation, {
|
|
66
86
|
classNames: "mbs-0.5"
|
|
67
87
|
}, /* @__PURE__ */ React.createElement(Input.Description, null, description))), /* @__PURE__ */ React.createElement("div", {
|
|
68
88
|
role: "none"
|
|
69
89
|
}, /* @__PURE__ */ React.createElement("div", {
|
|
70
90
|
role: "none",
|
|
71
|
-
className: "flex min-
|
|
91
|
+
className: "flex min-bs-[--rail-action] items-center"
|
|
72
92
|
}, children))));
|
|
73
93
|
if (secondary) {
|
|
74
94
|
return /* @__PURE__ */ React.createElement("div", {
|
|
75
|
-
role: "none"
|
|
76
|
-
className: "flex flex-col w-full"
|
|
95
|
+
role: "none"
|
|
77
96
|
}, primary, secondary);
|
|
78
97
|
}
|
|
79
98
|
return primary;
|
|
80
99
|
};
|
|
81
100
|
|
|
82
101
|
// packages/ui/react-ui-form/src/components/FieldEditor/FieldEditor.tsx
|
|
83
|
-
import
|
|
102
|
+
import React12, { useCallback as useCallback6, useEffect as useEffect7, useMemo as useMemo7, useState as useState4 } from "react";
|
|
84
103
|
import { FormatEnum as FormatEnum2, FormatEnums, formatToType } from "@dxos/echo-schema";
|
|
85
|
-
import { log as log3 } from "@dxos/log";
|
|
86
|
-
import { useTranslation as useTranslation3 } from "@dxos/react-ui";
|
|
87
|
-
import { getFormatSchema, getSchemaProperties as getSchemaProperties2, sortProperties } from "@dxos/schema";
|
|
88
|
-
|
|
89
|
-
// packages/ui/react-ui-form/src/components/Form/custom/GeoPointInput.tsx
|
|
90
|
-
import React3 from "react";
|
|
91
|
-
import { Input as Input2, useTranslation } from "@dxos/react-ui";
|
|
92
|
-
import { safeParseFloat } from "@dxos/util";
|
|
93
|
-
|
|
94
|
-
// packages/ui/react-ui-form/src/components/Form/Input.tsx
|
|
95
|
-
import React2 from "react";
|
|
96
|
-
import { Icon, Tooltip } from "@dxos/react-ui";
|
|
97
|
-
import { errorText } from "@dxos/react-ui-theme";
|
|
98
|
-
var InputHeader = ({ children, error }) => {
|
|
99
|
-
return /* @__PURE__ */ React2.createElement("div", {
|
|
100
|
-
role: "none",
|
|
101
|
-
className: "flex justify-between items-center mb-1"
|
|
102
|
-
}, children, error && /* @__PURE__ */ React2.createElement(Tooltip.Root, null, /* @__PURE__ */ React2.createElement(Tooltip.Trigger, {
|
|
103
|
-
asChild: true
|
|
104
|
-
}, /* @__PURE__ */ React2.createElement(Icon, {
|
|
105
|
-
icon: "ph--warning--regular",
|
|
106
|
-
size: 4,
|
|
107
|
-
classNames: errorText
|
|
108
|
-
})), /* @__PURE__ */ React2.createElement(Tooltip.Content, {
|
|
109
|
-
side: "bottom"
|
|
110
|
-
}, /* @__PURE__ */ React2.createElement(Tooltip.Arrow, null), error)));
|
|
111
|
-
};
|
|
112
|
-
|
|
113
|
-
// packages/ui/react-ui-form/src/components/Form/custom/GeoPointInput.tsx
|
|
114
|
-
var GeoPointInput = ({ property, type, label, disabled, getStatus, getValue: getValue2, onValueChange, onBlur }) => {
|
|
115
|
-
const { t } = useTranslation(translationKey);
|
|
116
|
-
const { status, error } = getStatus?.(property);
|
|
117
|
-
const [lng = 0, lat = 0] = getValue2(property) ?? [];
|
|
118
|
-
return /* @__PURE__ */ React3.createElement(Input2.Root, {
|
|
119
|
-
validationValence: status
|
|
120
|
-
}, /* @__PURE__ */ React3.createElement(InputHeader, {
|
|
121
|
-
error
|
|
122
|
-
}, /* @__PURE__ */ React3.createElement(Input2.Label, null, label)), /* @__PURE__ */ React3.createElement("div", {
|
|
123
|
-
className: "grid grid-cols-2 gap-2"
|
|
124
|
-
}, /* @__PURE__ */ React3.createElement(Input2.TextInput, {
|
|
125
|
-
type: "number",
|
|
126
|
-
disabled,
|
|
127
|
-
placeholder: t("placeholder longitude"),
|
|
128
|
-
value: lng,
|
|
129
|
-
onChange: (event) => onValueChange(property, type, [
|
|
130
|
-
lat,
|
|
131
|
-
safeParseFloat(event.target.value, 0)
|
|
132
|
-
]),
|
|
133
|
-
onBlur
|
|
134
|
-
}), /* @__PURE__ */ React3.createElement(Input2.TextInput, {
|
|
135
|
-
type: "number",
|
|
136
|
-
disabled,
|
|
137
|
-
placeholder: t("placeholder latitude"),
|
|
138
|
-
value: lat,
|
|
139
|
-
onChange: (event) => onValueChange(property, type, [
|
|
140
|
-
safeParseFloat(event.target.value, 0),
|
|
141
|
-
lng
|
|
142
|
-
]),
|
|
143
|
-
onBlur
|
|
144
|
-
})));
|
|
145
|
-
};
|
|
146
|
-
|
|
147
|
-
// packages/ui/react-ui-form/src/components/Form/custom/TupleInput.tsx
|
|
148
|
-
import React4 from "react";
|
|
149
|
-
import { Input as Input3 } from "@dxos/react-ui";
|
|
150
|
-
import { mx } from "@dxos/react-ui-theme";
|
|
151
|
-
import { safeParseFloat as safeParseFloat2 } from "@dxos/util";
|
|
152
|
-
var gridCols = [
|
|
153
|
-
"grid-cols-1",
|
|
154
|
-
"grid-cols-2",
|
|
155
|
-
"grid-cols-3",
|
|
156
|
-
"grid-cols-4"
|
|
157
|
-
];
|
|
158
|
-
var TupleInput = ({ binding, property, type, label, disabled, getStatus, getValue: getValue2, onValueChange, onBlur }) => {
|
|
159
|
-
const { status, error } = getStatus?.(property);
|
|
160
|
-
const values = getValue2(property) ?? {};
|
|
161
|
-
return /* @__PURE__ */ React4.createElement(Input3.Root, {
|
|
162
|
-
validationValence: status
|
|
163
|
-
}, /* @__PURE__ */ React4.createElement(InputHeader, {
|
|
164
|
-
error
|
|
165
|
-
}, /* @__PURE__ */ React4.createElement(Input3.Label, null, label)), /* @__PURE__ */ React4.createElement("div", {
|
|
166
|
-
className: mx("grid gap-2", gridCols[binding.length - 1])
|
|
167
|
-
}, binding.map((prop) => /* @__PURE__ */ React4.createElement(Input3.TextInput, {
|
|
168
|
-
key: prop,
|
|
169
|
-
type: "number",
|
|
170
|
-
disabled,
|
|
171
|
-
value: values[prop],
|
|
172
|
-
onChange: (event) => onValueChange(property, type, {
|
|
173
|
-
...values,
|
|
174
|
-
[prop]: safeParseFloat2(event.target.value, 0)
|
|
175
|
-
}),
|
|
176
|
-
onBlur
|
|
177
|
-
}))));
|
|
178
|
-
};
|
|
179
|
-
|
|
180
|
-
// packages/ui/react-ui-form/src/components/Form/Defaults.tsx
|
|
181
|
-
import React5 from "react";
|
|
182
|
-
import { Input as Input4, Select } from "@dxos/react-ui";
|
|
183
|
-
var TextInput = ({ property, type, label, inputOnly, disabled, placeholder, getStatus, getValue: getValue2, onValueChange, onBlur }) => {
|
|
184
|
-
const { status, error } = getStatus?.(property);
|
|
185
|
-
return /* @__PURE__ */ React5.createElement(Input4.Root, {
|
|
186
|
-
validationValence: status
|
|
187
|
-
}, !inputOnly && /* @__PURE__ */ React5.createElement(InputHeader, {
|
|
188
|
-
error
|
|
189
|
-
}, /* @__PURE__ */ React5.createElement(Input4.Label, null, label)), /* @__PURE__ */ React5.createElement(Input4.TextInput, {
|
|
190
|
-
disabled,
|
|
191
|
-
placeholder,
|
|
192
|
-
value: getValue2(property) ?? "",
|
|
193
|
-
onChange: (event) => onValueChange(property, type, event.target.value),
|
|
194
|
-
onBlur
|
|
195
|
-
}), inputOnly && /* @__PURE__ */ React5.createElement(Input4.Validation, null, error));
|
|
196
|
-
};
|
|
197
|
-
var NumberInput = ({ property, type, label, inputOnly, disabled, placeholder, getStatus, getValue: getValue2, onValueChange, onBlur }) => {
|
|
198
|
-
const { status, error } = getStatus?.(property);
|
|
199
|
-
return /* @__PURE__ */ React5.createElement(Input4.Root, {
|
|
200
|
-
validationValence: status
|
|
201
|
-
}, !inputOnly && /* @__PURE__ */ React5.createElement(InputHeader, {
|
|
202
|
-
error
|
|
203
|
-
}, /* @__PURE__ */ React5.createElement(Input4.Label, null, label)), /* @__PURE__ */ React5.createElement(Input4.TextInput, {
|
|
204
|
-
type: "number",
|
|
205
|
-
disabled,
|
|
206
|
-
placeholder,
|
|
207
|
-
value: getValue2(property) ?? 0,
|
|
208
|
-
onChange: (event) => onValueChange(property, type, event.target.value),
|
|
209
|
-
onBlur
|
|
210
|
-
}), inputOnly && /* @__PURE__ */ React5.createElement(Input4.DescriptionAndValidation, null, error));
|
|
211
|
-
};
|
|
212
|
-
var BooleanInput = ({ property, type, label, inputOnly, getStatus, getValue: getValue2, onValueChange }) => {
|
|
213
|
-
const { status, error } = getStatus?.(property);
|
|
214
|
-
return /* @__PURE__ */ React5.createElement(Input4.Root, {
|
|
215
|
-
validationValence: status
|
|
216
|
-
}, !inputOnly && /* @__PURE__ */ React5.createElement(InputHeader, {
|
|
217
|
-
error
|
|
218
|
-
}, /* @__PURE__ */ React5.createElement(Input4.Label, null, label)), /* @__PURE__ */ React5.createElement(Input4.Switch, {
|
|
219
|
-
checked: getValue2(property),
|
|
220
|
-
onCheckedChange: (value) => onValueChange(property, type, value)
|
|
221
|
-
}), inputOnly && /* @__PURE__ */ React5.createElement(Input4.DescriptionAndValidation, null, error));
|
|
222
|
-
};
|
|
223
|
-
var SelectInput = ({ property, type, label, inputOnly, disabled, placeholder, options, getStatus, getValue: getValue2, onValueChange }) => {
|
|
224
|
-
const { status, error } = getStatus?.(property);
|
|
225
|
-
return /* @__PURE__ */ React5.createElement(Input4.Root, {
|
|
226
|
-
validationValence: status
|
|
227
|
-
}, !inputOnly && /* @__PURE__ */ React5.createElement(InputHeader, {
|
|
228
|
-
error
|
|
229
|
-
}, /* @__PURE__ */ React5.createElement(Input4.Label, null, label)), /* @__PURE__ */ React5.createElement(Select.Root, {
|
|
230
|
-
value: getValue2(property),
|
|
231
|
-
onValueChange: (value) => onValueChange(property, type, value)
|
|
232
|
-
}, /* @__PURE__ */ React5.createElement(Select.TriggerButton, {
|
|
233
|
-
classNames: "is-full",
|
|
234
|
-
disabled,
|
|
235
|
-
placeholder
|
|
236
|
-
}), /* @__PURE__ */ React5.createElement(Select.Portal, null, /* @__PURE__ */ React5.createElement(Select.Content, null, /* @__PURE__ */ React5.createElement(Select.Viewport, null, options?.map(({ value, label: label2 }) => (
|
|
237
|
-
// NOTE: Numeric values are converted to and from strings.
|
|
238
|
-
/* @__PURE__ */ React5.createElement(Select.Option, {
|
|
239
|
-
key: String(value),
|
|
240
|
-
value: String(value)
|
|
241
|
-
}, label2 ?? String(value))
|
|
242
|
-
)))))), inputOnly && /* @__PURE__ */ React5.createElement(Input4.DescriptionAndValidation, null, error));
|
|
243
|
-
};
|
|
244
|
-
|
|
245
|
-
// packages/ui/react-ui-form/src/components/Form/Form.tsx
|
|
246
|
-
import { pipe } from "effect";
|
|
247
|
-
import { capitalize } from "effect/String";
|
|
248
|
-
import React6, { useEffect as useEffect2, useMemo as useMemo2 } from "react";
|
|
249
|
-
import { AST, S } from "@dxos/echo-schema";
|
|
250
|
-
import { findNode, getDiscriminatedType, isDiscriminatedUnion, SimpleType } from "@dxos/effect";
|
|
251
104
|
import { log as log2 } from "@dxos/log";
|
|
252
|
-
import {
|
|
253
|
-
import {
|
|
254
|
-
import { getSchemaProperties } from "@dxos/schema";
|
|
255
|
-
import { isNotFalsy } from "@dxos/util";
|
|
105
|
+
import { useTranslation as useTranslation5 } from "@dxos/react-ui";
|
|
106
|
+
import { getFormatSchema, getSchemaProperties as getSchemaProperties3, sortProperties } from "@dxos/schema";
|
|
256
107
|
|
|
257
|
-
// packages/ui/react-ui-form/src/components/Form/
|
|
258
|
-
import {
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
return GeoPointInput;
|
|
263
|
-
}
|
|
264
|
-
switch (type) {
|
|
265
|
-
case "string":
|
|
266
|
-
return TextInput;
|
|
267
|
-
case "number":
|
|
268
|
-
return NumberInput;
|
|
269
|
-
case "boolean":
|
|
270
|
-
return BooleanInput;
|
|
271
|
-
}
|
|
272
|
-
};
|
|
108
|
+
// packages/ui/react-ui-form/src/components/Form/FormContext.tsx
|
|
109
|
+
import React2, { createContext, useContext, useEffect as useEffect2, useMemo as useMemo2 } from "react";
|
|
110
|
+
import { raise } from "@dxos/debug";
|
|
111
|
+
import { getValue as getValue2 } from "@dxos/echo-schema";
|
|
112
|
+
import { createJsonPath as createJsonPath2 } from "@dxos/effect";
|
|
273
113
|
|
|
274
114
|
// packages/ui/react-ui-form/src/hooks/useForm.ts
|
|
275
115
|
import { useCallback, useEffect, useMemo, useState } from "react";
|
|
276
116
|
import { getValue, setValue } from "@dxos/echo-schema";
|
|
117
|
+
import { AST, createJsonPath, fromEffectValidationPath } from "@dxos/effect";
|
|
277
118
|
import { invariant } from "@dxos/invariant";
|
|
278
119
|
import { log } from "@dxos/log";
|
|
279
120
|
import { validateSchema } from "@dxos/schema";
|
|
280
121
|
var __dxlog_file = "/home/runner/work/dxos/dxos/packages/ui/react-ui-form/src/hooks/useForm.ts";
|
|
281
122
|
var useForm = ({ schema, initialValues, onValuesChanged, onValidate, onValid, onSave }) => {
|
|
123
|
+
invariant(AST.isTypeLiteral(schema.ast), void 0, {
|
|
124
|
+
F: __dxlog_file,
|
|
125
|
+
L: 92,
|
|
126
|
+
S: void 0,
|
|
127
|
+
A: [
|
|
128
|
+
"AST.isTypeLiteral(schema.ast)",
|
|
129
|
+
""
|
|
130
|
+
]
|
|
131
|
+
});
|
|
282
132
|
const [values, setValues] = useState(initialValues);
|
|
283
133
|
useEffect(() => {
|
|
284
134
|
setValues(initialValues);
|
|
@@ -315,8 +165,13 @@ var useForm = ({ schema, initialValues, onValuesChanged, onValidate, onValid, on
|
|
|
315
165
|
values,
|
|
316
166
|
schemaDirty
|
|
317
167
|
]);
|
|
318
|
-
const
|
|
319
|
-
|
|
168
|
+
const formIsValid = useMemo(() => {
|
|
169
|
+
return Object.keys(errors).length === 0;
|
|
170
|
+
}, [
|
|
171
|
+
errors
|
|
172
|
+
]);
|
|
173
|
+
const canSave = useMemo(() => !saving && // Check if any error paths that are touched have errors.
|
|
174
|
+
!Object.entries(touched).some(([path, isTouched]) => isTouched && Object.keys(errors).some((errorPath) => errorPath === path || errorPath.startsWith(`${path}.`) || errorPath.startsWith(`${path}[`))), [
|
|
320
175
|
touched,
|
|
321
176
|
errors,
|
|
322
177
|
saving
|
|
@@ -338,17 +193,23 @@ var useForm = ({ schema, initialValues, onValuesChanged, onValidate, onValid, on
|
|
|
338
193
|
onSave,
|
|
339
194
|
changed
|
|
340
195
|
]);
|
|
341
|
-
const getStatus = useCallback((
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
196
|
+
const getStatus = useCallback((path) => {
|
|
197
|
+
const jsonPath = Array.isArray(path) ? createJsonPath(path) : path;
|
|
198
|
+
const matchingError = Object.entries(errors).find(([errorPath]) => errorPath === jsonPath || errorPath.startsWith(`${jsonPath}.`) || errorPath.startsWith(`${jsonPath}[`));
|
|
199
|
+
return {
|
|
200
|
+
status: matchingError ? "error" : void 0,
|
|
201
|
+
error: matchingError ? matchingError[1] : void 0
|
|
202
|
+
};
|
|
203
|
+
}, [
|
|
346
204
|
errors
|
|
347
205
|
]);
|
|
348
|
-
const getFormValue = (
|
|
349
|
-
return getValue(values,
|
|
350
|
-
}
|
|
351
|
-
|
|
206
|
+
const getFormValue = useCallback((path) => {
|
|
207
|
+
return getValue(values, createJsonPath(path));
|
|
208
|
+
}, [
|
|
209
|
+
values
|
|
210
|
+
]);
|
|
211
|
+
const onValueChange = useCallback((path, type, value) => {
|
|
212
|
+
const jsonPath = createJsonPath(path);
|
|
352
213
|
let parsedValue = value;
|
|
353
214
|
try {
|
|
354
215
|
if (type === "number") {
|
|
@@ -357,19 +218,19 @@ var useForm = ({ schema, initialValues, onValuesChanged, onValidate, onValid, on
|
|
|
357
218
|
} catch (err) {
|
|
358
219
|
log.catch(err, void 0, {
|
|
359
220
|
F: __dxlog_file,
|
|
360
|
-
L:
|
|
221
|
+
L: 202,
|
|
361
222
|
S: void 0,
|
|
362
223
|
C: (f, a) => f(...a)
|
|
363
224
|
});
|
|
364
225
|
parsedValue = void 0;
|
|
365
226
|
}
|
|
366
227
|
const newValues = {
|
|
367
|
-
...setValue(values,
|
|
228
|
+
...setValue(values, jsonPath, parsedValue)
|
|
368
229
|
};
|
|
369
230
|
setValues(newValues);
|
|
370
231
|
setChanged((prev) => ({
|
|
371
232
|
...prev,
|
|
372
|
-
[
|
|
233
|
+
[jsonPath]: true
|
|
373
234
|
}));
|
|
374
235
|
onValuesChanged?.(newValues);
|
|
375
236
|
const isValid = validate(newValues);
|
|
@@ -378,40 +239,57 @@ var useForm = ({ schema, initialValues, onValuesChanged, onValidate, onValid, on
|
|
|
378
239
|
changed
|
|
379
240
|
});
|
|
380
241
|
}
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
|
|
242
|
+
}, [
|
|
243
|
+
values,
|
|
244
|
+
onValuesChanged,
|
|
245
|
+
validate,
|
|
246
|
+
onValid,
|
|
247
|
+
changed
|
|
248
|
+
]);
|
|
249
|
+
const onTouched = useCallback((path) => {
|
|
250
|
+
const jsonPath = createJsonPath(path);
|
|
384
251
|
setTouched((touched2) => ({
|
|
385
252
|
...touched2,
|
|
386
|
-
[
|
|
253
|
+
[jsonPath]: true
|
|
387
254
|
}));
|
|
388
|
-
if (event.relatedTarget?.getAttribute("type") === "submit") {
|
|
389
|
-
setTouched(createKeySet(values, true));
|
|
390
|
-
}
|
|
391
255
|
validate(values);
|
|
392
256
|
}, [
|
|
393
257
|
validate,
|
|
394
258
|
values
|
|
395
259
|
]);
|
|
396
|
-
return {
|
|
260
|
+
return useMemo(() => ({
|
|
397
261
|
// State.
|
|
398
262
|
values,
|
|
399
263
|
errors,
|
|
400
264
|
touched,
|
|
401
265
|
changed,
|
|
402
266
|
canSave,
|
|
267
|
+
formIsValid,
|
|
268
|
+
// Actions.
|
|
403
269
|
handleSave,
|
|
404
270
|
// Field utils.
|
|
405
271
|
getStatus,
|
|
406
272
|
getValue: getFormValue,
|
|
407
273
|
onValueChange,
|
|
408
|
-
|
|
409
|
-
}
|
|
274
|
+
onTouched
|
|
275
|
+
}), [
|
|
276
|
+
values,
|
|
277
|
+
errors,
|
|
278
|
+
touched,
|
|
279
|
+
changed,
|
|
280
|
+
canSave,
|
|
281
|
+
formIsValid,
|
|
282
|
+
handleSave,
|
|
283
|
+
getStatus,
|
|
284
|
+
getFormValue,
|
|
285
|
+
onValueChange,
|
|
286
|
+
onTouched
|
|
287
|
+
]);
|
|
410
288
|
};
|
|
411
289
|
var createKeySet = (obj, value) => {
|
|
412
290
|
invariant(obj, void 0, {
|
|
413
291
|
F: __dxlog_file,
|
|
414
|
-
L:
|
|
292
|
+
L: 264,
|
|
415
293
|
S: void 0,
|
|
416
294
|
A: [
|
|
417
295
|
"obj",
|
|
@@ -423,340 +301,858 @@ var createKeySet = (obj, value) => {
|
|
|
423
301
|
[key]: value
|
|
424
302
|
}), {});
|
|
425
303
|
};
|
|
426
|
-
var flatMap = (errors) => {
|
|
427
|
-
return errors.reduce((result, { path, message }) => {
|
|
428
|
-
|
|
429
|
-
|
|
304
|
+
var flatMap = (errors) => {
|
|
305
|
+
return errors.reduce((result, { path, message }) => {
|
|
306
|
+
const jsonPath = fromEffectValidationPath(path);
|
|
307
|
+
if (!(jsonPath in result)) {
|
|
308
|
+
result[jsonPath] = message;
|
|
309
|
+
}
|
|
310
|
+
return result;
|
|
311
|
+
}, {});
|
|
312
|
+
};
|
|
313
|
+
|
|
314
|
+
// packages/ui/react-ui-form/src/components/Form/FormContext.tsx
|
|
315
|
+
var FormContext = /* @__PURE__ */ createContext(void 0);
|
|
316
|
+
var useFormContext = () => {
|
|
317
|
+
return useContext(FormContext) ?? raise(new Error("Missing FormContext"));
|
|
318
|
+
};
|
|
319
|
+
var useFormValues = (path = []) => {
|
|
320
|
+
const { values: formValues } = useFormContext();
|
|
321
|
+
const jsonPath = createJsonPath2(path);
|
|
322
|
+
return getValue2(formValues, jsonPath);
|
|
323
|
+
};
|
|
324
|
+
var useInputProps = (path = []) => {
|
|
325
|
+
const { getStatus, getValue: getFormValue, onValueChange, onTouched } = useFormContext();
|
|
326
|
+
const stablePath = useMemo2(() => path, [
|
|
327
|
+
Array.isArray(path) ? path.join(".") : path
|
|
328
|
+
]);
|
|
329
|
+
return useMemo2(() => ({
|
|
330
|
+
getStatus: () => getStatus(stablePath),
|
|
331
|
+
getValue: () => getFormValue(stablePath),
|
|
332
|
+
onValueChange: (type, value) => onValueChange(stablePath, type, value),
|
|
333
|
+
onBlur: () => onTouched(stablePath)
|
|
334
|
+
}), [
|
|
335
|
+
getStatus,
|
|
336
|
+
getFormValue,
|
|
337
|
+
onValueChange,
|
|
338
|
+
onTouched,
|
|
339
|
+
stablePath
|
|
340
|
+
]);
|
|
341
|
+
};
|
|
342
|
+
var FormProvider = ({ children, formRef, autoSave, ...formOptions }) => {
|
|
343
|
+
const form = useForm(formOptions);
|
|
344
|
+
useEffect2(() => {
|
|
345
|
+
if (!formRef?.current) {
|
|
346
|
+
return;
|
|
347
|
+
}
|
|
348
|
+
const handleKeyDown = (event) => {
|
|
349
|
+
const keyIsEnter = event.key === "Enter";
|
|
350
|
+
const modifierUsed = event.ctrlKey || event.altKey || event.metaKey || event.shiftKey;
|
|
351
|
+
const inputIsTextarea = event.target.tagName.toLowerCase() === "textarea";
|
|
352
|
+
const inputOptOut = event.target.hasAttribute("data-no-submit");
|
|
353
|
+
const shouldSubmitRegularInput = !inputIsTextarea && keyIsEnter && !modifierUsed;
|
|
354
|
+
const shouldSubmitTextarea = inputIsTextarea && keyIsEnter && event.metaKey;
|
|
355
|
+
if ((shouldSubmitRegularInput || shouldSubmitTextarea) && !inputOptOut) {
|
|
356
|
+
if (!autoSave && form.canSave) {
|
|
357
|
+
form.handleSave();
|
|
358
|
+
}
|
|
359
|
+
if (autoSave && form.formIsValid) {
|
|
360
|
+
event.target.blur();
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
};
|
|
364
|
+
const formElement = formRef.current;
|
|
365
|
+
formElement.addEventListener("keydown", handleKeyDown);
|
|
366
|
+
return () => formElement.removeEventListener("keydown", handleKeyDown);
|
|
367
|
+
}, [
|
|
368
|
+
formRef,
|
|
369
|
+
form.canSave,
|
|
370
|
+
form.formIsValid,
|
|
371
|
+
form.handleSave,
|
|
372
|
+
autoSave
|
|
373
|
+
]);
|
|
374
|
+
return /* @__PURE__ */ React2.createElement(FormContext.Provider, {
|
|
375
|
+
value: form
|
|
376
|
+
}, children);
|
|
377
|
+
};
|
|
378
|
+
|
|
379
|
+
// packages/ui/react-ui-form/src/components/Form/custom/GeoPointInput.tsx
|
|
380
|
+
import React4, { useCallback as useCallback2, useState as useState2, useEffect as useEffect3, useMemo as useMemo3 } from "react";
|
|
381
|
+
import { GeoLocation } from "@dxos/echo-schema";
|
|
382
|
+
import { Input as Input2, useTranslation } from "@dxos/react-ui";
|
|
383
|
+
import { safeParseFloat } from "@dxos/util";
|
|
384
|
+
|
|
385
|
+
// packages/ui/react-ui-form/src/components/Form/Input.tsx
|
|
386
|
+
import React3 from "react";
|
|
387
|
+
import { Icon, Tooltip } from "@dxos/react-ui";
|
|
388
|
+
import { errorText } from "@dxos/react-ui-theme";
|
|
389
|
+
var InputHeader = ({ children, error }) => {
|
|
390
|
+
return /* @__PURE__ */ React3.createElement("div", {
|
|
391
|
+
role: "none",
|
|
392
|
+
className: "flex justify-between items-center mb-1"
|
|
393
|
+
}, children, error && /* @__PURE__ */ React3.createElement(Tooltip.Root, null, /* @__PURE__ */ React3.createElement(Tooltip.Trigger, {
|
|
394
|
+
asChild: true
|
|
395
|
+
}, /* @__PURE__ */ React3.createElement(Icon, {
|
|
396
|
+
icon: "ph--warning--regular",
|
|
397
|
+
size: 4,
|
|
398
|
+
classNames: errorText
|
|
399
|
+
})), /* @__PURE__ */ React3.createElement(Tooltip.Content, {
|
|
400
|
+
side: "bottom"
|
|
401
|
+
}, /* @__PURE__ */ React3.createElement(Tooltip.Arrow, null), error)));
|
|
402
|
+
};
|
|
403
|
+
|
|
404
|
+
// packages/ui/react-ui-form/src/components/Form/custom/GeoPointInput.tsx
|
|
405
|
+
var GeoPointInput = ({ type, label, disabled, getStatus, getValue: getValue3, onValueChange, onBlur }) => {
|
|
406
|
+
const { t } = useTranslation(translationKey);
|
|
407
|
+
const { status, error } = getStatus();
|
|
408
|
+
const geoPoint = useMemo3(() => getValue3() ?? [
|
|
409
|
+
0,
|
|
410
|
+
0
|
|
411
|
+
], [
|
|
412
|
+
getValue3
|
|
413
|
+
]);
|
|
414
|
+
const geoLocation = useMemo3(() => GeoLocation.fromGeoPoint(geoPoint), [
|
|
415
|
+
geoPoint
|
|
416
|
+
]);
|
|
417
|
+
const [longitudeText, setLongitudeText] = useState2(geoLocation.longitude?.toString());
|
|
418
|
+
const [latitudeText, setLatitudeText] = useState2(geoLocation.latitude?.toString());
|
|
419
|
+
useEffect3(() => {
|
|
420
|
+
const location = GeoLocation.fromGeoPoint(geoPoint);
|
|
421
|
+
setLongitudeText(location.longitude.toString());
|
|
422
|
+
setLatitudeText(location.latitude.toString());
|
|
423
|
+
}, [
|
|
424
|
+
geoPoint
|
|
425
|
+
]);
|
|
426
|
+
const handleCoordinateChange = useCallback2((coordinateType, setText) => (event) => {
|
|
427
|
+
const inputText = event.target.value;
|
|
428
|
+
setText(inputText);
|
|
429
|
+
if (inputText !== "" && inputText !== "-") {
|
|
430
|
+
const coord = safeParseFloat(inputText);
|
|
431
|
+
if (coord !== void 0 && !isNaN(coord)) {
|
|
432
|
+
const currentLocation = GeoLocation.fromGeoPoint(getValue3() ?? [
|
|
433
|
+
0,
|
|
434
|
+
0
|
|
435
|
+
]);
|
|
436
|
+
const newLocation = {
|
|
437
|
+
...currentLocation,
|
|
438
|
+
[coordinateType]: coord
|
|
439
|
+
};
|
|
440
|
+
const newValue = GeoLocation.toGeoPoint(newLocation);
|
|
441
|
+
onValueChange(type, newValue);
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
}, [
|
|
445
|
+
getValue3,
|
|
446
|
+
onValueChange,
|
|
447
|
+
type
|
|
448
|
+
]);
|
|
449
|
+
return /* @__PURE__ */ React4.createElement(Input2.Root, {
|
|
450
|
+
validationValence: status
|
|
451
|
+
}, /* @__PURE__ */ React4.createElement(InputHeader, {
|
|
452
|
+
error
|
|
453
|
+
}, /* @__PURE__ */ React4.createElement(Input2.Label, null, label)), /* @__PURE__ */ React4.createElement("div", {
|
|
454
|
+
role: "none",
|
|
455
|
+
className: "grid grid-cols-2 gap-2"
|
|
456
|
+
}, /* @__PURE__ */ React4.createElement(Input2.TextInput, {
|
|
457
|
+
type: "text",
|
|
458
|
+
pattern: "^-?[0-9]*\\.?[0-9]*$",
|
|
459
|
+
disabled,
|
|
460
|
+
placeholder: t("placeholder latitude"),
|
|
461
|
+
value: latitudeText,
|
|
462
|
+
onChange: handleCoordinateChange("latitude", setLatitudeText),
|
|
463
|
+
onBlur
|
|
464
|
+
}), /* @__PURE__ */ React4.createElement(Input2.TextInput, {
|
|
465
|
+
type: "text",
|
|
466
|
+
pattern: "^-?[0-9]*\\.?[0-9]*$",
|
|
467
|
+
disabled,
|
|
468
|
+
placeholder: t("placeholder longitude"),
|
|
469
|
+
value: longitudeText,
|
|
470
|
+
onChange: handleCoordinateChange("longitude", setLongitudeText),
|
|
471
|
+
onBlur
|
|
472
|
+
})));
|
|
473
|
+
};
|
|
474
|
+
|
|
475
|
+
// packages/ui/react-ui-form/src/components/Form/custom/SelectOptionsInput.tsx
|
|
476
|
+
import React5, { useCallback as useCallback3, useEffect as useEffect4, useState as useState3, useRef } from "react";
|
|
477
|
+
import { PublicKey } from "@dxos/keys";
|
|
478
|
+
import { Icon as Icon2, IconButton, Input as Input3, Tag, Toolbar, useTranslation as useTranslation2 } from "@dxos/react-ui";
|
|
479
|
+
import { List } from "@dxos/react-ui-list";
|
|
480
|
+
import { HuePicker } from "@dxos/react-ui-pickers";
|
|
481
|
+
import { hues, mx as mx2 } from "@dxos/react-ui-theme";
|
|
482
|
+
var SelectOptionInput = ({ type, label, disabled, getStatus, getValue: getValue3, onValueChange }) => {
|
|
483
|
+
const [selected, setSelectedId] = useState3(null);
|
|
484
|
+
const [isNewOption, setIsNewOption] = useState3(false);
|
|
485
|
+
const inputRef = useRef(null);
|
|
486
|
+
const { t } = useTranslation2(translationKey);
|
|
487
|
+
const { status, error } = getStatus();
|
|
488
|
+
const options = getValue3();
|
|
489
|
+
useEffect4(() => {
|
|
490
|
+
if (options === void 0) {
|
|
491
|
+
onValueChange(type, []);
|
|
492
|
+
}
|
|
493
|
+
}, [
|
|
494
|
+
options,
|
|
495
|
+
onValueChange,
|
|
496
|
+
type
|
|
497
|
+
]);
|
|
498
|
+
const randomHue = () => {
|
|
499
|
+
const usedHues = new Set(options?.map((option) => option.color) ?? []);
|
|
500
|
+
const unusedHues = hues.filter((hue) => !usedHues.has(hue));
|
|
501
|
+
if (unusedHues.length > 0) {
|
|
502
|
+
return unusedHues[Math.floor(Math.random() * unusedHues.length)];
|
|
503
|
+
}
|
|
504
|
+
const lastThree = new Set(options?.slice(-3).map((option) => option.color) ?? []);
|
|
505
|
+
const availableHues = hues.filter((hue) => !lastThree.has(hue));
|
|
506
|
+
return availableHues[Math.floor(Math.random() * availableHues.length)] ?? hues[Math.floor(Math.random() * hues.length)];
|
|
507
|
+
};
|
|
508
|
+
const handleAdd = useCallback3(() => {
|
|
509
|
+
const newId = PublicKey.random().truncate();
|
|
510
|
+
const newOption = {
|
|
511
|
+
id: newId,
|
|
512
|
+
title: "",
|
|
513
|
+
color: randomHue()
|
|
514
|
+
};
|
|
515
|
+
onValueChange(type, [
|
|
516
|
+
...options ?? [],
|
|
517
|
+
newOption
|
|
518
|
+
]);
|
|
519
|
+
setSelectedId(newId);
|
|
520
|
+
setIsNewOption(true);
|
|
521
|
+
}, [
|
|
522
|
+
options,
|
|
523
|
+
type,
|
|
524
|
+
onValueChange
|
|
525
|
+
]);
|
|
526
|
+
const handleDelete = useCallback3((id) => {
|
|
527
|
+
const newOptions = options?.filter((option) => option.id !== id) ?? [];
|
|
528
|
+
onValueChange(type, newOptions);
|
|
529
|
+
setSelectedId(null);
|
|
530
|
+
}, [
|
|
531
|
+
options,
|
|
532
|
+
type,
|
|
533
|
+
onValueChange
|
|
534
|
+
]);
|
|
535
|
+
const handleMove = useCallback3((from, to) => {
|
|
536
|
+
if (!options) {
|
|
537
|
+
return;
|
|
538
|
+
}
|
|
539
|
+
const newOptions = [
|
|
540
|
+
...options
|
|
541
|
+
];
|
|
542
|
+
const [removed] = newOptions.splice(from, 1);
|
|
543
|
+
newOptions.splice(to, 0, removed);
|
|
544
|
+
onValueChange(type, newOptions);
|
|
545
|
+
}, [
|
|
546
|
+
options,
|
|
547
|
+
type,
|
|
548
|
+
onValueChange
|
|
549
|
+
]);
|
|
550
|
+
const handleClick = useCallback3((id) => {
|
|
551
|
+
setSelectedId((current) => current === id ? null : id);
|
|
552
|
+
}, []);
|
|
553
|
+
const handleTitleChange = useCallback3((id) => (e) => {
|
|
554
|
+
const newOptions = options?.map((o) => o.id === id ? {
|
|
555
|
+
...o,
|
|
556
|
+
title: e.target.value
|
|
557
|
+
} : o);
|
|
558
|
+
onValueChange(type, newOptions ?? []);
|
|
559
|
+
}, [
|
|
560
|
+
options,
|
|
561
|
+
type,
|
|
562
|
+
onValueChange
|
|
563
|
+
]);
|
|
564
|
+
const handleKeyDown = useCallback3((e) => {
|
|
565
|
+
if (e.key === "Enter") {
|
|
566
|
+
setSelectedId(null);
|
|
567
|
+
}
|
|
568
|
+
}, []);
|
|
569
|
+
const handleColorChange = useCallback3((id) => (hue) => {
|
|
570
|
+
const newOptions = options?.map((o) => o.id === id ? {
|
|
571
|
+
...o,
|
|
572
|
+
color: hue
|
|
573
|
+
} : o);
|
|
574
|
+
onValueChange(type, newOptions ?? []);
|
|
575
|
+
}, [
|
|
576
|
+
options,
|
|
577
|
+
type,
|
|
578
|
+
onValueChange
|
|
579
|
+
]);
|
|
580
|
+
useEffect4(() => {
|
|
581
|
+
if (selected && isNewOption && inputRef.current) {
|
|
582
|
+
inputRef.current.focus();
|
|
583
|
+
setIsNewOption(false);
|
|
584
|
+
}
|
|
585
|
+
}, [
|
|
586
|
+
selected,
|
|
587
|
+
isNewOption
|
|
588
|
+
]);
|
|
589
|
+
return /* @__PURE__ */ React5.createElement(Input3.Root, {
|
|
590
|
+
validationValence: status
|
|
591
|
+
}, /* @__PURE__ */ React5.createElement(InputHeader, {
|
|
592
|
+
error
|
|
593
|
+
}, /* @__PURE__ */ React5.createElement(Input3.Label, null, label)), /* @__PURE__ */ React5.createElement("div", {
|
|
594
|
+
role: "none"
|
|
595
|
+
}, options && /* @__PURE__ */ React5.createElement(List.Root, {
|
|
596
|
+
items: options,
|
|
597
|
+
isItem: (item) => true,
|
|
598
|
+
onMove: handleMove
|
|
599
|
+
}, ({ items }) => /* @__PURE__ */ React5.createElement("div", {
|
|
600
|
+
role: "list",
|
|
601
|
+
className: "w-full overflow-auto"
|
|
602
|
+
}, items?.map((item) => /* @__PURE__ */ React5.createElement("div", {
|
|
603
|
+
key: item.id
|
|
604
|
+
}, /* @__PURE__ */ React5.createElement(List.Item, {
|
|
605
|
+
role: "button",
|
|
606
|
+
item,
|
|
607
|
+
classNames: mx2("p-1 plb-2", "flex flex-col", "cursor-pointer", "hover:bg-hoverOverlay"),
|
|
608
|
+
"aria-expanded": selected === item.id
|
|
609
|
+
}, /* @__PURE__ */ React5.createElement("div", {
|
|
610
|
+
className: "flex items-center"
|
|
611
|
+
}, /* @__PURE__ */ React5.createElement(List.ItemDragHandle, null), /* @__PURE__ */ React5.createElement(List.ItemTitle, {
|
|
612
|
+
onClick: () => handleClick(item.id),
|
|
613
|
+
classNames: "flex-1"
|
|
614
|
+
}, /* @__PURE__ */ React5.createElement(Tag, {
|
|
615
|
+
palette: item.color
|
|
616
|
+
}, item.title || "\u200B")), /* @__PURE__ */ React5.createElement(Icon2, {
|
|
617
|
+
icon: selected === item.id ? "ph--caret-down--regular" : "ph--caret-right--regular",
|
|
618
|
+
onClick: () => handleClick(item.id)
|
|
619
|
+
})), selected === item.id && /* @__PURE__ */ React5.createElement("div", {
|
|
620
|
+
className: "mis-4 mbs-2 flex flex-col gap-1"
|
|
621
|
+
}, /* @__PURE__ */ React5.createElement(Input3.Label, {
|
|
622
|
+
classNames: "text-xs"
|
|
623
|
+
}, t("select option label")), /* @__PURE__ */ React5.createElement("div", {
|
|
624
|
+
className: "flex flex-row items-center gap-1"
|
|
625
|
+
}, /* @__PURE__ */ React5.createElement(Input3.TextInput, {
|
|
626
|
+
placeholder: t("select option label placeholder"),
|
|
627
|
+
ref: selected === item.id ? inputRef : void 0,
|
|
628
|
+
value: item.title,
|
|
629
|
+
onChange: handleTitleChange(item.id),
|
|
630
|
+
onKeyDown: handleKeyDown,
|
|
631
|
+
classNames: "flex-1",
|
|
632
|
+
"data-no-submit": true
|
|
633
|
+
}), /* @__PURE__ */ React5.createElement(Toolbar.Root, {
|
|
634
|
+
classNames: "p-0 m-0 !is-auto"
|
|
635
|
+
}, /* @__PURE__ */ React5.createElement(HuePicker, {
|
|
636
|
+
value: item.color,
|
|
637
|
+
onChange: handleColorChange(item.id)
|
|
638
|
+
})), /* @__PURE__ */ React5.createElement(IconButton, {
|
|
639
|
+
icon: "ph--trash--fill",
|
|
640
|
+
iconOnly: true,
|
|
641
|
+
label: t("select option delete"),
|
|
642
|
+
onClick: () => handleDelete(item.id)
|
|
643
|
+
})))))), /* @__PURE__ */ React5.createElement("div", {
|
|
644
|
+
role: "listitem"
|
|
645
|
+
}, /* @__PURE__ */ React5.createElement("div", {
|
|
646
|
+
role: "button",
|
|
647
|
+
className: mx2("p-1 plb-2", "flex flex-col", "cursor-pointer", "hover:bg-hoverOverlay"),
|
|
648
|
+
onClick: handleAdd
|
|
649
|
+
}, /* @__PURE__ */ React5.createElement("div", {
|
|
650
|
+
className: "flex items-center gap-1"
|
|
651
|
+
}, /* @__PURE__ */ React5.createElement(Icon2, {
|
|
652
|
+
icon: "ph--plus--regular"
|
|
653
|
+
}), /* @__PURE__ */ React5.createElement("span", {
|
|
654
|
+
className: "text-sm"
|
|
655
|
+
}, t("select option add")))))))));
|
|
656
|
+
};
|
|
657
|
+
|
|
658
|
+
// packages/ui/react-ui-form/src/components/Form/custom/TupleInput.tsx
|
|
659
|
+
import React6 from "react";
|
|
660
|
+
import { Input as Input4 } from "@dxos/react-ui";
|
|
661
|
+
import { mx as mx3 } from "@dxos/react-ui-theme";
|
|
662
|
+
import { safeParseFloat as safeParseFloat2 } from "@dxos/util";
|
|
663
|
+
var gridCols = [
|
|
664
|
+
"grid-cols-1",
|
|
665
|
+
"grid-cols-2",
|
|
666
|
+
"grid-cols-3",
|
|
667
|
+
"grid-cols-4"
|
|
668
|
+
];
|
|
669
|
+
var TupleInput = ({ binding, type, label, disabled, getStatus, getValue: getValue3, onValueChange, onBlur }) => {
|
|
670
|
+
const { status, error } = getStatus();
|
|
671
|
+
const values = getValue3() ?? {};
|
|
672
|
+
return /* @__PURE__ */ React6.createElement(Input4.Root, {
|
|
673
|
+
validationValence: status
|
|
674
|
+
}, /* @__PURE__ */ React6.createElement(InputHeader, {
|
|
675
|
+
error
|
|
676
|
+
}, /* @__PURE__ */ React6.createElement(Input4.Label, null, label)), /* @__PURE__ */ React6.createElement("div", {
|
|
677
|
+
className: mx3("grid gap-2", gridCols[binding.length - 1])
|
|
678
|
+
}, binding.map((prop) => /* @__PURE__ */ React6.createElement(Input4.TextInput, {
|
|
679
|
+
key: prop,
|
|
680
|
+
type: "number",
|
|
681
|
+
disabled,
|
|
682
|
+
value: values[prop],
|
|
683
|
+
onChange: (event) => onValueChange(type, {
|
|
684
|
+
...values,
|
|
685
|
+
[prop]: safeParseFloat2(event.target.value, 0)
|
|
686
|
+
}),
|
|
687
|
+
onBlur
|
|
688
|
+
}))));
|
|
689
|
+
};
|
|
690
|
+
|
|
691
|
+
// packages/ui/react-ui-form/src/components/Form/Defaults.tsx
|
|
692
|
+
import React7, { useCallback as useCallback4, useEffect as useEffect5, useRef as useRef2 } from "react";
|
|
693
|
+
import { Input as Input5, Select } from "@dxos/react-ui";
|
|
694
|
+
var TextInput = ({ type, label, inputOnly, disabled, placeholder, getStatus, getValue: getValue3, onValueChange, onBlur }) => {
|
|
695
|
+
const { status, error } = getStatus();
|
|
696
|
+
return /* @__PURE__ */ React7.createElement(Input5.Root, {
|
|
697
|
+
validationValence: status
|
|
698
|
+
}, !inputOnly && /* @__PURE__ */ React7.createElement(InputHeader, {
|
|
699
|
+
error
|
|
700
|
+
}, /* @__PURE__ */ React7.createElement(Input5.Label, null, label)), /* @__PURE__ */ React7.createElement(Input5.TextInput, {
|
|
701
|
+
disabled,
|
|
702
|
+
placeholder,
|
|
703
|
+
value: getValue3() ?? "",
|
|
704
|
+
onChange: (event) => onValueChange(type, event.target.value),
|
|
705
|
+
onBlur
|
|
706
|
+
}), inputOnly && /* @__PURE__ */ React7.createElement(Input5.Validation, null, error));
|
|
707
|
+
};
|
|
708
|
+
var NumberInput = ({ type, label, inputOnly, disabled, placeholder, getStatus, getValue: getValue3, onValueChange, onBlur }) => {
|
|
709
|
+
const { status, error } = getStatus();
|
|
710
|
+
return /* @__PURE__ */ React7.createElement(Input5.Root, {
|
|
711
|
+
validationValence: status
|
|
712
|
+
}, !inputOnly && /* @__PURE__ */ React7.createElement(InputHeader, {
|
|
713
|
+
error
|
|
714
|
+
}, /* @__PURE__ */ React7.createElement(Input5.Label, null, label)), /* @__PURE__ */ React7.createElement(Input5.TextInput, {
|
|
715
|
+
type: "number",
|
|
716
|
+
disabled,
|
|
717
|
+
placeholder,
|
|
718
|
+
value: getValue3() ?? 0,
|
|
719
|
+
onChange: (event) => onValueChange(type, event.target.value),
|
|
720
|
+
onBlur
|
|
721
|
+
}), inputOnly && /* @__PURE__ */ React7.createElement(Input5.DescriptionAndValidation, null, error));
|
|
722
|
+
};
|
|
723
|
+
var BooleanInput = ({ type, label, inputOnly, getStatus, getValue: getValue3, onValueChange }) => {
|
|
724
|
+
const { status, error } = getStatus();
|
|
725
|
+
const checked = Boolean(getValue3());
|
|
726
|
+
return /* @__PURE__ */ React7.createElement(Input5.Root, {
|
|
727
|
+
validationValence: status
|
|
728
|
+
}, !inputOnly && /* @__PURE__ */ React7.createElement(InputHeader, {
|
|
729
|
+
error
|
|
730
|
+
}, /* @__PURE__ */ React7.createElement(Input5.Label, null, label)), /* @__PURE__ */ React7.createElement(Input5.Switch, {
|
|
731
|
+
checked,
|
|
732
|
+
onCheckedChange: (value) => onValueChange(type, value)
|
|
733
|
+
}), inputOnly && /* @__PURE__ */ React7.createElement(Input5.DescriptionAndValidation, null, error));
|
|
734
|
+
};
|
|
735
|
+
var SelectInput = ({ type, label, inputOnly, disabled, placeholder, options, getStatus, getValue: getValue3, onValueChange }) => {
|
|
736
|
+
const { status, error } = getStatus();
|
|
737
|
+
return /* @__PURE__ */ React7.createElement(Input5.Root, {
|
|
738
|
+
validationValence: status
|
|
739
|
+
}, !inputOnly && /* @__PURE__ */ React7.createElement(InputHeader, {
|
|
740
|
+
error
|
|
741
|
+
}, /* @__PURE__ */ React7.createElement(Input5.Label, null, label)), /* @__PURE__ */ React7.createElement(Select.Root, {
|
|
742
|
+
value: getValue3(),
|
|
743
|
+
onValueChange: (value) => onValueChange(type, value)
|
|
744
|
+
}, /* @__PURE__ */ React7.createElement(Select.TriggerButton, {
|
|
745
|
+
classNames: "is-full",
|
|
746
|
+
disabled,
|
|
747
|
+
placeholder
|
|
748
|
+
}), /* @__PURE__ */ React7.createElement(Select.Portal, null, /* @__PURE__ */ React7.createElement(Select.Content, null, /* @__PURE__ */ React7.createElement(Select.Viewport, null, options?.map(({ value, label: label2 }) => (
|
|
749
|
+
// NOTE: Numeric values are converted to and from strings.
|
|
750
|
+
/* @__PURE__ */ React7.createElement(Select.Option, {
|
|
751
|
+
key: String(value),
|
|
752
|
+
value: String(value)
|
|
753
|
+
}, label2 ?? String(value))
|
|
754
|
+
)))))), inputOnly && /* @__PURE__ */ React7.createElement(Input5.DescriptionAndValidation, null, error));
|
|
755
|
+
};
|
|
756
|
+
var MarkdownInput = ({ type, label, inputOnly, disabled, placeholder, getStatus, getValue: getValue3, onValueChange, onBlur }) => {
|
|
757
|
+
const { status, error } = getStatus();
|
|
758
|
+
const textareaRef = useRef2(null);
|
|
759
|
+
const adjustHeight = useCallback4(() => {
|
|
760
|
+
const textarea = textareaRef.current;
|
|
761
|
+
if (textarea) {
|
|
762
|
+
textarea.style.blockSize = "auto";
|
|
763
|
+
textarea.style.blockSize = `${textarea.scrollHeight + 2}px`;
|
|
430
764
|
}
|
|
431
|
-
|
|
432
|
-
|
|
765
|
+
}, []);
|
|
766
|
+
useEffect5(() => {
|
|
767
|
+
adjustHeight();
|
|
768
|
+
}, [
|
|
769
|
+
adjustHeight
|
|
770
|
+
]);
|
|
771
|
+
useEffect5(() => {
|
|
772
|
+
adjustHeight();
|
|
773
|
+
}, [
|
|
774
|
+
getValue3(),
|
|
775
|
+
adjustHeight
|
|
776
|
+
]);
|
|
777
|
+
return /* @__PURE__ */ React7.createElement(Input5.Root, {
|
|
778
|
+
validationValence: status
|
|
779
|
+
}, !inputOnly && /* @__PURE__ */ React7.createElement(InputHeader, {
|
|
780
|
+
error
|
|
781
|
+
}, /* @__PURE__ */ React7.createElement(Input5.Label, null, label)), /* @__PURE__ */ React7.createElement(Input5.TextArea, {
|
|
782
|
+
ref: textareaRef,
|
|
783
|
+
disabled,
|
|
784
|
+
placeholder,
|
|
785
|
+
value: getValue3() ?? "",
|
|
786
|
+
classNames: "min-bs-auto max-h-40 overflow-auto",
|
|
787
|
+
onChange: (event) => onValueChange(type, event.target.value),
|
|
788
|
+
onBlur,
|
|
789
|
+
style: {
|
|
790
|
+
resize: "none"
|
|
791
|
+
},
|
|
792
|
+
spellCheck: false
|
|
793
|
+
}), inputOnly && /* @__PURE__ */ React7.createElement(Input5.Validation, null, error));
|
|
433
794
|
};
|
|
434
795
|
|
|
435
796
|
// packages/ui/react-ui-form/src/components/Form/Form.tsx
|
|
436
|
-
|
|
797
|
+
import React11, { useEffect as useEffect6, useMemo as useMemo6, useRef as useRef3 } from "react";
|
|
798
|
+
import { mx as mx7 } from "@dxos/react-ui-theme";
|
|
799
|
+
|
|
800
|
+
// packages/ui/react-ui-form/src/components/Form/FormActions.tsx
|
|
801
|
+
import React8 from "react";
|
|
802
|
+
import { IconButton as IconButton2, useTranslation as useTranslation3 } from "@dxos/react-ui";
|
|
803
|
+
import { mx as mx4 } from "@dxos/react-ui-theme";
|
|
804
|
+
var FormActions = ({ onCancel, readonly }) => {
|
|
805
|
+
const { t } = useTranslation3(translationKey);
|
|
806
|
+
const { canSave, handleSave } = useFormContext();
|
|
807
|
+
return /* @__PURE__ */ React8.createElement("div", {
|
|
808
|
+
role: "none",
|
|
809
|
+
className: "mt-2 flex justify-center"
|
|
810
|
+
}, /* @__PURE__ */ React8.createElement("div", {
|
|
811
|
+
role: "none",
|
|
812
|
+
className: mx4(onCancel && !readonly && "grid grid-cols-2 gap-2")
|
|
813
|
+
}, onCancel && !readonly && /* @__PURE__ */ React8.createElement(IconButton2, {
|
|
814
|
+
"data-testid": "cancel-button",
|
|
815
|
+
icon: "ph--x--regular",
|
|
816
|
+
label: t("button cancel"),
|
|
817
|
+
onClick: onCancel
|
|
818
|
+
}), handleSave && /* @__PURE__ */ React8.createElement(IconButton2, {
|
|
819
|
+
type: "submit",
|
|
820
|
+
"data-testid": "save-button",
|
|
821
|
+
disabled: !canSave,
|
|
822
|
+
icon: "ph--check--regular",
|
|
823
|
+
label: t("button save"),
|
|
824
|
+
onClick: handleSave
|
|
825
|
+
})));
|
|
826
|
+
};
|
|
827
|
+
|
|
828
|
+
// packages/ui/react-ui-form/src/components/Form/FormContent.tsx
|
|
829
|
+
import { pipe as pipe2 } from "effect";
|
|
830
|
+
import { capitalize as capitalize2 } from "effect/String";
|
|
831
|
+
import React10, { useMemo as useMemo5 } from "react";
|
|
832
|
+
import { AST as AST3, S } from "@dxos/echo-schema";
|
|
833
|
+
import { createJsonPath as createJsonPath3, findNode as findNode2, getDiscriminatedType as getDiscriminatedType2, isDiscriminatedUnion as isDiscriminatedUnion2 } from "@dxos/effect";
|
|
834
|
+
import { mx as mx6 } from "@dxos/react-ui-theme";
|
|
835
|
+
import { getSchemaProperties as getSchemaProperties2 } from "@dxos/schema";
|
|
836
|
+
import { isNotFalsy } from "@dxos/util";
|
|
837
|
+
|
|
838
|
+
// packages/ui/react-ui-form/src/components/Form/ArrayField.tsx
|
|
839
|
+
import { pipe } from "effect";
|
|
840
|
+
import { capitalize } from "effect/String";
|
|
841
|
+
import React9, { useCallback as useCallback5, useMemo as useMemo4 } from "react";
|
|
842
|
+
import { AST as AST2 } from "@dxos/echo-schema";
|
|
843
|
+
import { findNode, getDiscriminatedType, isDiscriminatedUnion, SimpleType } from "@dxos/effect";
|
|
844
|
+
import { invariant as invariant2 } from "@dxos/invariant";
|
|
845
|
+
import { IconButton as IconButton3, useTranslation as useTranslation4 } from "@dxos/react-ui";
|
|
846
|
+
import { mx as mx5 } from "@dxos/react-ui-theme";
|
|
847
|
+
import { getSchemaProperties } from "@dxos/schema";
|
|
848
|
+
var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-form/src/components/Form/ArrayField.tsx";
|
|
437
849
|
var padding = "px-2";
|
|
438
|
-
var
|
|
439
|
-
const
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
850
|
+
var ArrayField = ({ property, readonly, path, inputProps, Custom, lookupComponent }) => {
|
|
851
|
+
const { t } = useTranslation4(translationKey);
|
|
852
|
+
const { ast, name, type, title } = property;
|
|
853
|
+
const values = useFormValues(path ?? []);
|
|
854
|
+
invariant2(Array.isArray(values), `Values at path ${path?.join(".")} must be an array.`, {
|
|
855
|
+
F: __dxlog_file2,
|
|
856
|
+
L: 37,
|
|
857
|
+
S: void 0,
|
|
858
|
+
A: [
|
|
859
|
+
"Array.isArray(values)",
|
|
860
|
+
"`Values at path ${path?.join('.')} must be an array.`"
|
|
861
|
+
]
|
|
450
862
|
});
|
|
451
|
-
const
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
863
|
+
const label = title ?? pipe(name, capitalize);
|
|
864
|
+
const tupleType = findNode(ast, AST2.isTupleType);
|
|
865
|
+
const elementType = tupleType?.rest[0]?.type;
|
|
866
|
+
const getDefaultObjectValue = (typeNode) => {
|
|
867
|
+
const baseNode = findNode(typeNode, isDiscriminatedUnion);
|
|
868
|
+
const typeLiteral = baseNode ? getDiscriminatedType(baseNode, {}) : findNode(typeNode, AST2.isTypeLiteral);
|
|
869
|
+
if (!typeLiteral) {
|
|
870
|
+
return {};
|
|
871
|
+
}
|
|
872
|
+
return Object.fromEntries(getSchemaProperties(typeLiteral, {}).map((prop) => [
|
|
873
|
+
prop.name,
|
|
874
|
+
prop.defaultValue
|
|
875
|
+
]));
|
|
876
|
+
};
|
|
877
|
+
const newValue = useMemo4(() => {
|
|
878
|
+
if (type === "object" && elementType) {
|
|
879
|
+
return getDefaultObjectValue(elementType);
|
|
880
|
+
} else {
|
|
881
|
+
return SimpleType.getDefaultValue(type);
|
|
882
|
+
}
|
|
459
883
|
}, [
|
|
460
|
-
|
|
461
|
-
|
|
884
|
+
type,
|
|
885
|
+
elementType
|
|
886
|
+
]);
|
|
887
|
+
const handleAdd = useCallback5(() => {
|
|
888
|
+
inputProps.onValueChange(type, [
|
|
889
|
+
...values,
|
|
890
|
+
newValue
|
|
891
|
+
]);
|
|
892
|
+
}, [
|
|
893
|
+
type,
|
|
894
|
+
elementType,
|
|
895
|
+
inputProps,
|
|
896
|
+
newValue,
|
|
462
897
|
values
|
|
463
898
|
]);
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
errors
|
|
468
|
-
}, {
|
|
469
|
-
F: __dxlog_file2,
|
|
470
|
-
L: 106,
|
|
471
|
-
S: void 0,
|
|
472
|
-
C: (f, a) => f(...a)
|
|
473
|
-
});
|
|
474
|
-
}
|
|
899
|
+
const handleRemove = useCallback5((index) => {
|
|
900
|
+
const newValues = values.filter((_, i) => i !== index);
|
|
901
|
+
inputProps.onValueChange(type, newValues);
|
|
475
902
|
}, [
|
|
476
|
-
|
|
903
|
+
type,
|
|
904
|
+
inputProps,
|
|
905
|
+
values
|
|
477
906
|
]);
|
|
478
|
-
|
|
479
|
-
role: "form",
|
|
480
|
-
className: mx2("flex flex-col w-full gap-2 py-2", classNames),
|
|
481
|
-
"data-testid": testId
|
|
482
|
-
}, properties.map((property) => {
|
|
483
|
-
const { ast, name, type, format, title, description, examples, options, array } = property;
|
|
484
|
-
const key = [
|
|
485
|
-
...path,
|
|
486
|
-
name
|
|
487
|
-
];
|
|
488
|
-
const label = title ?? pipe(name, capitalize);
|
|
489
|
-
const placeholder = examples?.length ? `Example: "${examples[0]}"` : description;
|
|
490
|
-
const FoundComponent = lookupComponent?.({
|
|
491
|
-
prop: name,
|
|
492
|
-
schema: S.make(ast),
|
|
493
|
-
inputProps: {
|
|
494
|
-
property: name,
|
|
495
|
-
type,
|
|
496
|
-
format,
|
|
497
|
-
label,
|
|
498
|
-
disabled: readonly,
|
|
499
|
-
placeholder,
|
|
500
|
-
...inputProps
|
|
501
|
-
}
|
|
502
|
-
});
|
|
503
|
-
if (FoundComponent) {
|
|
504
|
-
return /* @__PURE__ */ React6.createElement("div", {
|
|
505
|
-
key: name,
|
|
506
|
-
role: "none",
|
|
507
|
-
className: padding
|
|
508
|
-
}, FoundComponent);
|
|
509
|
-
}
|
|
510
|
-
let InputComponent = Custom?.[key.join(".")];
|
|
511
|
-
if (!InputComponent) {
|
|
512
|
-
if (options) {
|
|
513
|
-
return /* @__PURE__ */ React6.createElement("div", {
|
|
514
|
-
key: name,
|
|
515
|
-
role: "none",
|
|
516
|
-
className: padding
|
|
517
|
-
}, /* @__PURE__ */ React6.createElement(SelectInput, {
|
|
518
|
-
type,
|
|
519
|
-
format,
|
|
520
|
-
property: name,
|
|
521
|
-
disabled: readonly,
|
|
522
|
-
label,
|
|
523
|
-
options: options.map((option) => ({
|
|
524
|
-
value: option,
|
|
525
|
-
label: String(option)
|
|
526
|
-
})),
|
|
527
|
-
placeholder,
|
|
528
|
-
...inputProps
|
|
529
|
-
}));
|
|
530
|
-
}
|
|
531
|
-
InputComponent = getInputComponent(type, format);
|
|
532
|
-
if (array) {
|
|
533
|
-
return /* @__PURE__ */ React6.createElement(ArrayField, {
|
|
534
|
-
key: name,
|
|
535
|
-
name,
|
|
536
|
-
type,
|
|
537
|
-
array: true,
|
|
538
|
-
label,
|
|
539
|
-
ast,
|
|
540
|
-
values,
|
|
541
|
-
format,
|
|
542
|
-
readonly,
|
|
543
|
-
placeholder,
|
|
544
|
-
inputProps,
|
|
545
|
-
Custom
|
|
546
|
-
});
|
|
547
|
-
}
|
|
548
|
-
}
|
|
549
|
-
if (!InputComponent) {
|
|
550
|
-
if (type === "object") {
|
|
551
|
-
const baseNode = findNode(ast, isDiscriminatedUnion);
|
|
552
|
-
const typeLiteral = baseNode ? getDiscriminatedType(baseNode, values[name]) : findNode(ast, AST.isTypeLiteral);
|
|
553
|
-
if (typeLiteral) {
|
|
554
|
-
const schema2 = S.make(typeLiteral);
|
|
555
|
-
return /* @__PURE__ */ React6.createElement("div", {
|
|
556
|
-
key: name,
|
|
557
|
-
role: "none"
|
|
558
|
-
}, /* @__PURE__ */ React6.createElement("div", {
|
|
559
|
-
className: padding
|
|
560
|
-
}, label), /* @__PURE__ */ React6.createElement(Form, {
|
|
561
|
-
schema: schema2,
|
|
562
|
-
path: key,
|
|
563
|
-
values: values[name] ?? {},
|
|
564
|
-
onValuesChanged: (childValues) => {
|
|
565
|
-
inputProps.onValueChange(name, "object", childValues);
|
|
566
|
-
},
|
|
567
|
-
Custom
|
|
568
|
-
}));
|
|
569
|
-
}
|
|
570
|
-
}
|
|
571
|
-
log2("no renderer for property", {
|
|
572
|
-
name,
|
|
573
|
-
type
|
|
574
|
-
}, {
|
|
575
|
-
F: __dxlog_file2,
|
|
576
|
-
L: 213,
|
|
577
|
-
S: void 0,
|
|
578
|
-
C: (f, a) => f(...a)
|
|
579
|
-
});
|
|
580
|
-
return null;
|
|
581
|
-
}
|
|
582
|
-
return /* @__PURE__ */ React6.createElement("div", {
|
|
583
|
-
key: name,
|
|
584
|
-
role: "none",
|
|
585
|
-
className: padding
|
|
586
|
-
}, /* @__PURE__ */ React6.createElement(InputComponent, {
|
|
587
|
-
type,
|
|
588
|
-
format,
|
|
589
|
-
property: name,
|
|
590
|
-
disabled: readonly,
|
|
591
|
-
label,
|
|
592
|
-
placeholder,
|
|
593
|
-
...inputProps
|
|
594
|
-
}));
|
|
595
|
-
}).filter(isNotFalsy), (onCancel || onSave) && !autoSave && /* @__PURE__ */ React6.createElement(FormActions, {
|
|
596
|
-
onCancel,
|
|
597
|
-
onSubmit: handleSave,
|
|
598
|
-
canSubmit: canSave,
|
|
599
|
-
readonly
|
|
600
|
-
}));
|
|
601
|
-
};
|
|
602
|
-
var ArrayField = ({ name, type, label, ast, values, format, readonly, placeholder, inputProps, Custom }) => {
|
|
603
|
-
const { t } = useTranslation2(translationKey);
|
|
604
|
-
const arrayValues = values[name] ?? [];
|
|
605
|
-
const key = [
|
|
606
|
-
name
|
|
607
|
-
];
|
|
608
|
-
const tupleType = findNode(ast, AST.isTupleType);
|
|
609
|
-
const elementType = tupleType?.rest[0]?.type;
|
|
610
|
-
if (type === "object" && elementType) {
|
|
611
|
-
const baseNode = findNode(elementType, isDiscriminatedUnion);
|
|
612
|
-
const typeLiteral = baseNode ? getDiscriminatedType(baseNode, values[name]) : findNode(elementType, AST.isTypeLiteral);
|
|
613
|
-
if (typeLiteral) {
|
|
614
|
-
const schema = S.make(typeLiteral);
|
|
615
|
-
return /* @__PURE__ */ React6.createElement("div", {
|
|
616
|
-
key: name,
|
|
617
|
-
role: "none",
|
|
618
|
-
className: mx2(padding)
|
|
619
|
-
}, /* @__PURE__ */ React6.createElement(InputHeader, null, label), /* @__PURE__ */ React6.createElement("div", {
|
|
620
|
-
role: "none",
|
|
621
|
-
className: "flex flex-col gap-1"
|
|
622
|
-
}, arrayValues.map((value, index) => {
|
|
623
|
-
return /* @__PURE__ */ React6.createElement("div", {
|
|
624
|
-
key: index,
|
|
625
|
-
role: "none",
|
|
626
|
-
className: "flex items-center gap-1"
|
|
627
|
-
}, /* @__PURE__ */ React6.createElement("div", {
|
|
628
|
-
role: "none",
|
|
629
|
-
className: "flex-1"
|
|
630
|
-
}, /* @__PURE__ */ React6.createElement(Form, {
|
|
631
|
-
schema,
|
|
632
|
-
path: [
|
|
633
|
-
...key,
|
|
634
|
-
`[${index}]`
|
|
635
|
-
],
|
|
636
|
-
values: value,
|
|
637
|
-
onValuesChanged: (childValues) => {
|
|
638
|
-
const newValues = [
|
|
639
|
-
...arrayValues
|
|
640
|
-
];
|
|
641
|
-
newValues[index] = childValues;
|
|
642
|
-
inputProps.onValueChange(name, "object", newValues);
|
|
643
|
-
},
|
|
644
|
-
Custom
|
|
645
|
-
})), /* @__PURE__ */ React6.createElement(IconButton, {
|
|
646
|
-
icon: "ph--trash--regular",
|
|
647
|
-
iconOnly: true,
|
|
648
|
-
label: t("button remove"),
|
|
649
|
-
onClick: () => {
|
|
650
|
-
const newValues = arrayValues.filter((_, i) => i !== index);
|
|
651
|
-
inputProps.onValueChange(name, type, newValues);
|
|
652
|
-
}
|
|
653
|
-
}));
|
|
654
|
-
})), /* @__PURE__ */ React6.createElement("div", {
|
|
655
|
-
role: "none",
|
|
656
|
-
className: "flex justify-between items-center plb-1"
|
|
657
|
-
}, /* @__PURE__ */ React6.createElement(IconButton, {
|
|
658
|
-
icon: "ph--plus--regular",
|
|
659
|
-
iconOnly: true,
|
|
660
|
-
label: t("button add"),
|
|
661
|
-
onClick: () => {
|
|
662
|
-
const newValues = [
|
|
663
|
-
...arrayValues,
|
|
664
|
-
{}
|
|
665
|
-
];
|
|
666
|
-
inputProps.onValueChange(name, type, newValues);
|
|
667
|
-
}
|
|
668
|
-
})));
|
|
669
|
-
}
|
|
670
|
-
return /* @__PURE__ */ React6.createElement("div", {
|
|
671
|
-
key: name,
|
|
672
|
-
role: "none"
|
|
673
|
-
}, "Nested form not supported in arrays, yet.");
|
|
674
|
-
}
|
|
675
|
-
const InputComponent = getInputComponent(type, format);
|
|
676
|
-
if (!InputComponent) {
|
|
907
|
+
if (!elementType) {
|
|
677
908
|
return null;
|
|
678
909
|
}
|
|
679
|
-
return /* @__PURE__ */
|
|
910
|
+
return /* @__PURE__ */ React9.createElement("div", {
|
|
680
911
|
role: "none",
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
}, /* @__PURE__ */ React6.createElement(InputHeader, null, label), /* @__PURE__ */ React6.createElement("div", {
|
|
912
|
+
className: mx5(padding)
|
|
913
|
+
}, /* @__PURE__ */ React9.createElement(InputHeader, null, label), /* @__PURE__ */ React9.createElement("div", {
|
|
684
914
|
role: "none",
|
|
685
915
|
className: "flex flex-col gap-1"
|
|
686
|
-
},
|
|
916
|
+
}, values.map((_value, index) => /* @__PURE__ */ React9.createElement("div", {
|
|
687
917
|
key: index,
|
|
688
918
|
role: "none",
|
|
689
|
-
className: "flex items-
|
|
690
|
-
}, /* @__PURE__ */
|
|
919
|
+
className: "flex items-center gap-1"
|
|
920
|
+
}, /* @__PURE__ */ React9.createElement("div", {
|
|
691
921
|
role: "none",
|
|
692
922
|
className: "flex-1"
|
|
693
|
-
}, /* @__PURE__ */
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
923
|
+
}, /* @__PURE__ */ React9.createElement(FormField, {
|
|
924
|
+
property: {
|
|
925
|
+
...property,
|
|
926
|
+
array: false,
|
|
927
|
+
ast: elementType
|
|
928
|
+
},
|
|
929
|
+
path: [
|
|
930
|
+
...path ?? [],
|
|
931
|
+
index
|
|
932
|
+
],
|
|
933
|
+
readonly,
|
|
934
|
+
inline: true,
|
|
935
|
+
Custom,
|
|
936
|
+
lookupComponent
|
|
937
|
+
})), /* @__PURE__ */ React9.createElement(IconButton3, {
|
|
703
938
|
icon: "ph--trash--regular",
|
|
704
939
|
iconOnly: true,
|
|
705
940
|
label: t("button remove"),
|
|
706
|
-
onClick: () =>
|
|
707
|
-
|
|
708
|
-
inputProps.onValueChange(name, type, newValues);
|
|
709
|
-
}
|
|
710
|
-
})))), /* @__PURE__ */ React6.createElement("div", {
|
|
941
|
+
onClick: () => handleRemove(index)
|
|
942
|
+
})))), /* @__PURE__ */ React9.createElement("div", {
|
|
711
943
|
role: "none",
|
|
712
944
|
className: "flex justify-between items-center plb-1"
|
|
713
|
-
}, /* @__PURE__ */
|
|
945
|
+
}, /* @__PURE__ */ React9.createElement(IconButton3, {
|
|
714
946
|
icon: "ph--plus--regular",
|
|
715
947
|
iconOnly: true,
|
|
716
948
|
label: t("button add"),
|
|
717
|
-
onClick:
|
|
718
|
-
const newValues = [
|
|
719
|
-
...arrayValues,
|
|
720
|
-
SimpleType.getDefaultValue(type)
|
|
721
|
-
];
|
|
722
|
-
inputProps.onValueChange(name, type, newValues);
|
|
723
|
-
}
|
|
949
|
+
onClick: handleAdd
|
|
724
950
|
})));
|
|
725
951
|
};
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
952
|
+
|
|
953
|
+
// packages/ui/react-ui-form/src/components/Form/factory.tsx
|
|
954
|
+
import { FormatEnum } from "@dxos/echo-schema";
|
|
955
|
+
var getInputComponent = (type, format) => {
|
|
956
|
+
switch (format) {
|
|
957
|
+
case FormatEnum.GeoPoint:
|
|
958
|
+
return GeoPointInput;
|
|
959
|
+
case FormatEnum.Markdown:
|
|
960
|
+
return MarkdownInput;
|
|
961
|
+
}
|
|
962
|
+
switch (type) {
|
|
963
|
+
case "string":
|
|
964
|
+
return TextInput;
|
|
965
|
+
case "number":
|
|
966
|
+
return NumberInput;
|
|
967
|
+
case "boolean":
|
|
968
|
+
return BooleanInput;
|
|
969
|
+
}
|
|
970
|
+
};
|
|
971
|
+
|
|
972
|
+
// packages/ui/react-ui-form/src/components/Form/FormContent.tsx
|
|
973
|
+
var FormField = ({ property, path, readonly, inline, lookupComponent, Custom }) => {
|
|
974
|
+
const inputProps = useInputProps(path);
|
|
975
|
+
const { ast, name, type, format, title, description, options, examples, array } = property;
|
|
976
|
+
const label = useMemo5(() => title ?? pipe2(name, capitalize2), [
|
|
977
|
+
title,
|
|
978
|
+
name
|
|
979
|
+
]);
|
|
980
|
+
const placeholder = useMemo5(() => examples?.length ? `Example: "${examples[0]}"` : description, [
|
|
981
|
+
examples,
|
|
982
|
+
description
|
|
983
|
+
]);
|
|
984
|
+
const FoundComponent = lookupComponent?.({
|
|
985
|
+
prop: name,
|
|
986
|
+
schema: S.make(ast),
|
|
987
|
+
inputProps: {
|
|
988
|
+
type,
|
|
989
|
+
format,
|
|
990
|
+
label,
|
|
991
|
+
disabled: readonly,
|
|
992
|
+
placeholder,
|
|
993
|
+
...inputProps
|
|
994
|
+
}
|
|
995
|
+
});
|
|
996
|
+
if (FoundComponent) {
|
|
997
|
+
return /* @__PURE__ */ React10.createElement("div", {
|
|
998
|
+
role: "none"
|
|
999
|
+
}, FoundComponent);
|
|
1000
|
+
}
|
|
1001
|
+
const jsonPath = createJsonPath3(path ?? []);
|
|
1002
|
+
const CustomComponent = Custom?.[jsonPath];
|
|
1003
|
+
if (CustomComponent) {
|
|
1004
|
+
return /* @__PURE__ */ React10.createElement(CustomComponent, {
|
|
1005
|
+
type,
|
|
1006
|
+
format,
|
|
1007
|
+
label,
|
|
1008
|
+
inputOnly: inline,
|
|
1009
|
+
placeholder,
|
|
1010
|
+
disabled: readonly,
|
|
1011
|
+
...inputProps
|
|
1012
|
+
});
|
|
1013
|
+
}
|
|
1014
|
+
if (array) {
|
|
1015
|
+
return /* @__PURE__ */ React10.createElement(ArrayField, {
|
|
1016
|
+
property,
|
|
1017
|
+
path,
|
|
1018
|
+
inputProps,
|
|
1019
|
+
readonly,
|
|
1020
|
+
Custom
|
|
1021
|
+
});
|
|
1022
|
+
}
|
|
1023
|
+
const InputComponent = getInputComponent(type, format);
|
|
1024
|
+
if (InputComponent) {
|
|
1025
|
+
return /* @__PURE__ */ React10.createElement("div", {
|
|
1026
|
+
role: "none"
|
|
1027
|
+
}, /* @__PURE__ */ React10.createElement(InputComponent, {
|
|
1028
|
+
type,
|
|
1029
|
+
format,
|
|
1030
|
+
label,
|
|
1031
|
+
inputOnly: inline,
|
|
1032
|
+
placeholder,
|
|
1033
|
+
disabled: readonly,
|
|
1034
|
+
...inputProps
|
|
1035
|
+
}));
|
|
1036
|
+
}
|
|
1037
|
+
if (options) {
|
|
1038
|
+
return /* @__PURE__ */ React10.createElement("div", {
|
|
1039
|
+
role: "none"
|
|
1040
|
+
}, /* @__PURE__ */ React10.createElement(SelectInput, {
|
|
1041
|
+
type,
|
|
1042
|
+
format,
|
|
1043
|
+
disabled: readonly,
|
|
1044
|
+
inputOnly: inline,
|
|
1045
|
+
label,
|
|
1046
|
+
options: options.map((option) => ({
|
|
1047
|
+
value: option,
|
|
1048
|
+
label: String(option)
|
|
1049
|
+
})),
|
|
1050
|
+
placeholder,
|
|
1051
|
+
...inputProps
|
|
1052
|
+
}));
|
|
1053
|
+
}
|
|
1054
|
+
if (type === "object") {
|
|
1055
|
+
const baseNode = findNode2(ast, isDiscriminatedUnion2);
|
|
1056
|
+
const typeLiteral = baseNode ? getDiscriminatedType2(baseNode, inputProps.getValue()) : findNode2(ast, AST3.isTypeLiteral);
|
|
1057
|
+
if (typeLiteral) {
|
|
1058
|
+
return /* @__PURE__ */ React10.createElement("div", {
|
|
1059
|
+
role: "none"
|
|
1060
|
+
}, !inline && /* @__PURE__ */ React10.createElement("div", null, label), /* @__PURE__ */ React10.createElement(FormFields, {
|
|
1061
|
+
schema: S.make(typeLiteral),
|
|
1062
|
+
path,
|
|
1063
|
+
readonly,
|
|
1064
|
+
Custom
|
|
1065
|
+
}));
|
|
1066
|
+
}
|
|
1067
|
+
}
|
|
1068
|
+
return null;
|
|
1069
|
+
};
|
|
1070
|
+
var FormFields = ({ schema, path, filter, sort, readonly, lookupComponent, Custom }) => {
|
|
1071
|
+
const values = useFormValues(path);
|
|
1072
|
+
const properties = useMemo5(() => {
|
|
1073
|
+
const props = getSchemaProperties2(schema.ast, values);
|
|
1074
|
+
const filtered = filter ? filter(props) : props;
|
|
1075
|
+
return sort ? filtered.sort((a, b) => sort.indexOf(a.name) - sort.indexOf(b.name)) : filtered;
|
|
1076
|
+
}, [
|
|
1077
|
+
schema,
|
|
1078
|
+
values,
|
|
1079
|
+
filter,
|
|
1080
|
+
sort
|
|
1081
|
+
]);
|
|
1082
|
+
return /* @__PURE__ */ React10.createElement("div", {
|
|
1083
|
+
role: "form",
|
|
1084
|
+
className: mx6("flex flex-col w-full gap-2")
|
|
1085
|
+
}, properties.map((property) => {
|
|
1086
|
+
return /* @__PURE__ */ React10.createElement(FormField, {
|
|
1087
|
+
key: property.name,
|
|
1088
|
+
property,
|
|
1089
|
+
path: [
|
|
1090
|
+
...path ?? [],
|
|
1091
|
+
property.name
|
|
1092
|
+
],
|
|
1093
|
+
readonly,
|
|
1094
|
+
lookupComponent,
|
|
1095
|
+
Custom
|
|
1096
|
+
});
|
|
1097
|
+
}).filter(isNotFalsy));
|
|
1098
|
+
};
|
|
1099
|
+
|
|
1100
|
+
// packages/ui/react-ui-form/src/components/Form/Form.tsx
|
|
1101
|
+
var Form = ({ classNames, schema, values: initialValues, path = [], autoFocus, readonly, filter, sort, autoSave, testId, onValuesChanged, onValidate, onSave, onCancel, lookupComponent, Custom }) => {
|
|
1102
|
+
const formRef = useRef3(null);
|
|
1103
|
+
const onValid = useMemo6(() => autoSave ? onSave : void 0, [
|
|
1104
|
+
autoSave,
|
|
1105
|
+
onSave
|
|
1106
|
+
]);
|
|
1107
|
+
useEffect6(() => {
|
|
1108
|
+
if (autoFocus && formRef.current) {
|
|
1109
|
+
const input = formRef.current.querySelector("input");
|
|
1110
|
+
if (input) {
|
|
1111
|
+
input.focus();
|
|
1112
|
+
}
|
|
1113
|
+
}
|
|
1114
|
+
}, [
|
|
1115
|
+
autoFocus
|
|
1116
|
+
]);
|
|
1117
|
+
return /* @__PURE__ */ React11.createElement(FormProvider, {
|
|
1118
|
+
formRef,
|
|
1119
|
+
schema,
|
|
1120
|
+
autoSave,
|
|
1121
|
+
initialValues,
|
|
1122
|
+
onValuesChanged,
|
|
1123
|
+
onValidate,
|
|
1124
|
+
onValid,
|
|
1125
|
+
onSave
|
|
1126
|
+
}, /* @__PURE__ */ React11.createElement("div", {
|
|
1127
|
+
ref: formRef,
|
|
732
1128
|
role: "none",
|
|
733
|
-
className:
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
1129
|
+
className: mx7("p-2", classNames),
|
|
1130
|
+
"data-testid": testId
|
|
1131
|
+
}, /* @__PURE__ */ React11.createElement(FormFields, {
|
|
1132
|
+
schema,
|
|
1133
|
+
path,
|
|
1134
|
+
readonly,
|
|
1135
|
+
filter,
|
|
1136
|
+
sort,
|
|
1137
|
+
lookupComponent,
|
|
1138
|
+
Custom
|
|
1139
|
+
}), (onCancel || onSave) && !autoSave && /* @__PURE__ */ React11.createElement(FormActions, {
|
|
1140
|
+
onCancel,
|
|
1141
|
+
readonly
|
|
746
1142
|
})));
|
|
747
1143
|
};
|
|
748
1144
|
|
|
749
1145
|
// packages/ui/react-ui-form/src/components/FieldEditor/FieldEditor.tsx
|
|
750
1146
|
var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-form/src/components/FieldEditor/FieldEditor.tsx";
|
|
751
1147
|
var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
|
|
752
|
-
const { t } =
|
|
753
|
-
const [props, setProps] =
|
|
754
|
-
|
|
1148
|
+
const { t } = useTranslation5(translationKey);
|
|
1149
|
+
const [props, setProps] = useState4(projection.getFieldProjection(field.id).props);
|
|
1150
|
+
useEffect7(() => setProps(projection.getFieldProjection(field.id).props), [
|
|
755
1151
|
field,
|
|
756
1152
|
projection
|
|
757
1153
|
]);
|
|
758
|
-
const [schemas, setSchemas] =
|
|
759
|
-
|
|
1154
|
+
const [schemas, setSchemas] = useState4([]);
|
|
1155
|
+
useEffect7(() => {
|
|
760
1156
|
if (!registry) {
|
|
761
1157
|
return;
|
|
762
1158
|
}
|
|
@@ -774,17 +1170,17 @@ var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
|
|
|
774
1170
|
}, [
|
|
775
1171
|
registry
|
|
776
1172
|
]);
|
|
777
|
-
const [referenceSchema, setReferenceSchema] =
|
|
778
|
-
|
|
1173
|
+
const [referenceSchema, setReferenceSchema] = useState4();
|
|
1174
|
+
useEffect7(() => {
|
|
779
1175
|
setReferenceSchema(schemas.find((schema) => schema.typename === props?.referenceSchema));
|
|
780
1176
|
}, [
|
|
781
1177
|
schemas,
|
|
782
1178
|
props?.referenceSchema
|
|
783
1179
|
]);
|
|
784
|
-
const [{ fieldSchema }, setFieldSchema] =
|
|
1180
|
+
const [{ fieldSchema }, setFieldSchema] = useState4({
|
|
785
1181
|
fieldSchema: getFormatSchema(props?.format)
|
|
786
1182
|
});
|
|
787
|
-
const handleValuesChanged =
|
|
1183
|
+
const handleValuesChanged = useCallback6((_props) => {
|
|
788
1184
|
setFieldSchema((prev) => {
|
|
789
1185
|
const fieldSchema2 = getFormatSchema(_props.format);
|
|
790
1186
|
if (prev.fieldSchema === fieldSchema2) {
|
|
@@ -812,14 +1208,14 @@ var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
|
|
|
812
1208
|
type
|
|
813
1209
|
};
|
|
814
1210
|
}
|
|
815
|
-
return
|
|
1211
|
+
return _props;
|
|
816
1212
|
});
|
|
817
1213
|
}, [
|
|
818
1214
|
schemas,
|
|
819
1215
|
props.format,
|
|
820
1216
|
props.referenceSchema
|
|
821
1217
|
]);
|
|
822
|
-
const handleValidate =
|
|
1218
|
+
const handleValidate = useCallback6(({ property }) => {
|
|
823
1219
|
if (property && view.fields.find((f) => f.path === property && f.path !== field.path)) {
|
|
824
1220
|
return [
|
|
825
1221
|
{
|
|
@@ -832,7 +1228,7 @@ var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
|
|
|
832
1228
|
view.fields,
|
|
833
1229
|
field
|
|
834
1230
|
]);
|
|
835
|
-
const handleSave =
|
|
1231
|
+
const handleSave = useCallback6((props2) => {
|
|
836
1232
|
projection.setFieldProjection({
|
|
837
1233
|
field,
|
|
838
1234
|
props: props2
|
|
@@ -843,50 +1239,51 @@ var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
|
|
|
843
1239
|
field,
|
|
844
1240
|
onSave
|
|
845
1241
|
]);
|
|
846
|
-
const handleCancel =
|
|
1242
|
+
const handleCancel = useCallback6(() => {
|
|
847
1243
|
requestAnimationFrame(() => onCancel?.());
|
|
848
1244
|
onSave();
|
|
849
1245
|
}, [
|
|
850
1246
|
onSave
|
|
851
1247
|
]);
|
|
852
|
-
const Custom =
|
|
853
|
-
["format"]: (props2) => /* @__PURE__ */
|
|
1248
|
+
const Custom = useMemo7(() => ({
|
|
1249
|
+
["format"]: (props2) => /* @__PURE__ */ React12.createElement(SelectInput, {
|
|
854
1250
|
...props2,
|
|
855
1251
|
options: FormatEnums.filter((value) => value !== FormatEnum2.None).map((value) => ({
|
|
856
1252
|
value,
|
|
857
1253
|
label: t(`format ${value}`)
|
|
858
1254
|
}))
|
|
859
1255
|
}),
|
|
860
|
-
["referenceSchema"]: (props2) => /* @__PURE__ */
|
|
1256
|
+
["referenceSchema"]: (props2) => /* @__PURE__ */ React12.createElement(SelectInput, {
|
|
861
1257
|
...props2,
|
|
862
1258
|
options: schemas.map((schema) => ({
|
|
863
1259
|
value: schema.typename
|
|
864
1260
|
}))
|
|
865
1261
|
}),
|
|
866
|
-
["referencePath"]: (props2) => /* @__PURE__ */
|
|
1262
|
+
["referencePath"]: (props2) => /* @__PURE__ */ React12.createElement(SelectInput, {
|
|
867
1263
|
...props2,
|
|
868
|
-
options: referenceSchema ?
|
|
1264
|
+
options: referenceSchema ? getSchemaProperties3(referenceSchema.ast).sort(sortProperties).map((p) => ({
|
|
869
1265
|
value: p.name
|
|
870
1266
|
})) : []
|
|
871
|
-
})
|
|
1267
|
+
}),
|
|
1268
|
+
["options"]: (props2) => /* @__PURE__ */ React12.createElement(SelectOptionInput, props2)
|
|
872
1269
|
}), [
|
|
873
1270
|
t,
|
|
874
1271
|
schemas,
|
|
875
1272
|
referenceSchema
|
|
876
1273
|
]);
|
|
877
|
-
const propIsNotType =
|
|
1274
|
+
const propIsNotType = useCallback6((props2) => props2.filter((p) => p.name !== "type"), []);
|
|
878
1275
|
if (!fieldSchema) {
|
|
879
|
-
|
|
1276
|
+
log2.warn("invalid format", {
|
|
880
1277
|
props
|
|
881
1278
|
}, {
|
|
882
1279
|
F: __dxlog_file3,
|
|
883
|
-
L:
|
|
1280
|
+
L: 174,
|
|
884
1281
|
S: void 0,
|
|
885
1282
|
C: (f, a) => f(...a)
|
|
886
1283
|
});
|
|
887
1284
|
return null;
|
|
888
1285
|
}
|
|
889
|
-
return /* @__PURE__ */
|
|
1286
|
+
return /* @__PURE__ */ React12.createElement(Form, {
|
|
890
1287
|
key: field.id,
|
|
891
1288
|
autoFocus: true,
|
|
892
1289
|
values: props,
|
|
@@ -905,30 +1302,29 @@ var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
|
|
|
905
1302
|
};
|
|
906
1303
|
|
|
907
1304
|
// packages/ui/react-ui-form/src/components/ViewEditor/ViewEditor.tsx
|
|
908
|
-
import
|
|
909
|
-
import { AST as
|
|
910
|
-
import { IconButton as
|
|
911
|
-
import { List } from "@dxos/react-ui-list";
|
|
912
|
-
import { ghostHover, inputTextLabel, mx as
|
|
1305
|
+
import React13, { useCallback as useCallback7, useMemo as useMemo8, useState as useState5 } from "react";
|
|
1306
|
+
import { AST as AST4, Format, S as S2 } from "@dxos/echo-schema";
|
|
1307
|
+
import { IconButton as IconButton4, useTranslation as useTranslation6 } from "@dxos/react-ui";
|
|
1308
|
+
import { List as List2 } from "@dxos/react-ui-list";
|
|
1309
|
+
import { ghostHover, inputTextLabel, mx as mx8 } from "@dxos/react-ui-theme";
|
|
913
1310
|
import { FieldSchema, ViewProjection, VIEW_FIELD_LIMIT } from "@dxos/schema";
|
|
914
|
-
import { arrayMove } from "@dxos/util";
|
|
915
1311
|
var grid = "grid grid-cols-[32px_1fr_32px] min-bs-[2.5rem]";
|
|
916
1312
|
var ViewMetaSchema = S2.Struct({
|
|
917
1313
|
name: S2.String.annotations({
|
|
918
|
-
[
|
|
1314
|
+
[AST4.TitleAnnotationId]: "View"
|
|
919
1315
|
}),
|
|
920
|
-
typename: Format.
|
|
921
|
-
[
|
|
1316
|
+
typename: Format.URL.annotations({
|
|
1317
|
+
[AST4.TitleAnnotationId]: "Typename"
|
|
922
1318
|
})
|
|
923
1319
|
}).pipe(S2.mutable);
|
|
924
1320
|
var ViewEditor = ({ classNames, schema, view, registry, readonly, showHeading = false, onTypenameChanged, onDelete }) => {
|
|
925
|
-
const { t } =
|
|
926
|
-
const projection =
|
|
1321
|
+
const { t } = useTranslation6(translationKey);
|
|
1322
|
+
const projection = useMemo8(() => new ViewProjection(schema, view), [
|
|
927
1323
|
schema,
|
|
928
1324
|
view
|
|
929
1325
|
]);
|
|
930
|
-
const [field, setField] =
|
|
931
|
-
const viewValues =
|
|
1326
|
+
const [field, setField] = useState5();
|
|
1327
|
+
const viewValues = useMemo8(() => {
|
|
932
1328
|
return {
|
|
933
1329
|
name: view.name,
|
|
934
1330
|
// TODO(burdon): Need to warn user of possible consequences of editing.
|
|
@@ -938,7 +1334,7 @@ var ViewEditor = ({ classNames, schema, view, registry, readonly, showHeading =
|
|
|
938
1334
|
}, [
|
|
939
1335
|
view
|
|
940
1336
|
]);
|
|
941
|
-
const handleViewUpdate =
|
|
1337
|
+
const handleViewUpdate = useCallback7(({ name, typename }) => {
|
|
942
1338
|
requestAnimationFrame(() => {
|
|
943
1339
|
if (view.name !== name) {
|
|
944
1340
|
view.name = name;
|
|
@@ -952,67 +1348,71 @@ var ViewEditor = ({ classNames, schema, view, registry, readonly, showHeading =
|
|
|
952
1348
|
schema,
|
|
953
1349
|
onTypenameChanged
|
|
954
1350
|
]);
|
|
955
|
-
const handleSelect =
|
|
1351
|
+
const handleSelect = useCallback7((field2) => {
|
|
956
1352
|
setField((f) => f === field2 ? void 0 : field2);
|
|
957
1353
|
}, []);
|
|
958
|
-
const handleAdd =
|
|
1354
|
+
const handleAdd = useCallback7(() => {
|
|
959
1355
|
const field2 = projection.createFieldProjection();
|
|
960
1356
|
setField(field2);
|
|
961
1357
|
}, [
|
|
962
1358
|
view
|
|
963
1359
|
]);
|
|
964
|
-
const handleMove =
|
|
965
|
-
|
|
1360
|
+
const handleMove = useCallback7((fromIndex, toIndex) => {
|
|
1361
|
+
const fields = [
|
|
1362
|
+
...view.fields
|
|
1363
|
+
];
|
|
1364
|
+
const [moved] = fields.splice(fromIndex, 1);
|
|
1365
|
+
fields.splice(toIndex, 0, moved);
|
|
1366
|
+
view.fields = fields;
|
|
966
1367
|
}, [
|
|
967
1368
|
view.fields
|
|
968
1369
|
]);
|
|
969
|
-
const handleClose =
|
|
970
|
-
return /* @__PURE__ */
|
|
1370
|
+
const handleClose = useCallback7(() => setField(void 0), []);
|
|
1371
|
+
return /* @__PURE__ */ React13.createElement("div", {
|
|
971
1372
|
role: "none",
|
|
972
|
-
className:
|
|
973
|
-
}, /* @__PURE__ */
|
|
974
|
-
autoFocus: true,
|
|
1373
|
+
className: mx8("flex flex-col w-full divide-y divide-separator", classNames)
|
|
1374
|
+
}, /* @__PURE__ */ React13.createElement(Form, {
|
|
975
1375
|
autoSave: true,
|
|
976
1376
|
schema: ViewMetaSchema,
|
|
977
1377
|
values: viewValues,
|
|
978
1378
|
onSave: handleViewUpdate
|
|
979
|
-
}), /* @__PURE__ */
|
|
1379
|
+
}), /* @__PURE__ */ React13.createElement("div", null, /* @__PURE__ */ React13.createElement("div", {
|
|
980
1380
|
role: "none",
|
|
981
1381
|
className: "p-2"
|
|
982
|
-
}, /* @__PURE__ */
|
|
983
|
-
className:
|
|
984
|
-
}, t("fields label"))), /* @__PURE__ */
|
|
1382
|
+
}, /* @__PURE__ */ React13.createElement("label", {
|
|
1383
|
+
className: mx8(inputTextLabel)
|
|
1384
|
+
}, t("fields label"))), /* @__PURE__ */ React13.createElement(List2.Root, {
|
|
985
1385
|
items: view.fields,
|
|
986
1386
|
isItem: S2.is(FieldSchema),
|
|
987
1387
|
getId: (field2) => field2.id,
|
|
988
1388
|
onMove: handleMove
|
|
989
|
-
}, ({ items: fields }) => /* @__PURE__ */
|
|
1389
|
+
}, ({ items: fields }) => /* @__PURE__ */ React13.createElement(React13.Fragment, null, showHeading && /* @__PURE__ */ React13.createElement("div", {
|
|
990
1390
|
role: "heading",
|
|
991
1391
|
className: grid
|
|
992
|
-
}, /* @__PURE__ */
|
|
1392
|
+
}, /* @__PURE__ */ React13.createElement("div", null), /* @__PURE__ */ React13.createElement("div", {
|
|
993
1393
|
className: "flex items-center text-sm"
|
|
994
|
-
}, t("field path label"))), /* @__PURE__ */
|
|
1394
|
+
}, t("field path label"))), /* @__PURE__ */ React13.createElement("div", {
|
|
995
1395
|
role: "list",
|
|
996
1396
|
className: "flex flex-col w-full"
|
|
997
|
-
}, fields?.map((field2) => /* @__PURE__ */
|
|
1397
|
+
}, fields?.map((field2) => /* @__PURE__ */ React13.createElement(List2.Item, {
|
|
998
1398
|
key: field2.id,
|
|
999
1399
|
item: field2,
|
|
1000
|
-
classNames:
|
|
1001
|
-
}, /* @__PURE__ */
|
|
1400
|
+
classNames: mx8(grid, ghostHover, "cursor-pointer")
|
|
1401
|
+
}, /* @__PURE__ */ React13.createElement(List2.ItemDragHandle, null), /* @__PURE__ */ React13.createElement(List2.ItemTitle, {
|
|
1002
1402
|
onClick: () => handleSelect(field2)
|
|
1003
|
-
}, field2.path), /* @__PURE__ */
|
|
1403
|
+
}, field2.path), /* @__PURE__ */ React13.createElement(List2.ItemDeleteButton, {
|
|
1004
1404
|
disabled: view.fields.length <= 1,
|
|
1005
1405
|
onClick: () => onDelete(field2.id)
|
|
1006
|
-
}))))))), field && /* @__PURE__ */
|
|
1406
|
+
}))))))), field && /* @__PURE__ */ React13.createElement(FieldEditor, {
|
|
1007
1407
|
key: field.id,
|
|
1008
1408
|
view,
|
|
1009
1409
|
projection,
|
|
1010
1410
|
field,
|
|
1011
1411
|
registry,
|
|
1012
1412
|
onSave: handleClose
|
|
1013
|
-
}), !readonly && !field && /* @__PURE__ */
|
|
1413
|
+
}), !readonly && !field && /* @__PURE__ */ React13.createElement("div", {
|
|
1014
1414
|
className: "flex p-2 justify-center"
|
|
1015
|
-
}, /* @__PURE__ */
|
|
1415
|
+
}, /* @__PURE__ */ React13.createElement(IconButton4, {
|
|
1016
1416
|
icon: "ph--plus--regular",
|
|
1017
1417
|
label: t("button add property"),
|
|
1018
1418
|
onClick: handleAdd,
|
|
@@ -1022,7 +1422,7 @@ var ViewEditor = ({ classNames, schema, view, registry, readonly, showHeading =
|
|
|
1022
1422
|
};
|
|
1023
1423
|
|
|
1024
1424
|
// packages/ui/react-ui-form/src/util/field.ts
|
|
1025
|
-
import { FormatEnum as FormatEnum3, TypeEnum } from "@dxos/echo-schema";
|
|
1425
|
+
import { FormatEnum as FormatEnum3, GeoLocation as GeoLocation2, TypeEnum } from "@dxos/echo-schema";
|
|
1026
1426
|
var parseValue = ({ type, format, value }) => {
|
|
1027
1427
|
if (value === void 0 || value === null || value === "") {
|
|
1028
1428
|
return void 0;
|
|
@@ -1076,6 +1476,26 @@ var parseValue = ({ type, format, value }) => {
|
|
|
1076
1476
|
const date = new Date(value);
|
|
1077
1477
|
return isNaN(date.getTime()) ? null : date;
|
|
1078
1478
|
}
|
|
1479
|
+
case FormatEnum3.GeoPoint: {
|
|
1480
|
+
if (typeof value === "string") {
|
|
1481
|
+
const cleaned = value.replace(/[^0-9.,-]+/g, "");
|
|
1482
|
+
const parts = cleaned.split(",");
|
|
1483
|
+
if (parts.length === 2) {
|
|
1484
|
+
const lat = parseFloat(parts[0]);
|
|
1485
|
+
const long = parseFloat(parts[1]);
|
|
1486
|
+
if (!isNaN(lat) && !isNaN(long)) {
|
|
1487
|
+
return GeoLocation2.toGeoPoint({
|
|
1488
|
+
latitude: lat,
|
|
1489
|
+
longitude: long
|
|
1490
|
+
});
|
|
1491
|
+
}
|
|
1492
|
+
}
|
|
1493
|
+
}
|
|
1494
|
+
return [
|
|
1495
|
+
0,
|
|
1496
|
+
0
|
|
1497
|
+
];
|
|
1498
|
+
}
|
|
1079
1499
|
default: {
|
|
1080
1500
|
return value;
|
|
1081
1501
|
}
|
|
@@ -1134,7 +1554,7 @@ var pathNotUniqueError = (path) => ({
|
|
|
1134
1554
|
});
|
|
1135
1555
|
|
|
1136
1556
|
// packages/ui/react-ui-form/src/util/formatting.ts
|
|
1137
|
-
import { FormatEnum as FormatEnum4, TypeEnum as TypeEnum2 } from "@dxos/echo-schema";
|
|
1557
|
+
import { FormatEnum as FormatEnum4, GeoLocation as GeoLocation3, TypeEnum as TypeEnum2 } from "@dxos/echo-schema";
|
|
1138
1558
|
var formatForDisplay = ({ type, format, value, locale = void 0 }) => {
|
|
1139
1559
|
const formatScalar = (type2) => {
|
|
1140
1560
|
switch (type2) {
|
|
@@ -1187,6 +1607,16 @@ var formatForDisplay = ({ type, format, value, locale = void 0 }) => {
|
|
|
1187
1607
|
return date.toLocaleTimeString(locale);
|
|
1188
1608
|
}
|
|
1189
1609
|
}
|
|
1610
|
+
case FormatEnum4.GeoPoint: {
|
|
1611
|
+
if (value === null || value === void 0) {
|
|
1612
|
+
return "";
|
|
1613
|
+
}
|
|
1614
|
+
if (Array.isArray(value) && value.length >= 2 && value.every(Number.isFinite)) {
|
|
1615
|
+
const { latitude, longitude } = GeoLocation3.fromGeoPoint(value);
|
|
1616
|
+
return `${latitude},${longitude}`;
|
|
1617
|
+
}
|
|
1618
|
+
return String(value);
|
|
1619
|
+
}
|
|
1190
1620
|
default: {
|
|
1191
1621
|
if (value === null || value === "undefined") {
|
|
1192
1622
|
return "";
|
|
@@ -1235,6 +1665,16 @@ var formatForEditing = ({ type, format, value, locale = void 0 }) => {
|
|
|
1235
1665
|
const date = new Date(value);
|
|
1236
1666
|
return date.toISOString().split("T")[1].split(".")[0];
|
|
1237
1667
|
}
|
|
1668
|
+
case FormatEnum4.GeoPoint: {
|
|
1669
|
+
if (value === null || value === void 0) {
|
|
1670
|
+
return "";
|
|
1671
|
+
}
|
|
1672
|
+
if (Array.isArray(value) && value.length >= 2 && value.every(Number.isFinite)) {
|
|
1673
|
+
const { latitude, longitude } = GeoLocation3.fromGeoPoint(value);
|
|
1674
|
+
return `${latitude},${longitude}`;
|
|
1675
|
+
}
|
|
1676
|
+
return String(value);
|
|
1677
|
+
}
|
|
1238
1678
|
default: {
|
|
1239
1679
|
return String(value);
|
|
1240
1680
|
}
|
|
@@ -1242,14 +1682,16 @@ var formatForEditing = ({ type, format, value, locale = void 0 }) => {
|
|
|
1242
1682
|
};
|
|
1243
1683
|
export {
|
|
1244
1684
|
BooleanInput,
|
|
1685
|
+
DeprecatedFormContainer,
|
|
1245
1686
|
DeprecatedFormInput,
|
|
1246
1687
|
FieldEditor,
|
|
1247
1688
|
Form,
|
|
1248
|
-
FormActions,
|
|
1249
1689
|
GeoPointInput,
|
|
1250
1690
|
InputHeader,
|
|
1691
|
+
MarkdownInput,
|
|
1251
1692
|
NumberInput,
|
|
1252
1693
|
SelectInput,
|
|
1694
|
+
SelectOptionInput,
|
|
1253
1695
|
TextInput,
|
|
1254
1696
|
TupleInput,
|
|
1255
1697
|
ViewEditor,
|
|
@@ -1260,6 +1702,7 @@ export {
|
|
|
1260
1702
|
parseValue,
|
|
1261
1703
|
pathNotUniqueError,
|
|
1262
1704
|
translations_default as translations,
|
|
1263
|
-
useForm
|
|
1705
|
+
useForm,
|
|
1706
|
+
useFormValues
|
|
1264
1707
|
};
|
|
1265
1708
|
//# sourceMappingURL=index.mjs.map
|