@dxos/react-ui-form 0.7.5-main.9d2a38b → 0.7.5-main.b19bfc8
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 +971 -558
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node/index.cjs +998 -596
- package/dist/lib/node/index.cjs.map +4 -4
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node-esm/index.mjs +971 -558
- 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 +92 -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 +63 -49
- 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 useMemo6, 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 } 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,21 @@ 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,
|
|
206
|
+
const getFormValue = (path) => {
|
|
207
|
+
return getValue(values, createJsonPath(path));
|
|
350
208
|
};
|
|
351
|
-
const onValueChange = (
|
|
209
|
+
const onValueChange = (path, type, value) => {
|
|
210
|
+
const jsonPath = createJsonPath(path);
|
|
352
211
|
let parsedValue = value;
|
|
353
212
|
try {
|
|
354
213
|
if (type === "number") {
|
|
@@ -357,19 +216,19 @@ var useForm = ({ schema, initialValues, onValuesChanged, onValidate, onValid, on
|
|
|
357
216
|
} catch (err) {
|
|
358
217
|
log.catch(err, void 0, {
|
|
359
218
|
F: __dxlog_file,
|
|
360
|
-
L:
|
|
219
|
+
L: 198,
|
|
361
220
|
S: void 0,
|
|
362
221
|
C: (f, a) => f(...a)
|
|
363
222
|
});
|
|
364
223
|
parsedValue = void 0;
|
|
365
224
|
}
|
|
366
225
|
const newValues = {
|
|
367
|
-
...setValue(values,
|
|
226
|
+
...setValue(values, jsonPath, parsedValue)
|
|
368
227
|
};
|
|
369
228
|
setValues(newValues);
|
|
370
229
|
setChanged((prev) => ({
|
|
371
230
|
...prev,
|
|
372
|
-
[
|
|
231
|
+
[jsonPath]: true
|
|
373
232
|
}));
|
|
374
233
|
onValuesChanged?.(newValues);
|
|
375
234
|
const isValid = validate(newValues);
|
|
@@ -379,15 +238,12 @@ var useForm = ({ schema, initialValues, onValuesChanged, onValidate, onValid, on
|
|
|
379
238
|
});
|
|
380
239
|
}
|
|
381
240
|
};
|
|
382
|
-
const
|
|
383
|
-
const
|
|
241
|
+
const onTouched = useCallback((path) => {
|
|
242
|
+
const jsonPath = createJsonPath(path);
|
|
384
243
|
setTouched((touched2) => ({
|
|
385
244
|
...touched2,
|
|
386
|
-
[
|
|
245
|
+
[jsonPath]: true
|
|
387
246
|
}));
|
|
388
|
-
if (event.relatedTarget?.getAttribute("type") === "submit") {
|
|
389
|
-
setTouched(createKeySet(values, true));
|
|
390
|
-
}
|
|
391
247
|
validate(values);
|
|
392
248
|
}, [
|
|
393
249
|
validate,
|
|
@@ -401,17 +257,18 @@ var useForm = ({ schema, initialValues, onValuesChanged, onValidate, onValid, on
|
|
|
401
257
|
changed,
|
|
402
258
|
canSave,
|
|
403
259
|
handleSave,
|
|
260
|
+
formIsValid,
|
|
404
261
|
// Field utils.
|
|
405
262
|
getStatus,
|
|
406
263
|
getValue: getFormValue,
|
|
407
264
|
onValueChange,
|
|
408
|
-
|
|
265
|
+
onTouched
|
|
409
266
|
};
|
|
410
267
|
};
|
|
411
268
|
var createKeySet = (obj, value) => {
|
|
412
269
|
invariant(obj, void 0, {
|
|
413
270
|
F: __dxlog_file,
|
|
414
|
-
L:
|
|
271
|
+
L: 241,
|
|
415
272
|
S: void 0,
|
|
416
273
|
A: [
|
|
417
274
|
"obj",
|
|
@@ -425,338 +282,847 @@ var createKeySet = (obj, value) => {
|
|
|
425
282
|
};
|
|
426
283
|
var flatMap = (errors) => {
|
|
427
284
|
return errors.reduce((result, { path, message }) => {
|
|
428
|
-
|
|
429
|
-
|
|
285
|
+
const jsonPath = fromEffectValidationPath(path);
|
|
286
|
+
if (!(jsonPath in result)) {
|
|
287
|
+
result[jsonPath] = message;
|
|
430
288
|
}
|
|
431
289
|
return result;
|
|
432
290
|
}, {});
|
|
433
291
|
};
|
|
434
292
|
|
|
435
|
-
// packages/ui/react-ui-form/src/components/Form/
|
|
436
|
-
var
|
|
437
|
-
var
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
293
|
+
// packages/ui/react-ui-form/src/components/Form/FormContext.tsx
|
|
294
|
+
var FormContext = /* @__PURE__ */ createContext(void 0);
|
|
295
|
+
var useFormContext = () => {
|
|
296
|
+
return useContext(FormContext) ?? raise(new Error("Missing FormContext"));
|
|
297
|
+
};
|
|
298
|
+
var useFormValues = (path = []) => {
|
|
299
|
+
const { values: formValues } = useFormContext();
|
|
300
|
+
const jsonPath = createJsonPath2(path);
|
|
301
|
+
return getValue2(formValues, jsonPath);
|
|
302
|
+
};
|
|
303
|
+
var useInputProps = (path = []) => {
|
|
304
|
+
const { getStatus, getValue: getFormValue, onValueChange, onTouched } = useFormContext();
|
|
305
|
+
return {
|
|
306
|
+
getStatus: () => getStatus(path),
|
|
307
|
+
getValue: () => getFormValue(path),
|
|
308
|
+
onValueChange: (type, value) => onValueChange(path, type, value),
|
|
309
|
+
onBlur: () => onTouched(path)
|
|
310
|
+
};
|
|
311
|
+
};
|
|
312
|
+
var FormProvider = ({ children, formRef, autoSave, ...formOptions }) => {
|
|
313
|
+
const form = useForm(formOptions);
|
|
314
|
+
useEffect2(() => {
|
|
315
|
+
if (!formRef?.current) {
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
const handleKeyDown = (event) => {
|
|
319
|
+
const keyIsEnter = event.key === "Enter";
|
|
320
|
+
const modifierUsed = event.ctrlKey || event.altKey || event.metaKey || event.shiftKey;
|
|
321
|
+
const inputIsTextarea = event.target.tagName.toLowerCase() === "textarea";
|
|
322
|
+
const inputOptOut = event.target.hasAttribute("data-no-submit");
|
|
323
|
+
const shouldSubmitRegularInput = !inputIsTextarea && keyIsEnter && !modifierUsed;
|
|
324
|
+
const shouldSubmitTextarea = inputIsTextarea && keyIsEnter && event.metaKey;
|
|
325
|
+
if ((shouldSubmitRegularInput || shouldSubmitTextarea) && !inputOptOut) {
|
|
326
|
+
if (!autoSave && form.canSave) {
|
|
327
|
+
form.handleSave();
|
|
328
|
+
}
|
|
329
|
+
if (autoSave && form.formIsValid) {
|
|
330
|
+
event.target.blur();
|
|
331
|
+
}
|
|
332
|
+
}
|
|
457
333
|
};
|
|
458
|
-
|
|
334
|
+
const formElement = formRef.current;
|
|
335
|
+
formElement.addEventListener("keydown", handleKeyDown);
|
|
336
|
+
return () => formElement.removeEventListener("keydown", handleKeyDown);
|
|
459
337
|
}, [
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
338
|
+
formRef,
|
|
339
|
+
form.canSave,
|
|
340
|
+
form.formIsValid,
|
|
341
|
+
form.handleSave,
|
|
342
|
+
autoSave
|
|
463
343
|
]);
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
344
|
+
return /* @__PURE__ */ React2.createElement(FormContext.Provider, {
|
|
345
|
+
value: form
|
|
346
|
+
}, children);
|
|
347
|
+
};
|
|
348
|
+
|
|
349
|
+
// packages/ui/react-ui-form/src/components/Form/custom/GeoPointInput.tsx
|
|
350
|
+
import React4, { useCallback as useCallback2, useState as useState2, useEffect as useEffect3, useMemo as useMemo2 } from "react";
|
|
351
|
+
import { GeoLocation } from "@dxos/echo-schema";
|
|
352
|
+
import { Input as Input2, useTranslation } from "@dxos/react-ui";
|
|
353
|
+
import { safeParseFloat } from "@dxos/util";
|
|
354
|
+
|
|
355
|
+
// packages/ui/react-ui-form/src/components/Form/Input.tsx
|
|
356
|
+
import React3 from "react";
|
|
357
|
+
import { Icon, Tooltip } from "@dxos/react-ui";
|
|
358
|
+
import { errorText } from "@dxos/react-ui-theme";
|
|
359
|
+
var InputHeader = ({ children, error }) => {
|
|
360
|
+
return /* @__PURE__ */ React3.createElement("div", {
|
|
361
|
+
role: "none",
|
|
362
|
+
className: "flex justify-between items-center mb-1"
|
|
363
|
+
}, children, error && /* @__PURE__ */ React3.createElement(Tooltip.Root, null, /* @__PURE__ */ React3.createElement(Tooltip.Trigger, {
|
|
364
|
+
asChild: true
|
|
365
|
+
}, /* @__PURE__ */ React3.createElement(Icon, {
|
|
366
|
+
icon: "ph--warning--regular",
|
|
367
|
+
size: 4,
|
|
368
|
+
classNames: errorText
|
|
369
|
+
})), /* @__PURE__ */ React3.createElement(Tooltip.Content, {
|
|
370
|
+
side: "bottom"
|
|
371
|
+
}, /* @__PURE__ */ React3.createElement(Tooltip.Arrow, null), error)));
|
|
372
|
+
};
|
|
373
|
+
|
|
374
|
+
// packages/ui/react-ui-form/src/components/Form/custom/GeoPointInput.tsx
|
|
375
|
+
var GeoPointInput = ({ type, label, disabled, getStatus, getValue: getValue3, onValueChange, onBlur }) => {
|
|
376
|
+
const { t } = useTranslation(translationKey);
|
|
377
|
+
const { status, error } = getStatus();
|
|
378
|
+
const geoPoint = useMemo2(() => getValue3() ?? [
|
|
379
|
+
0,
|
|
380
|
+
0
|
|
381
|
+
], [
|
|
382
|
+
getValue3
|
|
383
|
+
]);
|
|
384
|
+
const geoLocation = useMemo2(() => GeoLocation.fromGeoPoint(geoPoint), [
|
|
385
|
+
geoPoint
|
|
386
|
+
]);
|
|
387
|
+
const [longitudeText, setLongitudeText] = useState2(geoLocation.longitude?.toString());
|
|
388
|
+
const [latitudeText, setLatitudeText] = useState2(geoLocation.latitude?.toString());
|
|
389
|
+
useEffect3(() => {
|
|
390
|
+
const location = GeoLocation.fromGeoPoint(geoPoint);
|
|
391
|
+
setLongitudeText(location.longitude.toString());
|
|
392
|
+
setLatitudeText(location.latitude.toString());
|
|
393
|
+
}, [
|
|
394
|
+
geoPoint
|
|
395
|
+
]);
|
|
396
|
+
const handleCoordinateChange = useCallback2((coordinateType, setText) => (event) => {
|
|
397
|
+
const inputText = event.target.value;
|
|
398
|
+
setText(inputText);
|
|
399
|
+
if (inputText !== "" && inputText !== "-") {
|
|
400
|
+
const coord = safeParseFloat(inputText);
|
|
401
|
+
if (coord !== void 0 && !isNaN(coord)) {
|
|
402
|
+
const currentLocation = GeoLocation.fromGeoPoint(getValue3() ?? [
|
|
403
|
+
0,
|
|
404
|
+
0
|
|
405
|
+
]);
|
|
406
|
+
const newLocation = {
|
|
407
|
+
...currentLocation,
|
|
408
|
+
[coordinateType]: coord
|
|
409
|
+
};
|
|
410
|
+
const newValue = GeoLocation.toGeoPoint(newLocation);
|
|
411
|
+
onValueChange(type, newValue);
|
|
412
|
+
}
|
|
474
413
|
}
|
|
475
414
|
}, [
|
|
476
|
-
|
|
415
|
+
getValue3,
|
|
416
|
+
onValueChange,
|
|
417
|
+
type
|
|
477
418
|
]);
|
|
478
|
-
return /* @__PURE__ */
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
},
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
419
|
+
return /* @__PURE__ */ React4.createElement(Input2.Root, {
|
|
420
|
+
validationValence: status
|
|
421
|
+
}, /* @__PURE__ */ React4.createElement(InputHeader, {
|
|
422
|
+
error
|
|
423
|
+
}, /* @__PURE__ */ React4.createElement(Input2.Label, null, label)), /* @__PURE__ */ React4.createElement("div", {
|
|
424
|
+
role: "none",
|
|
425
|
+
className: "grid grid-cols-2 gap-2"
|
|
426
|
+
}, /* @__PURE__ */ React4.createElement(Input2.TextInput, {
|
|
427
|
+
type: "text",
|
|
428
|
+
pattern: "^-?[0-9]*\\.?[0-9]*$",
|
|
429
|
+
disabled,
|
|
430
|
+
placeholder: t("placeholder latitude"),
|
|
431
|
+
value: latitudeText,
|
|
432
|
+
onChange: handleCoordinateChange("latitude", setLatitudeText),
|
|
433
|
+
onBlur
|
|
434
|
+
}), /* @__PURE__ */ React4.createElement(Input2.TextInput, {
|
|
435
|
+
type: "text",
|
|
436
|
+
pattern: "^-?[0-9]*\\.?[0-9]*$",
|
|
437
|
+
disabled,
|
|
438
|
+
placeholder: t("placeholder longitude"),
|
|
439
|
+
value: longitudeText,
|
|
440
|
+
onChange: handleCoordinateChange("longitude", setLongitudeText),
|
|
441
|
+
onBlur
|
|
442
|
+
})));
|
|
443
|
+
};
|
|
444
|
+
|
|
445
|
+
// packages/ui/react-ui-form/src/components/Form/custom/SelectOptionsInput.tsx
|
|
446
|
+
import React5, { useCallback as useCallback3, useEffect as useEffect4, useState as useState3, useRef } from "react";
|
|
447
|
+
import { PublicKey } from "@dxos/keys";
|
|
448
|
+
import { Icon as Icon2, IconButton, Input as Input3, Tag, Toolbar, useTranslation as useTranslation2 } from "@dxos/react-ui";
|
|
449
|
+
import { List } from "@dxos/react-ui-list";
|
|
450
|
+
import { HuePicker } from "@dxos/react-ui-pickers";
|
|
451
|
+
import { hues, mx as mx2 } from "@dxos/react-ui-theme";
|
|
452
|
+
var SelectOptionInput = ({ type, label, disabled, getStatus, getValue: getValue3, onValueChange }) => {
|
|
453
|
+
const [selected, setSelectedId] = useState3(null);
|
|
454
|
+
const [isNewOption, setIsNewOption] = useState3(false);
|
|
455
|
+
const inputRef = useRef(null);
|
|
456
|
+
const { t } = useTranslation2(translationKey);
|
|
457
|
+
const { status, error } = getStatus();
|
|
458
|
+
const options = getValue3();
|
|
459
|
+
useEffect4(() => {
|
|
460
|
+
if (options === void 0) {
|
|
461
|
+
onValueChange(type, []);
|
|
462
|
+
}
|
|
463
|
+
}, [
|
|
464
|
+
options,
|
|
465
|
+
onValueChange,
|
|
466
|
+
type
|
|
467
|
+
]);
|
|
468
|
+
const randomHue = () => {
|
|
469
|
+
const usedHues = new Set(options?.map((option) => option.color) ?? []);
|
|
470
|
+
const unusedHues = hues.filter((hue) => !usedHues.has(hue));
|
|
471
|
+
if (unusedHues.length > 0) {
|
|
472
|
+
return unusedHues[Math.floor(Math.random() * unusedHues.length)];
|
|
473
|
+
}
|
|
474
|
+
const lastThree = new Set(options?.slice(-3).map((option) => option.color) ?? []);
|
|
475
|
+
const availableHues = hues.filter((hue) => !lastThree.has(hue));
|
|
476
|
+
return availableHues[Math.floor(Math.random() * availableHues.length)] ?? hues[Math.floor(Math.random() * hues.length)];
|
|
477
|
+
};
|
|
478
|
+
const handleAdd = useCallback3(() => {
|
|
479
|
+
const newId = PublicKey.random().truncate();
|
|
480
|
+
const newOption = {
|
|
481
|
+
id: newId,
|
|
482
|
+
title: "",
|
|
483
|
+
color: randomHue()
|
|
484
|
+
};
|
|
485
|
+
onValueChange(type, [
|
|
486
|
+
...options ?? [],
|
|
487
|
+
newOption
|
|
488
|
+
]);
|
|
489
|
+
setSelectedId(newId);
|
|
490
|
+
setIsNewOption(true);
|
|
491
|
+
}, [
|
|
492
|
+
options,
|
|
493
|
+
type,
|
|
494
|
+
onValueChange
|
|
495
|
+
]);
|
|
496
|
+
const handleDelete = useCallback3((id) => {
|
|
497
|
+
const newOptions = options?.filter((option) => option.id !== id) ?? [];
|
|
498
|
+
onValueChange(type, newOptions);
|
|
499
|
+
setSelectedId(null);
|
|
500
|
+
}, [
|
|
501
|
+
options,
|
|
502
|
+
type,
|
|
503
|
+
onValueChange
|
|
504
|
+
]);
|
|
505
|
+
const handleMove = useCallback3((from, to) => {
|
|
506
|
+
if (!options) {
|
|
507
|
+
return;
|
|
508
|
+
}
|
|
509
|
+
const newOptions = [
|
|
510
|
+
...options
|
|
487
511
|
];
|
|
488
|
-
const
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
512
|
+
const [removed] = newOptions.splice(from, 1);
|
|
513
|
+
newOptions.splice(to, 0, removed);
|
|
514
|
+
onValueChange(type, newOptions);
|
|
515
|
+
}, [
|
|
516
|
+
options,
|
|
517
|
+
type,
|
|
518
|
+
onValueChange
|
|
519
|
+
]);
|
|
520
|
+
const handleClick = useCallback3((id) => {
|
|
521
|
+
setSelectedId((current) => current === id ? null : id);
|
|
522
|
+
}, []);
|
|
523
|
+
const handleTitleChange = useCallback3((id) => (e) => {
|
|
524
|
+
const newOptions = options?.map((o) => o.id === id ? {
|
|
525
|
+
...o,
|
|
526
|
+
title: e.target.value
|
|
527
|
+
} : o);
|
|
528
|
+
onValueChange(type, newOptions ?? []);
|
|
529
|
+
}, [
|
|
530
|
+
options,
|
|
531
|
+
type,
|
|
532
|
+
onValueChange
|
|
533
|
+
]);
|
|
534
|
+
const handleKeyDown = useCallback3((e) => {
|
|
535
|
+
if (e.key === "Enter") {
|
|
536
|
+
setSelectedId(null);
|
|
509
537
|
}
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
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
|
-
}
|
|
538
|
+
}, []);
|
|
539
|
+
const handleColorChange = useCallback3((id) => (hue) => {
|
|
540
|
+
const newOptions = options?.map((o) => o.id === id ? {
|
|
541
|
+
...o,
|
|
542
|
+
color: hue
|
|
543
|
+
} : o);
|
|
544
|
+
onValueChange(type, newOptions ?? []);
|
|
545
|
+
}, [
|
|
546
|
+
options,
|
|
547
|
+
type,
|
|
548
|
+
onValueChange
|
|
549
|
+
]);
|
|
550
|
+
useEffect4(() => {
|
|
551
|
+
if (selected && isNewOption && inputRef.current) {
|
|
552
|
+
inputRef.current.focus();
|
|
553
|
+
setIsNewOption(false);
|
|
548
554
|
}
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
555
|
+
}, [
|
|
556
|
+
selected,
|
|
557
|
+
isNewOption
|
|
558
|
+
]);
|
|
559
|
+
return /* @__PURE__ */ React5.createElement(Input3.Root, {
|
|
560
|
+
validationValence: status
|
|
561
|
+
}, /* @__PURE__ */ React5.createElement(InputHeader, {
|
|
562
|
+
error
|
|
563
|
+
}, /* @__PURE__ */ React5.createElement(Input3.Label, null, label)), /* @__PURE__ */ React5.createElement("div", {
|
|
564
|
+
role: "none"
|
|
565
|
+
}, options && /* @__PURE__ */ React5.createElement(List.Root, {
|
|
566
|
+
items: options,
|
|
567
|
+
isItem: (item) => true,
|
|
568
|
+
onMove: handleMove
|
|
569
|
+
}, ({ items }) => /* @__PURE__ */ React5.createElement("div", {
|
|
570
|
+
role: "list",
|
|
571
|
+
className: "w-full overflow-auto"
|
|
572
|
+
}, items?.map((item) => /* @__PURE__ */ React5.createElement("div", {
|
|
573
|
+
key: item.id
|
|
574
|
+
}, /* @__PURE__ */ React5.createElement(List.Item, {
|
|
575
|
+
role: "button",
|
|
576
|
+
item,
|
|
577
|
+
classNames: mx2("p-1 plb-2", "flex flex-col", "cursor-pointer", "hover:bg-hoverOverlay"),
|
|
578
|
+
"aria-expanded": selected === item.id
|
|
579
|
+
}, /* @__PURE__ */ React5.createElement("div", {
|
|
580
|
+
className: "flex items-center"
|
|
581
|
+
}, /* @__PURE__ */ React5.createElement(List.ItemDragHandle, null), /* @__PURE__ */ React5.createElement(List.ItemTitle, {
|
|
582
|
+
onClick: () => handleClick(item.id),
|
|
583
|
+
classNames: "flex-1"
|
|
584
|
+
}, /* @__PURE__ */ React5.createElement(Tag, {
|
|
585
|
+
palette: item.color
|
|
586
|
+
}, item.title || "\u200B")), /* @__PURE__ */ React5.createElement(Icon2, {
|
|
587
|
+
icon: selected === item.id ? "ph--caret-down--regular" : "ph--caret-right--regular",
|
|
588
|
+
onClick: () => handleClick(item.id)
|
|
589
|
+
})), selected === item.id && /* @__PURE__ */ React5.createElement("div", {
|
|
590
|
+
className: "mis-4 mbs-2 flex flex-col gap-1"
|
|
591
|
+
}, /* @__PURE__ */ React5.createElement(Input3.Label, {
|
|
592
|
+
classNames: "text-xs"
|
|
593
|
+
}, t("select option label")), /* @__PURE__ */ React5.createElement("div", {
|
|
594
|
+
className: "flex flex-row items-center gap-1"
|
|
595
|
+
}, /* @__PURE__ */ React5.createElement(Input3.TextInput, {
|
|
596
|
+
placeholder: t("select option label placeholder"),
|
|
597
|
+
ref: selected === item.id ? inputRef : void 0,
|
|
598
|
+
value: item.title,
|
|
599
|
+
onChange: handleTitleChange(item.id),
|
|
600
|
+
onKeyDown: handleKeyDown,
|
|
601
|
+
classNames: "flex-1",
|
|
602
|
+
"data-no-submit": true
|
|
603
|
+
}), /* @__PURE__ */ React5.createElement(Toolbar.Root, {
|
|
604
|
+
classNames: "p-0 m-0 !is-auto"
|
|
605
|
+
}, /* @__PURE__ */ React5.createElement(HuePicker, {
|
|
606
|
+
value: item.color,
|
|
607
|
+
onChange: handleColorChange(item.id)
|
|
608
|
+
})), /* @__PURE__ */ React5.createElement(IconButton, {
|
|
609
|
+
icon: "ph--trash--fill",
|
|
610
|
+
iconOnly: true,
|
|
611
|
+
label: t("select option delete"),
|
|
612
|
+
onClick: () => handleDelete(item.id)
|
|
613
|
+
})))))), /* @__PURE__ */ React5.createElement("div", {
|
|
614
|
+
role: "listitem"
|
|
615
|
+
}, /* @__PURE__ */ React5.createElement("div", {
|
|
616
|
+
role: "button",
|
|
617
|
+
className: mx2("p-1 plb-2", "flex flex-col", "cursor-pointer", "hover:bg-hoverOverlay"),
|
|
618
|
+
onClick: handleAdd
|
|
619
|
+
}, /* @__PURE__ */ React5.createElement("div", {
|
|
620
|
+
className: "flex items-center gap-1"
|
|
621
|
+
}, /* @__PURE__ */ React5.createElement(Icon2, {
|
|
622
|
+
icon: "ph--plus--regular"
|
|
623
|
+
}), /* @__PURE__ */ React5.createElement("span", {
|
|
624
|
+
className: "text-sm"
|
|
625
|
+
}, t("select option add")))))))));
|
|
626
|
+
};
|
|
627
|
+
|
|
628
|
+
// packages/ui/react-ui-form/src/components/Form/custom/TupleInput.tsx
|
|
629
|
+
import React6 from "react";
|
|
630
|
+
import { Input as Input4 } from "@dxos/react-ui";
|
|
631
|
+
import { mx as mx3 } from "@dxos/react-ui-theme";
|
|
632
|
+
import { safeParseFloat as safeParseFloat2 } from "@dxos/util";
|
|
633
|
+
var gridCols = [
|
|
634
|
+
"grid-cols-1",
|
|
635
|
+
"grid-cols-2",
|
|
636
|
+
"grid-cols-3",
|
|
637
|
+
"grid-cols-4"
|
|
638
|
+
];
|
|
639
|
+
var TupleInput = ({ binding, type, label, disabled, getStatus, getValue: getValue3, onValueChange, onBlur }) => {
|
|
640
|
+
const { status, error } = getStatus();
|
|
641
|
+
const values = getValue3() ?? {};
|
|
642
|
+
return /* @__PURE__ */ React6.createElement(Input4.Root, {
|
|
643
|
+
validationValence: status
|
|
644
|
+
}, /* @__PURE__ */ React6.createElement(InputHeader, {
|
|
645
|
+
error
|
|
646
|
+
}, /* @__PURE__ */ React6.createElement(Input4.Label, null, label)), /* @__PURE__ */ React6.createElement("div", {
|
|
647
|
+
className: mx3("grid gap-2", gridCols[binding.length - 1])
|
|
648
|
+
}, binding.map((prop) => /* @__PURE__ */ React6.createElement(Input4.TextInput, {
|
|
649
|
+
key: prop,
|
|
650
|
+
type: "number",
|
|
651
|
+
disabled,
|
|
652
|
+
value: values[prop],
|
|
653
|
+
onChange: (event) => onValueChange(type, {
|
|
654
|
+
...values,
|
|
655
|
+
[prop]: safeParseFloat2(event.target.value, 0)
|
|
656
|
+
}),
|
|
657
|
+
onBlur
|
|
658
|
+
}))));
|
|
659
|
+
};
|
|
660
|
+
|
|
661
|
+
// packages/ui/react-ui-form/src/components/Form/Defaults.tsx
|
|
662
|
+
import React7, { useCallback as useCallback4, useEffect as useEffect5, useRef as useRef2 } from "react";
|
|
663
|
+
import { Input as Input5, Select } from "@dxos/react-ui";
|
|
664
|
+
var TextInput = ({ type, label, inputOnly, disabled, placeholder, getStatus, getValue: getValue3, onValueChange, onBlur }) => {
|
|
665
|
+
const { status, error } = getStatus();
|
|
666
|
+
return /* @__PURE__ */ React7.createElement(Input5.Root, {
|
|
667
|
+
validationValence: status
|
|
668
|
+
}, !inputOnly && /* @__PURE__ */ React7.createElement(InputHeader, {
|
|
669
|
+
error
|
|
670
|
+
}, /* @__PURE__ */ React7.createElement(Input5.Label, null, label)), /* @__PURE__ */ React7.createElement(Input5.TextInput, {
|
|
671
|
+
disabled,
|
|
672
|
+
placeholder,
|
|
673
|
+
value: getValue3() ?? "",
|
|
674
|
+
onChange: (event) => onValueChange(type, event.target.value),
|
|
675
|
+
onBlur
|
|
676
|
+
}), inputOnly && /* @__PURE__ */ React7.createElement(Input5.Validation, null, error));
|
|
677
|
+
};
|
|
678
|
+
var NumberInput = ({ type, label, inputOnly, disabled, placeholder, getStatus, getValue: getValue3, onValueChange, onBlur }) => {
|
|
679
|
+
const { status, error } = getStatus();
|
|
680
|
+
return /* @__PURE__ */ React7.createElement(Input5.Root, {
|
|
681
|
+
validationValence: status
|
|
682
|
+
}, !inputOnly && /* @__PURE__ */ React7.createElement(InputHeader, {
|
|
683
|
+
error
|
|
684
|
+
}, /* @__PURE__ */ React7.createElement(Input5.Label, null, label)), /* @__PURE__ */ React7.createElement(Input5.TextInput, {
|
|
685
|
+
type: "number",
|
|
686
|
+
disabled,
|
|
687
|
+
placeholder,
|
|
688
|
+
value: getValue3() ?? 0,
|
|
689
|
+
onChange: (event) => onValueChange(type, event.target.value),
|
|
690
|
+
onBlur
|
|
691
|
+
}), inputOnly && /* @__PURE__ */ React7.createElement(Input5.DescriptionAndValidation, null, error));
|
|
692
|
+
};
|
|
693
|
+
var BooleanInput = ({ type, label, inputOnly, getStatus, getValue: getValue3, onValueChange }) => {
|
|
694
|
+
const { status, error } = getStatus();
|
|
695
|
+
const checked = Boolean(getValue3());
|
|
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.Switch, {
|
|
701
|
+
checked,
|
|
702
|
+
onCheckedChange: (value) => onValueChange(type, value)
|
|
703
|
+
}), inputOnly && /* @__PURE__ */ React7.createElement(Input5.DescriptionAndValidation, null, error));
|
|
704
|
+
};
|
|
705
|
+
var SelectInput = ({ type, label, inputOnly, disabled, placeholder, options, getStatus, getValue: getValue3, onValueChange }) => {
|
|
706
|
+
const { status, error } = getStatus();
|
|
707
|
+
return /* @__PURE__ */ React7.createElement(Input5.Root, {
|
|
708
|
+
validationValence: status
|
|
709
|
+
}, !inputOnly && /* @__PURE__ */ React7.createElement(InputHeader, {
|
|
710
|
+
error
|
|
711
|
+
}, /* @__PURE__ */ React7.createElement(Input5.Label, null, label)), /* @__PURE__ */ React7.createElement(Select.Root, {
|
|
712
|
+
value: getValue3(),
|
|
713
|
+
onValueChange: (value) => onValueChange(type, value)
|
|
714
|
+
}, /* @__PURE__ */ React7.createElement(Select.TriggerButton, {
|
|
715
|
+
classNames: "is-full",
|
|
716
|
+
disabled,
|
|
717
|
+
placeholder
|
|
718
|
+
}), /* @__PURE__ */ React7.createElement(Select.Portal, null, /* @__PURE__ */ React7.createElement(Select.Content, null, /* @__PURE__ */ React7.createElement(Select.Viewport, null, options?.map(({ value, label: label2 }) => (
|
|
719
|
+
// NOTE: Numeric values are converted to and from strings.
|
|
720
|
+
/* @__PURE__ */ React7.createElement(Select.Option, {
|
|
721
|
+
key: String(value),
|
|
722
|
+
value: String(value)
|
|
723
|
+
}, label2 ?? String(value))
|
|
724
|
+
)))))), inputOnly && /* @__PURE__ */ React7.createElement(Input5.DescriptionAndValidation, null, error));
|
|
725
|
+
};
|
|
726
|
+
var MarkdownInput = ({ type, label, inputOnly, disabled, placeholder, getStatus, getValue: getValue3, onValueChange, onBlur }) => {
|
|
727
|
+
const { status, error } = getStatus();
|
|
728
|
+
const textareaRef = useRef2(null);
|
|
729
|
+
const adjustHeight = useCallback4(() => {
|
|
730
|
+
const textarea = textareaRef.current;
|
|
731
|
+
if (textarea) {
|
|
732
|
+
textarea.style.blockSize = "auto";
|
|
733
|
+
textarea.style.blockSize = `${textarea.scrollHeight + 2}px`;
|
|
581
734
|
}
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
735
|
+
}, []);
|
|
736
|
+
useEffect5(() => {
|
|
737
|
+
adjustHeight();
|
|
738
|
+
}, [
|
|
739
|
+
adjustHeight
|
|
740
|
+
]);
|
|
741
|
+
useEffect5(() => {
|
|
742
|
+
adjustHeight();
|
|
743
|
+
}, [
|
|
744
|
+
getValue3(),
|
|
745
|
+
adjustHeight
|
|
746
|
+
]);
|
|
747
|
+
return /* @__PURE__ */ React7.createElement(Input5.Root, {
|
|
748
|
+
validationValence: status
|
|
749
|
+
}, !inputOnly && /* @__PURE__ */ React7.createElement(InputHeader, {
|
|
750
|
+
error
|
|
751
|
+
}, /* @__PURE__ */ React7.createElement(Input5.Label, null, label)), /* @__PURE__ */ React7.createElement(Input5.TextArea, {
|
|
752
|
+
ref: textareaRef,
|
|
753
|
+
disabled,
|
|
754
|
+
placeholder,
|
|
755
|
+
value: getValue3() ?? "",
|
|
756
|
+
classNames: "min-bs-auto max-h-40 overflow-auto",
|
|
757
|
+
onChange: (event) => onValueChange(type, event.target.value),
|
|
758
|
+
onBlur,
|
|
759
|
+
style: {
|
|
760
|
+
resize: "none"
|
|
761
|
+
},
|
|
762
|
+
spellCheck: false
|
|
763
|
+
}), inputOnly && /* @__PURE__ */ React7.createElement(Input5.Validation, null, error));
|
|
601
764
|
};
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
765
|
+
|
|
766
|
+
// packages/ui/react-ui-form/src/components/Form/Form.tsx
|
|
767
|
+
import React11, { useEffect as useEffect6, useMemo as useMemo5, useRef as useRef3 } from "react";
|
|
768
|
+
import { mx as mx7 } from "@dxos/react-ui-theme";
|
|
769
|
+
|
|
770
|
+
// packages/ui/react-ui-form/src/components/Form/FormActions.tsx
|
|
771
|
+
import React8 from "react";
|
|
772
|
+
import { IconButton as IconButton2, useTranslation as useTranslation3 } from "@dxos/react-ui";
|
|
773
|
+
import { mx as mx4 } from "@dxos/react-ui-theme";
|
|
774
|
+
var FormActions = ({ onCancel, readonly }) => {
|
|
775
|
+
const { t } = useTranslation3(translationKey);
|
|
776
|
+
const { canSave, handleSave } = useFormContext();
|
|
777
|
+
return /* @__PURE__ */ React8.createElement("div", {
|
|
778
|
+
role: "none",
|
|
779
|
+
className: "mt-2 flex justify-center"
|
|
780
|
+
}, /* @__PURE__ */ React8.createElement("div", {
|
|
781
|
+
role: "none",
|
|
782
|
+
className: mx4(onCancel && !readonly && "grid grid-cols-2 gap-2")
|
|
783
|
+
}, onCancel && !readonly && /* @__PURE__ */ React8.createElement(IconButton2, {
|
|
784
|
+
"data-testid": "cancel-button",
|
|
785
|
+
icon: "ph--x--regular",
|
|
786
|
+
label: t("button cancel"),
|
|
787
|
+
onClick: onCancel
|
|
788
|
+
}), handleSave && /* @__PURE__ */ React8.createElement(IconButton2, {
|
|
789
|
+
type: "submit",
|
|
790
|
+
"data-testid": "save-button",
|
|
791
|
+
disabled: !canSave,
|
|
792
|
+
icon: "ph--check--regular",
|
|
793
|
+
label: t("button save"),
|
|
794
|
+
onClick: handleSave
|
|
795
|
+
})));
|
|
796
|
+
};
|
|
797
|
+
|
|
798
|
+
// packages/ui/react-ui-form/src/components/Form/FormContent.tsx
|
|
799
|
+
import { pipe as pipe2 } from "effect";
|
|
800
|
+
import { capitalize as capitalize2 } from "effect/String";
|
|
801
|
+
import React10, { useMemo as useMemo4 } from "react";
|
|
802
|
+
import { AST as AST3, S } from "@dxos/echo-schema";
|
|
803
|
+
import { createJsonPath as createJsonPath3, findNode as findNode2, getDiscriminatedType as getDiscriminatedType2, isDiscriminatedUnion as isDiscriminatedUnion2 } from "@dxos/effect";
|
|
804
|
+
import { mx as mx6 } from "@dxos/react-ui-theme";
|
|
805
|
+
import { getSchemaProperties as getSchemaProperties2 } from "@dxos/schema";
|
|
806
|
+
import { isNotFalsy } from "@dxos/util";
|
|
807
|
+
|
|
808
|
+
// packages/ui/react-ui-form/src/components/Form/ArrayField.tsx
|
|
809
|
+
import { pipe } from "effect";
|
|
810
|
+
import { capitalize } from "effect/String";
|
|
811
|
+
import React9, { useCallback as useCallback5, useMemo as useMemo3 } from "react";
|
|
812
|
+
import { AST as AST2 } from "@dxos/echo-schema";
|
|
813
|
+
import { findNode, getDiscriminatedType, isDiscriminatedUnion, SimpleType } from "@dxos/effect";
|
|
814
|
+
import { invariant as invariant2 } from "@dxos/invariant";
|
|
815
|
+
import { IconButton as IconButton3, useTranslation as useTranslation4 } from "@dxos/react-ui";
|
|
816
|
+
import { mx as mx5 } from "@dxos/react-ui-theme";
|
|
817
|
+
import { getSchemaProperties } from "@dxos/schema";
|
|
818
|
+
var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-form/src/components/Form/ArrayField.tsx";
|
|
819
|
+
var padding = "px-2";
|
|
820
|
+
var ArrayField = ({ property, readonly, path, inputProps, Custom, lookupComponent }) => {
|
|
821
|
+
const { t } = useTranslation4(translationKey);
|
|
822
|
+
const { ast, name, type, title } = property;
|
|
823
|
+
const values = useFormValues(path ?? []);
|
|
824
|
+
invariant2(Array.isArray(values), `Values at path ${path?.join(".")} must be an array.`, {
|
|
825
|
+
F: __dxlog_file2,
|
|
826
|
+
L: 37,
|
|
827
|
+
S: void 0,
|
|
828
|
+
A: [
|
|
829
|
+
"Array.isArray(values)",
|
|
830
|
+
"`Values at path ${path?.join('.')} must be an array.`"
|
|
831
|
+
]
|
|
832
|
+
});
|
|
833
|
+
const label = title ?? pipe(name, capitalize);
|
|
834
|
+
const tupleType = findNode(ast, AST2.isTupleType);
|
|
609
835
|
const elementType = tupleType?.rest[0]?.type;
|
|
610
|
-
|
|
611
|
-
const baseNode = findNode(
|
|
612
|
-
const typeLiteral = baseNode ? getDiscriminatedType(baseNode,
|
|
613
|
-
if (typeLiteral) {
|
|
614
|
-
|
|
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
|
-
})));
|
|
836
|
+
const getDefaultObjectValue = (typeNode) => {
|
|
837
|
+
const baseNode = findNode(typeNode, isDiscriminatedUnion);
|
|
838
|
+
const typeLiteral = baseNode ? getDiscriminatedType(baseNode, {}) : findNode(typeNode, AST2.isTypeLiteral);
|
|
839
|
+
if (!typeLiteral) {
|
|
840
|
+
return {};
|
|
669
841
|
}
|
|
670
|
-
return
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
}
|
|
675
|
-
const
|
|
676
|
-
|
|
842
|
+
return Object.fromEntries(getSchemaProperties(typeLiteral, {}).map((prop) => [
|
|
843
|
+
prop.name,
|
|
844
|
+
prop.defaultValue
|
|
845
|
+
]));
|
|
846
|
+
};
|
|
847
|
+
const newValue = useMemo3(() => {
|
|
848
|
+
if (type === "object" && elementType) {
|
|
849
|
+
return getDefaultObjectValue(elementType);
|
|
850
|
+
} else {
|
|
851
|
+
return SimpleType.getDefaultValue(type);
|
|
852
|
+
}
|
|
853
|
+
}, [
|
|
854
|
+
type,
|
|
855
|
+
elementType
|
|
856
|
+
]);
|
|
857
|
+
const handleAdd = useCallback5(() => {
|
|
858
|
+
inputProps.onValueChange(type, [
|
|
859
|
+
...values,
|
|
860
|
+
newValue
|
|
861
|
+
]);
|
|
862
|
+
}, [
|
|
863
|
+
type,
|
|
864
|
+
elementType,
|
|
865
|
+
inputProps,
|
|
866
|
+
newValue,
|
|
867
|
+
values
|
|
868
|
+
]);
|
|
869
|
+
const handleRemove = useCallback5((index) => {
|
|
870
|
+
const newValues = values.filter((_, i) => i !== index);
|
|
871
|
+
inputProps.onValueChange(type, newValues);
|
|
872
|
+
}, [
|
|
873
|
+
type,
|
|
874
|
+
inputProps,
|
|
875
|
+
values
|
|
876
|
+
]);
|
|
877
|
+
if (!elementType) {
|
|
677
878
|
return null;
|
|
678
879
|
}
|
|
679
|
-
return /* @__PURE__ */
|
|
880
|
+
return /* @__PURE__ */ React9.createElement("div", {
|
|
680
881
|
role: "none",
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
}, /* @__PURE__ */ React6.createElement(InputHeader, null, label), /* @__PURE__ */ React6.createElement("div", {
|
|
882
|
+
className: mx5(padding)
|
|
883
|
+
}, /* @__PURE__ */ React9.createElement(InputHeader, null, label), /* @__PURE__ */ React9.createElement("div", {
|
|
684
884
|
role: "none",
|
|
685
885
|
className: "flex flex-col gap-1"
|
|
686
|
-
},
|
|
886
|
+
}, values.map((_value, index) => /* @__PURE__ */ React9.createElement("div", {
|
|
687
887
|
key: index,
|
|
688
888
|
role: "none",
|
|
689
|
-
className: "flex items-
|
|
690
|
-
}, /* @__PURE__ */
|
|
889
|
+
className: "flex items-center gap-1"
|
|
890
|
+
}, /* @__PURE__ */ React9.createElement("div", {
|
|
691
891
|
role: "none",
|
|
692
892
|
className: "flex-1"
|
|
693
|
-
}, /* @__PURE__ */
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
893
|
+
}, /* @__PURE__ */ React9.createElement(FormField, {
|
|
894
|
+
property: {
|
|
895
|
+
...property,
|
|
896
|
+
array: false,
|
|
897
|
+
ast: elementType
|
|
898
|
+
},
|
|
899
|
+
path: [
|
|
900
|
+
...path ?? [],
|
|
901
|
+
index
|
|
902
|
+
],
|
|
903
|
+
readonly,
|
|
904
|
+
inline: true,
|
|
905
|
+
Custom,
|
|
906
|
+
lookupComponent
|
|
907
|
+
})), /* @__PURE__ */ React9.createElement(IconButton3, {
|
|
703
908
|
icon: "ph--trash--regular",
|
|
704
909
|
iconOnly: true,
|
|
705
910
|
label: t("button remove"),
|
|
706
|
-
onClick: () =>
|
|
707
|
-
|
|
708
|
-
inputProps.onValueChange(name, type, newValues);
|
|
709
|
-
}
|
|
710
|
-
})))), /* @__PURE__ */ React6.createElement("div", {
|
|
911
|
+
onClick: () => handleRemove(index)
|
|
912
|
+
})))), /* @__PURE__ */ React9.createElement("div", {
|
|
711
913
|
role: "none",
|
|
712
914
|
className: "flex justify-between items-center plb-1"
|
|
713
|
-
}, /* @__PURE__ */
|
|
915
|
+
}, /* @__PURE__ */ React9.createElement(IconButton3, {
|
|
714
916
|
icon: "ph--plus--regular",
|
|
715
917
|
iconOnly: true,
|
|
716
918
|
label: t("button add"),
|
|
717
|
-
onClick:
|
|
718
|
-
const newValues = [
|
|
719
|
-
...arrayValues,
|
|
720
|
-
SimpleType.getDefaultValue(type)
|
|
721
|
-
];
|
|
722
|
-
inputProps.onValueChange(name, type, newValues);
|
|
723
|
-
}
|
|
919
|
+
onClick: handleAdd
|
|
724
920
|
})));
|
|
725
921
|
};
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
922
|
+
|
|
923
|
+
// packages/ui/react-ui-form/src/components/Form/factory.tsx
|
|
924
|
+
import { FormatEnum } from "@dxos/echo-schema";
|
|
925
|
+
var getInputComponent = (type, format) => {
|
|
926
|
+
switch (format) {
|
|
927
|
+
case FormatEnum.GeoPoint:
|
|
928
|
+
return GeoPointInput;
|
|
929
|
+
case FormatEnum.Markdown:
|
|
930
|
+
return MarkdownInput;
|
|
931
|
+
}
|
|
932
|
+
switch (type) {
|
|
933
|
+
case "string":
|
|
934
|
+
return TextInput;
|
|
935
|
+
case "number":
|
|
936
|
+
return NumberInput;
|
|
937
|
+
case "boolean":
|
|
938
|
+
return BooleanInput;
|
|
939
|
+
}
|
|
940
|
+
};
|
|
941
|
+
|
|
942
|
+
// packages/ui/react-ui-form/src/components/Form/FormContent.tsx
|
|
943
|
+
var FormField = ({ property, path, readonly, inline, lookupComponent, Custom }) => {
|
|
944
|
+
const inputProps = useInputProps(path);
|
|
945
|
+
const { ast, name, type, format, title, description, options, examples, array } = property;
|
|
946
|
+
const label = useMemo4(() => title ?? pipe2(name, capitalize2), [
|
|
947
|
+
title,
|
|
948
|
+
name
|
|
949
|
+
]);
|
|
950
|
+
const placeholder = useMemo4(() => examples?.length ? `Example: "${examples[0]}"` : description, [
|
|
951
|
+
examples,
|
|
952
|
+
description
|
|
953
|
+
]);
|
|
954
|
+
const FoundComponent = lookupComponent?.({
|
|
955
|
+
prop: name,
|
|
956
|
+
schema: S.make(ast),
|
|
957
|
+
inputProps: {
|
|
958
|
+
type,
|
|
959
|
+
format,
|
|
960
|
+
label,
|
|
961
|
+
disabled: readonly,
|
|
962
|
+
placeholder,
|
|
963
|
+
...inputProps
|
|
964
|
+
}
|
|
965
|
+
});
|
|
966
|
+
if (FoundComponent) {
|
|
967
|
+
return /* @__PURE__ */ React10.createElement("div", {
|
|
968
|
+
role: "none"
|
|
969
|
+
}, FoundComponent);
|
|
970
|
+
}
|
|
971
|
+
const jsonPath = createJsonPath3(path ?? []);
|
|
972
|
+
const CustomComponent = Custom?.[jsonPath];
|
|
973
|
+
if (CustomComponent) {
|
|
974
|
+
return /* @__PURE__ */ React10.createElement(CustomComponent, {
|
|
975
|
+
type,
|
|
976
|
+
format,
|
|
977
|
+
label,
|
|
978
|
+
inputOnly: inline,
|
|
979
|
+
placeholder,
|
|
980
|
+
disabled: readonly,
|
|
981
|
+
...inputProps
|
|
982
|
+
});
|
|
983
|
+
}
|
|
984
|
+
if (array) {
|
|
985
|
+
return /* @__PURE__ */ React10.createElement(ArrayField, {
|
|
986
|
+
property,
|
|
987
|
+
path,
|
|
988
|
+
inputProps,
|
|
989
|
+
readonly,
|
|
990
|
+
Custom
|
|
991
|
+
});
|
|
992
|
+
}
|
|
993
|
+
const InputComponent = getInputComponent(type, format);
|
|
994
|
+
if (InputComponent) {
|
|
995
|
+
return /* @__PURE__ */ React10.createElement("div", {
|
|
996
|
+
role: "none"
|
|
997
|
+
}, /* @__PURE__ */ React10.createElement(InputComponent, {
|
|
998
|
+
type,
|
|
999
|
+
format,
|
|
1000
|
+
label,
|
|
1001
|
+
inputOnly: inline,
|
|
1002
|
+
placeholder,
|
|
1003
|
+
disabled: readonly,
|
|
1004
|
+
...inputProps
|
|
1005
|
+
}));
|
|
1006
|
+
}
|
|
1007
|
+
if (options) {
|
|
1008
|
+
return /* @__PURE__ */ React10.createElement("div", {
|
|
1009
|
+
role: "none"
|
|
1010
|
+
}, /* @__PURE__ */ React10.createElement(SelectInput, {
|
|
1011
|
+
type,
|
|
1012
|
+
format,
|
|
1013
|
+
disabled: readonly,
|
|
1014
|
+
inputOnly: inline,
|
|
1015
|
+
label,
|
|
1016
|
+
options: options.map((option) => ({
|
|
1017
|
+
value: option,
|
|
1018
|
+
label: String(option)
|
|
1019
|
+
})),
|
|
1020
|
+
placeholder,
|
|
1021
|
+
...inputProps
|
|
1022
|
+
}));
|
|
1023
|
+
}
|
|
1024
|
+
if (type === "object") {
|
|
1025
|
+
const baseNode = findNode2(ast, isDiscriminatedUnion2);
|
|
1026
|
+
const typeLiteral = baseNode ? getDiscriminatedType2(baseNode, inputProps.getValue()) : findNode2(ast, AST3.isTypeLiteral);
|
|
1027
|
+
if (typeLiteral) {
|
|
1028
|
+
return /* @__PURE__ */ React10.createElement("div", {
|
|
1029
|
+
role: "none"
|
|
1030
|
+
}, !inline && /* @__PURE__ */ React10.createElement("div", null, label), /* @__PURE__ */ React10.createElement(FormFields, {
|
|
1031
|
+
schema: S.make(typeLiteral),
|
|
1032
|
+
path,
|
|
1033
|
+
readonly,
|
|
1034
|
+
Custom
|
|
1035
|
+
}));
|
|
1036
|
+
}
|
|
1037
|
+
}
|
|
1038
|
+
return null;
|
|
1039
|
+
};
|
|
1040
|
+
var FormFields = ({ schema, path, filter, sort, readonly, lookupComponent, Custom }) => {
|
|
1041
|
+
const values = useFormValues(path);
|
|
1042
|
+
const properties = useMemo4(() => {
|
|
1043
|
+
const props = getSchemaProperties2(schema.ast, values);
|
|
1044
|
+
const filtered = filter ? filter(props) : props;
|
|
1045
|
+
return sort ? filtered.sort((a, b) => sort.indexOf(a.name) - sort.indexOf(b.name)) : filtered;
|
|
1046
|
+
}, [
|
|
1047
|
+
schema,
|
|
1048
|
+
values,
|
|
1049
|
+
filter,
|
|
1050
|
+
sort
|
|
1051
|
+
]);
|
|
1052
|
+
return /* @__PURE__ */ React10.createElement("div", {
|
|
1053
|
+
role: "form",
|
|
1054
|
+
className: mx6("flex flex-col w-full gap-2")
|
|
1055
|
+
}, properties.map((property) => {
|
|
1056
|
+
return /* @__PURE__ */ React10.createElement(FormField, {
|
|
1057
|
+
key: property.name,
|
|
1058
|
+
property,
|
|
1059
|
+
path: [
|
|
1060
|
+
...path ?? [],
|
|
1061
|
+
property.name
|
|
1062
|
+
],
|
|
1063
|
+
readonly,
|
|
1064
|
+
lookupComponent,
|
|
1065
|
+
Custom
|
|
1066
|
+
});
|
|
1067
|
+
}).filter(isNotFalsy));
|
|
1068
|
+
};
|
|
1069
|
+
|
|
1070
|
+
// packages/ui/react-ui-form/src/components/Form/Form.tsx
|
|
1071
|
+
var Form = ({ classNames, schema, values: initialValues, path = [], autoFocus, readonly, filter, sort, autoSave, testId, onValuesChanged, onValidate, onSave, onCancel, lookupComponent, Custom }) => {
|
|
1072
|
+
const formRef = useRef3(null);
|
|
1073
|
+
const onValid = useMemo5(() => autoSave ? onSave : void 0, [
|
|
1074
|
+
autoSave,
|
|
1075
|
+
onSave
|
|
1076
|
+
]);
|
|
1077
|
+
useEffect6(() => {
|
|
1078
|
+
if (autoFocus && formRef.current) {
|
|
1079
|
+
const input = formRef.current.querySelector("input");
|
|
1080
|
+
if (input) {
|
|
1081
|
+
input.focus();
|
|
1082
|
+
}
|
|
1083
|
+
}
|
|
1084
|
+
}, [
|
|
1085
|
+
autoFocus
|
|
1086
|
+
]);
|
|
1087
|
+
return /* @__PURE__ */ React11.createElement(FormProvider, {
|
|
1088
|
+
formRef,
|
|
1089
|
+
schema,
|
|
1090
|
+
autoSave,
|
|
1091
|
+
initialValues,
|
|
1092
|
+
onValuesChanged,
|
|
1093
|
+
onValidate,
|
|
1094
|
+
onValid,
|
|
1095
|
+
onSave
|
|
1096
|
+
}, /* @__PURE__ */ React11.createElement("div", {
|
|
1097
|
+
ref: formRef,
|
|
732
1098
|
role: "none",
|
|
733
|
-
className:
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
1099
|
+
className: mx7("p-2", classNames),
|
|
1100
|
+
"data-testid": testId
|
|
1101
|
+
}, /* @__PURE__ */ React11.createElement(FormFields, {
|
|
1102
|
+
schema,
|
|
1103
|
+
path,
|
|
1104
|
+
readonly,
|
|
1105
|
+
filter,
|
|
1106
|
+
sort,
|
|
1107
|
+
lookupComponent,
|
|
1108
|
+
Custom
|
|
1109
|
+
}), (onCancel || onSave) && !autoSave && /* @__PURE__ */ React11.createElement(FormActions, {
|
|
1110
|
+
onCancel,
|
|
1111
|
+
readonly
|
|
746
1112
|
})));
|
|
747
1113
|
};
|
|
748
1114
|
|
|
749
1115
|
// packages/ui/react-ui-form/src/components/FieldEditor/FieldEditor.tsx
|
|
750
1116
|
var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-form/src/components/FieldEditor/FieldEditor.tsx";
|
|
751
1117
|
var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
|
|
752
|
-
const { t } =
|
|
753
|
-
const [props, setProps] =
|
|
754
|
-
|
|
1118
|
+
const { t } = useTranslation5(translationKey);
|
|
1119
|
+
const [props, setProps] = useState4(projection.getFieldProjection(field.id).props);
|
|
1120
|
+
useEffect7(() => setProps(projection.getFieldProjection(field.id).props), [
|
|
755
1121
|
field,
|
|
756
1122
|
projection
|
|
757
1123
|
]);
|
|
758
|
-
const [schemas, setSchemas] =
|
|
759
|
-
|
|
1124
|
+
const [schemas, setSchemas] = useState4([]);
|
|
1125
|
+
useEffect7(() => {
|
|
760
1126
|
if (!registry) {
|
|
761
1127
|
return;
|
|
762
1128
|
}
|
|
@@ -774,17 +1140,17 @@ var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
|
|
|
774
1140
|
}, [
|
|
775
1141
|
registry
|
|
776
1142
|
]);
|
|
777
|
-
const [referenceSchema, setReferenceSchema] =
|
|
778
|
-
|
|
1143
|
+
const [referenceSchema, setReferenceSchema] = useState4();
|
|
1144
|
+
useEffect7(() => {
|
|
779
1145
|
setReferenceSchema(schemas.find((schema) => schema.typename === props?.referenceSchema));
|
|
780
1146
|
}, [
|
|
781
1147
|
schemas,
|
|
782
1148
|
props?.referenceSchema
|
|
783
1149
|
]);
|
|
784
|
-
const [{ fieldSchema }, setFieldSchema] =
|
|
1150
|
+
const [{ fieldSchema }, setFieldSchema] = useState4({
|
|
785
1151
|
fieldSchema: getFormatSchema(props?.format)
|
|
786
1152
|
});
|
|
787
|
-
const handleValuesChanged =
|
|
1153
|
+
const handleValuesChanged = useCallback6((_props) => {
|
|
788
1154
|
setFieldSchema((prev) => {
|
|
789
1155
|
const fieldSchema2 = getFormatSchema(_props.format);
|
|
790
1156
|
if (prev.fieldSchema === fieldSchema2) {
|
|
@@ -812,14 +1178,14 @@ var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
|
|
|
812
1178
|
type
|
|
813
1179
|
};
|
|
814
1180
|
}
|
|
815
|
-
return
|
|
1181
|
+
return _props;
|
|
816
1182
|
});
|
|
817
1183
|
}, [
|
|
818
1184
|
schemas,
|
|
819
1185
|
props.format,
|
|
820
1186
|
props.referenceSchema
|
|
821
1187
|
]);
|
|
822
|
-
const handleValidate =
|
|
1188
|
+
const handleValidate = useCallback6(({ property }) => {
|
|
823
1189
|
if (property && view.fields.find((f) => f.path === property && f.path !== field.path)) {
|
|
824
1190
|
return [
|
|
825
1191
|
{
|
|
@@ -832,7 +1198,7 @@ var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
|
|
|
832
1198
|
view.fields,
|
|
833
1199
|
field
|
|
834
1200
|
]);
|
|
835
|
-
const handleSave =
|
|
1201
|
+
const handleSave = useCallback6((props2) => {
|
|
836
1202
|
projection.setFieldProjection({
|
|
837
1203
|
field,
|
|
838
1204
|
props: props2
|
|
@@ -843,50 +1209,51 @@ var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
|
|
|
843
1209
|
field,
|
|
844
1210
|
onSave
|
|
845
1211
|
]);
|
|
846
|
-
const handleCancel =
|
|
1212
|
+
const handleCancel = useCallback6(() => {
|
|
847
1213
|
requestAnimationFrame(() => onCancel?.());
|
|
848
1214
|
onSave();
|
|
849
1215
|
}, [
|
|
850
1216
|
onSave
|
|
851
1217
|
]);
|
|
852
|
-
const Custom =
|
|
853
|
-
["format"]: (props2) => /* @__PURE__ */
|
|
1218
|
+
const Custom = useMemo6(() => ({
|
|
1219
|
+
["format"]: (props2) => /* @__PURE__ */ React12.createElement(SelectInput, {
|
|
854
1220
|
...props2,
|
|
855
1221
|
options: FormatEnums.filter((value) => value !== FormatEnum2.None).map((value) => ({
|
|
856
1222
|
value,
|
|
857
1223
|
label: t(`format ${value}`)
|
|
858
1224
|
}))
|
|
859
1225
|
}),
|
|
860
|
-
["referenceSchema"]: (props2) => /* @__PURE__ */
|
|
1226
|
+
["referenceSchema"]: (props2) => /* @__PURE__ */ React12.createElement(SelectInput, {
|
|
861
1227
|
...props2,
|
|
862
1228
|
options: schemas.map((schema) => ({
|
|
863
1229
|
value: schema.typename
|
|
864
1230
|
}))
|
|
865
1231
|
}),
|
|
866
|
-
["referencePath"]: (props2) => /* @__PURE__ */
|
|
1232
|
+
["referencePath"]: (props2) => /* @__PURE__ */ React12.createElement(SelectInput, {
|
|
867
1233
|
...props2,
|
|
868
|
-
options: referenceSchema ?
|
|
1234
|
+
options: referenceSchema ? getSchemaProperties3(referenceSchema.ast).sort(sortProperties).map((p) => ({
|
|
869
1235
|
value: p.name
|
|
870
1236
|
})) : []
|
|
871
|
-
})
|
|
1237
|
+
}),
|
|
1238
|
+
["options"]: (props2) => /* @__PURE__ */ React12.createElement(SelectOptionInput, props2)
|
|
872
1239
|
}), [
|
|
873
1240
|
t,
|
|
874
1241
|
schemas,
|
|
875
1242
|
referenceSchema
|
|
876
1243
|
]);
|
|
877
|
-
const propIsNotType =
|
|
1244
|
+
const propIsNotType = useCallback6((props2) => props2.filter((p) => p.name !== "type"), []);
|
|
878
1245
|
if (!fieldSchema) {
|
|
879
|
-
|
|
1246
|
+
log2.warn("invalid format", {
|
|
880
1247
|
props
|
|
881
1248
|
}, {
|
|
882
1249
|
F: __dxlog_file3,
|
|
883
|
-
L:
|
|
1250
|
+
L: 174,
|
|
884
1251
|
S: void 0,
|
|
885
1252
|
C: (f, a) => f(...a)
|
|
886
1253
|
});
|
|
887
1254
|
return null;
|
|
888
1255
|
}
|
|
889
|
-
return /* @__PURE__ */
|
|
1256
|
+
return /* @__PURE__ */ React12.createElement(Form, {
|
|
890
1257
|
key: field.id,
|
|
891
1258
|
autoFocus: true,
|
|
892
1259
|
values: props,
|
|
@@ -905,30 +1272,29 @@ var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
|
|
|
905
1272
|
};
|
|
906
1273
|
|
|
907
1274
|
// 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
|
|
1275
|
+
import React13, { useCallback as useCallback7, useMemo as useMemo7, useState as useState5 } from "react";
|
|
1276
|
+
import { AST as AST4, Format, S as S2 } from "@dxos/echo-schema";
|
|
1277
|
+
import { IconButton as IconButton4, useTranslation as useTranslation6 } from "@dxos/react-ui";
|
|
1278
|
+
import { List as List2 } from "@dxos/react-ui-list";
|
|
1279
|
+
import { ghostHover, inputTextLabel, mx as mx8 } from "@dxos/react-ui-theme";
|
|
913
1280
|
import { FieldSchema, ViewProjection, VIEW_FIELD_LIMIT } from "@dxos/schema";
|
|
914
|
-
import { arrayMove } from "@dxos/util";
|
|
915
1281
|
var grid = "grid grid-cols-[32px_1fr_32px] min-bs-[2.5rem]";
|
|
916
1282
|
var ViewMetaSchema = S2.Struct({
|
|
917
1283
|
name: S2.String.annotations({
|
|
918
|
-
[
|
|
1284
|
+
[AST4.TitleAnnotationId]: "View"
|
|
919
1285
|
}),
|
|
920
|
-
typename: Format.
|
|
921
|
-
[
|
|
1286
|
+
typename: Format.URL.annotations({
|
|
1287
|
+
[AST4.TitleAnnotationId]: "Typename"
|
|
922
1288
|
})
|
|
923
1289
|
}).pipe(S2.mutable);
|
|
924
1290
|
var ViewEditor = ({ classNames, schema, view, registry, readonly, showHeading = false, onTypenameChanged, onDelete }) => {
|
|
925
|
-
const { t } =
|
|
926
|
-
const projection =
|
|
1291
|
+
const { t } = useTranslation6(translationKey);
|
|
1292
|
+
const projection = useMemo7(() => new ViewProjection(schema, view), [
|
|
927
1293
|
schema,
|
|
928
1294
|
view
|
|
929
1295
|
]);
|
|
930
|
-
const [field, setField] =
|
|
931
|
-
const viewValues =
|
|
1296
|
+
const [field, setField] = useState5();
|
|
1297
|
+
const viewValues = useMemo7(() => {
|
|
932
1298
|
return {
|
|
933
1299
|
name: view.name,
|
|
934
1300
|
// TODO(burdon): Need to warn user of possible consequences of editing.
|
|
@@ -938,7 +1304,7 @@ var ViewEditor = ({ classNames, schema, view, registry, readonly, showHeading =
|
|
|
938
1304
|
}, [
|
|
939
1305
|
view
|
|
940
1306
|
]);
|
|
941
|
-
const handleViewUpdate =
|
|
1307
|
+
const handleViewUpdate = useCallback7(({ name, typename }) => {
|
|
942
1308
|
requestAnimationFrame(() => {
|
|
943
1309
|
if (view.name !== name) {
|
|
944
1310
|
view.name = name;
|
|
@@ -952,67 +1318,71 @@ var ViewEditor = ({ classNames, schema, view, registry, readonly, showHeading =
|
|
|
952
1318
|
schema,
|
|
953
1319
|
onTypenameChanged
|
|
954
1320
|
]);
|
|
955
|
-
const handleSelect =
|
|
1321
|
+
const handleSelect = useCallback7((field2) => {
|
|
956
1322
|
setField((f) => f === field2 ? void 0 : field2);
|
|
957
1323
|
}, []);
|
|
958
|
-
const handleAdd =
|
|
1324
|
+
const handleAdd = useCallback7(() => {
|
|
959
1325
|
const field2 = projection.createFieldProjection();
|
|
960
1326
|
setField(field2);
|
|
961
1327
|
}, [
|
|
962
1328
|
view
|
|
963
1329
|
]);
|
|
964
|
-
const handleMove =
|
|
965
|
-
|
|
1330
|
+
const handleMove = useCallback7((fromIndex, toIndex) => {
|
|
1331
|
+
const fields = [
|
|
1332
|
+
...view.fields
|
|
1333
|
+
];
|
|
1334
|
+
const [moved] = fields.splice(fromIndex, 1);
|
|
1335
|
+
fields.splice(toIndex, 0, moved);
|
|
1336
|
+
view.fields = fields;
|
|
966
1337
|
}, [
|
|
967
1338
|
view.fields
|
|
968
1339
|
]);
|
|
969
|
-
const handleClose =
|
|
970
|
-
return /* @__PURE__ */
|
|
1340
|
+
const handleClose = useCallback7(() => setField(void 0), []);
|
|
1341
|
+
return /* @__PURE__ */ React13.createElement("div", {
|
|
971
1342
|
role: "none",
|
|
972
|
-
className:
|
|
973
|
-
}, /* @__PURE__ */
|
|
974
|
-
autoFocus: true,
|
|
1343
|
+
className: mx8("flex flex-col w-full divide-y divide-separator", classNames)
|
|
1344
|
+
}, /* @__PURE__ */ React13.createElement(Form, {
|
|
975
1345
|
autoSave: true,
|
|
976
1346
|
schema: ViewMetaSchema,
|
|
977
1347
|
values: viewValues,
|
|
978
1348
|
onSave: handleViewUpdate
|
|
979
|
-
}), /* @__PURE__ */
|
|
1349
|
+
}), /* @__PURE__ */ React13.createElement("div", null, /* @__PURE__ */ React13.createElement("div", {
|
|
980
1350
|
role: "none",
|
|
981
1351
|
className: "p-2"
|
|
982
|
-
}, /* @__PURE__ */
|
|
983
|
-
className:
|
|
984
|
-
}, t("fields label"))), /* @__PURE__ */
|
|
1352
|
+
}, /* @__PURE__ */ React13.createElement("label", {
|
|
1353
|
+
className: mx8(inputTextLabel)
|
|
1354
|
+
}, t("fields label"))), /* @__PURE__ */ React13.createElement(List2.Root, {
|
|
985
1355
|
items: view.fields,
|
|
986
1356
|
isItem: S2.is(FieldSchema),
|
|
987
1357
|
getId: (field2) => field2.id,
|
|
988
1358
|
onMove: handleMove
|
|
989
|
-
}, ({ items: fields }) => /* @__PURE__ */
|
|
1359
|
+
}, ({ items: fields }) => /* @__PURE__ */ React13.createElement(React13.Fragment, null, showHeading && /* @__PURE__ */ React13.createElement("div", {
|
|
990
1360
|
role: "heading",
|
|
991
1361
|
className: grid
|
|
992
|
-
}, /* @__PURE__ */
|
|
1362
|
+
}, /* @__PURE__ */ React13.createElement("div", null), /* @__PURE__ */ React13.createElement("div", {
|
|
993
1363
|
className: "flex items-center text-sm"
|
|
994
|
-
}, t("field path label"))), /* @__PURE__ */
|
|
1364
|
+
}, t("field path label"))), /* @__PURE__ */ React13.createElement("div", {
|
|
995
1365
|
role: "list",
|
|
996
1366
|
className: "flex flex-col w-full"
|
|
997
|
-
}, fields?.map((field2) => /* @__PURE__ */
|
|
1367
|
+
}, fields?.map((field2) => /* @__PURE__ */ React13.createElement(List2.Item, {
|
|
998
1368
|
key: field2.id,
|
|
999
1369
|
item: field2,
|
|
1000
|
-
classNames:
|
|
1001
|
-
}, /* @__PURE__ */
|
|
1370
|
+
classNames: mx8(grid, ghostHover, "cursor-pointer")
|
|
1371
|
+
}, /* @__PURE__ */ React13.createElement(List2.ItemDragHandle, null), /* @__PURE__ */ React13.createElement(List2.ItemTitle, {
|
|
1002
1372
|
onClick: () => handleSelect(field2)
|
|
1003
|
-
}, field2.path), /* @__PURE__ */
|
|
1373
|
+
}, field2.path), /* @__PURE__ */ React13.createElement(List2.ItemDeleteButton, {
|
|
1004
1374
|
disabled: view.fields.length <= 1,
|
|
1005
1375
|
onClick: () => onDelete(field2.id)
|
|
1006
|
-
}))))))), field && /* @__PURE__ */
|
|
1376
|
+
}))))))), field && /* @__PURE__ */ React13.createElement(FieldEditor, {
|
|
1007
1377
|
key: field.id,
|
|
1008
1378
|
view,
|
|
1009
1379
|
projection,
|
|
1010
1380
|
field,
|
|
1011
1381
|
registry,
|
|
1012
1382
|
onSave: handleClose
|
|
1013
|
-
}), !readonly && !field && /* @__PURE__ */
|
|
1383
|
+
}), !readonly && !field && /* @__PURE__ */ React13.createElement("div", {
|
|
1014
1384
|
className: "flex p-2 justify-center"
|
|
1015
|
-
}, /* @__PURE__ */
|
|
1385
|
+
}, /* @__PURE__ */ React13.createElement(IconButton4, {
|
|
1016
1386
|
icon: "ph--plus--regular",
|
|
1017
1387
|
label: t("button add property"),
|
|
1018
1388
|
onClick: handleAdd,
|
|
@@ -1022,7 +1392,7 @@ var ViewEditor = ({ classNames, schema, view, registry, readonly, showHeading =
|
|
|
1022
1392
|
};
|
|
1023
1393
|
|
|
1024
1394
|
// packages/ui/react-ui-form/src/util/field.ts
|
|
1025
|
-
import { FormatEnum as FormatEnum3, TypeEnum } from "@dxos/echo-schema";
|
|
1395
|
+
import { FormatEnum as FormatEnum3, GeoLocation as GeoLocation2, TypeEnum } from "@dxos/echo-schema";
|
|
1026
1396
|
var parseValue = ({ type, format, value }) => {
|
|
1027
1397
|
if (value === void 0 || value === null || value === "") {
|
|
1028
1398
|
return void 0;
|
|
@@ -1076,6 +1446,26 @@ var parseValue = ({ type, format, value }) => {
|
|
|
1076
1446
|
const date = new Date(value);
|
|
1077
1447
|
return isNaN(date.getTime()) ? null : date;
|
|
1078
1448
|
}
|
|
1449
|
+
case FormatEnum3.GeoPoint: {
|
|
1450
|
+
if (typeof value === "string") {
|
|
1451
|
+
const cleaned = value.replace(/[^0-9.,-]+/g, "");
|
|
1452
|
+
const parts = cleaned.split(",");
|
|
1453
|
+
if (parts.length === 2) {
|
|
1454
|
+
const lat = parseFloat(parts[0]);
|
|
1455
|
+
const long = parseFloat(parts[1]);
|
|
1456
|
+
if (!isNaN(lat) && !isNaN(long)) {
|
|
1457
|
+
return GeoLocation2.toGeoPoint({
|
|
1458
|
+
latitude: lat,
|
|
1459
|
+
longitude: long
|
|
1460
|
+
});
|
|
1461
|
+
}
|
|
1462
|
+
}
|
|
1463
|
+
}
|
|
1464
|
+
return [
|
|
1465
|
+
0,
|
|
1466
|
+
0
|
|
1467
|
+
];
|
|
1468
|
+
}
|
|
1079
1469
|
default: {
|
|
1080
1470
|
return value;
|
|
1081
1471
|
}
|
|
@@ -1134,7 +1524,7 @@ var pathNotUniqueError = (path) => ({
|
|
|
1134
1524
|
});
|
|
1135
1525
|
|
|
1136
1526
|
// packages/ui/react-ui-form/src/util/formatting.ts
|
|
1137
|
-
import { FormatEnum as FormatEnum4, TypeEnum as TypeEnum2 } from "@dxos/echo-schema";
|
|
1527
|
+
import { FormatEnum as FormatEnum4, GeoLocation as GeoLocation3, TypeEnum as TypeEnum2 } from "@dxos/echo-schema";
|
|
1138
1528
|
var formatForDisplay = ({ type, format, value, locale = void 0 }) => {
|
|
1139
1529
|
const formatScalar = (type2) => {
|
|
1140
1530
|
switch (type2) {
|
|
@@ -1187,6 +1577,16 @@ var formatForDisplay = ({ type, format, value, locale = void 0 }) => {
|
|
|
1187
1577
|
return date.toLocaleTimeString(locale);
|
|
1188
1578
|
}
|
|
1189
1579
|
}
|
|
1580
|
+
case FormatEnum4.GeoPoint: {
|
|
1581
|
+
if (value === null || value === void 0) {
|
|
1582
|
+
return "";
|
|
1583
|
+
}
|
|
1584
|
+
if (Array.isArray(value) && value.length >= 2 && value.every(Number.isFinite)) {
|
|
1585
|
+
const { latitude, longitude } = GeoLocation3.fromGeoPoint(value);
|
|
1586
|
+
return `${latitude},${longitude}`;
|
|
1587
|
+
}
|
|
1588
|
+
return String(value);
|
|
1589
|
+
}
|
|
1190
1590
|
default: {
|
|
1191
1591
|
if (value === null || value === "undefined") {
|
|
1192
1592
|
return "";
|
|
@@ -1235,6 +1635,16 @@ var formatForEditing = ({ type, format, value, locale = void 0 }) => {
|
|
|
1235
1635
|
const date = new Date(value);
|
|
1236
1636
|
return date.toISOString().split("T")[1].split(".")[0];
|
|
1237
1637
|
}
|
|
1638
|
+
case FormatEnum4.GeoPoint: {
|
|
1639
|
+
if (value === null || value === void 0) {
|
|
1640
|
+
return "";
|
|
1641
|
+
}
|
|
1642
|
+
if (Array.isArray(value) && value.length >= 2 && value.every(Number.isFinite)) {
|
|
1643
|
+
const { latitude, longitude } = GeoLocation3.fromGeoPoint(value);
|
|
1644
|
+
return `${latitude},${longitude}`;
|
|
1645
|
+
}
|
|
1646
|
+
return String(value);
|
|
1647
|
+
}
|
|
1238
1648
|
default: {
|
|
1239
1649
|
return String(value);
|
|
1240
1650
|
}
|
|
@@ -1242,14 +1652,16 @@ var formatForEditing = ({ type, format, value, locale = void 0 }) => {
|
|
|
1242
1652
|
};
|
|
1243
1653
|
export {
|
|
1244
1654
|
BooleanInput,
|
|
1655
|
+
DeprecatedFormContainer,
|
|
1245
1656
|
DeprecatedFormInput,
|
|
1246
1657
|
FieldEditor,
|
|
1247
1658
|
Form,
|
|
1248
|
-
FormActions,
|
|
1249
1659
|
GeoPointInput,
|
|
1250
1660
|
InputHeader,
|
|
1661
|
+
MarkdownInput,
|
|
1251
1662
|
NumberInput,
|
|
1252
1663
|
SelectInput,
|
|
1664
|
+
SelectOptionInput,
|
|
1253
1665
|
TextInput,
|
|
1254
1666
|
TupleInput,
|
|
1255
1667
|
ViewEditor,
|
|
@@ -1260,6 +1672,7 @@ export {
|
|
|
1260
1672
|
parseValue,
|
|
1261
1673
|
pathNotUniqueError,
|
|
1262
1674
|
translations_default as translations,
|
|
1263
|
-
useForm
|
|
1675
|
+
useForm,
|
|
1676
|
+
useFormValues
|
|
1264
1677
|
};
|
|
1265
1678
|
//# sourceMappingURL=index.mjs.map
|