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