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