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