@dxos/react-ui-form 0.8.2-main.f11618f → 0.8.2-staging.42af850
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 +1732 -1374
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node/index.cjs +1715 -1365
- package/dist/lib/node/index.cjs.map +4 -4
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node-esm/index.mjs +1732 -1374
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/types/src/components/ControlSection/ControlSection.d.ts +1 -1
- package/dist/types/src/components/ControlSection/ControlSection.d.ts.map +1 -1
- package/dist/types/src/components/FieldEditor/FieldEditor.d.ts.map +1 -1
- package/dist/types/src/components/FieldEditor/FieldEditor.test.d.ts +2 -0
- package/dist/types/src/components/FieldEditor/FieldEditor.test.d.ts.map +1 -0
- package/dist/types/src/components/Form/ArrayField.d.ts.map +1 -1
- package/dist/types/src/components/Form/Defaults.d.ts +4 -4
- package/dist/types/src/components/Form/Defaults.d.ts.map +1 -1
- package/dist/types/src/components/Form/Form.d.ts +4 -4
- package/dist/types/src/components/Form/Form.d.ts.map +1 -1
- package/dist/types/src/components/Form/Form.stories.d.ts +34 -34
- package/dist/types/src/components/Form/Form.stories.d.ts.map +1 -1
- package/dist/types/src/components/Form/FormActions.d.ts +1 -1
- package/dist/types/src/components/Form/FormActions.d.ts.map +1 -1
- package/dist/types/src/components/Form/FormContent.d.ts +9 -8
- package/dist/types/src/components/Form/FormContent.d.ts.map +1 -1
- package/dist/types/src/components/Form/FormContext.d.ts.map +1 -1
- package/dist/types/src/components/Form/Input.d.ts.map +1 -1
- package/dist/types/src/components/Form/RefField.d.ts +7 -18
- package/dist/types/src/components/Form/RefField.d.ts.map +1 -1
- package/dist/types/src/components/Form/custom/GeoPointInput.d.ts.map +1 -1
- package/dist/types/src/components/Form/custom/SelectOptionsInput.d.ts.map +1 -1
- package/dist/types/src/components/Form/custom/SelectOptionsInput.stories.d.ts.map +1 -1
- package/dist/types/src/components/Form/custom/TupleInput.d.ts.map +1 -1
- package/dist/types/src/components/Form/factory.d.ts +1 -1
- package/dist/types/src/components/Form/factory.d.ts.map +1 -1
- package/dist/types/src/components/Form/index.d.ts.map +1 -1
- 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 +5 -3
- package/dist/types/src/components/ViewEditor/ViewEditor.stories.d.ts.map +1 -1
- package/dist/types/src/components/deprecated/Form.d.ts +2 -2
- package/dist/types/src/components/deprecated/Form.d.ts.map +1 -1
- package/dist/types/src/components/deprecated/Form.stories.d.ts.map +1 -1
- package/dist/types/src/components/deprecated/FormInput.d.ts.map +1 -1
- package/dist/types/src/components/testing.d.ts.map +1 -1
- package/dist/types/src/hooks/index.d.ts +2 -0
- package/dist/types/src/hooks/index.d.ts.map +1 -1
- package/dist/types/src/hooks/useForm.d.ts +2 -2
- package/dist/types/src/hooks/useForm.d.ts.map +1 -1
- package/dist/types/src/hooks/useQueryRefOptions.d.ts +23 -0
- package/dist/types/src/hooks/useQueryRefOptions.d.ts.map +1 -0
- package/dist/types/src/hooks/useRefQueryLookupHandler.d.ts +8 -0
- package/dist/types/src/hooks/useRefQueryLookupHandler.d.ts.map +1 -0
- package/dist/types/src/translations.d.ts +5 -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/src/util/index.d.ts +2 -0
- package/dist/types/src/util/index.d.ts.map +1 -1
- package/dist/types/src/util/refs.d.ts +9 -0
- package/dist/types/src/util/refs.d.ts.map +1 -0
- package/dist/types/src/util/schema.d.ts +3 -0
- package/dist/types/src/util/schema.d.ts.map +1 -0
- package/dist/types/src/vitest-setup.d.ts +2 -0
- package/dist/types/src/vitest-setup.d.ts.map +1 -0
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +28 -25
- package/src/components/ControlSection/ControlSection.stories.tsx +1 -1
- package/src/components/ControlSection/ControlSection.tsx +2 -2
- package/src/components/FieldEditor/FieldEditor.stories.tsx +1 -1
- package/src/components/FieldEditor/FieldEditor.test.tsx +49 -0
- package/src/components/FieldEditor/FieldEditor.tsx +3 -2
- package/src/components/Form/ArrayField.tsx +60 -49
- package/src/components/Form/Defaults.tsx +77 -48
- package/src/components/Form/Form.stories.tsx +104 -122
- package/src/components/Form/Form.tsx +5 -6
- package/src/components/Form/FormActions.tsx +15 -18
- package/src/components/Form/FormContent.tsx +80 -54
- package/src/components/Form/FormContext.tsx +14 -8
- package/src/components/Form/Input.tsx +4 -10
- package/src/components/Form/RefField.tsx +167 -101
- package/src/components/Form/custom/SelectOptionsInput.stories.tsx +6 -5
- package/src/components/Form/factory.tsx +1 -1
- package/src/components/Form/index.ts +0 -1
- package/src/components/ViewEditor/ViewEditor.stories.tsx +19 -9
- package/src/components/ViewEditor/ViewEditor.tsx +65 -35
- package/src/components/deprecated/Form.tsx +6 -6
- package/src/components/testing.tsx +5 -9
- package/src/hooks/index.ts +3 -1
- package/src/hooks/useForm.ts +4 -3
- package/src/hooks/useQueryRefOptions.ts +53 -0
- package/src/hooks/useRefQueryLookupHandler.ts +39 -0
- package/src/translations.ts +9 -2
- package/src/util/index.ts +3 -1
- package/src/util/refs.ts +38 -0
- package/src/util/schema.ts +14 -0
- package/src/vitest-setup.ts +11 -0
|
@@ -8,6 +8,7 @@ var translations_default = [
|
|
|
8
8
|
[translationKey]: {
|
|
9
9
|
"fields label": "Fields",
|
|
10
10
|
"hidden fields label": "Hidden Fields",
|
|
11
|
+
"empty readonly ref field label": "(none)",
|
|
11
12
|
// TODO(burdon): Standardize field/property.
|
|
12
13
|
"button add property": "Add property",
|
|
13
14
|
"field property label": "Property",
|
|
@@ -17,6 +18,8 @@ var translations_default = [
|
|
|
17
18
|
"add field": "Add field",
|
|
18
19
|
"delete field": "Delete field",
|
|
19
20
|
"field limit reached": "Maximum number of fields reached",
|
|
21
|
+
"boolean input true value": "Yes",
|
|
22
|
+
"boolean input false value": "No",
|
|
20
23
|
// TODO(burdon): Factor out?
|
|
21
24
|
"button cancel": "Cancel",
|
|
22
25
|
"button save": "Save",
|
|
@@ -46,246 +49,324 @@ var translations_default = [
|
|
|
46
49
|
"format number": "Number",
|
|
47
50
|
"format uri": "URI",
|
|
48
51
|
"format uuid": "UUID",
|
|
49
|
-
// Placeholders
|
|
52
|
+
// Placeholders.
|
|
50
53
|
"placeholder latitude": "Latitude",
|
|
51
54
|
"placeholder longitude": "Longitude",
|
|
52
|
-
// SelectOptionsInput
|
|
55
|
+
// SelectOptionsInput.
|
|
53
56
|
"select option label": "Label",
|
|
54
57
|
"select option label placeholder": "Option label",
|
|
55
58
|
"select option color": "Color",
|
|
56
59
|
"select option delete": "Delete",
|
|
57
|
-
"select option add": "Add option"
|
|
60
|
+
"select option add": "Add option",
|
|
61
|
+
// System schema message.
|
|
62
|
+
"system schema title": "System Schema",
|
|
63
|
+
"system schema description": "This schema is managed by the system and cannot be modified."
|
|
58
64
|
}
|
|
59
65
|
}
|
|
60
66
|
}
|
|
61
67
|
];
|
|
62
68
|
|
|
63
69
|
// packages/ui/react-ui-form/src/components/deprecated/FormInput.tsx
|
|
70
|
+
import { useSignals as _useSignals } from "@preact-signals/safe-react/tracking";
|
|
64
71
|
import React from "react";
|
|
65
72
|
import { Input } from "@dxos/react-ui";
|
|
66
73
|
import { mx, textBlockWidth } from "@dxos/react-ui-theme";
|
|
67
74
|
var DeprecatedFormContainer = ({ children, classNames }) => {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
+
var _effect = _useSignals();
|
|
76
|
+
try {
|
|
77
|
+
return /* @__PURE__ */ React.createElement("div", {
|
|
78
|
+
role: "none",
|
|
79
|
+
className: "container-max-width p-4 justify-center overflow-x-hidden overflow-y-auto"
|
|
80
|
+
}, /* @__PURE__ */ React.createElement("div", {
|
|
81
|
+
role: "form",
|
|
82
|
+
className: mx("flex flex-col", textBlockWidth, classNames)
|
|
83
|
+
}, children));
|
|
84
|
+
} finally {
|
|
85
|
+
_effect.f();
|
|
86
|
+
}
|
|
75
87
|
};
|
|
76
88
|
var DeprecatedFormInput = ({ label, description, secondary, children }) => {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
role: "none",
|
|
94
|
-
className: "flex min-bs-[--rail-action] items-center"
|
|
95
|
-
}, children))));
|
|
96
|
-
if (secondary) {
|
|
97
|
-
return /* @__PURE__ */ React.createElement("div", {
|
|
89
|
+
var _effect = _useSignals();
|
|
90
|
+
try {
|
|
91
|
+
const primary = /* @__PURE__ */ React.createElement("div", {
|
|
92
|
+
role: "none",
|
|
93
|
+
className: "flex w-full gap-4 py-1"
|
|
94
|
+
}, /* @__PURE__ */ React.createElement(Input.Root, null, /* @__PURE__ */ React.createElement("div", {
|
|
95
|
+
role: "none",
|
|
96
|
+
className: "flex flex-col w-full"
|
|
97
|
+
}, /* @__PURE__ */ React.createElement(Input.Label, {
|
|
98
|
+
classNames: "flex min-bs-[--rail-action] items-center",
|
|
99
|
+
style: {
|
|
100
|
+
fontSize: "unset"
|
|
101
|
+
}
|
|
102
|
+
}, label), description && /* @__PURE__ */ React.createElement(Input.DescriptionAndValidation, {
|
|
103
|
+
classNames: "mbs-0.5"
|
|
104
|
+
}, /* @__PURE__ */ React.createElement(Input.Description, null, description))), /* @__PURE__ */ React.createElement("div", {
|
|
98
105
|
role: "none"
|
|
99
|
-
},
|
|
106
|
+
}, /* @__PURE__ */ React.createElement("div", {
|
|
107
|
+
role: "none",
|
|
108
|
+
className: "flex min-bs-[--rail-action] items-center"
|
|
109
|
+
}, children))));
|
|
110
|
+
if (secondary) {
|
|
111
|
+
return /* @__PURE__ */ React.createElement("div", {
|
|
112
|
+
role: "none"
|
|
113
|
+
}, primary, secondary);
|
|
114
|
+
}
|
|
115
|
+
return primary;
|
|
116
|
+
} finally {
|
|
117
|
+
_effect.f();
|
|
100
118
|
}
|
|
101
|
-
return primary;
|
|
102
119
|
};
|
|
103
120
|
|
|
104
121
|
// packages/ui/react-ui-form/src/components/ControlSection/ControlSection.tsx
|
|
122
|
+
import { useSignals as _useSignals2 } from "@preact-signals/safe-react/tracking";
|
|
105
123
|
import React2 from "react";
|
|
106
124
|
import { Button, Input as Input2, toLocalizedString, useTranslation } from "@dxos/react-ui";
|
|
107
125
|
import { mx as mx2 } from "@dxos/react-ui-theme";
|
|
108
126
|
var ControlPage = ({ children, classNames, ...props }) => {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
127
|
+
var _effect = _useSignals2();
|
|
128
|
+
try {
|
|
129
|
+
return /* @__PURE__ */ React2.createElement("div", {
|
|
130
|
+
role: "none",
|
|
131
|
+
className: mx2("pli-2", classNames),
|
|
132
|
+
...props
|
|
133
|
+
}, children);
|
|
134
|
+
} finally {
|
|
135
|
+
_effect.f();
|
|
136
|
+
}
|
|
114
137
|
};
|
|
115
138
|
var ControlSection = ({ title, description, children }) => {
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
139
|
+
var _effect = _useSignals2();
|
|
140
|
+
try {
|
|
141
|
+
return /* @__PURE__ */ React2.createElement(React2.Fragment, null, /* @__PURE__ */ React2.createElement(ControlSectionHeading, {
|
|
142
|
+
title,
|
|
143
|
+
description
|
|
144
|
+
}), children);
|
|
145
|
+
} finally {
|
|
146
|
+
_effect.f();
|
|
147
|
+
}
|
|
120
148
|
};
|
|
121
149
|
var ControlSectionHeading = ({ title, description }) => {
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
150
|
+
var _effect = _useSignals2();
|
|
151
|
+
try {
|
|
152
|
+
const { t } = useTranslation(translationKey);
|
|
153
|
+
return /* @__PURE__ */ React2.createElement(React2.Fragment, null, /* @__PURE__ */ React2.createElement("h2", {
|
|
154
|
+
className: "pli-4 container-max-width text-xl mbs-6 mbe-4"
|
|
155
|
+
}, toLocalizedString(title, t)), description && /* @__PURE__ */ React2.createElement("p", {
|
|
156
|
+
className: "pli-4 mlb-4 container-max-width text-description"
|
|
157
|
+
}, toLocalizedString(description, t)));
|
|
158
|
+
} finally {
|
|
159
|
+
_effect.f();
|
|
160
|
+
}
|
|
128
161
|
};
|
|
129
162
|
var ControlGroupButton = ({ classNames, ...props }) => {
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
classNames
|
|
135
|
-
|
|
136
|
-
|
|
163
|
+
var _effect = _useSignals2();
|
|
164
|
+
try {
|
|
165
|
+
return /* @__PURE__ */ React2.createElement(Button, {
|
|
166
|
+
...props,
|
|
167
|
+
classNames: [
|
|
168
|
+
"md:col-span-2",
|
|
169
|
+
classNames
|
|
170
|
+
]
|
|
171
|
+
});
|
|
172
|
+
} finally {
|
|
173
|
+
_effect.f();
|
|
174
|
+
}
|
|
175
|
+
};
|
|
176
|
+
var ControlGroup = ({ children, classNames }) => {
|
|
177
|
+
var _effect = _useSignals2();
|
|
178
|
+
try {
|
|
179
|
+
return /* @__PURE__ */ React2.createElement("div", {
|
|
180
|
+
role: "none",
|
|
181
|
+
className: mx2("group container-max-width grid grid-cols-1 md:grid-cols-[1fr_min-content] gap-4", classNames)
|
|
182
|
+
}, children);
|
|
183
|
+
} finally {
|
|
184
|
+
_effect.f();
|
|
185
|
+
}
|
|
186
|
+
};
|
|
187
|
+
var ControlFrame = ({ children }) => {
|
|
188
|
+
var _effect = _useSignals2();
|
|
189
|
+
try {
|
|
190
|
+
return /* @__PURE__ */ React2.createElement("div", {
|
|
191
|
+
role: "none",
|
|
192
|
+
className: "p-4 border border-separator rounded-lg container-max-width grid grid-cols-1 md:grid-cols-[1fr_1fr] gap-2 md:gap-8"
|
|
193
|
+
}, children);
|
|
194
|
+
} finally {
|
|
195
|
+
_effect.f();
|
|
196
|
+
}
|
|
137
197
|
};
|
|
138
|
-
var
|
|
139
|
-
|
|
140
|
-
className: mx2("group container-max-width grid grid-cols-1 md:grid-cols-[1fr_min-content] gap-4", classNames)
|
|
141
|
-
}, children);
|
|
142
|
-
var ControlFrame = ({ children }) => /* @__PURE__ */ React2.createElement("div", {
|
|
143
|
-
role: "none",
|
|
144
|
-
className: "p-4 border border-separator rounded-lg container-max-width grid grid-cols-1 md:grid-cols-[1fr_1fr] gap-2 md:gap-8"
|
|
145
|
-
}, children);
|
|
146
|
-
var controlItemClasses = "p-4 border border-separator rounded-lg container-max-width grid md:col-span-2 grid-cols-subgrid items-center";
|
|
147
|
-
var controlItemTitleClasses = "text-lg font-normal mbe-2";
|
|
198
|
+
var controlItemClasses = "p-4 border border-separator rounded-lg container-max-width grid md:col-span-2 grid-cols-subgrid items-center gap-2";
|
|
199
|
+
var controlItemTitleClasses = "text-lg font-normal";
|
|
148
200
|
var controlItemDescriptionClasses = "text-base mlb-2 md:mbe-0 text-description";
|
|
149
201
|
var ControlItem = ({ title, description, children }) => {
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
202
|
+
var _effect = _useSignals2();
|
|
203
|
+
try {
|
|
204
|
+
const { t } = useTranslation(translationKey);
|
|
205
|
+
return /* @__PURE__ */ React2.createElement("div", {
|
|
206
|
+
className: controlItemClasses
|
|
207
|
+
}, /* @__PURE__ */ React2.createElement("div", {
|
|
208
|
+
role: "none"
|
|
209
|
+
}, /* @__PURE__ */ React2.createElement("h3", {
|
|
210
|
+
className: controlItemTitleClasses
|
|
211
|
+
}, toLocalizedString(title, t)), description && /* @__PURE__ */ React2.createElement("p", {
|
|
212
|
+
className: controlItemDescriptionClasses
|
|
213
|
+
}, toLocalizedString(description, t))), children);
|
|
214
|
+
} finally {
|
|
215
|
+
_effect.f();
|
|
216
|
+
}
|
|
160
217
|
};
|
|
161
218
|
var ControlItemInput = ({ title, description, children }) => {
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
219
|
+
var _effect = _useSignals2();
|
|
220
|
+
try {
|
|
221
|
+
const { t } = useTranslation(translationKey);
|
|
222
|
+
return /* @__PURE__ */ React2.createElement(Input2.Root, null, /* @__PURE__ */ React2.createElement("div", {
|
|
223
|
+
className: controlItemClasses
|
|
224
|
+
}, /* @__PURE__ */ React2.createElement("div", {
|
|
225
|
+
role: "none"
|
|
226
|
+
}, /* @__PURE__ */ React2.createElement(Input2.Label, {
|
|
227
|
+
classNames: controlItemTitleClasses
|
|
228
|
+
}, toLocalizedString(title, t)), description && /* @__PURE__ */ React2.createElement(Input2.DescriptionAndValidation, null, /* @__PURE__ */ React2.createElement(Input2.Description, {
|
|
229
|
+
classNames: controlItemDescriptionClasses
|
|
230
|
+
}, toLocalizedString(description, t)))), children));
|
|
231
|
+
} finally {
|
|
232
|
+
_effect.f();
|
|
233
|
+
}
|
|
172
234
|
};
|
|
173
235
|
var ControlFrameItem = ({ title, description, children }) => {
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
236
|
+
var _effect = _useSignals2();
|
|
237
|
+
try {
|
|
238
|
+
const { t } = useTranslation(translationKey);
|
|
239
|
+
return /* @__PURE__ */ React2.createElement("div", {
|
|
240
|
+
role: "group",
|
|
241
|
+
className: "min-is-0"
|
|
242
|
+
}, /* @__PURE__ */ React2.createElement("h3", {
|
|
243
|
+
className: "text-lg mbe-2"
|
|
244
|
+
}, toLocalizedString(title, t)), description && /* @__PURE__ */ React2.createElement("p", {
|
|
245
|
+
className: "mlb-2 md:mbe-0 text-description"
|
|
246
|
+
}, toLocalizedString(description, t)), children);
|
|
247
|
+
} finally {
|
|
248
|
+
_effect.f();
|
|
249
|
+
}
|
|
183
250
|
};
|
|
184
251
|
|
|
185
252
|
// packages/ui/react-ui-form/src/components/FieldEditor/FieldEditor.tsx
|
|
186
|
-
import
|
|
187
|
-
import {
|
|
253
|
+
import { useSignals as _useSignals14 } from "@preact-signals/safe-react/tracking";
|
|
254
|
+
import React14, { useCallback as useCallback9, useEffect as useEffect8, useMemo as useMemo7, useState as useState5 } from "react";
|
|
255
|
+
import { FormatEnum as FormatEnum5, FormatEnums, formatToType } from "@dxos/echo-schema";
|
|
188
256
|
import { log as log3 } from "@dxos/log";
|
|
189
|
-
import { useTranslation as
|
|
257
|
+
import { useTranslation as useTranslation8 } from "@dxos/react-ui";
|
|
190
258
|
import { getFormatSchema, getSchemaProperties as getSchemaProperties3, sortProperties } from "@dxos/schema";
|
|
191
259
|
|
|
192
260
|
// packages/ui/react-ui-form/src/components/Form/custom/GeoPointInput.tsx
|
|
261
|
+
import { useSignals as _useSignals4 } from "@preact-signals/safe-react/tracking";
|
|
193
262
|
import React4, { useCallback, useState, useEffect, useMemo } from "react";
|
|
194
263
|
import { GeoLocation } from "@dxos/echo-schema";
|
|
195
264
|
import { Input as Input3, useTranslation as useTranslation2 } from "@dxos/react-ui";
|
|
196
265
|
import { safeParseFloat } from "@dxos/util";
|
|
197
266
|
|
|
198
267
|
// packages/ui/react-ui-form/src/components/Form/Input.tsx
|
|
268
|
+
import { useSignals as _useSignals3 } from "@preact-signals/safe-react/tracking";
|
|
199
269
|
import React3 from "react";
|
|
200
270
|
import { Icon, Tooltip } from "@dxos/react-ui";
|
|
201
271
|
import { errorText } from "@dxos/react-ui-theme";
|
|
202
272
|
var InputHeader = ({ children, error }) => {
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
273
|
+
var _effect = _useSignals3();
|
|
274
|
+
try {
|
|
275
|
+
return /* @__PURE__ */ React3.createElement("div", {
|
|
276
|
+
role: "none",
|
|
277
|
+
className: "flex justify-between items-center mbs-2 mbe-1 first:mbs-0"
|
|
278
|
+
}, children, error && /* @__PURE__ */ React3.createElement(Tooltip.Trigger, {
|
|
279
|
+
asChild: true,
|
|
280
|
+
content: error,
|
|
281
|
+
side: "bottom"
|
|
282
|
+
}, /* @__PURE__ */ React3.createElement(Icon, {
|
|
283
|
+
icon: "ph--warning--regular",
|
|
284
|
+
size: 4,
|
|
285
|
+
classNames: errorText
|
|
286
|
+
})));
|
|
287
|
+
} finally {
|
|
288
|
+
_effect.f();
|
|
289
|
+
}
|
|
215
290
|
};
|
|
216
291
|
|
|
217
292
|
// packages/ui/react-ui-form/src/components/Form/custom/GeoPointInput.tsx
|
|
218
293
|
var GeoPointInput = ({ type, label, disabled, getStatus, getValue: getValue3, onValueChange, onBlur }) => {
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
const
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
setText(
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
if (
|
|
245
|
-
const
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
294
|
+
var _effect = _useSignals4();
|
|
295
|
+
try {
|
|
296
|
+
const { t } = useTranslation2(translationKey);
|
|
297
|
+
const { status, error } = getStatus();
|
|
298
|
+
const geoPoint = useMemo(() => getValue3() ?? [
|
|
299
|
+
0,
|
|
300
|
+
0
|
|
301
|
+
], [
|
|
302
|
+
getValue3
|
|
303
|
+
]);
|
|
304
|
+
const geoLocation = useMemo(() => GeoLocation.fromGeoPoint(geoPoint), [
|
|
305
|
+
geoPoint
|
|
306
|
+
]);
|
|
307
|
+
const [longitudeText, setLongitudeText] = useState(geoLocation.longitude?.toString());
|
|
308
|
+
const [latitudeText, setLatitudeText] = useState(geoLocation.latitude?.toString());
|
|
309
|
+
useEffect(() => {
|
|
310
|
+
const location = GeoLocation.fromGeoPoint(geoPoint);
|
|
311
|
+
setLongitudeText(location.longitude.toString());
|
|
312
|
+
setLatitudeText(location.latitude.toString());
|
|
313
|
+
}, [
|
|
314
|
+
geoPoint
|
|
315
|
+
]);
|
|
316
|
+
const handleCoordinateChange = useCallback((coordinateType, setText) => (event) => {
|
|
317
|
+
const inputText = event.target.value;
|
|
318
|
+
setText(inputText);
|
|
319
|
+
if (inputText !== "" && inputText !== "-") {
|
|
320
|
+
const coord = safeParseFloat(inputText);
|
|
321
|
+
if (coord !== void 0 && !isNaN(coord)) {
|
|
322
|
+
const currentLocation = GeoLocation.fromGeoPoint(getValue3() ?? [
|
|
323
|
+
0,
|
|
324
|
+
0
|
|
325
|
+
]);
|
|
326
|
+
const newLocation = {
|
|
327
|
+
...currentLocation,
|
|
328
|
+
[coordinateType]: coord
|
|
329
|
+
};
|
|
330
|
+
const newValue = GeoLocation.toGeoPoint(newLocation);
|
|
331
|
+
onValueChange(type, newValue);
|
|
332
|
+
}
|
|
255
333
|
}
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
}
|
|
334
|
+
}, [
|
|
335
|
+
getValue3,
|
|
336
|
+
onValueChange,
|
|
337
|
+
type
|
|
338
|
+
]);
|
|
339
|
+
return /* @__PURE__ */ React4.createElement(Input3.Root, {
|
|
340
|
+
validationValence: status
|
|
341
|
+
}, /* @__PURE__ */ React4.createElement(InputHeader, {
|
|
342
|
+
error
|
|
343
|
+
}, /* @__PURE__ */ React4.createElement(Input3.Label, null, label)), /* @__PURE__ */ React4.createElement("div", {
|
|
344
|
+
role: "none",
|
|
345
|
+
className: "grid grid-cols-2 gap-2"
|
|
346
|
+
}, /* @__PURE__ */ React4.createElement(Input3.TextInput, {
|
|
347
|
+
type: "text",
|
|
348
|
+
pattern: "^-?[0-9]*\\.?[0-9]*$",
|
|
349
|
+
disabled,
|
|
350
|
+
placeholder: t("placeholder latitude"),
|
|
351
|
+
value: latitudeText,
|
|
352
|
+
onChange: handleCoordinateChange("latitude", setLatitudeText),
|
|
353
|
+
onBlur
|
|
354
|
+
}), /* @__PURE__ */ React4.createElement(Input3.TextInput, {
|
|
355
|
+
type: "text",
|
|
356
|
+
pattern: "^-?[0-9]*\\.?[0-9]*$",
|
|
357
|
+
disabled,
|
|
358
|
+
placeholder: t("placeholder longitude"),
|
|
359
|
+
value: longitudeText,
|
|
360
|
+
onChange: handleCoordinateChange("longitude", setLongitudeText),
|
|
361
|
+
onBlur
|
|
362
|
+
})));
|
|
363
|
+
} finally {
|
|
364
|
+
_effect.f();
|
|
365
|
+
}
|
|
286
366
|
};
|
|
287
367
|
|
|
288
368
|
// packages/ui/react-ui-form/src/components/Form/custom/SelectOptionsInput.tsx
|
|
369
|
+
import { useSignals as _useSignals5 } from "@preact-signals/safe-react/tracking";
|
|
289
370
|
import React5, { useCallback as useCallback2, useEffect as useEffect2, useState as useState2, useRef } from "react";
|
|
290
371
|
import { PublicKey } from "@dxos/keys";
|
|
291
372
|
import { Icon as Icon2, IconButton, Input as Input4, Tag, Toolbar, useTranslation as useTranslation3 } from "@dxos/react-ui";
|
|
@@ -293,183 +374,189 @@ import { List } from "@dxos/react-ui-list";
|
|
|
293
374
|
import { HuePicker } from "@dxos/react-ui-pickers";
|
|
294
375
|
import { hues, mx as mx3 } from "@dxos/react-ui-theme";
|
|
295
376
|
var SelectOptionInput = ({ type, label, disabled, getStatus, getValue: getValue3, onValueChange }) => {
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
const
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
const newId = PublicKey.random().truncate();
|
|
323
|
-
const newOption = {
|
|
324
|
-
id: newId,
|
|
325
|
-
title: "",
|
|
326
|
-
color: randomHue()
|
|
377
|
+
var _effect = _useSignals5();
|
|
378
|
+
try {
|
|
379
|
+
const [selected, setSelectedId] = useState2(null);
|
|
380
|
+
const [isNewOption, setIsNewOption] = useState2(false);
|
|
381
|
+
const inputRef = useRef(null);
|
|
382
|
+
const { t } = useTranslation3(translationKey);
|
|
383
|
+
const { status, error } = getStatus();
|
|
384
|
+
const options = getValue3();
|
|
385
|
+
useEffect2(() => {
|
|
386
|
+
if (options === void 0) {
|
|
387
|
+
onValueChange(type, []);
|
|
388
|
+
}
|
|
389
|
+
}, [
|
|
390
|
+
options,
|
|
391
|
+
onValueChange,
|
|
392
|
+
type
|
|
393
|
+
]);
|
|
394
|
+
const randomHue = () => {
|
|
395
|
+
const usedHues = new Set(options?.map((option) => option.color) ?? []);
|
|
396
|
+
const unusedHues = hues.filter((hue) => !usedHues.has(hue));
|
|
397
|
+
if (unusedHues.length > 0) {
|
|
398
|
+
return unusedHues[Math.floor(Math.random() * unusedHues.length)];
|
|
399
|
+
}
|
|
400
|
+
const lastThree = new Set(options?.slice(-3).map((option) => option.color) ?? []);
|
|
401
|
+
const availableHues = hues.filter((hue) => !lastThree.has(hue));
|
|
402
|
+
return availableHues[Math.floor(Math.random() * availableHues.length)] ?? hues[Math.floor(Math.random() * hues.length)];
|
|
327
403
|
};
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
newOption
|
|
404
|
+
const handleAdd = useCallback2(() => {
|
|
405
|
+
const newId = PublicKey.random().truncate();
|
|
406
|
+
const newOption = {
|
|
407
|
+
id: newId,
|
|
408
|
+
title: "",
|
|
409
|
+
color: randomHue()
|
|
410
|
+
};
|
|
411
|
+
onValueChange(type, [
|
|
412
|
+
...options ?? [],
|
|
413
|
+
newOption
|
|
414
|
+
]);
|
|
415
|
+
setSelectedId(newId);
|
|
416
|
+
setIsNewOption(true);
|
|
417
|
+
}, [
|
|
418
|
+
options,
|
|
419
|
+
type,
|
|
420
|
+
onValueChange
|
|
331
421
|
]);
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
options,
|
|
336
|
-
type,
|
|
337
|
-
onValueChange
|
|
338
|
-
]);
|
|
339
|
-
const handleDelete = useCallback2((id) => {
|
|
340
|
-
const newOptions = options?.filter((option) => option.id !== id) ?? [];
|
|
341
|
-
onValueChange(type, newOptions);
|
|
342
|
-
setSelectedId(null);
|
|
343
|
-
}, [
|
|
344
|
-
options,
|
|
345
|
-
type,
|
|
346
|
-
onValueChange
|
|
347
|
-
]);
|
|
348
|
-
const handleMove = useCallback2((from, to) => {
|
|
349
|
-
if (!options) {
|
|
350
|
-
return;
|
|
351
|
-
}
|
|
352
|
-
const newOptions = [
|
|
353
|
-
...options
|
|
354
|
-
];
|
|
355
|
-
const [removed] = newOptions.splice(from, 1);
|
|
356
|
-
newOptions.splice(to, 0, removed);
|
|
357
|
-
onValueChange(type, newOptions);
|
|
358
|
-
}, [
|
|
359
|
-
options,
|
|
360
|
-
type,
|
|
361
|
-
onValueChange
|
|
362
|
-
]);
|
|
363
|
-
const handleClick = useCallback2((id) => {
|
|
364
|
-
setSelectedId((current) => current === id ? null : id);
|
|
365
|
-
}, []);
|
|
366
|
-
const handleTitleChange = useCallback2((id) => (e) => {
|
|
367
|
-
const newOptions = options?.map((o) => o.id === id ? {
|
|
368
|
-
...o,
|
|
369
|
-
title: e.target.value
|
|
370
|
-
} : o);
|
|
371
|
-
onValueChange(type, newOptions ?? []);
|
|
372
|
-
}, [
|
|
373
|
-
options,
|
|
374
|
-
type,
|
|
375
|
-
onValueChange
|
|
376
|
-
]);
|
|
377
|
-
const handleKeyDown = useCallback2((e) => {
|
|
378
|
-
if (e.key === "Enter") {
|
|
422
|
+
const handleDelete = useCallback2((id) => {
|
|
423
|
+
const newOptions = options?.filter((option) => option.id !== id) ?? [];
|
|
424
|
+
onValueChange(type, newOptions);
|
|
379
425
|
setSelectedId(null);
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
426
|
+
}, [
|
|
427
|
+
options,
|
|
428
|
+
type,
|
|
429
|
+
onValueChange
|
|
430
|
+
]);
|
|
431
|
+
const handleMove = useCallback2((from, to) => {
|
|
432
|
+
if (!options) {
|
|
433
|
+
return;
|
|
434
|
+
}
|
|
435
|
+
const newOptions = [
|
|
436
|
+
...options
|
|
437
|
+
];
|
|
438
|
+
const [removed] = newOptions.splice(from, 1);
|
|
439
|
+
newOptions.splice(to, 0, removed);
|
|
440
|
+
onValueChange(type, newOptions);
|
|
441
|
+
}, [
|
|
442
|
+
options,
|
|
443
|
+
type,
|
|
444
|
+
onValueChange
|
|
445
|
+
]);
|
|
446
|
+
const handleClick = useCallback2((id) => {
|
|
447
|
+
setSelectedId((current) => current === id ? null : id);
|
|
448
|
+
}, []);
|
|
449
|
+
const handleTitleChange = useCallback2((id) => (e) => {
|
|
450
|
+
const newOptions = options?.map((o) => o.id === id ? {
|
|
451
|
+
...o,
|
|
452
|
+
title: e.target.value
|
|
453
|
+
} : o);
|
|
454
|
+
onValueChange(type, newOptions ?? []);
|
|
455
|
+
}, [
|
|
456
|
+
options,
|
|
457
|
+
type,
|
|
458
|
+
onValueChange
|
|
459
|
+
]);
|
|
460
|
+
const handleKeyDown = useCallback2((e) => {
|
|
461
|
+
if (e.key === "Enter") {
|
|
462
|
+
setSelectedId(null);
|
|
463
|
+
}
|
|
464
|
+
}, []);
|
|
465
|
+
const handleColorChange = useCallback2((id) => (hue) => {
|
|
466
|
+
const newOptions = options?.map((o) => o.id === id ? {
|
|
467
|
+
...o,
|
|
468
|
+
color: hue
|
|
469
|
+
} : o);
|
|
470
|
+
onValueChange(type, newOptions ?? []);
|
|
471
|
+
}, [
|
|
472
|
+
options,
|
|
473
|
+
type,
|
|
474
|
+
onValueChange
|
|
475
|
+
]);
|
|
476
|
+
useEffect2(() => {
|
|
477
|
+
if (selected && isNewOption && inputRef.current) {
|
|
478
|
+
inputRef.current.focus();
|
|
479
|
+
setIsNewOption(false);
|
|
480
|
+
}
|
|
481
|
+
}, [
|
|
482
|
+
selected,
|
|
483
|
+
isNewOption
|
|
484
|
+
]);
|
|
485
|
+
return /* @__PURE__ */ React5.createElement(Input4.Root, {
|
|
486
|
+
validationValence: status
|
|
487
|
+
}, /* @__PURE__ */ React5.createElement(InputHeader, {
|
|
488
|
+
error
|
|
489
|
+
}, /* @__PURE__ */ React5.createElement(Input4.Label, null, label)), /* @__PURE__ */ React5.createElement("div", {
|
|
490
|
+
role: "none"
|
|
491
|
+
}, options && /* @__PURE__ */ React5.createElement(List.Root, {
|
|
492
|
+
items: options,
|
|
493
|
+
isItem: (item) => true,
|
|
494
|
+
onMove: handleMove
|
|
495
|
+
}, ({ items }) => /* @__PURE__ */ React5.createElement("div", {
|
|
496
|
+
role: "list",
|
|
497
|
+
className: "w-full overflow-auto"
|
|
498
|
+
}, items?.map((item) => /* @__PURE__ */ React5.createElement("div", {
|
|
499
|
+
key: item.id
|
|
500
|
+
}, /* @__PURE__ */ React5.createElement(List.Item, {
|
|
501
|
+
role: "button",
|
|
502
|
+
item,
|
|
503
|
+
classNames: mx3("p-1 plb-2", "flex flex-col", "cursor-pointer", "hover:bg-hoverOverlay"),
|
|
504
|
+
"aria-expanded": selected === item.id
|
|
505
|
+
}, /* @__PURE__ */ React5.createElement("div", {
|
|
506
|
+
className: "flex items-center"
|
|
507
|
+
}, /* @__PURE__ */ React5.createElement(List.ItemDragHandle, null), /* @__PURE__ */ React5.createElement(List.ItemTitle, {
|
|
508
|
+
onClick: () => handleClick(item.id),
|
|
509
|
+
classNames: "flex-1"
|
|
510
|
+
}, /* @__PURE__ */ React5.createElement(Tag, {
|
|
511
|
+
palette: item.color
|
|
512
|
+
}, item.title || "\u200B")), /* @__PURE__ */ React5.createElement(Icon2, {
|
|
513
|
+
icon: selected === item.id ? "ph--caret-down--regular" : "ph--caret-right--regular",
|
|
514
|
+
onClick: () => handleClick(item.id)
|
|
515
|
+
})), selected === item.id && /* @__PURE__ */ React5.createElement("div", {
|
|
516
|
+
className: "mis-4 mbs-2 flex flex-col gap-1"
|
|
517
|
+
}, /* @__PURE__ */ React5.createElement(Input4.Label, {
|
|
518
|
+
classNames: "text-xs"
|
|
519
|
+
}, t("select option label")), /* @__PURE__ */ React5.createElement("div", {
|
|
520
|
+
className: "flex flex-row items-center gap-1"
|
|
521
|
+
}, /* @__PURE__ */ React5.createElement(Input4.TextInput, {
|
|
522
|
+
placeholder: t("select option label placeholder"),
|
|
523
|
+
ref: selected === item.id ? inputRef : void 0,
|
|
524
|
+
value: item.title,
|
|
525
|
+
onChange: handleTitleChange(item.id),
|
|
526
|
+
onKeyDown: handleKeyDown,
|
|
527
|
+
classNames: "flex-1",
|
|
528
|
+
"data-no-submit": true
|
|
529
|
+
}), /* @__PURE__ */ React5.createElement(Toolbar.Root, {
|
|
530
|
+
classNames: "p-0 m-0 !is-auto"
|
|
531
|
+
}, /* @__PURE__ */ React5.createElement(HuePicker, {
|
|
532
|
+
value: item.color,
|
|
533
|
+
onChange: handleColorChange(item.id),
|
|
534
|
+
rootVariant: "toolbar-button"
|
|
535
|
+
})), /* @__PURE__ */ React5.createElement(IconButton, {
|
|
536
|
+
icon: "ph--trash--fill",
|
|
537
|
+
iconOnly: true,
|
|
538
|
+
label: t("select option delete"),
|
|
539
|
+
onClick: () => handleDelete(item.id)
|
|
540
|
+
})))))), /* @__PURE__ */ React5.createElement("div", {
|
|
541
|
+
role: "listitem"
|
|
542
|
+
}, /* @__PURE__ */ React5.createElement("div", {
|
|
543
|
+
role: "button",
|
|
544
|
+
className: mx3("p-1 plb-2", "flex flex-col", "cursor-pointer", "hover:bg-hoverOverlay"),
|
|
545
|
+
onClick: handleAdd
|
|
546
|
+
}, /* @__PURE__ */ React5.createElement("div", {
|
|
547
|
+
className: "flex items-center gap-1"
|
|
548
|
+
}, /* @__PURE__ */ React5.createElement(Icon2, {
|
|
549
|
+
icon: "ph--plus--regular"
|
|
550
|
+
}), /* @__PURE__ */ React5.createElement("span", {
|
|
551
|
+
className: "text-sm"
|
|
552
|
+
}, t("select option add")))))))));
|
|
553
|
+
} finally {
|
|
554
|
+
_effect.f();
|
|
555
|
+
}
|
|
470
556
|
};
|
|
471
557
|
|
|
472
558
|
// packages/ui/react-ui-form/src/components/Form/custom/TupleInput.tsx
|
|
559
|
+
import { useSignals as _useSignals6 } from "@preact-signals/safe-react/tracking";
|
|
473
560
|
import React6 from "react";
|
|
474
561
|
import { Input as Input5 } from "@dxos/react-ui";
|
|
475
562
|
import { mx as mx4 } from "@dxos/react-ui-theme";
|
|
@@ -481,149 +568,188 @@ var gridCols = [
|
|
|
481
568
|
"grid-cols-4"
|
|
482
569
|
];
|
|
483
570
|
var TupleInput = ({ binding, type, label, disabled, getStatus, getValue: getValue3, onValueChange, onBlur }) => {
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
571
|
+
var _effect = _useSignals6();
|
|
572
|
+
try {
|
|
573
|
+
const { status, error } = getStatus();
|
|
574
|
+
const values = getValue3() ?? {};
|
|
575
|
+
return /* @__PURE__ */ React6.createElement(Input5.Root, {
|
|
576
|
+
validationValence: status
|
|
577
|
+
}, /* @__PURE__ */ React6.createElement(InputHeader, {
|
|
578
|
+
error
|
|
579
|
+
}, /* @__PURE__ */ React6.createElement(Input5.Label, null, label)), /* @__PURE__ */ React6.createElement("div", {
|
|
580
|
+
className: mx4("grid gap-2", gridCols[binding.length - 1])
|
|
581
|
+
}, binding.map((prop) => /* @__PURE__ */ React6.createElement(Input5.TextInput, {
|
|
582
|
+
key: prop,
|
|
583
|
+
type: "number",
|
|
584
|
+
disabled,
|
|
585
|
+
value: values[prop],
|
|
586
|
+
onChange: (event) => onValueChange(type, {
|
|
587
|
+
...values,
|
|
588
|
+
[prop]: safeParseFloat2(event.target.value, 0)
|
|
589
|
+
}),
|
|
590
|
+
onBlur
|
|
591
|
+
}))));
|
|
592
|
+
} finally {
|
|
593
|
+
_effect.f();
|
|
594
|
+
}
|
|
503
595
|
};
|
|
504
596
|
|
|
505
597
|
// packages/ui/react-ui-form/src/components/Form/Defaults.tsx
|
|
598
|
+
import { useSignals as _useSignals7 } from "@preact-signals/safe-react/tracking";
|
|
506
599
|
import React7, { useCallback as useCallback3, useEffect as useEffect3, useRef as useRef2 } from "react";
|
|
507
|
-
import { Input as Input6, Select } from "@dxos/react-ui";
|
|
600
|
+
import { Input as Input6, Select, useTranslation as useTranslation4 } from "@dxos/react-ui";
|
|
508
601
|
var TextInput = ({ type, label, inputOnly, disabled, placeholder, getStatus, getValue: getValue3, onValueChange, onBlur }) => {
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
602
|
+
var _effect = _useSignals7();
|
|
603
|
+
try {
|
|
604
|
+
const { status, error } = getStatus();
|
|
605
|
+
return disabled && !getValue3() ? null : disabled && inputOnly ? /* @__PURE__ */ React7.createElement("p", null, getValue3() ?? "") : /* @__PURE__ */ React7.createElement(Input6.Root, {
|
|
606
|
+
validationValence: status
|
|
607
|
+
}, !inputOnly && /* @__PURE__ */ React7.createElement(InputHeader, {
|
|
608
|
+
error
|
|
609
|
+
}, /* @__PURE__ */ React7.createElement(Input6.Label, null, label)), disabled ? /* @__PURE__ */ React7.createElement("p", null, getValue3() ?? "") : /* @__PURE__ */ React7.createElement(Input6.TextInput, {
|
|
610
|
+
disabled,
|
|
611
|
+
placeholder,
|
|
612
|
+
value: getValue3() ?? "",
|
|
613
|
+
onChange: (event) => onValueChange(type, event.target.value),
|
|
614
|
+
onBlur
|
|
615
|
+
}), inputOnly && /* @__PURE__ */ React7.createElement(Input6.Validation, null, error));
|
|
616
|
+
} finally {
|
|
617
|
+
_effect.f();
|
|
618
|
+
}
|
|
521
619
|
};
|
|
522
620
|
var NumberInput = ({ type, label, inputOnly, disabled, placeholder, getStatus, getValue: getValue3, onValueChange, onBlur }) => {
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
disabled,
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
621
|
+
var _effect = _useSignals7();
|
|
622
|
+
try {
|
|
623
|
+
const { status, error } = getStatus();
|
|
624
|
+
return disabled && !getValue3() ? null : disabled && inputOnly ? /* @__PURE__ */ React7.createElement("p", null, getValue3() ?? "") : /* @__PURE__ */ React7.createElement(Input6.Root, {
|
|
625
|
+
validationValence: status
|
|
626
|
+
}, !inputOnly && /* @__PURE__ */ React7.createElement(InputHeader, {
|
|
627
|
+
error
|
|
628
|
+
}, /* @__PURE__ */ React7.createElement(Input6.Label, null, label)), disabled ? /* @__PURE__ */ React7.createElement("p", null, getValue3() ?? "") : /* @__PURE__ */ React7.createElement(Input6.TextInput, {
|
|
629
|
+
type: "number",
|
|
630
|
+
disabled,
|
|
631
|
+
placeholder,
|
|
632
|
+
value: getValue3() ?? 0,
|
|
633
|
+
onChange: (event) => onValueChange(type, event.target.value),
|
|
634
|
+
onBlur
|
|
635
|
+
}), inputOnly && /* @__PURE__ */ React7.createElement(Input6.DescriptionAndValidation, null, error));
|
|
636
|
+
} finally {
|
|
637
|
+
_effect.f();
|
|
638
|
+
}
|
|
536
639
|
};
|
|
537
|
-
var BooleanInput = ({ type, label, inputOnly, getStatus, getValue: getValue3, onValueChange }) => {
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
640
|
+
var BooleanInput = ({ type, label, inputOnly, getStatus, getValue: getValue3, onValueChange, disabled }) => {
|
|
641
|
+
var _effect = _useSignals7();
|
|
642
|
+
try {
|
|
643
|
+
const { status, error } = getStatus();
|
|
644
|
+
const checked = Boolean(getValue3());
|
|
645
|
+
const { t } = useTranslation4(translationKey);
|
|
646
|
+
return /* @__PURE__ */ React7.createElement(Input6.Root, {
|
|
647
|
+
validationValence: status
|
|
648
|
+
}, !inputOnly && /* @__PURE__ */ React7.createElement(InputHeader, {
|
|
649
|
+
error
|
|
650
|
+
}, /* @__PURE__ */ React7.createElement(Input6.Label, null, label)), disabled ? /* @__PURE__ */ React7.createElement("p", null, t(checked ? "boolean input true value" : "boolean input false value")) : /* @__PURE__ */ React7.createElement(Input6.Switch, {
|
|
651
|
+
checked,
|
|
652
|
+
onCheckedChange: (value) => onValueChange(type, value)
|
|
653
|
+
}), inputOnly && /* @__PURE__ */ React7.createElement(Input6.DescriptionAndValidation, null, error));
|
|
654
|
+
} finally {
|
|
655
|
+
_effect.f();
|
|
656
|
+
}
|
|
548
657
|
};
|
|
549
658
|
var SelectInput = ({ type, label, inputOnly, disabled, placeholder, options, getStatus, getValue: getValue3, onValueChange }) => {
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
659
|
+
var _effect = _useSignals7();
|
|
660
|
+
try {
|
|
661
|
+
const { status, error } = getStatus();
|
|
662
|
+
const value = getValue3();
|
|
663
|
+
const handleValueChange = useCallback3((value2) => onValueChange(type, value2), [
|
|
664
|
+
type,
|
|
665
|
+
onValueChange
|
|
666
|
+
]);
|
|
667
|
+
return disabled && !value ? null : /* @__PURE__ */ React7.createElement(Input6.Root, {
|
|
668
|
+
validationValence: status
|
|
669
|
+
}, !inputOnly && /* @__PURE__ */ React7.createElement(InputHeader, {
|
|
670
|
+
error
|
|
671
|
+
}, /* @__PURE__ */ React7.createElement(Input6.Label, null, label)), disabled ? /* @__PURE__ */ React7.createElement("p", null, options?.find(({ value: optionValue }) => optionValue === value)?.label ?? String(value)) : /* @__PURE__ */ React7.createElement(Select.Root, {
|
|
672
|
+
value,
|
|
673
|
+
onValueChange: handleValueChange
|
|
674
|
+
}, /* @__PURE__ */ React7.createElement(Select.TriggerButton, {
|
|
675
|
+
classNames: "is-full",
|
|
676
|
+
disabled,
|
|
677
|
+
placeholder
|
|
678
|
+
}), /* @__PURE__ */ React7.createElement(Select.Portal, null, /* @__PURE__ */ React7.createElement(Select.Content, null, /* @__PURE__ */ React7.createElement(Select.Viewport, null, options?.map(({ value: value2, label: label2 }) => (
|
|
679
|
+
// NOTE: Numeric values are converted to and from strings.
|
|
680
|
+
/* @__PURE__ */ React7.createElement(Select.Option, {
|
|
681
|
+
key: String(value2),
|
|
682
|
+
value: String(value2)
|
|
683
|
+
}, label2 ?? String(value2))
|
|
684
|
+
)))))), inputOnly && /* @__PURE__ */ React7.createElement(Input6.DescriptionAndValidation, null, error));
|
|
685
|
+
} finally {
|
|
686
|
+
_effect.f();
|
|
687
|
+
}
|
|
569
688
|
};
|
|
570
689
|
var MarkdownInput = ({ type, label, inputOnly, disabled, placeholder, getStatus, getValue: getValue3, onValueChange, onBlur }) => {
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
const
|
|
575
|
-
|
|
576
|
-
textarea
|
|
577
|
-
textarea
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
disabled,
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
690
|
+
var _effect = _useSignals7();
|
|
691
|
+
try {
|
|
692
|
+
const { status, error } = getStatus();
|
|
693
|
+
const textareaRef = useRef2(null);
|
|
694
|
+
const adjustHeight = useCallback3(() => {
|
|
695
|
+
const textarea = textareaRef.current;
|
|
696
|
+
if (textarea) {
|
|
697
|
+
textarea.style.blockSize = "auto";
|
|
698
|
+
textarea.style.blockSize = `${textarea.scrollHeight + 2}px`;
|
|
699
|
+
}
|
|
700
|
+
}, []);
|
|
701
|
+
useEffect3(() => {
|
|
702
|
+
adjustHeight();
|
|
703
|
+
}, [
|
|
704
|
+
adjustHeight
|
|
705
|
+
]);
|
|
706
|
+
useEffect3(() => {
|
|
707
|
+
adjustHeight();
|
|
708
|
+
}, [
|
|
709
|
+
getValue3(),
|
|
710
|
+
adjustHeight
|
|
711
|
+
]);
|
|
712
|
+
return /* @__PURE__ */ React7.createElement(Input6.Root, {
|
|
713
|
+
validationValence: status
|
|
714
|
+
}, !inputOnly && /* @__PURE__ */ React7.createElement(InputHeader, {
|
|
715
|
+
error
|
|
716
|
+
}, /* @__PURE__ */ React7.createElement(Input6.Label, null, label)), disabled ? /* @__PURE__ */ React7.createElement("p", null, getValue3() ?? "") : /* @__PURE__ */ React7.createElement(Input6.TextArea, {
|
|
717
|
+
ref: textareaRef,
|
|
718
|
+
disabled,
|
|
719
|
+
placeholder,
|
|
720
|
+
value: getValue3() ?? "",
|
|
721
|
+
classNames: "min-bs-auto max-h-40 overflow-auto",
|
|
722
|
+
onChange: (event) => onValueChange(type, event.target.value),
|
|
723
|
+
onBlur,
|
|
724
|
+
style: {
|
|
725
|
+
resize: "none"
|
|
726
|
+
},
|
|
727
|
+
spellCheck: false
|
|
728
|
+
}), inputOnly && /* @__PURE__ */ React7.createElement(Input6.Validation, null, error));
|
|
729
|
+
} finally {
|
|
730
|
+
_effect.f();
|
|
731
|
+
}
|
|
608
732
|
};
|
|
609
733
|
|
|
610
734
|
// packages/ui/react-ui-form/src/components/Form/Form.tsx
|
|
735
|
+
import { useSignals as _useSignals13 } from "@preact-signals/safe-react/tracking";
|
|
611
736
|
import React13, { useEffect as useEffect7, useMemo as useMemo6, useRef as useRef3 } from "react";
|
|
612
|
-
import { mx as
|
|
737
|
+
import { mx as mx7 } from "@dxos/react-ui-theme";
|
|
613
738
|
|
|
614
739
|
// packages/ui/react-ui-form/src/components/Form/FormActions.tsx
|
|
740
|
+
import { useSignals as _useSignals9 } from "@preact-signals/safe-react/tracking";
|
|
615
741
|
import React9 from "react";
|
|
616
|
-
import { IconButton as IconButton2, useTranslation as
|
|
617
|
-
import { mx as mx5 } from "@dxos/react-ui-theme";
|
|
742
|
+
import { IconButton as IconButton2, useTranslation as useTranslation5 } from "@dxos/react-ui";
|
|
618
743
|
|
|
619
744
|
// packages/ui/react-ui-form/src/components/Form/FormContext.tsx
|
|
620
|
-
import
|
|
745
|
+
import { useSignals as _useSignals8 } from "@preact-signals/safe-react/tracking";
|
|
746
|
+
import React8, { createContext, useContext, useEffect as useEffect6, useMemo as useMemo3, useCallback as useCallback6 } from "react";
|
|
621
747
|
import { raise } from "@dxos/debug";
|
|
622
748
|
import { getValue as getValue2 } from "@dxos/echo-schema";
|
|
623
749
|
import { createJsonPath as createJsonPath2 } from "@dxos/effect";
|
|
624
750
|
|
|
625
751
|
// packages/ui/react-ui-form/src/hooks/useForm.ts
|
|
626
|
-
import { SchemaAST
|
|
752
|
+
import { SchemaAST } from "effect";
|
|
627
753
|
import { useCallback as useCallback4, useEffect as useEffect4, useMemo as useMemo2, useState as useState3 } from "react";
|
|
628
754
|
import { getValue, setValue } from "@dxos/echo-schema";
|
|
629
755
|
import { createJsonPath, fromEffectValidationPath } from "@dxos/effect";
|
|
@@ -632,12 +758,12 @@ import { log } from "@dxos/log";
|
|
|
632
758
|
import { validateSchema } from "@dxos/schema";
|
|
633
759
|
var __dxlog_file = "/home/runner/work/dxos/dxos/packages/ui/react-ui-form/src/hooks/useForm.ts";
|
|
634
760
|
var useForm = ({ schema, initialValues, onValuesChanged, onValidate, onValid, onSave }) => {
|
|
635
|
-
invariant(
|
|
761
|
+
invariant(SchemaAST.isTypeLiteral(schema.ast), void 0, {
|
|
636
762
|
F: __dxlog_file,
|
|
637
763
|
L: 93,
|
|
638
764
|
S: void 0,
|
|
639
765
|
A: [
|
|
640
|
-
"
|
|
766
|
+
"SchemaAST.isTypeLiteral(schema.ast)",
|
|
641
767
|
""
|
|
642
768
|
]
|
|
643
769
|
});
|
|
@@ -738,7 +864,7 @@ var useForm = ({ schema, initialValues, onValuesChanged, onValidate, onValid, on
|
|
|
738
864
|
} catch (err) {
|
|
739
865
|
log.catch(err, void 0, {
|
|
740
866
|
F: __dxlog_file,
|
|
741
|
-
L:
|
|
867
|
+
L: 213,
|
|
742
868
|
S: void 0,
|
|
743
869
|
C: (f, a) => f(...a)
|
|
744
870
|
});
|
|
@@ -809,7 +935,7 @@ var useForm = ({ schema, initialValues, onValuesChanged, onValidate, onValid, on
|
|
|
809
935
|
var createKeySet = (obj, value) => {
|
|
810
936
|
invariant(obj, void 0, {
|
|
811
937
|
F: __dxlog_file,
|
|
812
|
-
L:
|
|
938
|
+
L: 275,
|
|
813
939
|
S: void 0,
|
|
814
940
|
A: [
|
|
815
941
|
"obj",
|
|
@@ -831,6 +957,80 @@ var flatMap = (errors) => {
|
|
|
831
957
|
}, {});
|
|
832
958
|
};
|
|
833
959
|
|
|
960
|
+
// packages/ui/react-ui-form/src/hooks/useRefQueryLookupHandler.ts
|
|
961
|
+
import { useCallback as useCallback5 } from "react";
|
|
962
|
+
import { getDXN } from "@dxos/echo-schema";
|
|
963
|
+
import { Filter } from "@dxos/react-client/echo";
|
|
964
|
+
import { isNonNullable } from "@dxos/util";
|
|
965
|
+
var useRefQueryLookupHandler = ({ space }) => {
|
|
966
|
+
return useCallback5(async (typeInfo) => {
|
|
967
|
+
if (!space) {
|
|
968
|
+
return [];
|
|
969
|
+
}
|
|
970
|
+
const query = space.db.query(Filter.typename(typeInfo.typename));
|
|
971
|
+
const { objects } = await query.run();
|
|
972
|
+
return objects.map((object) => {
|
|
973
|
+
const dxn = getDXN(object);
|
|
974
|
+
if (!dxn) {
|
|
975
|
+
return void 0;
|
|
976
|
+
}
|
|
977
|
+
const item = {
|
|
978
|
+
dxn,
|
|
979
|
+
label: object?.name ?? object?.id ?? ""
|
|
980
|
+
};
|
|
981
|
+
return item;
|
|
982
|
+
}).filter(isNonNullable);
|
|
983
|
+
}, [
|
|
984
|
+
space
|
|
985
|
+
]);
|
|
986
|
+
};
|
|
987
|
+
|
|
988
|
+
// packages/ui/react-ui-form/src/hooks/useQueryRefOptions.ts
|
|
989
|
+
import { useEffect as useEffect5, useState as useState4 } from "react";
|
|
990
|
+
import { log as log2 } from "@dxos/log";
|
|
991
|
+
var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-form/src/hooks/useQueryRefOptions.ts";
|
|
992
|
+
var useQueryRefOptions = ({ refTypeInfo, onQueryRefOptions }) => {
|
|
993
|
+
const [options, setOptions] = useState4([]);
|
|
994
|
+
const [loading, setLoading] = useState4(false);
|
|
995
|
+
useEffect5(() => {
|
|
996
|
+
if (!refTypeInfo || !onQueryRefOptions) {
|
|
997
|
+
return;
|
|
998
|
+
}
|
|
999
|
+
const fetchOptions = async () => {
|
|
1000
|
+
setLoading(true);
|
|
1001
|
+
try {
|
|
1002
|
+
const fetchedOptions = await onQueryRefOptions(refTypeInfo);
|
|
1003
|
+
setOptions(fetchedOptions.map((option) => {
|
|
1004
|
+
const dxn = option.dxn.toString();
|
|
1005
|
+
return {
|
|
1006
|
+
id: dxn,
|
|
1007
|
+
label: option.label ?? dxn,
|
|
1008
|
+
hue: "neutral"
|
|
1009
|
+
};
|
|
1010
|
+
}));
|
|
1011
|
+
} catch (error) {
|
|
1012
|
+
log2.error("Failed to fetch ref options:", error, {
|
|
1013
|
+
F: __dxlog_file2,
|
|
1014
|
+
L: 42,
|
|
1015
|
+
S: void 0,
|
|
1016
|
+
C: (f, a) => f(...a)
|
|
1017
|
+
});
|
|
1018
|
+
setOptions([]);
|
|
1019
|
+
} finally {
|
|
1020
|
+
setLoading(false);
|
|
1021
|
+
}
|
|
1022
|
+
};
|
|
1023
|
+
void fetchOptions();
|
|
1024
|
+
}, [
|
|
1025
|
+
refTypeInfo,
|
|
1026
|
+
onQueryRefOptions
|
|
1027
|
+
]);
|
|
1028
|
+
return {
|
|
1029
|
+
options,
|
|
1030
|
+
loading
|
|
1031
|
+
};
|
|
1032
|
+
};
|
|
1033
|
+
|
|
834
1034
|
// packages/ui/react-ui-form/src/components/Form/FormContext.tsx
|
|
835
1035
|
var FormContext = /* @__PURE__ */ createContext(void 0);
|
|
836
1036
|
var useFormContext = () => {
|
|
@@ -860,16 +1060,14 @@ var useInputProps = (path = []) => {
|
|
|
860
1060
|
]);
|
|
861
1061
|
};
|
|
862
1062
|
var FormProvider = ({ children, formRef, autoSave, ...formOptions }) => {
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
}
|
|
868
|
-
const handleKeyDown = (event) => {
|
|
1063
|
+
var _effect = _useSignals8();
|
|
1064
|
+
try {
|
|
1065
|
+
const form = useForm(formOptions);
|
|
1066
|
+
const handleKeyDown = useCallback6((event) => {
|
|
869
1067
|
const keyIsEnter = event.key === "Enter";
|
|
870
1068
|
const modifierUsed = event.ctrlKey || event.altKey || event.metaKey || event.shiftKey;
|
|
871
1069
|
const inputIsTextarea = event.target.tagName.toLowerCase() === "textarea";
|
|
872
|
-
const inputOptOut = event.target.hasAttribute("data-no-submit");
|
|
1070
|
+
const inputOptOut = event.target.hasAttribute("data-no-submit") || event.target.closest("[data-no-submit]") !== null;
|
|
873
1071
|
const shouldSubmitRegularInput = !inputIsTextarea && keyIsEnter && !modifierUsed;
|
|
874
1072
|
const shouldSubmitTextarea = inputIsTextarea && keyIsEnter && event.metaKey;
|
|
875
1073
|
if ((shouldSubmitRegularInput || shouldSubmitTextarea) && !inputOptOut) {
|
|
@@ -880,881 +1078,108 @@ var FormProvider = ({ children, formRef, autoSave, ...formOptions }) => {
|
|
|
880
1078
|
event.target.blur();
|
|
881
1079
|
}
|
|
882
1080
|
}
|
|
883
|
-
}
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
1081
|
+
}, [
|
|
1082
|
+
form,
|
|
1083
|
+
autoSave
|
|
1084
|
+
]);
|
|
1085
|
+
useEffect6(() => {
|
|
1086
|
+
if (!formRef?.current) {
|
|
1087
|
+
return;
|
|
1088
|
+
}
|
|
1089
|
+
const formElement = formRef.current;
|
|
1090
|
+
formElement.addEventListener("keydown", handleKeyDown);
|
|
1091
|
+
return () => formElement.removeEventListener("keydown", handleKeyDown);
|
|
1092
|
+
}, [
|
|
1093
|
+
formRef,
|
|
1094
|
+
form.canSave,
|
|
1095
|
+
form.formIsValid,
|
|
1096
|
+
form.handleSave,
|
|
1097
|
+
autoSave
|
|
1098
|
+
]);
|
|
1099
|
+
return /* @__PURE__ */ React8.createElement(FormContext.Provider, {
|
|
1100
|
+
value: form
|
|
1101
|
+
}, children);
|
|
1102
|
+
} finally {
|
|
1103
|
+
_effect.f();
|
|
1104
|
+
}
|
|
897
1105
|
};
|
|
898
1106
|
|
|
899
1107
|
// packages/ui/react-ui-form/src/components/Form/FormActions.tsx
|
|
900
|
-
var FormActions = ({
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
}
|
|
1108
|
+
var FormActions = ({ readonly, onCancel }) => {
|
|
1109
|
+
var _effect = _useSignals9();
|
|
1110
|
+
try {
|
|
1111
|
+
const { t } = useTranslation5(translationKey);
|
|
1112
|
+
const { canSave, handleSave } = useFormContext();
|
|
1113
|
+
return /* @__PURE__ */ React9.createElement("div", {
|
|
1114
|
+
role: "none",
|
|
1115
|
+
className: "flex [&_button]:grow gap-1"
|
|
1116
|
+
}, onCancel && !readonly && /* @__PURE__ */ React9.createElement(IconButton2, {
|
|
1117
|
+
"data-testid": "cancel-button",
|
|
1118
|
+
icon: "ph--x--regular",
|
|
1119
|
+
label: t("button cancel"),
|
|
1120
|
+
onClick: onCancel
|
|
1121
|
+
}), handleSave && /* @__PURE__ */ React9.createElement(IconButton2, {
|
|
1122
|
+
type: "submit",
|
|
1123
|
+
"data-testid": "save-button",
|
|
1124
|
+
disabled: !canSave,
|
|
1125
|
+
icon: "ph--check--regular",
|
|
1126
|
+
label: t("button save"),
|
|
1127
|
+
onClick: handleSave
|
|
1128
|
+
}));
|
|
1129
|
+
} finally {
|
|
1130
|
+
_effect.f();
|
|
1131
|
+
}
|
|
922
1132
|
};
|
|
923
1133
|
|
|
924
1134
|
// packages/ui/react-ui-form/src/components/Form/FormContent.tsx
|
|
925
|
-
import {
|
|
1135
|
+
import { useSignals as _useSignals12 } from "@preact-signals/safe-react/tracking";
|
|
1136
|
+
import { Schema, SchemaAST as SchemaAST4, pipe as pipe2 } from "effect";
|
|
926
1137
|
import { capitalize as capitalize2 } from "effect/String";
|
|
927
1138
|
import React12, { useMemo as useMemo5 } from "react";
|
|
928
|
-
import {
|
|
929
|
-
import {
|
|
930
|
-
import { mx as mx7 } from "@dxos/react-ui-theme";
|
|
1139
|
+
import { createJsonPath as createJsonPath3, findNode as findNode3, getDiscriminatedType as getDiscriminatedType2, isDiscriminatedUnion as isDiscriminatedUnion2 } from "@dxos/effect";
|
|
1140
|
+
import { mx as mx6 } from "@dxos/react-ui-theme";
|
|
931
1141
|
import { getSchemaProperties as getSchemaProperties2 } from "@dxos/schema";
|
|
932
1142
|
import { isNotFalsy } from "@dxos/util";
|
|
933
1143
|
|
|
934
1144
|
// packages/ui/react-ui-form/src/components/Form/ArrayField.tsx
|
|
935
|
-
import {
|
|
1145
|
+
import { useSignals as _useSignals10 } from "@preact-signals/safe-react/tracking";
|
|
1146
|
+
import { SchemaAST as SchemaAST3, pipe } from "effect";
|
|
936
1147
|
import { capitalize } from "effect/String";
|
|
937
|
-
import React10, {
|
|
938
|
-
import {
|
|
939
|
-
import { findNode, getDiscriminatedType, isDiscriminatedUnion, SimpleType } from "@dxos/effect";
|
|
1148
|
+
import React10, { Fragment, useCallback as useCallback7 } from "react";
|
|
1149
|
+
import { findNode as findNode2, getDiscriminatedType, isDiscriminatedUnion, SimpleType } from "@dxos/effect";
|
|
940
1150
|
import { invariant as invariant2 } from "@dxos/invariant";
|
|
941
|
-
import { IconButton as IconButton3, useTranslation as
|
|
942
|
-
import { mx as mx6 } from "@dxos/react-ui-theme";
|
|
1151
|
+
import { IconButton as IconButton3, useTranslation as useTranslation6 } from "@dxos/react-ui";
|
|
943
1152
|
import { getSchemaProperties } from "@dxos/schema";
|
|
944
|
-
var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-form/src/components/Form/ArrayField.tsx";
|
|
945
|
-
var padding = "px-2";
|
|
946
|
-
var ArrayField = ({ property, readonly, path, inputProps, Custom, lookupComponent }) => {
|
|
947
|
-
const { t } = useTranslation5(translationKey);
|
|
948
|
-
const { ast, name, type, title } = property;
|
|
949
|
-
const values = useFormValues(path ?? []) ?? [];
|
|
950
|
-
invariant2(Array.isArray(values), `Values at path ${path?.join(".")} must be an array.`, {
|
|
951
|
-
F: __dxlog_file2,
|
|
952
|
-
L: 39,
|
|
953
|
-
S: void 0,
|
|
954
|
-
A: [
|
|
955
|
-
"Array.isArray(values)",
|
|
956
|
-
"`Values at path ${path?.join('.')} must be an array.`"
|
|
957
|
-
]
|
|
958
|
-
});
|
|
959
|
-
const label = title ?? pipe(name, capitalize);
|
|
960
|
-
const tupleType = findNode(ast, AST2.isTupleType);
|
|
961
|
-
const elementType = tupleType?.rest[0]?.type;
|
|
962
|
-
const getDefaultObjectValue = (typeNode) => {
|
|
963
|
-
const baseNode = findNode(typeNode, isDiscriminatedUnion);
|
|
964
|
-
const typeLiteral = baseNode ? getDiscriminatedType(baseNode, {}) : findNode(typeNode, AST2.isTypeLiteral);
|
|
965
|
-
if (!typeLiteral) {
|
|
966
|
-
return {};
|
|
967
|
-
}
|
|
968
|
-
return Object.fromEntries(getSchemaProperties(typeLiteral, {}).map((prop) => [
|
|
969
|
-
prop.name,
|
|
970
|
-
prop.defaultValue
|
|
971
|
-
]));
|
|
972
|
-
};
|
|
973
|
-
const newValue = useMemo4(() => {
|
|
974
|
-
if (type === "object" && elementType) {
|
|
975
|
-
return getDefaultObjectValue(elementType);
|
|
976
|
-
} else {
|
|
977
|
-
return SimpleType.getDefaultValue(type);
|
|
978
|
-
}
|
|
979
|
-
}, [
|
|
980
|
-
type,
|
|
981
|
-
elementType
|
|
982
|
-
]);
|
|
983
|
-
const handleAdd = useCallback5(() => {
|
|
984
|
-
inputProps.onValueChange(type, [
|
|
985
|
-
...values,
|
|
986
|
-
newValue
|
|
987
|
-
]);
|
|
988
|
-
}, [
|
|
989
|
-
type,
|
|
990
|
-
elementType,
|
|
991
|
-
inputProps,
|
|
992
|
-
newValue,
|
|
993
|
-
values
|
|
994
|
-
]);
|
|
995
|
-
const handleRemove = useCallback5((index) => {
|
|
996
|
-
const newValues = values.filter((_, i) => i !== index);
|
|
997
|
-
inputProps.onValueChange(type, newValues);
|
|
998
|
-
}, [
|
|
999
|
-
type,
|
|
1000
|
-
inputProps,
|
|
1001
|
-
values
|
|
1002
|
-
]);
|
|
1003
|
-
if (!elementType) {
|
|
1004
|
-
return null;
|
|
1005
|
-
}
|
|
1006
|
-
return /* @__PURE__ */ React10.createElement("div", {
|
|
1007
|
-
role: "none",
|
|
1008
|
-
className: mx6(padding)
|
|
1009
|
-
}, /* @__PURE__ */ React10.createElement(InputHeader, null, label), /* @__PURE__ */ React10.createElement("div", {
|
|
1010
|
-
role: "none",
|
|
1011
|
-
className: "flex flex-col gap-1"
|
|
1012
|
-
}, values.map((_value, index) => /* @__PURE__ */ React10.createElement("div", {
|
|
1013
|
-
key: index,
|
|
1014
|
-
role: "none",
|
|
1015
|
-
className: "flex items-center gap-1"
|
|
1016
|
-
}, /* @__PURE__ */ React10.createElement("div", {
|
|
1017
|
-
role: "none",
|
|
1018
|
-
className: "flex-1"
|
|
1019
|
-
}, /* @__PURE__ */ React10.createElement(FormField, {
|
|
1020
|
-
property: {
|
|
1021
|
-
...property,
|
|
1022
|
-
array: false,
|
|
1023
|
-
ast: elementType
|
|
1024
|
-
},
|
|
1025
|
-
path: [
|
|
1026
|
-
...path ?? [],
|
|
1027
|
-
index
|
|
1028
|
-
],
|
|
1029
|
-
readonly,
|
|
1030
|
-
inline: true,
|
|
1031
|
-
Custom,
|
|
1032
|
-
lookupComponent
|
|
1033
|
-
})), /* @__PURE__ */ React10.createElement(IconButton3, {
|
|
1034
|
-
icon: "ph--trash--regular",
|
|
1035
|
-
iconOnly: true,
|
|
1036
|
-
label: t("button remove"),
|
|
1037
|
-
onClick: () => handleRemove(index)
|
|
1038
|
-
})))), /* @__PURE__ */ React10.createElement("div", {
|
|
1039
|
-
role: "none",
|
|
1040
|
-
className: "flex justify-between items-center plb-1"
|
|
1041
|
-
}, /* @__PURE__ */ React10.createElement(IconButton3, {
|
|
1042
|
-
icon: "ph--plus--regular",
|
|
1043
|
-
iconOnly: true,
|
|
1044
|
-
label: t("button add"),
|
|
1045
|
-
onClick: handleAdd
|
|
1046
|
-
})));
|
|
1047
|
-
};
|
|
1048
1153
|
|
|
1049
|
-
// packages/ui/react-ui-form/src/
|
|
1050
|
-
import
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
import { refFromDXN, RefImpl } from "@dxos/live-object";
|
|
1055
|
-
import { log as log2 } from "@dxos/log";
|
|
1056
|
-
var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-form/src/components/Form/RefField.tsx";
|
|
1057
|
-
var RefField = ({ ast, type, label, readonly, placeholder, inline, onQueryRefOptions, inputProps }) => {
|
|
1058
|
-
const { getValue: getValue3, onValueChange, ...restInputProps } = inputProps;
|
|
1059
|
-
const refTypeInfo = findAnnotation(ast, ReferenceAnnotationId);
|
|
1060
|
-
const [refOptions, setRefOptions] = useState4([]);
|
|
1061
|
-
const [loading, setLoading] = useState4(false);
|
|
1062
|
-
useEffect6(() => {
|
|
1063
|
-
if (!refTypeInfo || !onQueryRefOptions) {
|
|
1064
|
-
return;
|
|
1065
|
-
}
|
|
1066
|
-
const fetchOptions = async () => {
|
|
1067
|
-
setLoading(true);
|
|
1068
|
-
try {
|
|
1069
|
-
const options = await onQueryRefOptions(refTypeInfo);
|
|
1070
|
-
setRefOptions(options.map((option) => ({
|
|
1071
|
-
label: option.label,
|
|
1072
|
-
value: option.dxn.toString()
|
|
1073
|
-
})));
|
|
1074
|
-
} catch (error) {
|
|
1075
|
-
log2.error("Failed to fetch ref options:", error, {
|
|
1076
|
-
F: __dxlog_file3,
|
|
1077
|
-
L: 68,
|
|
1078
|
-
S: void 0,
|
|
1079
|
-
C: (f, a) => f(...a)
|
|
1080
|
-
});
|
|
1081
|
-
setRefOptions([]);
|
|
1082
|
-
} finally {
|
|
1083
|
-
setLoading(false);
|
|
1084
|
-
}
|
|
1085
|
-
};
|
|
1086
|
-
void fetchOptions();
|
|
1087
|
-
}, [
|
|
1088
|
-
refTypeInfo,
|
|
1089
|
-
onQueryRefOptions
|
|
1090
|
-
]);
|
|
1091
|
-
if (!refTypeInfo) {
|
|
1092
|
-
return null;
|
|
1154
|
+
// packages/ui/react-ui-form/src/util/field.ts
|
|
1155
|
+
import { FormatEnum, GeoLocation as GeoLocation2, TypeEnum } from "@dxos/echo-schema";
|
|
1156
|
+
var parseValue = ({ type, format, value }) => {
|
|
1157
|
+
if (value === void 0 || value === null || value === "") {
|
|
1158
|
+
return void 0;
|
|
1093
1159
|
}
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1160
|
+
const parseScalar = (type2) => {
|
|
1161
|
+
switch (type2) {
|
|
1162
|
+
case TypeEnum.Boolean: {
|
|
1163
|
+
if (typeof value === "string") {
|
|
1164
|
+
const lowercaseValue = value.toLowerCase();
|
|
1165
|
+
if (lowercaseValue === "0" || lowercaseValue === "false") {
|
|
1166
|
+
return false;
|
|
1167
|
+
} else if (lowercaseValue === "1" || lowercaseValue === "true") {
|
|
1168
|
+
return true;
|
|
1169
|
+
}
|
|
1170
|
+
}
|
|
1171
|
+
return Boolean(value);
|
|
1103
1172
|
}
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
return formValue;
|
|
1173
|
+
case TypeEnum.Number: {
|
|
1174
|
+
const cleaned = typeof value === "string" ? value.replace(/[^0-9.-]+/g, "") : value;
|
|
1175
|
+
const num = Number(cleaned);
|
|
1176
|
+
return Number.isNaN(num) ? null : num;
|
|
1109
1177
|
}
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
return /* @__PURE__ */ React11.createElement(TextInput, {
|
|
1116
|
-
type,
|
|
1117
|
-
label,
|
|
1118
|
-
disabled: readonly,
|
|
1119
|
-
placeholder,
|
|
1120
|
-
inputOnly: inline,
|
|
1121
|
-
getValue: handleGetValue2,
|
|
1122
|
-
onValueChange: handleOnValueChange,
|
|
1123
|
-
...restInputProps
|
|
1124
|
-
});
|
|
1125
|
-
}
|
|
1126
|
-
const handleGetValue = () => {
|
|
1127
|
-
const formValue = getValue3();
|
|
1128
|
-
if (formValue instanceof RefImpl) {
|
|
1129
|
-
return formValue.dxn.toString();
|
|
1130
|
-
}
|
|
1131
|
-
return void 0;
|
|
1132
|
-
};
|
|
1133
|
-
const handleValueChanged = (_type, dxnString) => {
|
|
1134
|
-
const dxn = DXN.parse(dxnString);
|
|
1135
|
-
const ref = refFromDXN(dxn);
|
|
1136
|
-
onValueChange("object", ref);
|
|
1137
|
-
};
|
|
1138
|
-
return /* @__PURE__ */ React11.createElement(SelectInput, {
|
|
1139
|
-
type,
|
|
1140
|
-
label,
|
|
1141
|
-
disabled: readonly || loading,
|
|
1142
|
-
placeholder: loading ? "Loading options..." : placeholder,
|
|
1143
|
-
inputOnly: inline,
|
|
1144
|
-
getValue: handleGetValue,
|
|
1145
|
-
onValueChange: handleValueChanged,
|
|
1146
|
-
options: refOptions,
|
|
1147
|
-
...restInputProps
|
|
1148
|
-
});
|
|
1149
|
-
};
|
|
1150
|
-
|
|
1151
|
-
// packages/ui/react-ui-form/src/components/Form/factory.tsx
|
|
1152
|
-
import { FormatEnum } from "@dxos/echo-schema";
|
|
1153
|
-
var getInputComponent = (type, format) => {
|
|
1154
|
-
switch (format) {
|
|
1155
|
-
case FormatEnum.GeoPoint:
|
|
1156
|
-
return GeoPointInput;
|
|
1157
|
-
case FormatEnum.Markdown:
|
|
1158
|
-
return MarkdownInput;
|
|
1159
|
-
}
|
|
1160
|
-
switch (type) {
|
|
1161
|
-
case "string":
|
|
1162
|
-
return TextInput;
|
|
1163
|
-
case "number":
|
|
1164
|
-
return NumberInput;
|
|
1165
|
-
case "boolean":
|
|
1166
|
-
return BooleanInput;
|
|
1167
|
-
}
|
|
1168
|
-
};
|
|
1169
|
-
|
|
1170
|
-
// packages/ui/react-ui-form/src/components/Form/FormContent.tsx
|
|
1171
|
-
var FormField = ({ property, path, readonly, inline, onQueryRefOptions, lookupComponent, Custom }) => {
|
|
1172
|
-
const inputProps = useInputProps(path);
|
|
1173
|
-
const { ast, name, type, format, title, description, options, examples, array } = property;
|
|
1174
|
-
const label = useMemo5(() => title ?? pipe2(name, capitalize2), [
|
|
1175
|
-
title,
|
|
1176
|
-
name
|
|
1177
|
-
]);
|
|
1178
|
-
const placeholder = useMemo5(() => examples?.length ? `Example: "${examples[0]}"` : description, [
|
|
1179
|
-
examples,
|
|
1180
|
-
description
|
|
1181
|
-
]);
|
|
1182
|
-
const FoundComponent = lookupComponent?.({
|
|
1183
|
-
prop: name,
|
|
1184
|
-
schema: S.make(ast),
|
|
1185
|
-
inputProps: {
|
|
1186
|
-
type,
|
|
1187
|
-
format,
|
|
1188
|
-
label,
|
|
1189
|
-
disabled: readonly,
|
|
1190
|
-
placeholder,
|
|
1191
|
-
...inputProps
|
|
1192
|
-
}
|
|
1193
|
-
});
|
|
1194
|
-
if (FoundComponent) {
|
|
1195
|
-
return /* @__PURE__ */ React12.createElement("div", {
|
|
1196
|
-
role: "none"
|
|
1197
|
-
}, FoundComponent);
|
|
1198
|
-
}
|
|
1199
|
-
const jsonPath = createJsonPath3(path ?? []);
|
|
1200
|
-
const CustomComponent = Custom?.[jsonPath];
|
|
1201
|
-
if (CustomComponent) {
|
|
1202
|
-
return /* @__PURE__ */ React12.createElement(CustomComponent, {
|
|
1203
|
-
type,
|
|
1204
|
-
format,
|
|
1205
|
-
label,
|
|
1206
|
-
inputOnly: inline,
|
|
1207
|
-
placeholder,
|
|
1208
|
-
disabled: readonly,
|
|
1209
|
-
...inputProps
|
|
1210
|
-
});
|
|
1211
|
-
}
|
|
1212
|
-
if (array) {
|
|
1213
|
-
return /* @__PURE__ */ React12.createElement(ArrayField, {
|
|
1214
|
-
property,
|
|
1215
|
-
path,
|
|
1216
|
-
inputProps,
|
|
1217
|
-
readonly,
|
|
1218
|
-
Custom
|
|
1219
|
-
});
|
|
1220
|
-
}
|
|
1221
|
-
const InputComponent = getInputComponent(type, format);
|
|
1222
|
-
if (InputComponent) {
|
|
1223
|
-
return /* @__PURE__ */ React12.createElement("div", {
|
|
1224
|
-
role: "none"
|
|
1225
|
-
}, /* @__PURE__ */ React12.createElement(InputComponent, {
|
|
1226
|
-
type,
|
|
1227
|
-
format,
|
|
1228
|
-
label,
|
|
1229
|
-
inputOnly: inline,
|
|
1230
|
-
placeholder,
|
|
1231
|
-
disabled: readonly,
|
|
1232
|
-
...inputProps
|
|
1233
|
-
}));
|
|
1234
|
-
}
|
|
1235
|
-
if (options) {
|
|
1236
|
-
return /* @__PURE__ */ React12.createElement("div", {
|
|
1237
|
-
role: "none"
|
|
1238
|
-
}, /* @__PURE__ */ React12.createElement(SelectInput, {
|
|
1239
|
-
type,
|
|
1240
|
-
format,
|
|
1241
|
-
disabled: readonly,
|
|
1242
|
-
inputOnly: inline,
|
|
1243
|
-
label,
|
|
1244
|
-
options: options.map((option) => ({
|
|
1245
|
-
value: option,
|
|
1246
|
-
label: String(option)
|
|
1247
|
-
})),
|
|
1248
|
-
placeholder,
|
|
1249
|
-
...inputProps
|
|
1250
|
-
}));
|
|
1251
|
-
}
|
|
1252
|
-
if (format === "ref") {
|
|
1253
|
-
return /* @__PURE__ */ React12.createElement(RefField, {
|
|
1254
|
-
ast,
|
|
1255
|
-
type,
|
|
1256
|
-
label,
|
|
1257
|
-
readonly,
|
|
1258
|
-
placeholder,
|
|
1259
|
-
inline,
|
|
1260
|
-
onQueryRefOptions,
|
|
1261
|
-
inputProps
|
|
1262
|
-
});
|
|
1263
|
-
}
|
|
1264
|
-
if (type === "object") {
|
|
1265
|
-
const baseNode = findNode2(ast, isDiscriminatedUnion2);
|
|
1266
|
-
const typeLiteral = baseNode ? getDiscriminatedType2(baseNode, inputProps.getValue()) : findNode2(ast, AST3.isTypeLiteral);
|
|
1267
|
-
if (typeLiteral) {
|
|
1268
|
-
return /* @__PURE__ */ React12.createElement("div", {
|
|
1269
|
-
role: "none"
|
|
1270
|
-
}, !inline && /* @__PURE__ */ React12.createElement("h3", {
|
|
1271
|
-
className: "text-lg mbs-2 mbe-1"
|
|
1272
|
-
}, label), /* @__PURE__ */ React12.createElement(FormFields, {
|
|
1273
|
-
schema: S.make(typeLiteral),
|
|
1274
|
-
path,
|
|
1275
|
-
readonly,
|
|
1276
|
-
onQueryRefOptions,
|
|
1277
|
-
Custom,
|
|
1278
|
-
lookupComponent
|
|
1279
|
-
}));
|
|
1280
|
-
}
|
|
1281
|
-
}
|
|
1282
|
-
return null;
|
|
1283
|
-
};
|
|
1284
|
-
var FormFields = ({ schema, path, filter, sort, readonly, onQueryRefOptions, lookupComponent, Custom }) => {
|
|
1285
|
-
const values = useFormValues(path);
|
|
1286
|
-
const properties = useMemo5(() => {
|
|
1287
|
-
const props = getSchemaProperties2(schema.ast, values);
|
|
1288
|
-
const filtered = filter ? filter(props) : props;
|
|
1289
|
-
return sort ? filtered.sort((a, b) => sort.indexOf(a.name) - sort.indexOf(b.name)) : filtered;
|
|
1290
|
-
}, [
|
|
1291
|
-
schema,
|
|
1292
|
-
values,
|
|
1293
|
-
filter,
|
|
1294
|
-
sort
|
|
1295
|
-
]);
|
|
1296
|
-
return /* @__PURE__ */ React12.createElement("div", {
|
|
1297
|
-
role: "form",
|
|
1298
|
-
className: mx7("flex flex-col w-full gap-2")
|
|
1299
|
-
}, properties.map((property) => {
|
|
1300
|
-
return /* @__PURE__ */ React12.createElement(FormField, {
|
|
1301
|
-
key: property.name,
|
|
1302
|
-
property,
|
|
1303
|
-
path: [
|
|
1304
|
-
...path ?? [],
|
|
1305
|
-
property.name
|
|
1306
|
-
],
|
|
1307
|
-
readonly,
|
|
1308
|
-
onQueryRefOptions,
|
|
1309
|
-
lookupComponent,
|
|
1310
|
-
Custom
|
|
1311
|
-
});
|
|
1312
|
-
}).filter(isNotFalsy));
|
|
1313
|
-
};
|
|
1314
|
-
|
|
1315
|
-
// packages/ui/react-ui-form/src/components/Form/Form.tsx
|
|
1316
|
-
var Form = ({ classNames, schema, values: initialValues, path = [], autoFocus, readonly, filter, sort, autoSave, testId, onValuesChanged, onValidate, onSave, onCancel, onQueryRefOptions, lookupComponent, Custom }) => {
|
|
1317
|
-
const formRef = useRef3(null);
|
|
1318
|
-
const onValid = useMemo6(() => autoSave ? onSave : void 0, [
|
|
1319
|
-
autoSave,
|
|
1320
|
-
onSave
|
|
1321
|
-
]);
|
|
1322
|
-
useEffect7(() => {
|
|
1323
|
-
if (autoFocus && formRef.current) {
|
|
1324
|
-
const input = formRef.current.querySelector("input");
|
|
1325
|
-
if (input) {
|
|
1326
|
-
input.focus();
|
|
1327
|
-
}
|
|
1328
|
-
}
|
|
1329
|
-
}, [
|
|
1330
|
-
autoFocus
|
|
1331
|
-
]);
|
|
1332
|
-
return /* @__PURE__ */ React13.createElement(FormProvider, {
|
|
1333
|
-
formRef,
|
|
1334
|
-
schema,
|
|
1335
|
-
autoSave,
|
|
1336
|
-
initialValues,
|
|
1337
|
-
onValuesChanged,
|
|
1338
|
-
onValidate,
|
|
1339
|
-
onValid,
|
|
1340
|
-
onSave
|
|
1341
|
-
}, /* @__PURE__ */ React13.createElement("div", {
|
|
1342
|
-
ref: formRef,
|
|
1343
|
-
role: "none",
|
|
1344
|
-
className: mx8("p-2", classNames),
|
|
1345
|
-
"data-testid": testId
|
|
1346
|
-
}, /* @__PURE__ */ React13.createElement(FormFields, {
|
|
1347
|
-
schema,
|
|
1348
|
-
path,
|
|
1349
|
-
readonly,
|
|
1350
|
-
filter,
|
|
1351
|
-
sort,
|
|
1352
|
-
onQueryRefOptions,
|
|
1353
|
-
lookupComponent,
|
|
1354
|
-
Custom
|
|
1355
|
-
}), (onCancel || onSave) && !autoSave && /* @__PURE__ */ React13.createElement(FormActions, {
|
|
1356
|
-
onCancel,
|
|
1357
|
-
readonly
|
|
1358
|
-
})));
|
|
1359
|
-
};
|
|
1360
|
-
|
|
1361
|
-
// packages/ui/react-ui-form/src/components/FieldEditor/FieldEditor.tsx
|
|
1362
|
-
var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-form/src/components/FieldEditor/FieldEditor.tsx";
|
|
1363
|
-
var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
|
|
1364
|
-
const { t } = useTranslation6(translationKey);
|
|
1365
|
-
const [props, setProps] = useState5(projection.getFieldProjection(field.id).props);
|
|
1366
|
-
useEffect8(() => setProps(projection.getFieldProjection(field.id).props), [
|
|
1367
|
-
field,
|
|
1368
|
-
projection
|
|
1369
|
-
]);
|
|
1370
|
-
const [schemas, setSchemas] = useState5([]);
|
|
1371
|
-
useEffect8(() => {
|
|
1372
|
-
if (!registry) {
|
|
1373
|
-
return;
|
|
1374
|
-
}
|
|
1375
|
-
const subscription = registry.query().subscribe((query) => setSchemas(query.results), {
|
|
1376
|
-
fire: true
|
|
1377
|
-
});
|
|
1378
|
-
const t2 = setTimeout(async () => {
|
|
1379
|
-
const schemas2 = await registry.query().run();
|
|
1380
|
-
setSchemas(schemas2);
|
|
1381
|
-
});
|
|
1382
|
-
return () => {
|
|
1383
|
-
clearTimeout(t2);
|
|
1384
|
-
subscription?.();
|
|
1385
|
-
};
|
|
1386
|
-
}, [
|
|
1387
|
-
registry
|
|
1388
|
-
]);
|
|
1389
|
-
const [referenceSchema, setReferenceSchema] = useState5();
|
|
1390
|
-
useEffect8(() => {
|
|
1391
|
-
setReferenceSchema(schemas.find((schema) => schema.typename === props?.referenceSchema));
|
|
1392
|
-
}, [
|
|
1393
|
-
schemas,
|
|
1394
|
-
props?.referenceSchema
|
|
1395
|
-
]);
|
|
1396
|
-
const [{ fieldSchema }, setFieldSchema] = useState5({
|
|
1397
|
-
fieldSchema: getFormatSchema(props?.format)
|
|
1398
|
-
});
|
|
1399
|
-
const handleValuesChanged = useCallback6((_props) => {
|
|
1400
|
-
setFieldSchema((prev) => {
|
|
1401
|
-
const fieldSchema2 = getFormatSchema(_props.format);
|
|
1402
|
-
if (prev.fieldSchema === fieldSchema2) {
|
|
1403
|
-
return prev;
|
|
1404
|
-
}
|
|
1405
|
-
return {
|
|
1406
|
-
fieldSchema: fieldSchema2
|
|
1407
|
-
};
|
|
1408
|
-
});
|
|
1409
|
-
setReferenceSchema((prev) => {
|
|
1410
|
-
if (_props.referenceSchema !== prev?.typename) {
|
|
1411
|
-
const newSchema = schemas.find((schema) => schema.typename === _props.referenceSchema);
|
|
1412
|
-
if (newSchema) {
|
|
1413
|
-
return newSchema;
|
|
1414
|
-
}
|
|
1415
|
-
}
|
|
1416
|
-
return prev;
|
|
1417
|
-
});
|
|
1418
|
-
setProps((props2) => {
|
|
1419
|
-
const type = formatToType[_props.format];
|
|
1420
|
-
if (props2.type !== type) {
|
|
1421
|
-
return {
|
|
1422
|
-
...props2,
|
|
1423
|
-
..._props,
|
|
1424
|
-
type
|
|
1425
|
-
};
|
|
1426
|
-
}
|
|
1427
|
-
return _props;
|
|
1428
|
-
});
|
|
1429
|
-
}, [
|
|
1430
|
-
schemas,
|
|
1431
|
-
props.format,
|
|
1432
|
-
props.referenceSchema
|
|
1433
|
-
]);
|
|
1434
|
-
const handleValidate = useCallback6(({ property }) => {
|
|
1435
|
-
if (property && view.fields.find((f) => f.path === property && f.path !== field.path)) {
|
|
1436
|
-
return [
|
|
1437
|
-
{
|
|
1438
|
-
path: "property",
|
|
1439
|
-
message: `property is not unique: '${property}'`
|
|
1440
|
-
}
|
|
1441
|
-
];
|
|
1442
|
-
}
|
|
1443
|
-
}, [
|
|
1444
|
-
view.fields,
|
|
1445
|
-
field
|
|
1446
|
-
]);
|
|
1447
|
-
const handleSave = useCallback6((props2) => {
|
|
1448
|
-
projection.setFieldProjection({
|
|
1449
|
-
field,
|
|
1450
|
-
props: props2
|
|
1451
|
-
});
|
|
1452
|
-
onSave();
|
|
1453
|
-
}, [
|
|
1454
|
-
projection,
|
|
1455
|
-
field,
|
|
1456
|
-
onSave
|
|
1457
|
-
]);
|
|
1458
|
-
const handleCancel = useCallback6(() => {
|
|
1459
|
-
requestAnimationFrame(() => onCancel?.());
|
|
1460
|
-
onSave();
|
|
1461
|
-
}, [
|
|
1462
|
-
onSave
|
|
1463
|
-
]);
|
|
1464
|
-
const Custom = useMemo7(() => ({
|
|
1465
|
-
["format"]: (props2) => /* @__PURE__ */ React14.createElement(SelectInput, {
|
|
1466
|
-
...props2,
|
|
1467
|
-
options: FormatEnums.filter((value) => value !== FormatEnum2.None).map((value) => ({
|
|
1468
|
-
value,
|
|
1469
|
-
label: t(`format ${value}`)
|
|
1470
|
-
}))
|
|
1471
|
-
}),
|
|
1472
|
-
["referenceSchema"]: (props2) => /* @__PURE__ */ React14.createElement(SelectInput, {
|
|
1473
|
-
...props2,
|
|
1474
|
-
options: schemas.map((schema) => ({
|
|
1475
|
-
value: schema.typename
|
|
1476
|
-
}))
|
|
1477
|
-
}),
|
|
1478
|
-
["referencePath"]: (props2) => /* @__PURE__ */ React14.createElement(SelectInput, {
|
|
1479
|
-
...props2,
|
|
1480
|
-
options: referenceSchema ? getSchemaProperties3(referenceSchema.ast).sort(sortProperties).map((p) => ({
|
|
1481
|
-
value: p.name
|
|
1482
|
-
})) : []
|
|
1483
|
-
}),
|
|
1484
|
-
["options"]: (props2) => /* @__PURE__ */ React14.createElement(SelectOptionInput, props2)
|
|
1485
|
-
}), [
|
|
1486
|
-
t,
|
|
1487
|
-
schemas,
|
|
1488
|
-
referenceSchema
|
|
1489
|
-
]);
|
|
1490
|
-
const propIsNotType = useCallback6((props2) => props2.filter((p) => p.name !== "type"), []);
|
|
1491
|
-
if (!fieldSchema) {
|
|
1492
|
-
log3.warn("invalid format", {
|
|
1493
|
-
props
|
|
1494
|
-
}, {
|
|
1495
|
-
F: __dxlog_file4,
|
|
1496
|
-
L: 174,
|
|
1497
|
-
S: void 0,
|
|
1498
|
-
C: (f, a) => f(...a)
|
|
1499
|
-
});
|
|
1500
|
-
return null;
|
|
1501
|
-
}
|
|
1502
|
-
return /* @__PURE__ */ React14.createElement(Form, {
|
|
1503
|
-
key: field.id,
|
|
1504
|
-
autoFocus: true,
|
|
1505
|
-
values: props,
|
|
1506
|
-
schema: fieldSchema,
|
|
1507
|
-
filter: propIsNotType,
|
|
1508
|
-
sort: [
|
|
1509
|
-
"property",
|
|
1510
|
-
"format"
|
|
1511
|
-
],
|
|
1512
|
-
onValuesChanged: handleValuesChanged,
|
|
1513
|
-
onValidate: handleValidate,
|
|
1514
|
-
onSave: handleSave,
|
|
1515
|
-
onCancel: handleCancel,
|
|
1516
|
-
Custom
|
|
1517
|
-
});
|
|
1518
|
-
};
|
|
1519
|
-
|
|
1520
|
-
// packages/ui/react-ui-form/src/components/ViewEditor/ViewEditor.tsx
|
|
1521
|
-
import React15, { useCallback as useCallback7, useMemo as useMemo8, useState as useState6 } from "react";
|
|
1522
|
-
import { AST as AST4, Format, S as S2 } from "@dxos/echo-schema";
|
|
1523
|
-
import { invariant as invariant3 } from "@dxos/invariant";
|
|
1524
|
-
import { IconButton as IconButton4, useTranslation as useTranslation7 } from "@dxos/react-ui";
|
|
1525
|
-
import { List as List2 } from "@dxos/react-ui-list";
|
|
1526
|
-
import { ghostHover, inputTextLabel, mx as mx9 } from "@dxos/react-ui-theme";
|
|
1527
|
-
import { FieldSchema, ViewProjection, VIEW_FIELD_LIMIT } from "@dxos/schema";
|
|
1528
|
-
var __dxlog_file5 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-form/src/components/ViewEditor/ViewEditor.tsx";
|
|
1529
|
-
var grid = "grid grid-cols-[32px_1fr_32px] min-bs-[2.5rem]";
|
|
1530
|
-
var ViewMetaSchema = S2.Struct({
|
|
1531
|
-
name: S2.String.annotations({
|
|
1532
|
-
[AST4.TitleAnnotationId]: "View"
|
|
1533
|
-
}),
|
|
1534
|
-
typename: Format.URL.annotations({
|
|
1535
|
-
[AST4.TitleAnnotationId]: "Typename"
|
|
1536
|
-
})
|
|
1537
|
-
}).pipe(S2.mutable);
|
|
1538
|
-
var ViewEditor = ({ classNames, schema, view, registry, readonly, showHeading = false, onTypenameChanged, onDelete }) => {
|
|
1539
|
-
const { t } = useTranslation7(translationKey);
|
|
1540
|
-
const projection = useMemo8(() => new ViewProjection(schema.jsonSchema, view), [
|
|
1541
|
-
schema,
|
|
1542
|
-
view
|
|
1543
|
-
]);
|
|
1544
|
-
const [field, setField] = useState6();
|
|
1545
|
-
const viewValues = useMemo8(() => {
|
|
1546
|
-
return {
|
|
1547
|
-
name: view.name,
|
|
1548
|
-
// TODO(burdon): Need to warn user of possible consequences of editing.
|
|
1549
|
-
// TODO(burdon): Settings should have domain name owned by user.
|
|
1550
|
-
typename: view.query.typename
|
|
1551
|
-
};
|
|
1552
|
-
}, [
|
|
1553
|
-
view
|
|
1554
|
-
]);
|
|
1555
|
-
const handleSelect = useCallback7((field2) => {
|
|
1556
|
-
setField((f) => f === field2 ? void 0 : field2);
|
|
1557
|
-
}, []);
|
|
1558
|
-
const handleAdd = useCallback7(() => {
|
|
1559
|
-
invariant3(!schema.readonly, void 0, {
|
|
1560
|
-
F: __dxlog_file5,
|
|
1561
|
-
L: 76,
|
|
1562
|
-
S: void 0,
|
|
1563
|
-
A: [
|
|
1564
|
-
"!schema.readonly",
|
|
1565
|
-
""
|
|
1566
|
-
]
|
|
1567
|
-
});
|
|
1568
|
-
const field2 = projection.createFieldProjection();
|
|
1569
|
-
setField(field2);
|
|
1570
|
-
}, [
|
|
1571
|
-
schema,
|
|
1572
|
-
view
|
|
1573
|
-
]);
|
|
1574
|
-
const handleUpdate = useCallback7(({ name, typename }) => {
|
|
1575
|
-
invariant3(!schema.readonly, void 0, {
|
|
1576
|
-
F: __dxlog_file5,
|
|
1577
|
-
L: 83,
|
|
1578
|
-
S: void 0,
|
|
1579
|
-
A: [
|
|
1580
|
-
"!schema.readonly",
|
|
1581
|
-
""
|
|
1582
|
-
]
|
|
1583
|
-
});
|
|
1584
|
-
requestAnimationFrame(() => {
|
|
1585
|
-
if (view.name !== name) {
|
|
1586
|
-
view.name = name;
|
|
1587
|
-
}
|
|
1588
|
-
if (view.query.typename !== typename) {
|
|
1589
|
-
onTypenameChanged?.(typename);
|
|
1590
|
-
}
|
|
1591
|
-
});
|
|
1592
|
-
}, [
|
|
1593
|
-
schema,
|
|
1594
|
-
view,
|
|
1595
|
-
onTypenameChanged
|
|
1596
|
-
]);
|
|
1597
|
-
const handleDelete = useCallback7((fieldId) => {
|
|
1598
|
-
invariant3(!schema.readonly, void 0, {
|
|
1599
|
-
F: __dxlog_file5,
|
|
1600
|
-
L: 99,
|
|
1601
|
-
S: void 0,
|
|
1602
|
-
A: [
|
|
1603
|
-
"!schema.readonly",
|
|
1604
|
-
""
|
|
1605
|
-
]
|
|
1606
|
-
});
|
|
1607
|
-
if (fieldId === field?.id) {
|
|
1608
|
-
setField(void 0);
|
|
1609
|
-
}
|
|
1610
|
-
onDelete?.(fieldId);
|
|
1611
|
-
}, [
|
|
1612
|
-
schema,
|
|
1613
|
-
field,
|
|
1614
|
-
onDelete
|
|
1615
|
-
]);
|
|
1616
|
-
const handleMove = useCallback7((fromIndex, toIndex) => {
|
|
1617
|
-
invariant3(!schema.readonly, void 0, {
|
|
1618
|
-
F: __dxlog_file5,
|
|
1619
|
-
L: 111,
|
|
1620
|
-
S: void 0,
|
|
1621
|
-
A: [
|
|
1622
|
-
"!schema.readonly",
|
|
1623
|
-
""
|
|
1624
|
-
]
|
|
1625
|
-
});
|
|
1626
|
-
const fields = [
|
|
1627
|
-
...view.fields
|
|
1628
|
-
];
|
|
1629
|
-
const [moved] = fields.splice(fromIndex, 1);
|
|
1630
|
-
fields.splice(toIndex, 0, moved);
|
|
1631
|
-
view.fields = fields;
|
|
1632
|
-
}, [
|
|
1633
|
-
schema,
|
|
1634
|
-
view.fields
|
|
1635
|
-
]);
|
|
1636
|
-
const handleClose = useCallback7(() => setField(void 0), []);
|
|
1637
|
-
const hiddenProperties = projection.getHiddenProperties();
|
|
1638
|
-
const handleHide = useCallback7((fieldId) => {
|
|
1639
|
-
setField(void 0);
|
|
1640
|
-
projection.hideFieldProjection(fieldId);
|
|
1641
|
-
}, [
|
|
1642
|
-
projection
|
|
1643
|
-
]);
|
|
1644
|
-
const handleShow = useCallback7((property) => {
|
|
1645
|
-
setField(void 0);
|
|
1646
|
-
projection.showFieldProjection(property);
|
|
1647
|
-
}, [
|
|
1648
|
-
projection
|
|
1649
|
-
]);
|
|
1650
|
-
return /* @__PURE__ */ React15.createElement("div", {
|
|
1651
|
-
role: "none",
|
|
1652
|
-
className: mx9("flex flex-col w-full divide-y divide-separator", classNames)
|
|
1653
|
-
}, /* @__PURE__ */ React15.createElement(Form, {
|
|
1654
|
-
autoSave: true,
|
|
1655
|
-
schema: ViewMetaSchema,
|
|
1656
|
-
values: viewValues,
|
|
1657
|
-
onSave: schema.readonly ? void 0 : handleUpdate
|
|
1658
|
-
}), /* @__PURE__ */ React15.createElement("div", null, /* @__PURE__ */ React15.createElement("div", {
|
|
1659
|
-
role: "none",
|
|
1660
|
-
className: "p-2"
|
|
1661
|
-
}, /* @__PURE__ */ React15.createElement("label", {
|
|
1662
|
-
className: mx9(inputTextLabel)
|
|
1663
|
-
}, t("fields label"))), /* @__PURE__ */ React15.createElement(List2.Root, {
|
|
1664
|
-
items: view.fields,
|
|
1665
|
-
isItem: S2.is(FieldSchema),
|
|
1666
|
-
getId: (field2) => field2.id,
|
|
1667
|
-
onMove: schema.readonly ? void 0 : handleMove
|
|
1668
|
-
}, ({ items: fields }) => /* @__PURE__ */ React15.createElement(React15.Fragment, null, showHeading && /* @__PURE__ */ React15.createElement("div", {
|
|
1669
|
-
role: "heading",
|
|
1670
|
-
className: grid
|
|
1671
|
-
}, /* @__PURE__ */ React15.createElement("div", null), /* @__PURE__ */ React15.createElement("div", {
|
|
1672
|
-
className: "flex items-center text-sm"
|
|
1673
|
-
}, t("field path label"))), /* @__PURE__ */ React15.createElement("div", {
|
|
1674
|
-
role: "list",
|
|
1675
|
-
className: "flex flex-col w-full"
|
|
1676
|
-
}, fields?.map((field2) => /* @__PURE__ */ React15.createElement(List2.Item, {
|
|
1677
|
-
key: field2.id,
|
|
1678
|
-
item: field2,
|
|
1679
|
-
classNames: mx9(grid, ghostHover, "cursor-pointer")
|
|
1680
|
-
}, /* @__PURE__ */ React15.createElement(List2.ItemDragHandle, null), /* @__PURE__ */ React15.createElement(List2.ItemTitle, {
|
|
1681
|
-
onClick: () => handleSelect(field2)
|
|
1682
|
-
}, field2.path), /* @__PURE__ */ React15.createElement("div", {
|
|
1683
|
-
className: "flex items-center gap-2 -ml-4"
|
|
1684
|
-
}, /* @__PURE__ */ React15.createElement(List2.ItemButton, {
|
|
1685
|
-
icon: "ph--eye-slash--regular",
|
|
1686
|
-
disabled: view.fields.length <= 1,
|
|
1687
|
-
onClick: () => handleHide(field2.id)
|
|
1688
|
-
}), !schema.readonly && /* @__PURE__ */ React15.createElement(List2.ItemDeleteButton, {
|
|
1689
|
-
icon: "ph--trash--regular",
|
|
1690
|
-
disabled: view.fields.length <= 1,
|
|
1691
|
-
onClick: () => handleDelete(field2.id)
|
|
1692
|
-
}))))))), hiddenProperties.length > 0 && /* @__PURE__ */ React15.createElement("div", null, /* @__PURE__ */ React15.createElement("div", {
|
|
1693
|
-
role: "none",
|
|
1694
|
-
className: "p-2"
|
|
1695
|
-
}, /* @__PURE__ */ React15.createElement("label", {
|
|
1696
|
-
className: mx9(inputTextLabel)
|
|
1697
|
-
}, t("hidden fields label"))), /* @__PURE__ */ React15.createElement(List2.Root, {
|
|
1698
|
-
items: hiddenProperties,
|
|
1699
|
-
isItem: (item) => typeof item === "string",
|
|
1700
|
-
getId: (property) => property
|
|
1701
|
-
}, ({ items: properties }) => /* @__PURE__ */ React15.createElement("div", {
|
|
1702
|
-
role: "list",
|
|
1703
|
-
className: "flex flex-col w-full"
|
|
1704
|
-
}, properties?.map((property) => /* @__PURE__ */ React15.createElement(List2.Item, {
|
|
1705
|
-
key: property,
|
|
1706
|
-
item: property,
|
|
1707
|
-
classNames: mx9(grid, ghostHover, "cursor-pointer")
|
|
1708
|
-
}, /* @__PURE__ */ React15.createElement("div", null), /* @__PURE__ */ React15.createElement(List2.ItemTitle, null, property), /* @__PURE__ */ React15.createElement(List2.ItemButton, {
|
|
1709
|
-
icon: "ph--eye--regular",
|
|
1710
|
-
onClick: () => handleShow(property)
|
|
1711
|
-
}))))))), field && /* @__PURE__ */ React15.createElement(FieldEditor, {
|
|
1712
|
-
key: field.id,
|
|
1713
|
-
view,
|
|
1714
|
-
projection,
|
|
1715
|
-
field,
|
|
1716
|
-
registry,
|
|
1717
|
-
onSave: handleClose
|
|
1718
|
-
}), !readonly && !field && /* @__PURE__ */ React15.createElement("div", {
|
|
1719
|
-
className: "flex p-2 justify-center"
|
|
1720
|
-
}, /* @__PURE__ */ React15.createElement(IconButton4, {
|
|
1721
|
-
icon: "ph--plus--regular",
|
|
1722
|
-
label: t("button add property"),
|
|
1723
|
-
onClick: schema.readonly ? void 0 : handleAdd,
|
|
1724
|
-
// TODO(burdon): Show field limit in ux (not tooltip).
|
|
1725
|
-
disabled: view.fields.length >= VIEW_FIELD_LIMIT
|
|
1726
|
-
})));
|
|
1727
|
-
};
|
|
1728
|
-
|
|
1729
|
-
// packages/ui/react-ui-form/src/util/field.ts
|
|
1730
|
-
import { FormatEnum as FormatEnum3, GeoLocation as GeoLocation2, TypeEnum } from "@dxos/echo-schema";
|
|
1731
|
-
var parseValue = ({ type, format, value }) => {
|
|
1732
|
-
if (value === void 0 || value === null || value === "") {
|
|
1733
|
-
return void 0;
|
|
1734
|
-
}
|
|
1735
|
-
const parseScalar = (type2) => {
|
|
1736
|
-
switch (type2) {
|
|
1737
|
-
case TypeEnum.Boolean: {
|
|
1738
|
-
if (typeof value === "string") {
|
|
1739
|
-
const lowercaseValue = value.toLowerCase();
|
|
1740
|
-
if (lowercaseValue === "0" || lowercaseValue === "false") {
|
|
1741
|
-
return false;
|
|
1742
|
-
} else if (lowercaseValue === "1" || lowercaseValue === "true") {
|
|
1743
|
-
return true;
|
|
1744
|
-
}
|
|
1745
|
-
}
|
|
1746
|
-
return Boolean(value);
|
|
1747
|
-
}
|
|
1748
|
-
case TypeEnum.Number: {
|
|
1749
|
-
const cleaned = typeof value === "string" ? value.replace(/[^0-9.-]+/g, "") : value;
|
|
1750
|
-
const num = Number(cleaned);
|
|
1751
|
-
return Number.isNaN(num) ? null : num;
|
|
1752
|
-
}
|
|
1753
|
-
case TypeEnum.String:
|
|
1754
|
-
case TypeEnum.Ref:
|
|
1755
|
-
return String(value);
|
|
1756
|
-
default: {
|
|
1757
|
-
return value;
|
|
1178
|
+
case TypeEnum.String:
|
|
1179
|
+
case TypeEnum.Ref:
|
|
1180
|
+
return String(value);
|
|
1181
|
+
default: {
|
|
1182
|
+
return value;
|
|
1758
1183
|
}
|
|
1759
1184
|
}
|
|
1760
1185
|
};
|
|
@@ -1762,26 +1187,26 @@ var parseValue = ({ type, format, value }) => {
|
|
|
1762
1187
|
return parseScalar(type);
|
|
1763
1188
|
}
|
|
1764
1189
|
switch (format) {
|
|
1765
|
-
case
|
|
1190
|
+
case FormatEnum.Boolean:
|
|
1766
1191
|
return parseScalar(TypeEnum.Boolean);
|
|
1767
|
-
case
|
|
1768
|
-
case
|
|
1769
|
-
case
|
|
1192
|
+
case FormatEnum.Number:
|
|
1193
|
+
case FormatEnum.Percent:
|
|
1194
|
+
case FormatEnum.Currency:
|
|
1770
1195
|
return parseScalar(TypeEnum.Number);
|
|
1771
|
-
case
|
|
1772
|
-
case
|
|
1196
|
+
case FormatEnum.String:
|
|
1197
|
+
case FormatEnum.Markdown: {
|
|
1773
1198
|
return parseScalar(TypeEnum.String);
|
|
1774
1199
|
}
|
|
1775
|
-
case
|
|
1776
|
-
throw new Error(`unexpected format: ${
|
|
1777
|
-
case
|
|
1778
|
-
case
|
|
1779
|
-
case
|
|
1780
|
-
case
|
|
1200
|
+
case FormatEnum.Ref:
|
|
1201
|
+
throw new Error(`unexpected format: ${FormatEnum.Ref}`);
|
|
1202
|
+
case FormatEnum.DateTime:
|
|
1203
|
+
case FormatEnum.Date:
|
|
1204
|
+
case FormatEnum.Time:
|
|
1205
|
+
case FormatEnum.Timestamp: {
|
|
1781
1206
|
const date = new Date(value);
|
|
1782
1207
|
return isNaN(date.getTime()) ? null : date;
|
|
1783
1208
|
}
|
|
1784
|
-
case
|
|
1209
|
+
case FormatEnum.GeoPoint: {
|
|
1785
1210
|
if (typeof value === "string") {
|
|
1786
1211
|
const cleaned = value.replace(/[^0-9.,-]+/g, "");
|
|
1787
1212
|
const parts = cleaned.split(",");
|
|
@@ -1829,23 +1254,23 @@ var cellClassesForFieldType = ({ type, format }) => {
|
|
|
1829
1254
|
}
|
|
1830
1255
|
}
|
|
1831
1256
|
switch (format) {
|
|
1832
|
-
case
|
|
1257
|
+
case FormatEnum.Markdown:
|
|
1833
1258
|
return void 0;
|
|
1834
|
-
case
|
|
1835
|
-
case
|
|
1836
|
-
case
|
|
1837
|
-
case
|
|
1838
|
-
case
|
|
1259
|
+
case FormatEnum.Time:
|
|
1260
|
+
case FormatEnum.Timestamp:
|
|
1261
|
+
case FormatEnum.DateTime:
|
|
1262
|
+
case FormatEnum.Date:
|
|
1263
|
+
case FormatEnum.Duration:
|
|
1839
1264
|
return [
|
|
1840
1265
|
"font-mono",
|
|
1841
1266
|
"text-right"
|
|
1842
1267
|
];
|
|
1843
|
-
case
|
|
1268
|
+
case FormatEnum.Currency:
|
|
1844
1269
|
return [
|
|
1845
1270
|
"text-right"
|
|
1846
1271
|
];
|
|
1847
|
-
case
|
|
1848
|
-
case
|
|
1272
|
+
case FormatEnum.JSON:
|
|
1273
|
+
case FormatEnum.DID:
|
|
1849
1274
|
return [
|
|
1850
1275
|
"font-mono"
|
|
1851
1276
|
];
|
|
@@ -1860,7 +1285,7 @@ var pathNotUniqueError = (path) => ({
|
|
|
1860
1285
|
|
|
1861
1286
|
// packages/ui/react-ui-form/src/util/formatting.ts
|
|
1862
1287
|
import { format as formatDate } from "date-fns/format";
|
|
1863
|
-
import { FormatEnum as
|
|
1288
|
+
import { FormatEnum as FormatEnum2, GeoLocation as GeoLocation3, TypeEnum as TypeEnum2 } from "@dxos/echo-schema";
|
|
1864
1289
|
var formatForDisplay = ({ type, format, value, locale = void 0 }) => {
|
|
1865
1290
|
const formatScalar = (type2) => {
|
|
1866
1291
|
switch (type2) {
|
|
@@ -1880,20 +1305,20 @@ var formatForDisplay = ({ type, format, value, locale = void 0 }) => {
|
|
|
1880
1305
|
return formatScalar(type);
|
|
1881
1306
|
}
|
|
1882
1307
|
switch (format) {
|
|
1883
|
-
case
|
|
1308
|
+
case FormatEnum2.Boolean: {
|
|
1884
1309
|
return formatScalar(TypeEnum2.Boolean);
|
|
1885
1310
|
}
|
|
1886
|
-
case
|
|
1311
|
+
case FormatEnum2.Number: {
|
|
1887
1312
|
return formatScalar(TypeEnum2.Number);
|
|
1888
1313
|
}
|
|
1889
|
-
case
|
|
1890
|
-
case
|
|
1314
|
+
case FormatEnum2.String:
|
|
1315
|
+
case FormatEnum2.Ref: {
|
|
1891
1316
|
return formatScalar(TypeEnum2.String);
|
|
1892
1317
|
}
|
|
1893
|
-
case
|
|
1318
|
+
case FormatEnum2.Percent: {
|
|
1894
1319
|
return `${value * 100}%`;
|
|
1895
1320
|
}
|
|
1896
|
-
case
|
|
1321
|
+
case FormatEnum2.Currency: {
|
|
1897
1322
|
return value.toLocaleString(locale, {
|
|
1898
1323
|
style: "currency",
|
|
1899
1324
|
currency: "USD",
|
|
@@ -1901,28 +1326,28 @@ var formatForDisplay = ({ type, format, value, locale = void 0 }) => {
|
|
|
1901
1326
|
maximumFractionDigits: 2
|
|
1902
1327
|
});
|
|
1903
1328
|
}
|
|
1904
|
-
case
|
|
1329
|
+
case FormatEnum2.Date: {
|
|
1905
1330
|
try {
|
|
1906
1331
|
return formatDate(new Date(value), "yyyy-MM-dd");
|
|
1907
1332
|
} catch (error) {
|
|
1908
1333
|
return "Invalid Date";
|
|
1909
1334
|
}
|
|
1910
1335
|
}
|
|
1911
|
-
case
|
|
1336
|
+
case FormatEnum2.Time: {
|
|
1912
1337
|
try {
|
|
1913
1338
|
return formatDate(new Date(value), "HH:mm:ss");
|
|
1914
1339
|
} catch (error) {
|
|
1915
1340
|
return "Invalid Time";
|
|
1916
1341
|
}
|
|
1917
1342
|
}
|
|
1918
|
-
case
|
|
1343
|
+
case FormatEnum2.DateTime: {
|
|
1919
1344
|
try {
|
|
1920
1345
|
return formatDate(new Date(value), "yyyy-MM-dd HH:mm:ss");
|
|
1921
1346
|
} catch (error) {
|
|
1922
1347
|
return "Invalid DateTime";
|
|
1923
1348
|
}
|
|
1924
1349
|
}
|
|
1925
|
-
case
|
|
1350
|
+
case FormatEnum2.GeoPoint: {
|
|
1926
1351
|
if (value === null || value === void 0) {
|
|
1927
1352
|
return "";
|
|
1928
1353
|
}
|
|
@@ -1956,31 +1381,31 @@ var formatForEditing = ({ type, format, value, locale = void 0 }) => {
|
|
|
1956
1381
|
return formatScalar(type);
|
|
1957
1382
|
}
|
|
1958
1383
|
switch (format) {
|
|
1959
|
-
case
|
|
1960
|
-
case
|
|
1961
|
-
case
|
|
1962
|
-
case
|
|
1384
|
+
case FormatEnum2.Boolean:
|
|
1385
|
+
case FormatEnum2.Number:
|
|
1386
|
+
case FormatEnum2.String:
|
|
1387
|
+
case FormatEnum2.Ref: {
|
|
1963
1388
|
return formatScalar(type);
|
|
1964
1389
|
}
|
|
1965
|
-
case
|
|
1390
|
+
case FormatEnum2.Percent: {
|
|
1966
1391
|
return String(value * 100);
|
|
1967
1392
|
}
|
|
1968
|
-
case
|
|
1393
|
+
case FormatEnum2.Currency: {
|
|
1969
1394
|
return String(value);
|
|
1970
1395
|
}
|
|
1971
|
-
case
|
|
1396
|
+
case FormatEnum2.DateTime: {
|
|
1972
1397
|
const date = new Date(value);
|
|
1973
1398
|
return date.toISOString();
|
|
1974
1399
|
}
|
|
1975
|
-
case
|
|
1400
|
+
case FormatEnum2.Date: {
|
|
1976
1401
|
const date = new Date(value);
|
|
1977
1402
|
return date.toISOString().split("T")[0];
|
|
1978
1403
|
}
|
|
1979
|
-
case
|
|
1404
|
+
case FormatEnum2.Time: {
|
|
1980
1405
|
const date = new Date(value);
|
|
1981
1406
|
return date.toISOString().split("T")[1].split(".")[0];
|
|
1982
1407
|
}
|
|
1983
|
-
case
|
|
1408
|
+
case FormatEnum2.GeoPoint: {
|
|
1984
1409
|
if (value === null || value === void 0) {
|
|
1985
1410
|
return "";
|
|
1986
1411
|
}
|
|
@@ -1995,6 +1420,935 @@ var formatForEditing = ({ type, format, value, locale = void 0 }) => {
|
|
|
1995
1420
|
}
|
|
1996
1421
|
}
|
|
1997
1422
|
};
|
|
1423
|
+
|
|
1424
|
+
// packages/ui/react-ui-form/src/util/refs.ts
|
|
1425
|
+
import { FormatEnum as FormatEnum3, ReferenceAnnotationId } from "@dxos/echo-schema";
|
|
1426
|
+
import { findAnnotation } from "@dxos/effect";
|
|
1427
|
+
|
|
1428
|
+
// packages/ui/react-ui-form/src/util/schema.ts
|
|
1429
|
+
import { SchemaAST as SchemaAST2 } from "effect";
|
|
1430
|
+
import { findNode } from "@dxos/effect";
|
|
1431
|
+
var findArrayElementType = (ast) => {
|
|
1432
|
+
const tupleType = findNode(ast, SchemaAST2.isTupleType);
|
|
1433
|
+
const elementType = tupleType?.rest[0]?.type;
|
|
1434
|
+
return elementType;
|
|
1435
|
+
};
|
|
1436
|
+
|
|
1437
|
+
// packages/ui/react-ui-form/src/util/refs.ts
|
|
1438
|
+
var getRefProps = (property) => {
|
|
1439
|
+
const { ast, format, array } = property;
|
|
1440
|
+
if (format === FormatEnum3.Ref) {
|
|
1441
|
+
return {
|
|
1442
|
+
ast,
|
|
1443
|
+
isArray: false
|
|
1444
|
+
};
|
|
1445
|
+
}
|
|
1446
|
+
if (array) {
|
|
1447
|
+
const elementType = findArrayElementType(ast);
|
|
1448
|
+
if (elementType) {
|
|
1449
|
+
const annotation = findAnnotation(elementType, ReferenceAnnotationId);
|
|
1450
|
+
if (annotation) {
|
|
1451
|
+
return {
|
|
1452
|
+
ast: elementType,
|
|
1453
|
+
isArray: true
|
|
1454
|
+
};
|
|
1455
|
+
}
|
|
1456
|
+
}
|
|
1457
|
+
}
|
|
1458
|
+
return void 0;
|
|
1459
|
+
};
|
|
1460
|
+
|
|
1461
|
+
// packages/ui/react-ui-form/src/components/Form/ArrayField.tsx
|
|
1462
|
+
var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-form/src/components/Form/ArrayField.tsx";
|
|
1463
|
+
var ArrayField = ({ property, readonly, path, inputProps, Custom, lookupComponent }) => {
|
|
1464
|
+
var _effect = _useSignals10();
|
|
1465
|
+
try {
|
|
1466
|
+
const { t } = useTranslation6(translationKey);
|
|
1467
|
+
const { ast, name, type, title } = property;
|
|
1468
|
+
const values = useFormValues(path ?? []) ?? [];
|
|
1469
|
+
invariant2(Array.isArray(values), `Values at path ${path?.join(".")} must be an array.`, {
|
|
1470
|
+
F: __dxlog_file3,
|
|
1471
|
+
L: 36,
|
|
1472
|
+
S: void 0,
|
|
1473
|
+
A: [
|
|
1474
|
+
"Array.isArray(values)",
|
|
1475
|
+
"`Values at path ${path?.join('.')} must be an array.`"
|
|
1476
|
+
]
|
|
1477
|
+
});
|
|
1478
|
+
const label = title ?? pipe(name, capitalize);
|
|
1479
|
+
const elementType = findArrayElementType(ast);
|
|
1480
|
+
const getDefaultObjectValue = (typeNode) => {
|
|
1481
|
+
const baseNode = findNode2(typeNode, isDiscriminatedUnion);
|
|
1482
|
+
const typeLiteral = baseNode ? getDiscriminatedType(baseNode, {}) : findNode2(typeNode, SchemaAST3.isTypeLiteral);
|
|
1483
|
+
if (!typeLiteral) {
|
|
1484
|
+
return {};
|
|
1485
|
+
}
|
|
1486
|
+
return Object.fromEntries(getSchemaProperties(typeLiteral, {}).map((prop) => [
|
|
1487
|
+
prop.name,
|
|
1488
|
+
prop.defaultValue
|
|
1489
|
+
]));
|
|
1490
|
+
};
|
|
1491
|
+
const getDefaultValue = () => type === "object" && elementType ? getDefaultObjectValue(elementType) : SimpleType.getDefaultValue(type);
|
|
1492
|
+
const handleAdd = useCallback7(() => {
|
|
1493
|
+
inputProps.onValueChange(type, [
|
|
1494
|
+
...values,
|
|
1495
|
+
getDefaultValue()
|
|
1496
|
+
]);
|
|
1497
|
+
}, [
|
|
1498
|
+
type,
|
|
1499
|
+
elementType,
|
|
1500
|
+
inputProps,
|
|
1501
|
+
values
|
|
1502
|
+
]);
|
|
1503
|
+
const handleRemove = useCallback7((index) => {
|
|
1504
|
+
const newValues = values.filter((_, i) => i !== index);
|
|
1505
|
+
inputProps.onValueChange(type, newValues);
|
|
1506
|
+
}, [
|
|
1507
|
+
type,
|
|
1508
|
+
inputProps,
|
|
1509
|
+
values
|
|
1510
|
+
]);
|
|
1511
|
+
if (!elementType) {
|
|
1512
|
+
return null;
|
|
1513
|
+
}
|
|
1514
|
+
return readonly && values.length < 1 ? null : /* @__PURE__ */ React10.createElement(React10.Fragment, null, /* @__PURE__ */ React10.createElement(InputHeader, null, label), /* @__PURE__ */ React10.createElement("div", {
|
|
1515
|
+
role: "none",
|
|
1516
|
+
className: readonly ? "flex flex-wrap gap-1 mlb-1" : values.length > 0 ? "grid gap-1 grid-cols-[1fr_min-content] mlb-1" : "hidden"
|
|
1517
|
+
}, values.map((_value, index) => {
|
|
1518
|
+
const field = /* @__PURE__ */ React10.createElement(FormField, {
|
|
1519
|
+
property: {
|
|
1520
|
+
...property,
|
|
1521
|
+
array: false,
|
|
1522
|
+
ast: elementType
|
|
1523
|
+
},
|
|
1524
|
+
path: [
|
|
1525
|
+
...path ?? [],
|
|
1526
|
+
index
|
|
1527
|
+
],
|
|
1528
|
+
readonly,
|
|
1529
|
+
inline: true,
|
|
1530
|
+
Custom,
|
|
1531
|
+
lookupComponent
|
|
1532
|
+
});
|
|
1533
|
+
return readonly ? field : /* @__PURE__ */ React10.createElement(Fragment, {
|
|
1534
|
+
key: index
|
|
1535
|
+
}, /* @__PURE__ */ React10.createElement("div", {
|
|
1536
|
+
role: "none"
|
|
1537
|
+
}, field), /* @__PURE__ */ React10.createElement(IconButton3, {
|
|
1538
|
+
icon: "ph--trash--regular",
|
|
1539
|
+
iconOnly: true,
|
|
1540
|
+
label: t("button remove"),
|
|
1541
|
+
onClick: () => handleRemove(index),
|
|
1542
|
+
classNames: "self-center"
|
|
1543
|
+
}));
|
|
1544
|
+
})), !readonly && /* @__PURE__ */ React10.createElement(IconButton3, {
|
|
1545
|
+
classNames: "is-full mlb-1 flex",
|
|
1546
|
+
icon: "ph--plus--regular",
|
|
1547
|
+
label: t("add field"),
|
|
1548
|
+
onClick: handleAdd
|
|
1549
|
+
}));
|
|
1550
|
+
} finally {
|
|
1551
|
+
_effect.f();
|
|
1552
|
+
}
|
|
1553
|
+
};
|
|
1554
|
+
|
|
1555
|
+
// packages/ui/react-ui-form/src/components/Form/RefField.tsx
|
|
1556
|
+
import { useSignals as _useSignals11 } from "@preact-signals/safe-react/tracking";
|
|
1557
|
+
import React11, { useCallback as useCallback8, useMemo as useMemo4 } from "react";
|
|
1558
|
+
import { Expando, getTypeAnnotation, Ref, ReferenceAnnotationId as ReferenceAnnotationId2 } from "@dxos/echo-schema";
|
|
1559
|
+
import { findAnnotation as findAnnotation2 } from "@dxos/effect";
|
|
1560
|
+
import { DXN } from "@dxos/keys";
|
|
1561
|
+
import { DxRefTag } from "@dxos/lit-ui/react";
|
|
1562
|
+
import { Input as Input7, useTranslation as useTranslation7 } from "@dxos/react-ui";
|
|
1563
|
+
import { TagPicker } from "@dxos/react-ui-tag-picker";
|
|
1564
|
+
import { descriptionText, mx as mx5 } from "@dxos/react-ui-theme";
|
|
1565
|
+
import { isNonNullable as isNonNullable2 } from "@dxos/util";
|
|
1566
|
+
var RefField = ({ type, label, disabled, placeholder, inputOnly, array, ast, getValue: getValue3, onBlur, onQueryRefOptions, onValueChange, ...restInputProps }) => {
|
|
1567
|
+
var _effect = _useSignals11();
|
|
1568
|
+
try {
|
|
1569
|
+
const { t } = useTranslation7(translationKey);
|
|
1570
|
+
const refTypeInfo = useMemo4(() => ast ? findAnnotation2(ast, ReferenceAnnotationId2) : void 0, [
|
|
1571
|
+
ast
|
|
1572
|
+
]);
|
|
1573
|
+
const { options: availableOptions, loading: _loading } = useQueryRefOptions({
|
|
1574
|
+
refTypeInfo,
|
|
1575
|
+
onQueryRefOptions
|
|
1576
|
+
});
|
|
1577
|
+
if (refTypeInfo && refTypeInfo?.typename === getTypeAnnotation(Expando)?.typename || !onQueryRefOptions) {
|
|
1578
|
+
return /* @__PURE__ */ React11.createElement(RefFieldFallback, {
|
|
1579
|
+
type,
|
|
1580
|
+
label,
|
|
1581
|
+
placeholder,
|
|
1582
|
+
disabled,
|
|
1583
|
+
inputOnly,
|
|
1584
|
+
getValue: getValue3,
|
|
1585
|
+
onBlur,
|
|
1586
|
+
onValueChange,
|
|
1587
|
+
...restInputProps
|
|
1588
|
+
});
|
|
1589
|
+
}
|
|
1590
|
+
const handleGetValue = useCallback8(() => {
|
|
1591
|
+
const formValue = getValue3();
|
|
1592
|
+
const unknownToRefOption = (val) => {
|
|
1593
|
+
if (Ref.isRef(val)) {
|
|
1594
|
+
const dxnString = val.dxn.toString();
|
|
1595
|
+
const matchingOption = availableOptions.find((option2) => option2.id === dxnString);
|
|
1596
|
+
if (matchingOption) {
|
|
1597
|
+
return matchingOption;
|
|
1598
|
+
}
|
|
1599
|
+
}
|
|
1600
|
+
return void 0;
|
|
1601
|
+
};
|
|
1602
|
+
if (array && Array.isArray(formValue)) {
|
|
1603
|
+
return formValue.map(unknownToRefOption).filter(isNonNullable2) ?? [];
|
|
1604
|
+
}
|
|
1605
|
+
const option = unknownToRefOption(formValue);
|
|
1606
|
+
if (option) {
|
|
1607
|
+
return [
|
|
1608
|
+
option
|
|
1609
|
+
];
|
|
1610
|
+
}
|
|
1611
|
+
return [];
|
|
1612
|
+
}, [
|
|
1613
|
+
getValue3,
|
|
1614
|
+
availableOptions,
|
|
1615
|
+
array
|
|
1616
|
+
]);
|
|
1617
|
+
const handleSearch = useCallback8((text, ids) => availableOptions.filter((option) => !ids.includes(option.id)).filter((option) => option.label.toLowerCase().includes(text.toLowerCase())).map((option) => ({
|
|
1618
|
+
id: option.id,
|
|
1619
|
+
label: option.label,
|
|
1620
|
+
hue: option.hue
|
|
1621
|
+
})), [
|
|
1622
|
+
availableOptions
|
|
1623
|
+
]);
|
|
1624
|
+
const handleUpdate = useCallback8((ids) => {
|
|
1625
|
+
if (ids.length === 0) {
|
|
1626
|
+
onValueChange("object", void 0);
|
|
1627
|
+
return;
|
|
1628
|
+
}
|
|
1629
|
+
const refs = ids.map((id) => {
|
|
1630
|
+
const item = availableOptions.find((option) => option.id === id);
|
|
1631
|
+
if (item) {
|
|
1632
|
+
const dxn = DXN.parse(item.id);
|
|
1633
|
+
return Ref.fromDXN(dxn);
|
|
1634
|
+
}
|
|
1635
|
+
return null;
|
|
1636
|
+
}).filter(isNonNullable2);
|
|
1637
|
+
if (array) {
|
|
1638
|
+
onValueChange("object", refs);
|
|
1639
|
+
} else {
|
|
1640
|
+
onValueChange("object", refs[0]);
|
|
1641
|
+
}
|
|
1642
|
+
}, [
|
|
1643
|
+
availableOptions,
|
|
1644
|
+
array,
|
|
1645
|
+
onValueChange
|
|
1646
|
+
]);
|
|
1647
|
+
const tagPickerMode = useMemo4(() => array ? "multi-select" : "single-select", [
|
|
1648
|
+
array
|
|
1649
|
+
]);
|
|
1650
|
+
if (!refTypeInfo) {
|
|
1651
|
+
return null;
|
|
1652
|
+
}
|
|
1653
|
+
const { status, error } = restInputProps.getStatus();
|
|
1654
|
+
const items = handleGetValue();
|
|
1655
|
+
return disabled && items.length < 1 ? null : /* @__PURE__ */ React11.createElement(Input7.Root, {
|
|
1656
|
+
validationValence: status
|
|
1657
|
+
}, !inputOnly && /* @__PURE__ */ React11.createElement(InputHeader, {
|
|
1658
|
+
error
|
|
1659
|
+
}, /* @__PURE__ */ React11.createElement(Input7.Label, null, label)), /* @__PURE__ */ React11.createElement("div", {
|
|
1660
|
+
"data-no-submit": true
|
|
1661
|
+
}, disabled ? items.length < 1 ? /* @__PURE__ */ React11.createElement("p", {
|
|
1662
|
+
className: mx5(descriptionText, "mbe-2")
|
|
1663
|
+
}, t("empty readonly ref field label")) : items.map((item) => /* @__PURE__ */ React11.createElement(DxRefTag, {
|
|
1664
|
+
key: item.id,
|
|
1665
|
+
refid: item.id,
|
|
1666
|
+
rootclassname: "mie-1",
|
|
1667
|
+
style: {
|
|
1668
|
+
marginInlineEnd: ".25rem"
|
|
1669
|
+
}
|
|
1670
|
+
}, item.label)) : /* @__PURE__ */ React11.createElement(TagPicker, {
|
|
1671
|
+
readonly: disabled,
|
|
1672
|
+
items,
|
|
1673
|
+
mode: tagPickerMode,
|
|
1674
|
+
onBlur: (event) => onBlur(event),
|
|
1675
|
+
onUpdate: handleUpdate,
|
|
1676
|
+
onSearch: handleSearch,
|
|
1677
|
+
classNames: "rounded-sm bg-inputSurface p-1.5"
|
|
1678
|
+
})), inputOnly && /* @__PURE__ */ React11.createElement(Input7.DescriptionAndValidation, null, error));
|
|
1679
|
+
} finally {
|
|
1680
|
+
_effect.f();
|
|
1681
|
+
}
|
|
1682
|
+
};
|
|
1683
|
+
var RefFieldFallback = ({ type, label, disabled, placeholder, inputOnly, getValue: getValue3, onValueChange, ...restInputProps }) => {
|
|
1684
|
+
var _effect = _useSignals11();
|
|
1685
|
+
try {
|
|
1686
|
+
const handleOnValueChange = (_type, dxnString) => {
|
|
1687
|
+
const dxn = DXN.tryParse(dxnString);
|
|
1688
|
+
if (dxn) {
|
|
1689
|
+
onValueChange?.("object", Ref.fromDXN(dxn));
|
|
1690
|
+
} else if (dxnString === "") {
|
|
1691
|
+
onValueChange?.("object", void 0);
|
|
1692
|
+
} else {
|
|
1693
|
+
onValueChange?.("string", dxnString);
|
|
1694
|
+
}
|
|
1695
|
+
};
|
|
1696
|
+
const handleGetValue = () => {
|
|
1697
|
+
const formValue = getValue3();
|
|
1698
|
+
if (typeof formValue === "string") {
|
|
1699
|
+
return formValue;
|
|
1700
|
+
}
|
|
1701
|
+
if (Ref.isRef(formValue)) {
|
|
1702
|
+
return formValue.dxn.toString();
|
|
1703
|
+
}
|
|
1704
|
+
return void 0;
|
|
1705
|
+
};
|
|
1706
|
+
return /* @__PURE__ */ React11.createElement(TextInput, {
|
|
1707
|
+
type,
|
|
1708
|
+
label,
|
|
1709
|
+
disabled,
|
|
1710
|
+
placeholder,
|
|
1711
|
+
inputOnly,
|
|
1712
|
+
getValue: handleGetValue,
|
|
1713
|
+
onValueChange: handleOnValueChange,
|
|
1714
|
+
...restInputProps
|
|
1715
|
+
});
|
|
1716
|
+
} finally {
|
|
1717
|
+
_effect.f();
|
|
1718
|
+
}
|
|
1719
|
+
};
|
|
1720
|
+
|
|
1721
|
+
// packages/ui/react-ui-form/src/components/Form/factory.tsx
|
|
1722
|
+
import { FormatEnum as FormatEnum4 } from "@dxos/echo-schema";
|
|
1723
|
+
var getInputComponent = (type, format) => {
|
|
1724
|
+
switch (format) {
|
|
1725
|
+
case FormatEnum4.GeoPoint:
|
|
1726
|
+
return GeoPointInput;
|
|
1727
|
+
case FormatEnum4.Markdown:
|
|
1728
|
+
return MarkdownInput;
|
|
1729
|
+
}
|
|
1730
|
+
switch (type) {
|
|
1731
|
+
case "string":
|
|
1732
|
+
return TextInput;
|
|
1733
|
+
case "number":
|
|
1734
|
+
return NumberInput;
|
|
1735
|
+
case "boolean":
|
|
1736
|
+
return BooleanInput;
|
|
1737
|
+
}
|
|
1738
|
+
};
|
|
1739
|
+
|
|
1740
|
+
// packages/ui/react-ui-form/src/components/Form/FormContent.tsx
|
|
1741
|
+
var FormField = ({ property, path, readonly, inline, onQueryRefOptions, lookupComponent, Custom }) => {
|
|
1742
|
+
var _effect = _useSignals12();
|
|
1743
|
+
try {
|
|
1744
|
+
const inputProps = useInputProps(path);
|
|
1745
|
+
const { ast, name, type, format, title, description, options, examples, array } = property;
|
|
1746
|
+
const label = useMemo5(() => title ?? pipe2(name, capitalize2), [
|
|
1747
|
+
title,
|
|
1748
|
+
name
|
|
1749
|
+
]);
|
|
1750
|
+
const placeholder = useMemo5(() => examples?.length ? `Example: "${examples[0]}"` : description, [
|
|
1751
|
+
examples,
|
|
1752
|
+
description
|
|
1753
|
+
]);
|
|
1754
|
+
const FoundComponent = lookupComponent?.({
|
|
1755
|
+
prop: name,
|
|
1756
|
+
schema: Schema.make(ast),
|
|
1757
|
+
inputProps: {
|
|
1758
|
+
type,
|
|
1759
|
+
format,
|
|
1760
|
+
label,
|
|
1761
|
+
disabled: readonly,
|
|
1762
|
+
placeholder,
|
|
1763
|
+
...inputProps
|
|
1764
|
+
}
|
|
1765
|
+
});
|
|
1766
|
+
if (FoundComponent) {
|
|
1767
|
+
return FoundComponent;
|
|
1768
|
+
}
|
|
1769
|
+
const jsonPath = createJsonPath3(path ?? []);
|
|
1770
|
+
const CustomComponent = Custom?.[jsonPath];
|
|
1771
|
+
if (CustomComponent) {
|
|
1772
|
+
return /* @__PURE__ */ React12.createElement(CustomComponent, {
|
|
1773
|
+
type,
|
|
1774
|
+
format,
|
|
1775
|
+
label,
|
|
1776
|
+
inputOnly: inline,
|
|
1777
|
+
placeholder,
|
|
1778
|
+
disabled: readonly,
|
|
1779
|
+
...inputProps
|
|
1780
|
+
});
|
|
1781
|
+
}
|
|
1782
|
+
const refProps = getRefProps(property);
|
|
1783
|
+
if (refProps) {
|
|
1784
|
+
return /* @__PURE__ */ React12.createElement(RefField, {
|
|
1785
|
+
ast: refProps.ast,
|
|
1786
|
+
array: refProps.isArray,
|
|
1787
|
+
type,
|
|
1788
|
+
format,
|
|
1789
|
+
label,
|
|
1790
|
+
placeholder,
|
|
1791
|
+
disabled: readonly,
|
|
1792
|
+
inputOnly: inline,
|
|
1793
|
+
onQueryRefOptions,
|
|
1794
|
+
...inputProps
|
|
1795
|
+
});
|
|
1796
|
+
}
|
|
1797
|
+
if (array) {
|
|
1798
|
+
return /* @__PURE__ */ React12.createElement(ArrayField, {
|
|
1799
|
+
property,
|
|
1800
|
+
path,
|
|
1801
|
+
inputProps,
|
|
1802
|
+
readonly,
|
|
1803
|
+
Custom
|
|
1804
|
+
});
|
|
1805
|
+
}
|
|
1806
|
+
const InputComponent = getInputComponent(type, format);
|
|
1807
|
+
if (InputComponent) {
|
|
1808
|
+
return /* @__PURE__ */ React12.createElement(InputComponent, {
|
|
1809
|
+
type,
|
|
1810
|
+
format,
|
|
1811
|
+
label,
|
|
1812
|
+
inputOnly: inline,
|
|
1813
|
+
placeholder,
|
|
1814
|
+
disabled: readonly,
|
|
1815
|
+
...inputProps
|
|
1816
|
+
});
|
|
1817
|
+
}
|
|
1818
|
+
if (options) {
|
|
1819
|
+
return /* @__PURE__ */ React12.createElement(SelectInput, {
|
|
1820
|
+
type,
|
|
1821
|
+
format,
|
|
1822
|
+
disabled: readonly,
|
|
1823
|
+
inputOnly: inline,
|
|
1824
|
+
label,
|
|
1825
|
+
options: options.map((option) => ({
|
|
1826
|
+
value: option,
|
|
1827
|
+
label: String(option)
|
|
1828
|
+
})),
|
|
1829
|
+
placeholder,
|
|
1830
|
+
...inputProps
|
|
1831
|
+
});
|
|
1832
|
+
}
|
|
1833
|
+
if (type === "object") {
|
|
1834
|
+
const baseNode = findNode3(ast, isDiscriminatedUnion2);
|
|
1835
|
+
const typeLiteral = baseNode ? getDiscriminatedType2(baseNode, inputProps.getValue()) : findNode3(ast, SchemaAST4.isTypeLiteral);
|
|
1836
|
+
if (typeLiteral) {
|
|
1837
|
+
return /* @__PURE__ */ React12.createElement(React12.Fragment, null, !inline && /* @__PURE__ */ React12.createElement("h3", {
|
|
1838
|
+
className: "text-lg mbs-2 mbe-1 first:mbs-0"
|
|
1839
|
+
}, label), /* @__PURE__ */ React12.createElement(FormFields, {
|
|
1840
|
+
schema: Schema.make(typeLiteral),
|
|
1841
|
+
path,
|
|
1842
|
+
readonly,
|
|
1843
|
+
onQueryRefOptions,
|
|
1844
|
+
Custom,
|
|
1845
|
+
lookupComponent
|
|
1846
|
+
}));
|
|
1847
|
+
}
|
|
1848
|
+
}
|
|
1849
|
+
return null;
|
|
1850
|
+
} finally {
|
|
1851
|
+
_effect.f();
|
|
1852
|
+
}
|
|
1853
|
+
};
|
|
1854
|
+
var FormFields = ({ classNames, Custom, schema, path, filter, sort, readonly, lookupComponent, onQueryRefOptions }) => {
|
|
1855
|
+
var _effect = _useSignals12();
|
|
1856
|
+
try {
|
|
1857
|
+
const values = useFormValues(path);
|
|
1858
|
+
const properties = useMemo5(() => {
|
|
1859
|
+
const props = getSchemaProperties2(schema.ast, values);
|
|
1860
|
+
const filtered = filter ? filter(props) : props;
|
|
1861
|
+
return sort ? filtered.sort((a, b) => sort.indexOf(a.name) - sort.indexOf(b.name)) : filtered;
|
|
1862
|
+
}, [
|
|
1863
|
+
schema,
|
|
1864
|
+
values,
|
|
1865
|
+
filter,
|
|
1866
|
+
sort
|
|
1867
|
+
]);
|
|
1868
|
+
return (
|
|
1869
|
+
// TODO(burdon): Consistent padding (with composite forms).
|
|
1870
|
+
/* @__PURE__ */ React12.createElement("div", {
|
|
1871
|
+
role: "form",
|
|
1872
|
+
className: mx6("p-2 is-full", classNames)
|
|
1873
|
+
}, properties.map((property) => {
|
|
1874
|
+
return /* @__PURE__ */ React12.createElement(FormField, {
|
|
1875
|
+
key: property.name,
|
|
1876
|
+
property,
|
|
1877
|
+
path: [
|
|
1878
|
+
...path ?? [],
|
|
1879
|
+
property.name
|
|
1880
|
+
],
|
|
1881
|
+
readonly,
|
|
1882
|
+
onQueryRefOptions,
|
|
1883
|
+
lookupComponent,
|
|
1884
|
+
Custom
|
|
1885
|
+
});
|
|
1886
|
+
}).filter(isNotFalsy))
|
|
1887
|
+
);
|
|
1888
|
+
} finally {
|
|
1889
|
+
_effect.f();
|
|
1890
|
+
}
|
|
1891
|
+
};
|
|
1892
|
+
|
|
1893
|
+
// packages/ui/react-ui-form/src/components/Form/Form.tsx
|
|
1894
|
+
var Form = ({ classNames, schema, values: initialValues, path = [], autoFocus, readonly, filter, sort, autoSave, testId, onValuesChanged, onValidate, onSave, onCancel, onQueryRefOptions, lookupComponent, Custom }) => {
|
|
1895
|
+
var _effect = _useSignals13();
|
|
1896
|
+
try {
|
|
1897
|
+
const formRef = useRef3(null);
|
|
1898
|
+
const onValid = useMemo6(() => autoSave ? onSave : void 0, [
|
|
1899
|
+
autoSave,
|
|
1900
|
+
onSave
|
|
1901
|
+
]);
|
|
1902
|
+
useEffect7(() => {
|
|
1903
|
+
if (autoFocus && formRef.current) {
|
|
1904
|
+
const input = formRef.current.querySelector("input");
|
|
1905
|
+
if (input) {
|
|
1906
|
+
input.focus();
|
|
1907
|
+
}
|
|
1908
|
+
}
|
|
1909
|
+
}, [
|
|
1910
|
+
autoFocus
|
|
1911
|
+
]);
|
|
1912
|
+
return /* @__PURE__ */ React13.createElement(FormProvider, {
|
|
1913
|
+
formRef,
|
|
1914
|
+
schema,
|
|
1915
|
+
autoSave,
|
|
1916
|
+
initialValues,
|
|
1917
|
+
onValuesChanged,
|
|
1918
|
+
onValidate,
|
|
1919
|
+
onValid,
|
|
1920
|
+
onSave
|
|
1921
|
+
}, /* @__PURE__ */ React13.createElement("div", {
|
|
1922
|
+
ref: formRef,
|
|
1923
|
+
role: "none",
|
|
1924
|
+
className: mx7("flex flex-col gap-4", classNames),
|
|
1925
|
+
"data-testid": testId
|
|
1926
|
+
}, /* @__PURE__ */ React13.createElement(FormFields, {
|
|
1927
|
+
schema,
|
|
1928
|
+
path,
|
|
1929
|
+
readonly,
|
|
1930
|
+
filter,
|
|
1931
|
+
sort,
|
|
1932
|
+
onQueryRefOptions,
|
|
1933
|
+
lookupComponent,
|
|
1934
|
+
Custom
|
|
1935
|
+
}), (onCancel || onSave) && !autoSave && /* @__PURE__ */ React13.createElement(FormActions, {
|
|
1936
|
+
onCancel,
|
|
1937
|
+
readonly
|
|
1938
|
+
})));
|
|
1939
|
+
} finally {
|
|
1940
|
+
_effect.f();
|
|
1941
|
+
}
|
|
1942
|
+
};
|
|
1943
|
+
|
|
1944
|
+
// packages/ui/react-ui-form/src/components/FieldEditor/FieldEditor.tsx
|
|
1945
|
+
var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-form/src/components/FieldEditor/FieldEditor.tsx";
|
|
1946
|
+
var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
|
|
1947
|
+
var _effect = _useSignals14();
|
|
1948
|
+
try {
|
|
1949
|
+
const { t } = useTranslation8(translationKey);
|
|
1950
|
+
const [props, setProps] = useState5(projection.getFieldProjection(field.id).props);
|
|
1951
|
+
useEffect8(() => setProps(projection.getFieldProjection(field.id).props), [
|
|
1952
|
+
field,
|
|
1953
|
+
projection
|
|
1954
|
+
]);
|
|
1955
|
+
const [schemas, setSchemas] = useState5([]);
|
|
1956
|
+
useEffect8(() => {
|
|
1957
|
+
if (!registry) {
|
|
1958
|
+
return;
|
|
1959
|
+
}
|
|
1960
|
+
const subscription = registry.query().subscribe((query) => setSchemas(query.results), {
|
|
1961
|
+
fire: true
|
|
1962
|
+
});
|
|
1963
|
+
const t2 = setTimeout(async () => {
|
|
1964
|
+
const schemas2 = await registry.query().run();
|
|
1965
|
+
setSchemas(schemas2);
|
|
1966
|
+
});
|
|
1967
|
+
return () => {
|
|
1968
|
+
clearTimeout(t2);
|
|
1969
|
+
subscription?.();
|
|
1970
|
+
};
|
|
1971
|
+
}, [
|
|
1972
|
+
registry
|
|
1973
|
+
]);
|
|
1974
|
+
const [referenceSchema, setReferenceSchema] = useState5();
|
|
1975
|
+
useEffect8(() => {
|
|
1976
|
+
setReferenceSchema(schemas.find((schema) => schema.typename === props?.referenceSchema));
|
|
1977
|
+
}, [
|
|
1978
|
+
schemas,
|
|
1979
|
+
props?.referenceSchema
|
|
1980
|
+
]);
|
|
1981
|
+
const [{ fieldSchema }, setFieldSchema] = useState5({
|
|
1982
|
+
fieldSchema: getFormatSchema(props?.format)
|
|
1983
|
+
});
|
|
1984
|
+
const handleValuesChanged = useCallback9((_props) => {
|
|
1985
|
+
setFieldSchema((prev) => {
|
|
1986
|
+
const fieldSchema2 = getFormatSchema(_props.format);
|
|
1987
|
+
if (prev.fieldSchema === fieldSchema2) {
|
|
1988
|
+
return prev;
|
|
1989
|
+
}
|
|
1990
|
+
return {
|
|
1991
|
+
fieldSchema: fieldSchema2
|
|
1992
|
+
};
|
|
1993
|
+
});
|
|
1994
|
+
setReferenceSchema((prev) => {
|
|
1995
|
+
if (_props.referenceSchema !== prev?.typename) {
|
|
1996
|
+
const newSchema = schemas.find((schema) => schema.typename === _props.referenceSchema);
|
|
1997
|
+
if (newSchema) {
|
|
1998
|
+
return newSchema;
|
|
1999
|
+
}
|
|
2000
|
+
}
|
|
2001
|
+
return prev;
|
|
2002
|
+
});
|
|
2003
|
+
setProps((props2) => {
|
|
2004
|
+
const type = formatToType[_props.format];
|
|
2005
|
+
if (props2.type !== type) {
|
|
2006
|
+
return {
|
|
2007
|
+
...props2,
|
|
2008
|
+
..._props,
|
|
2009
|
+
type
|
|
2010
|
+
};
|
|
2011
|
+
}
|
|
2012
|
+
return _props;
|
|
2013
|
+
});
|
|
2014
|
+
}, [
|
|
2015
|
+
schemas,
|
|
2016
|
+
props.format,
|
|
2017
|
+
props.referenceSchema
|
|
2018
|
+
]);
|
|
2019
|
+
const handleValidate = useCallback9(({ property }) => {
|
|
2020
|
+
if (property && view.fields.find((f) => f.path === property && f.path !== field.path)) {
|
|
2021
|
+
return [
|
|
2022
|
+
{
|
|
2023
|
+
path: "property",
|
|
2024
|
+
message: `property is not unique: '${property}'`
|
|
2025
|
+
}
|
|
2026
|
+
];
|
|
2027
|
+
}
|
|
2028
|
+
}, [
|
|
2029
|
+
view.fields,
|
|
2030
|
+
field
|
|
2031
|
+
]);
|
|
2032
|
+
const handleSave = useCallback9((props2) => {
|
|
2033
|
+
projection.setFieldProjection({
|
|
2034
|
+
field,
|
|
2035
|
+
props: props2
|
|
2036
|
+
});
|
|
2037
|
+
onSave();
|
|
2038
|
+
}, [
|
|
2039
|
+
projection,
|
|
2040
|
+
field,
|
|
2041
|
+
onSave
|
|
2042
|
+
]);
|
|
2043
|
+
const handleCancel = useCallback9(() => {
|
|
2044
|
+
requestAnimationFrame(() => onCancel?.());
|
|
2045
|
+
onSave();
|
|
2046
|
+
}, [
|
|
2047
|
+
onSave
|
|
2048
|
+
]);
|
|
2049
|
+
const custom = useMemo7(() => ({
|
|
2050
|
+
["format"]: (props2) => /* @__PURE__ */ React14.createElement(SelectInput, {
|
|
2051
|
+
...props2,
|
|
2052
|
+
options: FormatEnums.filter((value) => value !== FormatEnum5.None).map((value) => ({
|
|
2053
|
+
value,
|
|
2054
|
+
label: t(`format ${value}`)
|
|
2055
|
+
}))
|
|
2056
|
+
}),
|
|
2057
|
+
["referenceSchema"]: (props2) => /* @__PURE__ */ React14.createElement(SelectInput, {
|
|
2058
|
+
...props2,
|
|
2059
|
+
options: schemas.map((schema) => ({
|
|
2060
|
+
value: schema.typename
|
|
2061
|
+
}))
|
|
2062
|
+
}),
|
|
2063
|
+
["referencePath"]: (props2) => /* @__PURE__ */ React14.createElement(SelectInput, {
|
|
2064
|
+
...props2,
|
|
2065
|
+
options: referenceSchema ? getSchemaProperties3(referenceSchema.ast).sort(sortProperties).map((p) => ({
|
|
2066
|
+
value: p.name
|
|
2067
|
+
})) : []
|
|
2068
|
+
}),
|
|
2069
|
+
["options"]: (props2) => /* @__PURE__ */ React14.createElement(SelectOptionInput, props2)
|
|
2070
|
+
}), [
|
|
2071
|
+
t,
|
|
2072
|
+
schemas,
|
|
2073
|
+
referenceSchema
|
|
2074
|
+
]);
|
|
2075
|
+
const propIsNotType = useCallback9((props2) => props2.filter((p) => p.name !== "type"), []);
|
|
2076
|
+
if (!fieldSchema) {
|
|
2077
|
+
log3.warn("invalid format", {
|
|
2078
|
+
props
|
|
2079
|
+
}, {
|
|
2080
|
+
F: __dxlog_file4,
|
|
2081
|
+
L: 175,
|
|
2082
|
+
S: void 0,
|
|
2083
|
+
C: (f, a) => f(...a)
|
|
2084
|
+
});
|
|
2085
|
+
return null;
|
|
2086
|
+
}
|
|
2087
|
+
return /* @__PURE__ */ React14.createElement(Form, {
|
|
2088
|
+
key: field.id,
|
|
2089
|
+
autoFocus: true,
|
|
2090
|
+
values: props,
|
|
2091
|
+
schema: fieldSchema,
|
|
2092
|
+
filter: propIsNotType,
|
|
2093
|
+
sort: [
|
|
2094
|
+
"property",
|
|
2095
|
+
"format"
|
|
2096
|
+
],
|
|
2097
|
+
onValuesChanged: handleValuesChanged,
|
|
2098
|
+
onValidate: handleValidate,
|
|
2099
|
+
onSave: handleSave,
|
|
2100
|
+
onCancel: handleCancel,
|
|
2101
|
+
Custom: custom
|
|
2102
|
+
});
|
|
2103
|
+
} finally {
|
|
2104
|
+
_effect.f();
|
|
2105
|
+
}
|
|
2106
|
+
};
|
|
2107
|
+
|
|
2108
|
+
// packages/ui/react-ui-form/src/components/ViewEditor/ViewEditor.tsx
|
|
2109
|
+
import { useSignals as _useSignals15 } from "@preact-signals/safe-react/tracking";
|
|
2110
|
+
import { Schema as Schema2 } from "effect";
|
|
2111
|
+
import React15, { useCallback as useCallback10, useMemo as useMemo8, useState as useState6 } from "react";
|
|
2112
|
+
import { EchoSchema, Format, isMutable, toJsonSchema } from "@dxos/echo-schema";
|
|
2113
|
+
import { invariant as invariant3 } from "@dxos/invariant";
|
|
2114
|
+
import { Icon as Icon3, IconButton as IconButton4, Message, useTranslation as useTranslation9 } from "@dxos/react-ui";
|
|
2115
|
+
import { List as List2 } from "@dxos/react-ui-list";
|
|
2116
|
+
import { ghostHover, inputTextLabel, mx as mx8 } from "@dxos/react-ui-theme";
|
|
2117
|
+
import { FieldSchema, ViewProjection, VIEW_FIELD_LIMIT } from "@dxos/schema";
|
|
2118
|
+
var __dxlog_file5 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-form/src/components/ViewEditor/ViewEditor.tsx";
|
|
2119
|
+
var grid = "grid grid-cols-[32px_1fr_32px] min-bs-[2.5rem]";
|
|
2120
|
+
var ViewMetaSchema = Schema2.Struct({
|
|
2121
|
+
name: Schema2.String.annotations({
|
|
2122
|
+
title: "View"
|
|
2123
|
+
}),
|
|
2124
|
+
typename: Format.URL.annotations({
|
|
2125
|
+
title: "Typename"
|
|
2126
|
+
})
|
|
2127
|
+
}).pipe(Schema2.mutable);
|
|
2128
|
+
var ViewEditor = ({ classNames, schema, view, registry, readonly, showHeading = false, onTypenameChanged, onDelete }) => {
|
|
2129
|
+
var _effect = _useSignals15();
|
|
2130
|
+
try {
|
|
2131
|
+
const { t } = useTranslation9(translationKey);
|
|
2132
|
+
const projection = useMemo8(() => {
|
|
2133
|
+
const jsonSchema = schema instanceof EchoSchema ? schema.jsonSchema : toJsonSchema(schema);
|
|
2134
|
+
return new ViewProjection(jsonSchema, view);
|
|
2135
|
+
}, [
|
|
2136
|
+
schema,
|
|
2137
|
+
view
|
|
2138
|
+
]);
|
|
2139
|
+
const [field, setField] = useState6();
|
|
2140
|
+
const immutable = readonly || !isMutable(schema);
|
|
2141
|
+
const viewValues = useMemo8(() => {
|
|
2142
|
+
return {
|
|
2143
|
+
name: view.name,
|
|
2144
|
+
// TODO(burdon): Need to warn user of possible consequences of editing.
|
|
2145
|
+
// TODO(burdon): Settings should have domain name owned by user.
|
|
2146
|
+
typename: view.query.typename
|
|
2147
|
+
};
|
|
2148
|
+
}, [
|
|
2149
|
+
view
|
|
2150
|
+
]);
|
|
2151
|
+
const handleSelect = useCallback10((field2) => {
|
|
2152
|
+
if (immutable) {
|
|
2153
|
+
return;
|
|
2154
|
+
}
|
|
2155
|
+
setField((f) => f === field2 ? void 0 : field2);
|
|
2156
|
+
}, [
|
|
2157
|
+
immutable
|
|
2158
|
+
]);
|
|
2159
|
+
const handleAdd = useCallback10(() => {
|
|
2160
|
+
invariant3(!immutable, void 0, {
|
|
2161
|
+
F: __dxlog_file5,
|
|
2162
|
+
L: 88,
|
|
2163
|
+
S: void 0,
|
|
2164
|
+
A: [
|
|
2165
|
+
"!immutable",
|
|
2166
|
+
""
|
|
2167
|
+
]
|
|
2168
|
+
});
|
|
2169
|
+
const field2 = projection.createFieldProjection();
|
|
2170
|
+
setField(field2);
|
|
2171
|
+
}, [
|
|
2172
|
+
schema,
|
|
2173
|
+
view
|
|
2174
|
+
]);
|
|
2175
|
+
const handleUpdate = useCallback10(({ name, typename }) => {
|
|
2176
|
+
invariant3(!immutable, void 0, {
|
|
2177
|
+
F: __dxlog_file5,
|
|
2178
|
+
L: 95,
|
|
2179
|
+
S: void 0,
|
|
2180
|
+
A: [
|
|
2181
|
+
"!immutable",
|
|
2182
|
+
""
|
|
2183
|
+
]
|
|
2184
|
+
});
|
|
2185
|
+
requestAnimationFrame(() => {
|
|
2186
|
+
if (view.name !== name) {
|
|
2187
|
+
view.name = name;
|
|
2188
|
+
}
|
|
2189
|
+
if (view.query.typename !== typename && !immutable) {
|
|
2190
|
+
onTypenameChanged?.(typename);
|
|
2191
|
+
}
|
|
2192
|
+
});
|
|
2193
|
+
}, [
|
|
2194
|
+
schema,
|
|
2195
|
+
view,
|
|
2196
|
+
onTypenameChanged,
|
|
2197
|
+
immutable
|
|
2198
|
+
]);
|
|
2199
|
+
const handleDelete = useCallback10((fieldId) => {
|
|
2200
|
+
invariant3(!immutable, void 0, {
|
|
2201
|
+
F: __dxlog_file5,
|
|
2202
|
+
L: 111,
|
|
2203
|
+
S: void 0,
|
|
2204
|
+
A: [
|
|
2205
|
+
"!immutable",
|
|
2206
|
+
""
|
|
2207
|
+
]
|
|
2208
|
+
});
|
|
2209
|
+
if (fieldId === field?.id) {
|
|
2210
|
+
setField(void 0);
|
|
2211
|
+
}
|
|
2212
|
+
onDelete?.(fieldId);
|
|
2213
|
+
}, [
|
|
2214
|
+
schema,
|
|
2215
|
+
field,
|
|
2216
|
+
onDelete
|
|
2217
|
+
]);
|
|
2218
|
+
const handleMove = useCallback10((fromIndex, toIndex) => {
|
|
2219
|
+
invariant3(!immutable, void 0, {
|
|
2220
|
+
F: __dxlog_file5,
|
|
2221
|
+
L: 123,
|
|
2222
|
+
S: void 0,
|
|
2223
|
+
A: [
|
|
2224
|
+
"!immutable",
|
|
2225
|
+
""
|
|
2226
|
+
]
|
|
2227
|
+
});
|
|
2228
|
+
const fields = [
|
|
2229
|
+
...view.fields
|
|
2230
|
+
];
|
|
2231
|
+
const [moved] = fields.splice(fromIndex, 1);
|
|
2232
|
+
fields.splice(toIndex, 0, moved);
|
|
2233
|
+
view.fields = fields;
|
|
2234
|
+
}, [
|
|
2235
|
+
schema,
|
|
2236
|
+
view.fields
|
|
2237
|
+
]);
|
|
2238
|
+
const handleClose = useCallback10(() => setField(void 0), []);
|
|
2239
|
+
const hiddenProperties = projection.getHiddenProperties();
|
|
2240
|
+
const handleHide = useCallback10((fieldId) => {
|
|
2241
|
+
setField(void 0);
|
|
2242
|
+
projection.hideFieldProjection(fieldId);
|
|
2243
|
+
}, [
|
|
2244
|
+
projection
|
|
2245
|
+
]);
|
|
2246
|
+
const handleShow = useCallback10((property) => {
|
|
2247
|
+
setField(void 0);
|
|
2248
|
+
projection.showFieldProjection(property);
|
|
2249
|
+
}, [
|
|
2250
|
+
projection
|
|
2251
|
+
]);
|
|
2252
|
+
return /* @__PURE__ */ React15.createElement("div", {
|
|
2253
|
+
role: "none",
|
|
2254
|
+
className: mx8("overflow-y-auto", classNames)
|
|
2255
|
+
}, /* @__PURE__ */ React15.createElement("div", {
|
|
2256
|
+
role: "none",
|
|
2257
|
+
className: "p-2"
|
|
2258
|
+
}, /* @__PURE__ */ React15.createElement("div", {
|
|
2259
|
+
role: "none",
|
|
2260
|
+
className: "mbe-2"
|
|
2261
|
+
}, immutable && /* @__PURE__ */ React15.createElement(Message.Root, {
|
|
2262
|
+
valence: "neutral",
|
|
2263
|
+
className: "rounded"
|
|
2264
|
+
}, /* @__PURE__ */ React15.createElement(Message.Title, null, /* @__PURE__ */ React15.createElement(Icon3, {
|
|
2265
|
+
icon: "ph--info--regular",
|
|
2266
|
+
size: 5,
|
|
2267
|
+
classNames: "inline"
|
|
2268
|
+
}), " ", t("system schema title")), /* @__PURE__ */ React15.createElement(Message.Body, null, t("system schema description")))), /* @__PURE__ */ React15.createElement(Form, {
|
|
2269
|
+
autoSave: true,
|
|
2270
|
+
schema: ViewMetaSchema,
|
|
2271
|
+
values: viewValues,
|
|
2272
|
+
onSave: handleUpdate,
|
|
2273
|
+
classNames: "min-bs-0 overflow-y-auto"
|
|
2274
|
+
})), /* @__PURE__ */ React15.createElement("div", {
|
|
2275
|
+
role: "none",
|
|
2276
|
+
className: "min-bs-0 overflow-y-auto"
|
|
2277
|
+
}, /* @__PURE__ */ React15.createElement("div", {
|
|
2278
|
+
role: "none",
|
|
2279
|
+
className: "p-2"
|
|
2280
|
+
}, /* @__PURE__ */ React15.createElement("label", {
|
|
2281
|
+
className: mx8(inputTextLabel)
|
|
2282
|
+
}, t("fields label"))), /* @__PURE__ */ React15.createElement(List2.Root, {
|
|
2283
|
+
items: view.fields,
|
|
2284
|
+
isItem: Schema2.is(FieldSchema),
|
|
2285
|
+
getId: (field2) => field2.id,
|
|
2286
|
+
onMove: immutable ? void 0 : handleMove
|
|
2287
|
+
}, ({ items: fields }) => /* @__PURE__ */ React15.createElement(React15.Fragment, null, showHeading && /* @__PURE__ */ React15.createElement("div", {
|
|
2288
|
+
role: "heading",
|
|
2289
|
+
className: grid
|
|
2290
|
+
}, /* @__PURE__ */ React15.createElement("div", null), /* @__PURE__ */ React15.createElement("div", {
|
|
2291
|
+
className: "flex items-center text-sm"
|
|
2292
|
+
}, t("field path label"))), /* @__PURE__ */ React15.createElement("div", {
|
|
2293
|
+
role: "list",
|
|
2294
|
+
className: "flex flex-col w-full"
|
|
2295
|
+
}, fields?.map((field2) => /* @__PURE__ */ React15.createElement(List2.Item, {
|
|
2296
|
+
key: field2.id,
|
|
2297
|
+
item: field2,
|
|
2298
|
+
classNames: mx8(grid, ghostHover, !immutable && "cursor-pointer")
|
|
2299
|
+
}, /* @__PURE__ */ React15.createElement(List2.ItemDragHandle, null), /* @__PURE__ */ React15.createElement(List2.ItemTitle, {
|
|
2300
|
+
onClick: () => handleSelect(field2)
|
|
2301
|
+
}, field2.path), /* @__PURE__ */ React15.createElement("div", {
|
|
2302
|
+
className: "flex items-center gap-2 -ml-4"
|
|
2303
|
+
}, /* @__PURE__ */ React15.createElement(List2.ItemButton, {
|
|
2304
|
+
icon: "ph--eye-slash--regular",
|
|
2305
|
+
disabled: view.fields.length <= 1,
|
|
2306
|
+
onClick: () => handleHide(field2.id)
|
|
2307
|
+
}), !immutable && /* @__PURE__ */ React15.createElement(List2.ItemDeleteButton, {
|
|
2308
|
+
icon: "ph--trash--regular",
|
|
2309
|
+
disabled: view.fields.length <= 1,
|
|
2310
|
+
onClick: () => handleDelete(field2.id)
|
|
2311
|
+
}))))))), hiddenProperties.length > 0 && /* @__PURE__ */ React15.createElement("div", null, /* @__PURE__ */ React15.createElement("div", {
|
|
2312
|
+
role: "none",
|
|
2313
|
+
className: "p-2"
|
|
2314
|
+
}, /* @__PURE__ */ React15.createElement("label", {
|
|
2315
|
+
className: mx8(inputTextLabel)
|
|
2316
|
+
}, t("hidden fields label"))), /* @__PURE__ */ React15.createElement(List2.Root, {
|
|
2317
|
+
items: hiddenProperties,
|
|
2318
|
+
isItem: (item) => typeof item === "string",
|
|
2319
|
+
getId: (property) => property
|
|
2320
|
+
}, ({ items: properties }) => /* @__PURE__ */ React15.createElement("div", {
|
|
2321
|
+
role: "list",
|
|
2322
|
+
className: "flex flex-col w-full"
|
|
2323
|
+
}, properties?.map((property) => /* @__PURE__ */ React15.createElement(List2.Item, {
|
|
2324
|
+
key: property,
|
|
2325
|
+
item: property,
|
|
2326
|
+
classNames: mx8(grid, ghostHover, !immutable && "cursor-pointer")
|
|
2327
|
+
}, /* @__PURE__ */ React15.createElement("div", null), /* @__PURE__ */ React15.createElement(List2.ItemTitle, null, property), /* @__PURE__ */ React15.createElement(List2.ItemButton, {
|
|
2328
|
+
icon: "ph--eye--regular",
|
|
2329
|
+
onClick: () => handleShow(property)
|
|
2330
|
+
}))))))), field && /* @__PURE__ */ React15.createElement(FieldEditor, {
|
|
2331
|
+
key: field.id,
|
|
2332
|
+
view,
|
|
2333
|
+
projection,
|
|
2334
|
+
field,
|
|
2335
|
+
registry,
|
|
2336
|
+
onSave: handleClose
|
|
2337
|
+
}), !readonly && !field && /* @__PURE__ */ React15.createElement("div", {
|
|
2338
|
+
role: "none",
|
|
2339
|
+
className: "p-2"
|
|
2340
|
+
}, /* @__PURE__ */ React15.createElement(IconButton4, {
|
|
2341
|
+
icon: "ph--plus--regular",
|
|
2342
|
+
label: t("button add property"),
|
|
2343
|
+
onClick: immutable ? void 0 : handleAdd,
|
|
2344
|
+
// TODO(burdon): Show field limit in ux (not tooltip).
|
|
2345
|
+
disabled: view.fields.length >= VIEW_FIELD_LIMIT,
|
|
2346
|
+
classNames: "flex is-full"
|
|
2347
|
+
})));
|
|
2348
|
+
} finally {
|
|
2349
|
+
_effect.f();
|
|
2350
|
+
}
|
|
2351
|
+
};
|
|
1998
2352
|
export {
|
|
1999
2353
|
BooleanInput,
|
|
2000
2354
|
ControlFrame,
|
|
@@ -2022,14 +2376,18 @@ export {
|
|
|
2022
2376
|
ViewEditor,
|
|
2023
2377
|
cellClassesForFieldType,
|
|
2024
2378
|
controlItemClasses,
|
|
2379
|
+
findArrayElementType,
|
|
2025
2380
|
formatForDisplay,
|
|
2026
2381
|
formatForEditing,
|
|
2382
|
+
getRefProps,
|
|
2027
2383
|
parseValue,
|
|
2028
2384
|
pathNotUniqueError,
|
|
2029
2385
|
translations_default as translations,
|
|
2030
2386
|
useForm,
|
|
2031
2387
|
useFormContext,
|
|
2032
2388
|
useFormValues,
|
|
2033
|
-
useInputProps
|
|
2389
|
+
useInputProps,
|
|
2390
|
+
useQueryRefOptions,
|
|
2391
|
+
useRefQueryLookupHandler
|
|
2034
2392
|
};
|
|
2035
2393
|
//# sourceMappingURL=index.mjs.map
|