@dxos/react-ui-form 0.7.5-main.9d26e3a → 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 +1020 -571
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node/index.cjs +1046 -608
- package/dist/lib/node/index.cjs.map +4 -4
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node-esm/index.mjs +1020 -571
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/types/src/components/FieldEditor/FieldEditor.d.ts +1 -2
- package/dist/types/src/components/FieldEditor/FieldEditor.d.ts.map +1 -1
- package/dist/types/src/components/Form/ArrayField.d.ts +15 -0
- package/dist/types/src/components/Form/ArrayField.d.ts.map +1 -0
- package/dist/types/src/components/Form/Defaults.d.ts +6 -7
- package/dist/types/src/components/Form/Defaults.d.ts.map +1 -1
- package/dist/types/src/components/Form/Form.d.ts +13 -16
- 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 +2 -2
- package/dist/types/src/components/ViewEditor/ViewEditor.d.ts.map +1 -1
- package/dist/types/src/components/ViewEditor/ViewEditor.stories.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/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +29 -27
- package/src/components/FieldEditor/FieldEditor.stories.tsx +1 -1
- package/src/components/FieldEditor/FieldEditor.tsx +58 -40
- 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 +51 -327
- 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.stories.tsx +25 -4
- package/src/components/ViewEditor/ViewEditor.tsx +16 -8
- 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",
|
|
@@ -423,320 +280,849 @@ var createKeySet = (obj, value) => {
|
|
|
423
280
|
[key]: value
|
|
424
281
|
}), {});
|
|
425
282
|
};
|
|
426
|
-
var flatMap = (errors) => {
|
|
427
|
-
return errors.reduce((result, { path, message }) => {
|
|
428
|
-
|
|
429
|
-
|
|
283
|
+
var flatMap = (errors) => {
|
|
284
|
+
return errors.reduce((result, { path, message }) => {
|
|
285
|
+
const jsonPath = fromEffectValidationPath(path);
|
|
286
|
+
if (!(jsonPath in result)) {
|
|
287
|
+
result[jsonPath] = message;
|
|
288
|
+
}
|
|
289
|
+
return result;
|
|
290
|
+
}, {});
|
|
291
|
+
};
|
|
292
|
+
|
|
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
|
+
}
|
|
333
|
+
};
|
|
334
|
+
const formElement = formRef.current;
|
|
335
|
+
formElement.addEventListener("keydown", handleKeyDown);
|
|
336
|
+
return () => formElement.removeEventListener("keydown", handleKeyDown);
|
|
337
|
+
}, [
|
|
338
|
+
formRef,
|
|
339
|
+
form.canSave,
|
|
340
|
+
form.formIsValid,
|
|
341
|
+
form.handleSave,
|
|
342
|
+
autoSave
|
|
343
|
+
]);
|
|
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
|
+
}
|
|
413
|
+
}
|
|
414
|
+
}, [
|
|
415
|
+
getValue3,
|
|
416
|
+
onValueChange,
|
|
417
|
+
type
|
|
418
|
+
]);
|
|
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
|
|
511
|
+
];
|
|
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);
|
|
537
|
+
}
|
|
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);
|
|
554
|
+
}
|
|
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`;
|
|
430
734
|
}
|
|
431
|
-
|
|
432
|
-
|
|
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));
|
|
433
764
|
};
|
|
434
765
|
|
|
435
766
|
// packages/ui/react-ui-form/src/components/Form/Form.tsx
|
|
436
|
-
|
|
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";
|
|
437
819
|
var padding = "px-2";
|
|
438
|
-
var
|
|
439
|
-
const
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
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
|
+
]
|
|
450
832
|
});
|
|
451
|
-
const
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
833
|
+
const label = title ?? pipe(name, capitalize);
|
|
834
|
+
const tupleType = findNode(ast, AST2.isTupleType);
|
|
835
|
+
const elementType = tupleType?.rest[0]?.type;
|
|
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 {};
|
|
841
|
+
}
|
|
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
|
+
}
|
|
459
853
|
}, [
|
|
460
|
-
|
|
461
|
-
|
|
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,
|
|
462
867
|
values
|
|
463
868
|
]);
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
errors
|
|
468
|
-
}, {
|
|
469
|
-
F: __dxlog_file2,
|
|
470
|
-
L: 99,
|
|
471
|
-
S: void 0,
|
|
472
|
-
C: (f, a) => f(...a)
|
|
473
|
-
});
|
|
474
|
-
}
|
|
869
|
+
const handleRemove = useCallback5((index) => {
|
|
870
|
+
const newValues = values.filter((_, i) => i !== index);
|
|
871
|
+
inputProps.onValueChange(type, newValues);
|
|
475
872
|
}, [
|
|
476
|
-
|
|
873
|
+
type,
|
|
874
|
+
inputProps,
|
|
875
|
+
values
|
|
477
876
|
]);
|
|
478
|
-
|
|
479
|
-
role: "form",
|
|
480
|
-
className: mx2("flex flex-col w-full gap-2 py-2", classNames),
|
|
481
|
-
"data-testid": testId
|
|
482
|
-
}, properties.map((property) => {
|
|
483
|
-
const { ast, name, type, format, title, description, examples, options, array } = property;
|
|
484
|
-
const key = [
|
|
485
|
-
...path,
|
|
486
|
-
name
|
|
487
|
-
];
|
|
488
|
-
const label = title ?? pipe(name, capitalize);
|
|
489
|
-
const placeholder = examples?.length ? `Example: "${examples[0]}"` : description;
|
|
490
|
-
let InputComponent = Custom?.[key.join(".")];
|
|
491
|
-
if (!InputComponent) {
|
|
492
|
-
if (options) {
|
|
493
|
-
return /* @__PURE__ */ React6.createElement("div", {
|
|
494
|
-
key: name,
|
|
495
|
-
role: "none",
|
|
496
|
-
className: padding
|
|
497
|
-
}, /* @__PURE__ */ React6.createElement(SelectInput, {
|
|
498
|
-
type,
|
|
499
|
-
format,
|
|
500
|
-
property: name,
|
|
501
|
-
disabled: readonly,
|
|
502
|
-
label,
|
|
503
|
-
options: options.map((option) => ({
|
|
504
|
-
value: option,
|
|
505
|
-
label: String(option)
|
|
506
|
-
})),
|
|
507
|
-
placeholder,
|
|
508
|
-
...inputProps
|
|
509
|
-
}));
|
|
510
|
-
}
|
|
511
|
-
InputComponent = getInputComponent(type, format);
|
|
512
|
-
if (array) {
|
|
513
|
-
return /* @__PURE__ */ React6.createElement(ArrayField, {
|
|
514
|
-
key: name,
|
|
515
|
-
name,
|
|
516
|
-
type,
|
|
517
|
-
array: true,
|
|
518
|
-
label,
|
|
519
|
-
ast,
|
|
520
|
-
values,
|
|
521
|
-
format,
|
|
522
|
-
readonly,
|
|
523
|
-
placeholder,
|
|
524
|
-
inputProps,
|
|
525
|
-
Custom
|
|
526
|
-
});
|
|
527
|
-
}
|
|
528
|
-
}
|
|
529
|
-
if (!InputComponent) {
|
|
530
|
-
if (type === "object") {
|
|
531
|
-
const baseNode = findNode(ast, isDiscriminatedUnion);
|
|
532
|
-
const typeLiteral = baseNode ? getDiscriminatedType(baseNode, values[name]) : findNode(ast, AST.isTypeLiteral);
|
|
533
|
-
if (typeLiteral) {
|
|
534
|
-
const schema2 = S.make(typeLiteral);
|
|
535
|
-
return /* @__PURE__ */ React6.createElement("div", {
|
|
536
|
-
key: name,
|
|
537
|
-
role: "none"
|
|
538
|
-
}, /* @__PURE__ */ React6.createElement("div", {
|
|
539
|
-
className: padding
|
|
540
|
-
}, label), /* @__PURE__ */ React6.createElement(Form, {
|
|
541
|
-
schema: schema2,
|
|
542
|
-
path: key,
|
|
543
|
-
values: values[name] ?? {},
|
|
544
|
-
onValuesChanged: (childValues) => {
|
|
545
|
-
inputProps.onValueChange(name, "object", childValues);
|
|
546
|
-
},
|
|
547
|
-
Custom
|
|
548
|
-
}));
|
|
549
|
-
}
|
|
550
|
-
}
|
|
551
|
-
log2("no renderer for property", {
|
|
552
|
-
name,
|
|
553
|
-
type
|
|
554
|
-
}, {
|
|
555
|
-
F: __dxlog_file2,
|
|
556
|
-
L: 184,
|
|
557
|
-
S: void 0,
|
|
558
|
-
C: (f, a) => f(...a)
|
|
559
|
-
});
|
|
560
|
-
return null;
|
|
561
|
-
}
|
|
562
|
-
return /* @__PURE__ */ React6.createElement("div", {
|
|
563
|
-
key: name,
|
|
564
|
-
role: "none",
|
|
565
|
-
className: padding
|
|
566
|
-
}, /* @__PURE__ */ React6.createElement(InputComponent, {
|
|
567
|
-
type,
|
|
568
|
-
format,
|
|
569
|
-
property: name,
|
|
570
|
-
disabled: readonly,
|
|
571
|
-
label,
|
|
572
|
-
placeholder,
|
|
573
|
-
...inputProps
|
|
574
|
-
}));
|
|
575
|
-
}).filter(isNotFalsy), (onCancel || onSave) && !autoSave && /* @__PURE__ */ React6.createElement(FormActions, {
|
|
576
|
-
onCancel,
|
|
577
|
-
onSubmit: handleSave,
|
|
578
|
-
canSubmit: canSave,
|
|
579
|
-
readonly
|
|
580
|
-
}));
|
|
581
|
-
};
|
|
582
|
-
var ArrayField = ({ name, type, label, ast, values, format, readonly, placeholder, inputProps, Custom }) => {
|
|
583
|
-
const { t } = useTranslation2(translationKey);
|
|
584
|
-
const arrayValues = values[name] ?? [];
|
|
585
|
-
const key = [
|
|
586
|
-
name
|
|
587
|
-
];
|
|
588
|
-
const tupleType = findNode(ast, AST.isTupleType);
|
|
589
|
-
const elementType = tupleType?.rest[0]?.type;
|
|
590
|
-
if (type === "object" && elementType) {
|
|
591
|
-
const baseNode = findNode(elementType, isDiscriminatedUnion);
|
|
592
|
-
const typeLiteral = baseNode ? getDiscriminatedType(baseNode, values[name]) : findNode(elementType, AST.isTypeLiteral);
|
|
593
|
-
if (typeLiteral) {
|
|
594
|
-
const schema = S.make(typeLiteral);
|
|
595
|
-
return /* @__PURE__ */ React6.createElement("div", {
|
|
596
|
-
key: name,
|
|
597
|
-
role: "none",
|
|
598
|
-
className: mx2(padding)
|
|
599
|
-
}, /* @__PURE__ */ React6.createElement(InputHeader, null, label), /* @__PURE__ */ React6.createElement("div", {
|
|
600
|
-
role: "none",
|
|
601
|
-
className: "flex flex-col gap-1"
|
|
602
|
-
}, arrayValues.map((value, index) => {
|
|
603
|
-
return /* @__PURE__ */ React6.createElement("div", {
|
|
604
|
-
key: index,
|
|
605
|
-
role: "none",
|
|
606
|
-
className: "flex items-center gap-1"
|
|
607
|
-
}, /* @__PURE__ */ React6.createElement("div", {
|
|
608
|
-
role: "none",
|
|
609
|
-
className: "flex-1"
|
|
610
|
-
}, /* @__PURE__ */ React6.createElement(Form, {
|
|
611
|
-
schema,
|
|
612
|
-
path: [
|
|
613
|
-
...key,
|
|
614
|
-
`[${index}]`
|
|
615
|
-
],
|
|
616
|
-
values: value,
|
|
617
|
-
onValuesChanged: (childValues) => {
|
|
618
|
-
const newValues = [
|
|
619
|
-
...arrayValues
|
|
620
|
-
];
|
|
621
|
-
newValues[index] = childValues;
|
|
622
|
-
inputProps.onValueChange(name, "object", newValues);
|
|
623
|
-
},
|
|
624
|
-
Custom
|
|
625
|
-
})), /* @__PURE__ */ React6.createElement(IconButton, {
|
|
626
|
-
icon: "ph--trash--regular",
|
|
627
|
-
iconOnly: true,
|
|
628
|
-
label: t("button remove"),
|
|
629
|
-
onClick: () => {
|
|
630
|
-
const newValues = arrayValues.filter((_, i) => i !== index);
|
|
631
|
-
inputProps.onValueChange(name, type, newValues);
|
|
632
|
-
}
|
|
633
|
-
}));
|
|
634
|
-
})), /* @__PURE__ */ React6.createElement("div", {
|
|
635
|
-
role: "none",
|
|
636
|
-
className: "flex justify-between items-center plb-1"
|
|
637
|
-
}, /* @__PURE__ */ React6.createElement(IconButton, {
|
|
638
|
-
icon: "ph--plus--regular",
|
|
639
|
-
iconOnly: true,
|
|
640
|
-
label: t("button add"),
|
|
641
|
-
onClick: () => {
|
|
642
|
-
const newValues = [
|
|
643
|
-
...arrayValues,
|
|
644
|
-
{}
|
|
645
|
-
];
|
|
646
|
-
inputProps.onValueChange(name, type, newValues);
|
|
647
|
-
}
|
|
648
|
-
})));
|
|
649
|
-
}
|
|
650
|
-
return /* @__PURE__ */ React6.createElement("div", {
|
|
651
|
-
key: name,
|
|
652
|
-
role: "none"
|
|
653
|
-
}, "Nested form not supported in arrays, yet.");
|
|
654
|
-
}
|
|
655
|
-
const InputComponent = getInputComponent(type, format);
|
|
656
|
-
if (!InputComponent) {
|
|
877
|
+
if (!elementType) {
|
|
657
878
|
return null;
|
|
658
879
|
}
|
|
659
|
-
return /* @__PURE__ */
|
|
880
|
+
return /* @__PURE__ */ React9.createElement("div", {
|
|
660
881
|
role: "none",
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
}, /* @__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", {
|
|
664
884
|
role: "none",
|
|
665
885
|
className: "flex flex-col gap-1"
|
|
666
|
-
},
|
|
886
|
+
}, values.map((_value, index) => /* @__PURE__ */ React9.createElement("div", {
|
|
667
887
|
key: index,
|
|
668
888
|
role: "none",
|
|
669
|
-
className: "flex items-
|
|
670
|
-
}, /* @__PURE__ */
|
|
889
|
+
className: "flex items-center gap-1"
|
|
890
|
+
}, /* @__PURE__ */ React9.createElement("div", {
|
|
671
891
|
role: "none",
|
|
672
892
|
className: "flex-1"
|
|
673
|
-
}, /* @__PURE__ */
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
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, {
|
|
683
908
|
icon: "ph--trash--regular",
|
|
684
909
|
iconOnly: true,
|
|
685
910
|
label: t("button remove"),
|
|
686
|
-
onClick: () =>
|
|
687
|
-
|
|
688
|
-
inputProps.onValueChange(name, type, newValues);
|
|
689
|
-
}
|
|
690
|
-
})))), /* @__PURE__ */ React6.createElement("div", {
|
|
911
|
+
onClick: () => handleRemove(index)
|
|
912
|
+
})))), /* @__PURE__ */ React9.createElement("div", {
|
|
691
913
|
role: "none",
|
|
692
914
|
className: "flex justify-between items-center plb-1"
|
|
693
|
-
}, /* @__PURE__ */
|
|
915
|
+
}, /* @__PURE__ */ React9.createElement(IconButton3, {
|
|
694
916
|
icon: "ph--plus--regular",
|
|
695
917
|
iconOnly: true,
|
|
696
918
|
label: t("button add"),
|
|
697
|
-
onClick:
|
|
698
|
-
const newValues = [
|
|
699
|
-
...arrayValues,
|
|
700
|
-
SimpleType.getDefaultValue(type)
|
|
701
|
-
];
|
|
702
|
-
inputProps.onValueChange(name, type, newValues);
|
|
703
|
-
}
|
|
919
|
+
onClick: handleAdd
|
|
704
920
|
})));
|
|
705
921
|
};
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
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,
|
|
712
1098
|
role: "none",
|
|
713
|
-
className:
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
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
|
|
726
1112
|
})));
|
|
727
1113
|
};
|
|
728
1114
|
|
|
729
1115
|
// packages/ui/react-ui-form/src/components/FieldEditor/FieldEditor.tsx
|
|
730
1116
|
var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-form/src/components/FieldEditor/FieldEditor.tsx";
|
|
731
1117
|
var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
|
|
732
|
-
const { t } =
|
|
733
|
-
const [props, setProps] =
|
|
734
|
-
|
|
1118
|
+
const { t } = useTranslation5(translationKey);
|
|
1119
|
+
const [props, setProps] = useState4(projection.getFieldProjection(field.id).props);
|
|
1120
|
+
useEffect7(() => setProps(projection.getFieldProjection(field.id).props), [
|
|
735
1121
|
field,
|
|
736
1122
|
projection
|
|
737
1123
|
]);
|
|
738
|
-
const [schemas, setSchemas] =
|
|
739
|
-
|
|
1124
|
+
const [schemas, setSchemas] = useState4([]);
|
|
1125
|
+
useEffect7(() => {
|
|
740
1126
|
if (!registry) {
|
|
741
1127
|
return;
|
|
742
1128
|
}
|
|
@@ -754,17 +1140,17 @@ var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
|
|
|
754
1140
|
}, [
|
|
755
1141
|
registry
|
|
756
1142
|
]);
|
|
757
|
-
const [
|
|
758
|
-
|
|
759
|
-
|
|
1143
|
+
const [referenceSchema, setReferenceSchema] = useState4();
|
|
1144
|
+
useEffect7(() => {
|
|
1145
|
+
setReferenceSchema(schemas.find((schema) => schema.typename === props?.referenceSchema));
|
|
760
1146
|
}, [
|
|
761
1147
|
schemas,
|
|
762
1148
|
props?.referenceSchema
|
|
763
1149
|
]);
|
|
764
|
-
const [{ fieldSchema }, setFieldSchema] =
|
|
1150
|
+
const [{ fieldSchema }, setFieldSchema] = useState4({
|
|
765
1151
|
fieldSchema: getFormatSchema(props?.format)
|
|
766
1152
|
});
|
|
767
|
-
const handleValuesChanged =
|
|
1153
|
+
const handleValuesChanged = useCallback6((_props) => {
|
|
768
1154
|
setFieldSchema((prev) => {
|
|
769
1155
|
const fieldSchema2 = getFormatSchema(_props.format);
|
|
770
1156
|
if (prev.fieldSchema === fieldSchema2) {
|
|
@@ -774,9 +1160,15 @@ var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
|
|
|
774
1160
|
fieldSchema: fieldSchema2
|
|
775
1161
|
};
|
|
776
1162
|
});
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
1163
|
+
setReferenceSchema((prev) => {
|
|
1164
|
+
if (_props.referenceSchema !== prev?.typename) {
|
|
1165
|
+
const newSchema = schemas.find((schema) => schema.typename === _props.referenceSchema);
|
|
1166
|
+
if (newSchema) {
|
|
1167
|
+
return newSchema;
|
|
1168
|
+
}
|
|
1169
|
+
}
|
|
1170
|
+
return prev;
|
|
1171
|
+
});
|
|
780
1172
|
setProps((props2) => {
|
|
781
1173
|
const type = formatToType[_props.format];
|
|
782
1174
|
if (props2.type !== type) {
|
|
@@ -786,14 +1178,14 @@ var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
|
|
|
786
1178
|
type
|
|
787
1179
|
};
|
|
788
1180
|
}
|
|
789
|
-
return
|
|
1181
|
+
return _props;
|
|
790
1182
|
});
|
|
791
1183
|
}, [
|
|
792
1184
|
schemas,
|
|
793
1185
|
props.format,
|
|
794
1186
|
props.referenceSchema
|
|
795
1187
|
]);
|
|
796
|
-
const handleValidate =
|
|
1188
|
+
const handleValidate = useCallback6(({ property }) => {
|
|
797
1189
|
if (property && view.fields.find((f) => f.path === property && f.path !== field.path)) {
|
|
798
1190
|
return [
|
|
799
1191
|
{
|
|
@@ -806,7 +1198,7 @@ var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
|
|
|
806
1198
|
view.fields,
|
|
807
1199
|
field
|
|
808
1200
|
]);
|
|
809
|
-
const handleSave =
|
|
1201
|
+
const handleSave = useCallback6((props2) => {
|
|
810
1202
|
projection.setFieldProjection({
|
|
811
1203
|
field,
|
|
812
1204
|
props: props2
|
|
@@ -817,29 +1209,56 @@ var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
|
|
|
817
1209
|
field,
|
|
818
1210
|
onSave
|
|
819
1211
|
]);
|
|
820
|
-
const handleCancel =
|
|
1212
|
+
const handleCancel = useCallback6(() => {
|
|
821
1213
|
requestAnimationFrame(() => onCancel?.());
|
|
822
1214
|
onSave();
|
|
823
1215
|
}, [
|
|
824
1216
|
onSave
|
|
825
1217
|
]);
|
|
1218
|
+
const Custom = useMemo6(() => ({
|
|
1219
|
+
["format"]: (props2) => /* @__PURE__ */ React12.createElement(SelectInput, {
|
|
1220
|
+
...props2,
|
|
1221
|
+
options: FormatEnums.filter((value) => value !== FormatEnum2.None).map((value) => ({
|
|
1222
|
+
value,
|
|
1223
|
+
label: t(`format ${value}`)
|
|
1224
|
+
}))
|
|
1225
|
+
}),
|
|
1226
|
+
["referenceSchema"]: (props2) => /* @__PURE__ */ React12.createElement(SelectInput, {
|
|
1227
|
+
...props2,
|
|
1228
|
+
options: schemas.map((schema) => ({
|
|
1229
|
+
value: schema.typename
|
|
1230
|
+
}))
|
|
1231
|
+
}),
|
|
1232
|
+
["referencePath"]: (props2) => /* @__PURE__ */ React12.createElement(SelectInput, {
|
|
1233
|
+
...props2,
|
|
1234
|
+
options: referenceSchema ? getSchemaProperties3(referenceSchema.ast).sort(sortProperties).map((p) => ({
|
|
1235
|
+
value: p.name
|
|
1236
|
+
})) : []
|
|
1237
|
+
}),
|
|
1238
|
+
["options"]: (props2) => /* @__PURE__ */ React12.createElement(SelectOptionInput, props2)
|
|
1239
|
+
}), [
|
|
1240
|
+
t,
|
|
1241
|
+
schemas,
|
|
1242
|
+
referenceSchema
|
|
1243
|
+
]);
|
|
1244
|
+
const propIsNotType = useCallback6((props2) => props2.filter((p) => p.name !== "type"), []);
|
|
826
1245
|
if (!fieldSchema) {
|
|
827
|
-
|
|
1246
|
+
log2.warn("invalid format", {
|
|
828
1247
|
props
|
|
829
1248
|
}, {
|
|
830
1249
|
F: __dxlog_file3,
|
|
831
|
-
L:
|
|
1250
|
+
L: 174,
|
|
832
1251
|
S: void 0,
|
|
833
1252
|
C: (f, a) => f(...a)
|
|
834
1253
|
});
|
|
835
1254
|
return null;
|
|
836
1255
|
}
|
|
837
|
-
return /* @__PURE__ */
|
|
1256
|
+
return /* @__PURE__ */ React12.createElement(Form, {
|
|
838
1257
|
key: field.id,
|
|
839
1258
|
autoFocus: true,
|
|
840
1259
|
values: props,
|
|
841
1260
|
schema: fieldSchema,
|
|
842
|
-
filter:
|
|
1261
|
+
filter: propIsNotType,
|
|
843
1262
|
sort: [
|
|
844
1263
|
"property",
|
|
845
1264
|
"format"
|
|
@@ -848,55 +1267,34 @@ var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
|
|
|
848
1267
|
onValidate: handleValidate,
|
|
849
1268
|
onSave: handleSave,
|
|
850
1269
|
onCancel: handleCancel,
|
|
851
|
-
Custom
|
|
852
|
-
["format"]: (props2) => /* @__PURE__ */ React7.createElement(SelectInput, {
|
|
853
|
-
...props2,
|
|
854
|
-
options: FormatEnums.filter((value) => value !== FormatEnum2.None).map((value) => ({
|
|
855
|
-
value,
|
|
856
|
-
label: t(`format ${value}`)
|
|
857
|
-
}))
|
|
858
|
-
}),
|
|
859
|
-
["referenceSchema"]: (props2) => /* @__PURE__ */ React7.createElement(SelectInput, {
|
|
860
|
-
...props2,
|
|
861
|
-
options: schemas.map((schema2) => ({
|
|
862
|
-
value: schema2.typename
|
|
863
|
-
}))
|
|
864
|
-
}),
|
|
865
|
-
["referencePath"]: (props2) => /* @__PURE__ */ React7.createElement(SelectInput, {
|
|
866
|
-
...props2,
|
|
867
|
-
options: schema ? getSchemaProperties2(schema.ast).sort(sortProperties).map((p) => ({
|
|
868
|
-
value: p.name
|
|
869
|
-
})) : []
|
|
870
|
-
})
|
|
871
|
-
}
|
|
1270
|
+
Custom
|
|
872
1271
|
});
|
|
873
1272
|
};
|
|
874
1273
|
|
|
875
1274
|
// packages/ui/react-ui-form/src/components/ViewEditor/ViewEditor.tsx
|
|
876
|
-
import
|
|
877
|
-
import { AST as
|
|
878
|
-
import { IconButton as
|
|
879
|
-
import { List } from "@dxos/react-ui-list";
|
|
880
|
-
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";
|
|
881
1280
|
import { FieldSchema, ViewProjection, VIEW_FIELD_LIMIT } from "@dxos/schema";
|
|
882
|
-
import { arrayMove } from "@dxos/util";
|
|
883
1281
|
var grid = "grid grid-cols-[32px_1fr_32px] min-bs-[2.5rem]";
|
|
884
1282
|
var ViewMetaSchema = S2.Struct({
|
|
885
1283
|
name: S2.String.annotations({
|
|
886
|
-
[
|
|
1284
|
+
[AST4.TitleAnnotationId]: "View"
|
|
887
1285
|
}),
|
|
888
|
-
typename: Format.
|
|
889
|
-
[
|
|
1286
|
+
typename: Format.URL.annotations({
|
|
1287
|
+
[AST4.TitleAnnotationId]: "Typename"
|
|
890
1288
|
})
|
|
891
1289
|
}).pipe(S2.mutable);
|
|
892
|
-
var ViewEditor = ({ classNames, schema, view, registry, readonly, showHeading = false, onDelete }) => {
|
|
893
|
-
const { t } =
|
|
894
|
-
const projection =
|
|
1290
|
+
var ViewEditor = ({ classNames, schema, view, registry, readonly, showHeading = false, onTypenameChanged, onDelete }) => {
|
|
1291
|
+
const { t } = useTranslation6(translationKey);
|
|
1292
|
+
const projection = useMemo7(() => new ViewProjection(schema, view), [
|
|
895
1293
|
schema,
|
|
896
1294
|
view
|
|
897
1295
|
]);
|
|
898
|
-
const [field, setField] =
|
|
899
|
-
const viewValues =
|
|
1296
|
+
const [field, setField] = useState5();
|
|
1297
|
+
const viewValues = useMemo7(() => {
|
|
900
1298
|
return {
|
|
901
1299
|
name: view.name,
|
|
902
1300
|
// TODO(burdon): Need to warn user of possible consequences of editing.
|
|
@@ -906,77 +1304,85 @@ var ViewEditor = ({ classNames, schema, view, registry, readonly, showHeading =
|
|
|
906
1304
|
}, [
|
|
907
1305
|
view
|
|
908
1306
|
]);
|
|
909
|
-
const handleViewUpdate =
|
|
1307
|
+
const handleViewUpdate = useCallback7(({ name, typename }) => {
|
|
910
1308
|
requestAnimationFrame(() => {
|
|
911
|
-
view.name
|
|
912
|
-
|
|
913
|
-
|
|
1309
|
+
if (view.name !== name) {
|
|
1310
|
+
view.name = name;
|
|
1311
|
+
}
|
|
1312
|
+
if (view.query.type !== typename) {
|
|
1313
|
+
onTypenameChanged(typename);
|
|
1314
|
+
}
|
|
914
1315
|
});
|
|
915
1316
|
}, [
|
|
916
1317
|
view,
|
|
917
|
-
schema
|
|
1318
|
+
schema,
|
|
1319
|
+
onTypenameChanged
|
|
918
1320
|
]);
|
|
919
|
-
const handleSelect =
|
|
1321
|
+
const handleSelect = useCallback7((field2) => {
|
|
920
1322
|
setField((f) => f === field2 ? void 0 : field2);
|
|
921
1323
|
}, []);
|
|
922
|
-
const handleAdd =
|
|
1324
|
+
const handleAdd = useCallback7(() => {
|
|
923
1325
|
const field2 = projection.createFieldProjection();
|
|
924
1326
|
setField(field2);
|
|
925
1327
|
}, [
|
|
926
1328
|
view
|
|
927
1329
|
]);
|
|
928
|
-
const handleMove =
|
|
929
|
-
|
|
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;
|
|
930
1337
|
}, [
|
|
931
1338
|
view.fields
|
|
932
1339
|
]);
|
|
933
|
-
const handleClose =
|
|
934
|
-
return /* @__PURE__ */
|
|
1340
|
+
const handleClose = useCallback7(() => setField(void 0), []);
|
|
1341
|
+
return /* @__PURE__ */ React13.createElement("div", {
|
|
935
1342
|
role: "none",
|
|
936
|
-
className:
|
|
937
|
-
}, /* @__PURE__ */
|
|
938
|
-
autoFocus: true,
|
|
1343
|
+
className: mx8("flex flex-col w-full divide-y divide-separator", classNames)
|
|
1344
|
+
}, /* @__PURE__ */ React13.createElement(Form, {
|
|
939
1345
|
autoSave: true,
|
|
940
1346
|
schema: ViewMetaSchema,
|
|
941
1347
|
values: viewValues,
|
|
942
1348
|
onSave: handleViewUpdate
|
|
943
|
-
}), /* @__PURE__ */
|
|
1349
|
+
}), /* @__PURE__ */ React13.createElement("div", null, /* @__PURE__ */ React13.createElement("div", {
|
|
944
1350
|
role: "none",
|
|
945
1351
|
className: "p-2"
|
|
946
|
-
}, /* @__PURE__ */
|
|
947
|
-
className:
|
|
948
|
-
}, t("fields label"))), /* @__PURE__ */
|
|
1352
|
+
}, /* @__PURE__ */ React13.createElement("label", {
|
|
1353
|
+
className: mx8(inputTextLabel)
|
|
1354
|
+
}, t("fields label"))), /* @__PURE__ */ React13.createElement(List2.Root, {
|
|
949
1355
|
items: view.fields,
|
|
950
1356
|
isItem: S2.is(FieldSchema),
|
|
951
1357
|
getId: (field2) => field2.id,
|
|
952
1358
|
onMove: handleMove
|
|
953
|
-
}, ({ items: fields }) => /* @__PURE__ */
|
|
1359
|
+
}, ({ items: fields }) => /* @__PURE__ */ React13.createElement(React13.Fragment, null, showHeading && /* @__PURE__ */ React13.createElement("div", {
|
|
954
1360
|
role: "heading",
|
|
955
1361
|
className: grid
|
|
956
|
-
}, /* @__PURE__ */
|
|
1362
|
+
}, /* @__PURE__ */ React13.createElement("div", null), /* @__PURE__ */ React13.createElement("div", {
|
|
957
1363
|
className: "flex items-center text-sm"
|
|
958
|
-
}, t("field path label"))), /* @__PURE__ */
|
|
1364
|
+
}, t("field path label"))), /* @__PURE__ */ React13.createElement("div", {
|
|
959
1365
|
role: "list",
|
|
960
1366
|
className: "flex flex-col w-full"
|
|
961
|
-
}, fields?.map((field2) => /* @__PURE__ */
|
|
1367
|
+
}, fields?.map((field2) => /* @__PURE__ */ React13.createElement(List2.Item, {
|
|
962
1368
|
key: field2.id,
|
|
963
1369
|
item: field2,
|
|
964
|
-
classNames:
|
|
965
|
-
}, /* @__PURE__ */
|
|
1370
|
+
classNames: mx8(grid, ghostHover, "cursor-pointer")
|
|
1371
|
+
}, /* @__PURE__ */ React13.createElement(List2.ItemDragHandle, null), /* @__PURE__ */ React13.createElement(List2.ItemTitle, {
|
|
966
1372
|
onClick: () => handleSelect(field2)
|
|
967
|
-
}, field2.path), /* @__PURE__ */
|
|
1373
|
+
}, field2.path), /* @__PURE__ */ React13.createElement(List2.ItemDeleteButton, {
|
|
968
1374
|
disabled: view.fields.length <= 1,
|
|
969
1375
|
onClick: () => onDelete(field2.id)
|
|
970
|
-
}))))))), field && /* @__PURE__ */
|
|
1376
|
+
}))))))), field && /* @__PURE__ */ React13.createElement(FieldEditor, {
|
|
971
1377
|
key: field.id,
|
|
972
1378
|
view,
|
|
973
1379
|
projection,
|
|
974
1380
|
field,
|
|
975
1381
|
registry,
|
|
976
1382
|
onSave: handleClose
|
|
977
|
-
}), !readonly && !field && /* @__PURE__ */
|
|
1383
|
+
}), !readonly && !field && /* @__PURE__ */ React13.createElement("div", {
|
|
978
1384
|
className: "flex p-2 justify-center"
|
|
979
|
-
}, /* @__PURE__ */
|
|
1385
|
+
}, /* @__PURE__ */ React13.createElement(IconButton4, {
|
|
980
1386
|
icon: "ph--plus--regular",
|
|
981
1387
|
label: t("button add property"),
|
|
982
1388
|
onClick: handleAdd,
|
|
@@ -986,7 +1392,7 @@ var ViewEditor = ({ classNames, schema, view, registry, readonly, showHeading =
|
|
|
986
1392
|
};
|
|
987
1393
|
|
|
988
1394
|
// packages/ui/react-ui-form/src/util/field.ts
|
|
989
|
-
import { FormatEnum as FormatEnum3, TypeEnum } from "@dxos/echo-schema";
|
|
1395
|
+
import { FormatEnum as FormatEnum3, GeoLocation as GeoLocation2, TypeEnum } from "@dxos/echo-schema";
|
|
990
1396
|
var parseValue = ({ type, format, value }) => {
|
|
991
1397
|
if (value === void 0 || value === null || value === "") {
|
|
992
1398
|
return void 0;
|
|
@@ -1040,6 +1446,26 @@ var parseValue = ({ type, format, value }) => {
|
|
|
1040
1446
|
const date = new Date(value);
|
|
1041
1447
|
return isNaN(date.getTime()) ? null : date;
|
|
1042
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
|
+
}
|
|
1043
1469
|
default: {
|
|
1044
1470
|
return value;
|
|
1045
1471
|
}
|
|
@@ -1098,7 +1524,7 @@ var pathNotUniqueError = (path) => ({
|
|
|
1098
1524
|
});
|
|
1099
1525
|
|
|
1100
1526
|
// packages/ui/react-ui-form/src/util/formatting.ts
|
|
1101
|
-
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";
|
|
1102
1528
|
var formatForDisplay = ({ type, format, value, locale = void 0 }) => {
|
|
1103
1529
|
const formatScalar = (type2) => {
|
|
1104
1530
|
switch (type2) {
|
|
@@ -1151,6 +1577,16 @@ var formatForDisplay = ({ type, format, value, locale = void 0 }) => {
|
|
|
1151
1577
|
return date.toLocaleTimeString(locale);
|
|
1152
1578
|
}
|
|
1153
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
|
+
}
|
|
1154
1590
|
default: {
|
|
1155
1591
|
if (value === null || value === "undefined") {
|
|
1156
1592
|
return "";
|
|
@@ -1199,6 +1635,16 @@ var formatForEditing = ({ type, format, value, locale = void 0 }) => {
|
|
|
1199
1635
|
const date = new Date(value);
|
|
1200
1636
|
return date.toISOString().split("T")[1].split(".")[0];
|
|
1201
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
|
+
}
|
|
1202
1648
|
default: {
|
|
1203
1649
|
return String(value);
|
|
1204
1650
|
}
|
|
@@ -1206,14 +1652,16 @@ var formatForEditing = ({ type, format, value, locale = void 0 }) => {
|
|
|
1206
1652
|
};
|
|
1207
1653
|
export {
|
|
1208
1654
|
BooleanInput,
|
|
1655
|
+
DeprecatedFormContainer,
|
|
1209
1656
|
DeprecatedFormInput,
|
|
1210
1657
|
FieldEditor,
|
|
1211
1658
|
Form,
|
|
1212
|
-
FormActions,
|
|
1213
1659
|
GeoPointInput,
|
|
1214
1660
|
InputHeader,
|
|
1661
|
+
MarkdownInput,
|
|
1215
1662
|
NumberInput,
|
|
1216
1663
|
SelectInput,
|
|
1664
|
+
SelectOptionInput,
|
|
1217
1665
|
TextInput,
|
|
1218
1666
|
TupleInput,
|
|
1219
1667
|
ViewEditor,
|
|
@@ -1224,6 +1672,7 @@ export {
|
|
|
1224
1672
|
parseValue,
|
|
1225
1673
|
pathNotUniqueError,
|
|
1226
1674
|
translations_default as translations,
|
|
1227
|
-
useForm
|
|
1675
|
+
useForm,
|
|
1676
|
+
useFormValues
|
|
1228
1677
|
};
|
|
1229
1678
|
//# sourceMappingURL=index.mjs.map
|