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