@dxos/react-ui-form 0.7.5-labs.e27f9b9 → 0.7.5-labs.f400bbc

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.
Files changed (65) hide show
  1. package/dist/lib/browser/index.mjs +546 -362
  2. package/dist/lib/browser/index.mjs.map +4 -4
  3. package/dist/lib/browser/meta.json +1 -1
  4. package/dist/lib/node/index.cjs +589 -401
  5. package/dist/lib/node/index.cjs.map +4 -4
  6. package/dist/lib/node/meta.json +1 -1
  7. package/dist/lib/node-esm/index.mjs +546 -362
  8. package/dist/lib/node-esm/index.mjs.map +4 -4
  9. package/dist/lib/node-esm/meta.json +1 -1
  10. package/dist/types/src/components/FieldEditor/FieldEditor.d.ts +1 -2
  11. package/dist/types/src/components/FieldEditor/FieldEditor.d.ts.map +1 -1
  12. package/dist/types/src/components/Form/ArrayField.d.ts +1 -2
  13. package/dist/types/src/components/Form/ArrayField.d.ts.map +1 -1
  14. package/dist/types/src/components/Form/Defaults.d.ts +5 -5
  15. package/dist/types/src/components/Form/Defaults.d.ts.map +1 -1
  16. package/dist/types/src/components/Form/Form.d.ts +2 -2
  17. package/dist/types/src/components/Form/Form.d.ts.map +1 -1
  18. package/dist/types/src/components/Form/FormActions.d.ts +1 -2
  19. package/dist/types/src/components/Form/FormActions.d.ts.map +1 -1
  20. package/dist/types/src/components/Form/FormContent.d.ts +2 -3
  21. package/dist/types/src/components/Form/FormContent.d.ts.map +1 -1
  22. package/dist/types/src/components/Form/FormContext.d.ts +4 -1
  23. package/dist/types/src/components/Form/FormContext.d.ts.map +1 -1
  24. package/dist/types/src/components/Form/Input.d.ts +2 -2
  25. package/dist/types/src/components/Form/Input.d.ts.map +1 -1
  26. package/dist/types/src/components/Form/custom/GeoPointInput.d.ts +1 -2
  27. package/dist/types/src/components/Form/custom/GeoPointInput.d.ts.map +1 -1
  28. package/dist/types/src/components/Form/custom/SelectOptionsInput.d.ts +1 -2
  29. package/dist/types/src/components/Form/custom/SelectOptionsInput.d.ts.map +1 -1
  30. package/dist/types/src/components/Form/custom/TupleInput.d.ts +1 -2
  31. package/dist/types/src/components/Form/custom/TupleInput.d.ts.map +1 -1
  32. package/dist/types/src/components/Form/factory.d.ts.map +1 -1
  33. package/dist/types/src/components/Form/index.d.ts +2 -0
  34. package/dist/types/src/components/Form/index.d.ts.map +1 -1
  35. package/dist/types/src/components/ViewEditor/Test.stories.d.ts +1 -2
  36. package/dist/types/src/components/ViewEditor/Test.stories.d.ts.map +1 -1
  37. package/dist/types/src/components/ViewEditor/ViewEditor.d.ts +1 -2
  38. package/dist/types/src/components/ViewEditor/ViewEditor.d.ts.map +1 -1
  39. package/dist/types/src/components/deprecated/Form.d.ts +1 -2
  40. package/dist/types/src/components/deprecated/Form.d.ts.map +1 -1
  41. package/dist/types/src/components/deprecated/Form.stories.d.ts +1 -2
  42. package/dist/types/src/components/deprecated/Form.stories.d.ts.map +1 -1
  43. package/dist/types/src/components/deprecated/FormInput.d.ts +2 -2
  44. package/dist/types/src/components/deprecated/FormInput.d.ts.map +1 -1
  45. package/dist/types/src/components/testing.d.ts +3 -3
  46. package/dist/types/src/components/testing.d.ts.map +1 -1
  47. package/dist/types/src/hooks/useForm.d.ts +1 -0
  48. package/dist/types/src/hooks/useForm.d.ts.map +1 -1
  49. package/dist/types/src/util/field.d.ts.map +1 -1
  50. package/dist/types/src/util/formatting.d.ts.map +1 -1
  51. package/package.json +25 -24
  52. package/src/components/Form/Defaults.tsx +61 -4
  53. package/src/components/Form/Form.tsx +9 -5
  54. package/src/components/Form/FormActions.tsx +1 -1
  55. package/src/components/Form/FormContent.tsx +10 -13
  56. package/src/components/Form/FormContext.tsx +58 -10
  57. package/src/components/Form/custom/GeoPointInput.tsx +42 -12
  58. package/src/components/Form/custom/SelectOptionsInput.tsx +7 -9
  59. package/src/components/Form/factory.tsx +4 -2
  60. package/src/components/Form/index.ts +3 -0
  61. package/src/components/ViewEditor/ViewEditor.tsx +2 -2
  62. package/src/hooks/useForm.ts +69 -40
  63. package/src/translations.ts +1 -1
  64. package/src/util/field.ts +19 -1
  65. package/src/util/formatting.ts +29 -1
@@ -31,7 +31,7 @@ var translations_default = [
31
31
  "format hostname": "Hostname",
32
32
  "format integer": "Integer",
33
33
  "format json": "JSON",
34
- "format latlng": "LatLng",
34
+ "format latlng": "Geopoint",
35
35
  "format markdown": "Markdown",
36
36
  "format percent": "Percent",
37
37
  "format ref": "Reference",
@@ -101,85 +101,394 @@ var DeprecatedFormInput = ({ label, description, secondary, children }) => {
101
101
  };
102
102
 
103
103
  // packages/ui/react-ui-form/src/components/FieldEditor/FieldEditor.tsx
104
- import React12, { useCallback as useCallback4, useEffect as useEffect4, useMemo as useMemo5, useState as useState3 } from "react";
104
+ import React12, { useCallback as useCallback6, useEffect as useEffect7, useMemo as useMemo7, useState as useState4 } from "react";
105
105
  import { FormatEnum as FormatEnum2, FormatEnums, formatToType } from "@dxos/echo-schema";
106
106
  import { log as log2 } from "@dxos/log";
107
107
  import { useTranslation as useTranslation5 } from "@dxos/react-ui";
108
108
  import { getFormatSchema, getSchemaProperties as getSchemaProperties3, sortProperties } from "@dxos/schema";
109
109
 
110
+ // packages/ui/react-ui-form/src/components/Form/FormContext.tsx
111
+ import React2, { createContext, useContext, useEffect as useEffect2, useMemo as useMemo2 } from "react";
112
+ import { raise } from "@dxos/debug";
113
+ import { getValue as getValue2 } from "@dxos/echo-schema";
114
+ import { createJsonPath as createJsonPath2 } from "@dxos/effect";
115
+
116
+ // packages/ui/react-ui-form/src/hooks/useForm.ts
117
+ import { useCallback, useEffect, useMemo, useState } from "react";
118
+ import { getValue, setValue } from "@dxos/echo-schema";
119
+ import { AST, createJsonPath, fromEffectValidationPath } from "@dxos/effect";
120
+ import { invariant } from "@dxos/invariant";
121
+ import { log } from "@dxos/log";
122
+ import { validateSchema } from "@dxos/schema";
123
+ var __dxlog_file = "/home/runner/work/dxos/dxos/packages/ui/react-ui-form/src/hooks/useForm.ts";
124
+ var useForm = ({ schema, initialValues, onValuesChanged, onValidate, onValid, onSave }) => {
125
+ invariant(AST.isTypeLiteral(schema.ast), void 0, {
126
+ F: __dxlog_file,
127
+ L: 92,
128
+ S: void 0,
129
+ A: [
130
+ "AST.isTypeLiteral(schema.ast)",
131
+ ""
132
+ ]
133
+ });
134
+ const [values, setValues] = useState(initialValues);
135
+ useEffect(() => {
136
+ setValues(initialValues);
137
+ }, [
138
+ initialValues
139
+ ]);
140
+ const [touched, setTouched] = useState(createKeySet(initialValues, false));
141
+ const [changed, setChanged] = useState(createKeySet(initialValues, false));
142
+ const [errors, setErrors] = useState({});
143
+ const [saving, setSaving] = useState(false);
144
+ const validate = useCallback((values2) => {
145
+ let errors2 = validateSchema(schema, values2) ?? [];
146
+ if (errors2.length === 0 && onValidate) {
147
+ const validatedValues = values2;
148
+ errors2 = onValidate(validatedValues) ?? [];
149
+ }
150
+ setErrors(flatMap(errors2));
151
+ const valid = errors2.length === 0;
152
+ return valid;
153
+ }, [
154
+ schema,
155
+ onValidate
156
+ ]);
157
+ const [schemaDirty, setSchemaDirty] = useState(false);
158
+ useEffect(() => setSchemaDirty(true), [
159
+ schema
160
+ ]);
161
+ useEffect(() => {
162
+ if (schemaDirty) {
163
+ validate(values);
164
+ setSchemaDirty(false);
165
+ }
166
+ }, [
167
+ values,
168
+ schemaDirty
169
+ ]);
170
+ const formIsValid = useMemo(() => {
171
+ return Object.keys(errors).length === 0;
172
+ }, [
173
+ errors
174
+ ]);
175
+ const canSave = useMemo(() => !saving && // Check if any error paths that are touched have errors.
176
+ !Object.entries(touched).some(([path, isTouched]) => isTouched && Object.keys(errors).some((errorPath) => errorPath === path || errorPath.startsWith(`${path}.`) || errorPath.startsWith(`${path}[`))), [
177
+ touched,
178
+ errors,
179
+ saving
180
+ ]);
181
+ const handleSave = useCallback(async () => {
182
+ if (validate(values)) {
183
+ setSaving(true);
184
+ try {
185
+ await onSave?.(values, {
186
+ changed
187
+ });
188
+ } finally {
189
+ setSaving(false);
190
+ }
191
+ }
192
+ }, [
193
+ values,
194
+ validate,
195
+ onSave,
196
+ changed
197
+ ]);
198
+ const getStatus = useCallback((path) => {
199
+ const jsonPath = Array.isArray(path) ? createJsonPath(path) : path;
200
+ const matchingError = Object.entries(errors).find(([errorPath]) => errorPath === jsonPath || errorPath.startsWith(`${jsonPath}.`) || errorPath.startsWith(`${jsonPath}[`));
201
+ return {
202
+ status: matchingError ? "error" : void 0,
203
+ error: matchingError ? matchingError[1] : void 0
204
+ };
205
+ }, [
206
+ errors
207
+ ]);
208
+ const getFormValue = useCallback((path) => {
209
+ return getValue(values, createJsonPath(path));
210
+ }, [
211
+ values
212
+ ]);
213
+ const onValueChange = useCallback((path, type, value) => {
214
+ const jsonPath = createJsonPath(path);
215
+ let parsedValue = value;
216
+ try {
217
+ if (type === "number") {
218
+ parsedValue = parseFloat(value) || 0;
219
+ }
220
+ } catch (err) {
221
+ log.catch(err, void 0, {
222
+ F: __dxlog_file,
223
+ L: 202,
224
+ S: void 0,
225
+ C: (f, a) => f(...a)
226
+ });
227
+ parsedValue = void 0;
228
+ }
229
+ const newValues = {
230
+ ...setValue(values, jsonPath, parsedValue)
231
+ };
232
+ setValues(newValues);
233
+ setChanged((prev) => ({
234
+ ...prev,
235
+ [jsonPath]: true
236
+ }));
237
+ onValuesChanged?.(newValues);
238
+ const isValid = validate(newValues);
239
+ if (isValid && onValid) {
240
+ onValid(newValues, {
241
+ changed
242
+ });
243
+ }
244
+ }, [
245
+ values,
246
+ onValuesChanged,
247
+ validate,
248
+ onValid,
249
+ changed
250
+ ]);
251
+ const onTouched = useCallback((path) => {
252
+ const jsonPath = createJsonPath(path);
253
+ setTouched((touched2) => ({
254
+ ...touched2,
255
+ [jsonPath]: true
256
+ }));
257
+ validate(values);
258
+ }, [
259
+ validate,
260
+ values
261
+ ]);
262
+ return useMemo(() => ({
263
+ // State.
264
+ values,
265
+ errors,
266
+ touched,
267
+ changed,
268
+ canSave,
269
+ formIsValid,
270
+ // Actions.
271
+ handleSave,
272
+ // Field utils.
273
+ getStatus,
274
+ getValue: getFormValue,
275
+ onValueChange,
276
+ onTouched
277
+ }), [
278
+ values,
279
+ errors,
280
+ touched,
281
+ changed,
282
+ canSave,
283
+ formIsValid,
284
+ handleSave,
285
+ getStatus,
286
+ getFormValue,
287
+ onValueChange,
288
+ onTouched
289
+ ]);
290
+ };
291
+ var createKeySet = (obj, value) => {
292
+ invariant(obj, void 0, {
293
+ F: __dxlog_file,
294
+ L: 264,
295
+ S: void 0,
296
+ A: [
297
+ "obj",
298
+ ""
299
+ ]
300
+ });
301
+ return Object.keys(obj).reduce((acc, key) => ({
302
+ ...acc,
303
+ [key]: value
304
+ }), {});
305
+ };
306
+ var flatMap = (errors) => {
307
+ return errors.reduce((result, { path, message }) => {
308
+ const jsonPath = fromEffectValidationPath(path);
309
+ if (!(jsonPath in result)) {
310
+ result[jsonPath] = message;
311
+ }
312
+ return result;
313
+ }, {});
314
+ };
315
+
316
+ // packages/ui/react-ui-form/src/components/Form/FormContext.tsx
317
+ var FormContext = /* @__PURE__ */ createContext(void 0);
318
+ var useFormContext = () => {
319
+ return useContext(FormContext) ?? raise(new Error("Missing FormContext"));
320
+ };
321
+ var useFormValues = (path = []) => {
322
+ const { values: formValues } = useFormContext();
323
+ const jsonPath = createJsonPath2(path);
324
+ return getValue2(formValues, jsonPath);
325
+ };
326
+ var useInputProps = (path = []) => {
327
+ const { getStatus, getValue: getFormValue, onValueChange, onTouched } = useFormContext();
328
+ const stablePath = useMemo2(() => path, [
329
+ Array.isArray(path) ? path.join(".") : path
330
+ ]);
331
+ return useMemo2(() => ({
332
+ getStatus: () => getStatus(stablePath),
333
+ getValue: () => getFormValue(stablePath),
334
+ onValueChange: (type, value) => onValueChange(stablePath, type, value),
335
+ onBlur: () => onTouched(stablePath)
336
+ }), [
337
+ getStatus,
338
+ getFormValue,
339
+ onValueChange,
340
+ onTouched,
341
+ stablePath
342
+ ]);
343
+ };
344
+ var FormProvider = ({ children, formRef, autoSave, ...formOptions }) => {
345
+ const form = useForm(formOptions);
346
+ useEffect2(() => {
347
+ if (!formRef?.current) {
348
+ return;
349
+ }
350
+ const handleKeyDown = (event) => {
351
+ const keyIsEnter = event.key === "Enter";
352
+ const modifierUsed = event.ctrlKey || event.altKey || event.metaKey || event.shiftKey;
353
+ const inputIsTextarea = event.target.tagName.toLowerCase() === "textarea";
354
+ const inputOptOut = event.target.hasAttribute("data-no-submit");
355
+ const shouldSubmitRegularInput = !inputIsTextarea && keyIsEnter && !modifierUsed;
356
+ const shouldSubmitTextarea = inputIsTextarea && keyIsEnter && event.metaKey;
357
+ if ((shouldSubmitRegularInput || shouldSubmitTextarea) && !inputOptOut) {
358
+ if (!autoSave && form.canSave) {
359
+ form.handleSave();
360
+ }
361
+ if (autoSave && form.formIsValid) {
362
+ event.target.blur();
363
+ }
364
+ }
365
+ };
366
+ const formElement = formRef.current;
367
+ formElement.addEventListener("keydown", handleKeyDown);
368
+ return () => formElement.removeEventListener("keydown", handleKeyDown);
369
+ }, [
370
+ formRef,
371
+ form.canSave,
372
+ form.formIsValid,
373
+ form.handleSave,
374
+ autoSave
375
+ ]);
376
+ return /* @__PURE__ */ React2.createElement(FormContext.Provider, {
377
+ value: form
378
+ }, children);
379
+ };
380
+
110
381
  // packages/ui/react-ui-form/src/components/Form/custom/GeoPointInput.tsx
111
- import React3 from "react";
382
+ import React4, { useCallback as useCallback2, useState as useState2, useEffect as useEffect3, useMemo as useMemo3 } from "react";
383
+ import { GeoLocation } from "@dxos/echo-schema";
112
384
  import { Input as Input2, useTranslation } from "@dxos/react-ui";
113
385
  import { safeParseFloat } from "@dxos/util";
114
386
 
115
387
  // packages/ui/react-ui-form/src/components/Form/Input.tsx
116
- import React2 from "react";
388
+ import React3 from "react";
117
389
  import { Icon, Tooltip } from "@dxos/react-ui";
118
390
  import { errorText } from "@dxos/react-ui-theme";
119
391
  var InputHeader = ({ children, error }) => {
120
- return /* @__PURE__ */ React2.createElement("div", {
392
+ return /* @__PURE__ */ React3.createElement("div", {
121
393
  role: "none",
122
394
  className: "flex justify-between items-center mb-1"
123
- }, children, error && /* @__PURE__ */ React2.createElement(Tooltip.Root, null, /* @__PURE__ */ React2.createElement(Tooltip.Trigger, {
395
+ }, children, error && /* @__PURE__ */ React3.createElement(Tooltip.Root, null, /* @__PURE__ */ React3.createElement(Tooltip.Trigger, {
124
396
  asChild: true
125
- }, /* @__PURE__ */ React2.createElement(Icon, {
397
+ }, /* @__PURE__ */ React3.createElement(Icon, {
126
398
  icon: "ph--warning--regular",
127
399
  size: 4,
128
400
  classNames: errorText
129
- })), /* @__PURE__ */ React2.createElement(Tooltip.Content, {
401
+ })), /* @__PURE__ */ React3.createElement(Tooltip.Content, {
130
402
  side: "bottom"
131
- }, /* @__PURE__ */ React2.createElement(Tooltip.Arrow, null), error)));
403
+ }, /* @__PURE__ */ React3.createElement(Tooltip.Arrow, null), error)));
132
404
  };
133
405
 
134
406
  // packages/ui/react-ui-form/src/components/Form/custom/GeoPointInput.tsx
135
407
  var GeoPointInput = ({ type, label, disabled, getStatus, getValue: getValue3, onValueChange, onBlur }) => {
136
408
  const { t } = useTranslation(translationKey);
137
409
  const { status, error } = getStatus();
138
- const [lng = 0, lat = 0] = getValue3() ?? [];
139
- return /* @__PURE__ */ React3.createElement(Input2.Root, {
410
+ const geoPoint = useMemo3(() => getValue3() ?? [
411
+ 0,
412
+ 0
413
+ ], [
414
+ getValue3
415
+ ]);
416
+ const geoLocation = useMemo3(() => GeoLocation.fromGeoPoint(geoPoint), [
417
+ geoPoint
418
+ ]);
419
+ const [longitudeText, setLongitudeText] = useState2(geoLocation.longitude?.toString());
420
+ const [latitudeText, setLatitudeText] = useState2(geoLocation.latitude?.toString());
421
+ useEffect3(() => {
422
+ const location = GeoLocation.fromGeoPoint(geoPoint);
423
+ setLongitudeText(location.longitude.toString());
424
+ setLatitudeText(location.latitude.toString());
425
+ }, [
426
+ geoPoint
427
+ ]);
428
+ const handleCoordinateChange = useCallback2((coordinateType, setText) => (event) => {
429
+ const inputText = event.target.value;
430
+ setText(inputText);
431
+ if (inputText !== "" && inputText !== "-") {
432
+ const coord = safeParseFloat(inputText);
433
+ if (coord !== void 0 && !isNaN(coord)) {
434
+ const currentLocation = GeoLocation.fromGeoPoint(getValue3() ?? [
435
+ 0,
436
+ 0
437
+ ]);
438
+ const newLocation = {
439
+ ...currentLocation,
440
+ [coordinateType]: coord
441
+ };
442
+ const newValue = GeoLocation.toGeoPoint(newLocation);
443
+ onValueChange(type, newValue);
444
+ }
445
+ }
446
+ }, [
447
+ getValue3,
448
+ onValueChange,
449
+ type
450
+ ]);
451
+ return /* @__PURE__ */ React4.createElement(Input2.Root, {
140
452
  validationValence: status
141
- }, /* @__PURE__ */ React3.createElement(InputHeader, {
453
+ }, /* @__PURE__ */ React4.createElement(InputHeader, {
142
454
  error
143
- }, /* @__PURE__ */ React3.createElement(Input2.Label, null, label)), /* @__PURE__ */ React3.createElement("div", {
455
+ }, /* @__PURE__ */ React4.createElement(Input2.Label, null, label)), /* @__PURE__ */ React4.createElement("div", {
456
+ role: "none",
144
457
  className: "grid grid-cols-2 gap-2"
145
- }, /* @__PURE__ */ React3.createElement(Input2.TextInput, {
146
- type: "number",
458
+ }, /* @__PURE__ */ React4.createElement(Input2.TextInput, {
459
+ type: "text",
460
+ pattern: "^-?[0-9]*\\.?[0-9]*$",
147
461
  disabled,
148
- placeholder: t("placeholder longitude"),
149
- value: lng,
150
- onChange: (event) => onValueChange(type, [
151
- lat,
152
- safeParseFloat(event.target.value, 0)
153
- ]),
462
+ placeholder: t("placeholder latitude"),
463
+ value: latitudeText,
464
+ onChange: handleCoordinateChange("latitude", setLatitudeText),
154
465
  onBlur
155
- }), /* @__PURE__ */ React3.createElement(Input2.TextInput, {
156
- type: "number",
466
+ }), /* @__PURE__ */ React4.createElement(Input2.TextInput, {
467
+ type: "text",
468
+ pattern: "^-?[0-9]*\\.?[0-9]*$",
157
469
  disabled,
158
- placeholder: t("placeholder latitude"),
159
- value: lat,
160
- onChange: (event) => onValueChange(type, [
161
- safeParseFloat(event.target.value, 0),
162
- lng
163
- ]),
470
+ placeholder: t("placeholder longitude"),
471
+ value: longitudeText,
472
+ onChange: handleCoordinateChange("longitude", setLongitudeText),
164
473
  onBlur
165
474
  })));
166
475
  };
167
476
 
168
477
  // packages/ui/react-ui-form/src/components/Form/custom/SelectOptionsInput.tsx
169
- import React4, { useCallback, useEffect, useState, useRef } from "react";
478
+ import React5, { useCallback as useCallback3, useEffect as useEffect4, useState as useState3, useRef } from "react";
170
479
  import { PublicKey } from "@dxos/keys";
171
480
  import { Icon as Icon2, IconButton, Input as Input3, Tag, Toolbar, useTranslation as useTranslation2 } from "@dxos/react-ui";
172
481
  import { List } from "@dxos/react-ui-list";
173
- import { HuePickerToolbarButton } from "@dxos/react-ui-pickers";
174
- import { hueTokenThemes, mx as mx2 } from "@dxos/react-ui-theme";
482
+ import { HuePicker } from "@dxos/react-ui-pickers";
483
+ import { hues, mx as mx2 } from "@dxos/react-ui-theme";
175
484
  var SelectOptionInput = ({ type, label, disabled, getStatus, getValue: getValue3, onValueChange }) => {
176
- const [selected, setSelectedId] = useState(null);
177
- const [isNewOption, setIsNewOption] = useState(false);
485
+ const [selected, setSelectedId] = useState3(null);
486
+ const [isNewOption, setIsNewOption] = useState3(false);
178
487
  const inputRef = useRef(null);
179
488
  const { t } = useTranslation2(translationKey);
180
489
  const { status, error } = getStatus();
181
490
  const options = getValue3();
182
- useEffect(() => {
491
+ useEffect4(() => {
183
492
  if (options === void 0) {
184
493
  onValueChange(type, []);
185
494
  }
@@ -190,16 +499,15 @@ var SelectOptionInput = ({ type, label, disabled, getStatus, getValue: getValue3
190
499
  ]);
191
500
  const randomHue = () => {
192
501
  const usedHues = new Set(options?.map((option) => option.color) ?? []);
193
- const hueKeys = Object.keys(hueTokenThemes);
194
- const unusedHues = hueKeys.filter((hue) => !usedHues.has(hue));
502
+ const unusedHues = hues.filter((hue) => !usedHues.has(hue));
195
503
  if (unusedHues.length > 0) {
196
504
  return unusedHues[Math.floor(Math.random() * unusedHues.length)];
197
505
  }
198
506
  const lastThree = new Set(options?.slice(-3).map((option) => option.color) ?? []);
199
- const availableHues = hueKeys.filter((hue) => !lastThree.has(hue));
200
- return availableHues[Math.floor(Math.random() * availableHues.length)] ?? hueKeys[Math.floor(Math.random() * hueKeys.length)];
507
+ const availableHues = hues.filter((hue) => !lastThree.has(hue));
508
+ return availableHues[Math.floor(Math.random() * availableHues.length)] ?? hues[Math.floor(Math.random() * hues.length)];
201
509
  };
202
- const handleAdd = useCallback(() => {
510
+ const handleAdd = useCallback3(() => {
203
511
  const newId = PublicKey.random().truncate();
204
512
  const newOption = {
205
513
  id: newId,
@@ -217,7 +525,7 @@ var SelectOptionInput = ({ type, label, disabled, getStatus, getValue: getValue3
217
525
  type,
218
526
  onValueChange
219
527
  ]);
220
- const handleDelete = useCallback((id) => {
528
+ const handleDelete = useCallback3((id) => {
221
529
  const newOptions = options?.filter((option) => option.id !== id) ?? [];
222
530
  onValueChange(type, newOptions);
223
531
  setSelectedId(null);
@@ -226,7 +534,7 @@ var SelectOptionInput = ({ type, label, disabled, getStatus, getValue: getValue3
226
534
  type,
227
535
  onValueChange
228
536
  ]);
229
- const handleMove = useCallback((from, to) => {
537
+ const handleMove = useCallback3((from, to) => {
230
538
  if (!options) {
231
539
  return;
232
540
  }
@@ -241,10 +549,10 @@ var SelectOptionInput = ({ type, label, disabled, getStatus, getValue: getValue3
241
549
  type,
242
550
  onValueChange
243
551
  ]);
244
- const handleClick = useCallback((id) => {
552
+ const handleClick = useCallback3((id) => {
245
553
  setSelectedId((current) => current === id ? null : id);
246
554
  }, []);
247
- const handleTitleChange = useCallback((id) => (e) => {
555
+ const handleTitleChange = useCallback3((id) => (e) => {
248
556
  const newOptions = options?.map((o) => o.id === id ? {
249
557
  ...o,
250
558
  title: e.target.value
@@ -255,12 +563,12 @@ var SelectOptionInput = ({ type, label, disabled, getStatus, getValue: getValue3
255
563
  type,
256
564
  onValueChange
257
565
  ]);
258
- const handleKeyDown = useCallback((e) => {
566
+ const handleKeyDown = useCallback3((e) => {
259
567
  if (e.key === "Enter") {
260
568
  setSelectedId(null);
261
569
  }
262
570
  }, []);
263
- const handleColorChange = useCallback((id) => (hue) => {
571
+ const handleColorChange = useCallback3((id) => (hue) => {
264
572
  const newOptions = options?.map((o) => o.id === id ? {
265
573
  ...o,
266
574
  color: hue
@@ -271,7 +579,7 @@ var SelectOptionInput = ({ type, label, disabled, getStatus, getValue: getValue3
271
579
  type,
272
580
  onValueChange
273
581
  ]);
274
- useEffect(() => {
582
+ useEffect4(() => {
275
583
  if (selected && isNewOption && inputRef.current) {
276
584
  inputRef.current.focus();
277
585
  setIsNewOption(false);
@@ -280,76 +588,77 @@ var SelectOptionInput = ({ type, label, disabled, getStatus, getValue: getValue3
280
588
  selected,
281
589
  isNewOption
282
590
  ]);
283
- return /* @__PURE__ */ React4.createElement(Input3.Root, {
591
+ return /* @__PURE__ */ React5.createElement(Input3.Root, {
284
592
  validationValence: status
285
- }, /* @__PURE__ */ React4.createElement(InputHeader, {
593
+ }, /* @__PURE__ */ React5.createElement(InputHeader, {
286
594
  error
287
- }, /* @__PURE__ */ React4.createElement(Input3.Label, null, label)), /* @__PURE__ */ React4.createElement("div", {
595
+ }, /* @__PURE__ */ React5.createElement(Input3.Label, null, label)), /* @__PURE__ */ React5.createElement("div", {
288
596
  role: "none"
289
- }, options && /* @__PURE__ */ React4.createElement(List.Root, {
597
+ }, options && /* @__PURE__ */ React5.createElement(List.Root, {
290
598
  items: options,
291
599
  isItem: (item) => true,
292
600
  onMove: handleMove
293
- }, ({ items }) => /* @__PURE__ */ React4.createElement("div", {
601
+ }, ({ items }) => /* @__PURE__ */ React5.createElement("div", {
294
602
  role: "list",
295
603
  className: "w-full overflow-auto"
296
- }, items?.map((item) => /* @__PURE__ */ React4.createElement("div", {
604
+ }, items?.map((item) => /* @__PURE__ */ React5.createElement("div", {
297
605
  key: item.id
298
- }, /* @__PURE__ */ React4.createElement(List.Item, {
606
+ }, /* @__PURE__ */ React5.createElement(List.Item, {
299
607
  role: "button",
300
608
  item,
301
609
  classNames: mx2("p-1 plb-2", "flex flex-col", "cursor-pointer", "hover:bg-hoverOverlay"),
302
610
  "aria-expanded": selected === item.id
303
- }, /* @__PURE__ */ React4.createElement("div", {
611
+ }, /* @__PURE__ */ React5.createElement("div", {
304
612
  className: "flex items-center"
305
- }, /* @__PURE__ */ React4.createElement(List.ItemDragHandle, null), /* @__PURE__ */ React4.createElement(List.ItemTitle, {
613
+ }, /* @__PURE__ */ React5.createElement(List.ItemDragHandle, null), /* @__PURE__ */ React5.createElement(List.ItemTitle, {
306
614
  onClick: () => handleClick(item.id),
307
615
  classNames: "flex-1"
308
- }, /* @__PURE__ */ React4.createElement(Tag, {
616
+ }, /* @__PURE__ */ React5.createElement(Tag, {
309
617
  palette: item.color
310
- }, item.title || "\u200B")), /* @__PURE__ */ React4.createElement(Icon2, {
618
+ }, item.title || "\u200B")), /* @__PURE__ */ React5.createElement(Icon2, {
311
619
  icon: selected === item.id ? "ph--caret-down--regular" : "ph--caret-right--regular",
312
620
  onClick: () => handleClick(item.id)
313
- })), selected === item.id && /* @__PURE__ */ React4.createElement("div", {
621
+ })), selected === item.id && /* @__PURE__ */ React5.createElement("div", {
314
622
  className: "mis-4 mbs-2 flex flex-col gap-1"
315
- }, /* @__PURE__ */ React4.createElement(Input3.Label, {
623
+ }, /* @__PURE__ */ React5.createElement(Input3.Label, {
316
624
  classNames: "text-xs"
317
- }, t("select option label")), /* @__PURE__ */ React4.createElement("div", {
625
+ }, t("select option label")), /* @__PURE__ */ React5.createElement("div", {
318
626
  className: "flex flex-row items-center gap-1"
319
- }, /* @__PURE__ */ React4.createElement(Input3.TextInput, {
627
+ }, /* @__PURE__ */ React5.createElement(Input3.TextInput, {
320
628
  placeholder: t("select option label placeholder"),
321
629
  ref: selected === item.id ? inputRef : void 0,
322
630
  value: item.title,
323
631
  onChange: handleTitleChange(item.id),
324
632
  onKeyDown: handleKeyDown,
325
- classNames: "flex-1"
326
- }), /* @__PURE__ */ React4.createElement(Toolbar.Root, {
633
+ classNames: "flex-1",
634
+ "data-no-submit": true
635
+ }), /* @__PURE__ */ React5.createElement(Toolbar.Root, {
327
636
  classNames: "p-0 m-0 !is-auto"
328
- }, /* @__PURE__ */ React4.createElement(HuePickerToolbarButton, {
329
- hue: item.color,
330
- onChangeHue: handleColorChange(item.id)
331
- })), /* @__PURE__ */ React4.createElement(IconButton, {
637
+ }, /* @__PURE__ */ React5.createElement(HuePicker, {
638
+ value: item.color,
639
+ onChange: handleColorChange(item.id)
640
+ })), /* @__PURE__ */ React5.createElement(IconButton, {
332
641
  icon: "ph--trash--fill",
333
642
  iconOnly: true,
334
643
  label: t("select option delete"),
335
644
  onClick: () => handleDelete(item.id)
336
- })))))), /* @__PURE__ */ React4.createElement("div", {
645
+ })))))), /* @__PURE__ */ React5.createElement("div", {
337
646
  role: "listitem"
338
- }, /* @__PURE__ */ React4.createElement("div", {
647
+ }, /* @__PURE__ */ React5.createElement("div", {
339
648
  role: "button",
340
649
  className: mx2("p-1 plb-2", "flex flex-col", "cursor-pointer", "hover:bg-hoverOverlay"),
341
650
  onClick: handleAdd
342
- }, /* @__PURE__ */ React4.createElement("div", {
651
+ }, /* @__PURE__ */ React5.createElement("div", {
343
652
  className: "flex items-center gap-1"
344
- }, /* @__PURE__ */ React4.createElement(Icon2, {
653
+ }, /* @__PURE__ */ React5.createElement(Icon2, {
345
654
  icon: "ph--plus--regular"
346
- }), /* @__PURE__ */ React4.createElement("span", {
655
+ }), /* @__PURE__ */ React5.createElement("span", {
347
656
  className: "text-sm"
348
657
  }, t("select option add")))))))));
349
658
  };
350
659
 
351
660
  // packages/ui/react-ui-form/src/components/Form/custom/TupleInput.tsx
352
- import React5 from "react";
661
+ import React6 from "react";
353
662
  import { Input as Input4 } from "@dxos/react-ui";
354
663
  import { mx as mx3 } from "@dxos/react-ui-theme";
355
664
  import { safeParseFloat as safeParseFloat2 } from "@dxos/util";
@@ -362,13 +671,13 @@ var gridCols = [
362
671
  var TupleInput = ({ binding, type, label, disabled, getStatus, getValue: getValue3, onValueChange, onBlur }) => {
363
672
  const { status, error } = getStatus();
364
673
  const values = getValue3() ?? {};
365
- return /* @__PURE__ */ React5.createElement(Input4.Root, {
674
+ return /* @__PURE__ */ React6.createElement(Input4.Root, {
366
675
  validationValence: status
367
- }, /* @__PURE__ */ React5.createElement(InputHeader, {
676
+ }, /* @__PURE__ */ React6.createElement(InputHeader, {
368
677
  error
369
- }, /* @__PURE__ */ React5.createElement(Input4.Label, null, label)), /* @__PURE__ */ React5.createElement("div", {
678
+ }, /* @__PURE__ */ React6.createElement(Input4.Label, null, label)), /* @__PURE__ */ React6.createElement("div", {
370
679
  className: mx3("grid gap-2", gridCols[binding.length - 1])
371
- }, binding.map((prop) => /* @__PURE__ */ React5.createElement(Input4.TextInput, {
680
+ }, binding.map((prop) => /* @__PURE__ */ React6.createElement(Input4.TextInput, {
372
681
  key: prop,
373
682
  type: "number",
374
683
  disabled,
@@ -382,291 +691,124 @@ var TupleInput = ({ binding, type, label, disabled, getStatus, getValue: getValu
382
691
  };
383
692
 
384
693
  // packages/ui/react-ui-form/src/components/Form/Defaults.tsx
385
- import React6 from "react";
694
+ import React7, { useCallback as useCallback4, useEffect as useEffect5, useRef as useRef2 } from "react";
386
695
  import { Input as Input5, Select } from "@dxos/react-ui";
387
696
  var TextInput = ({ type, label, inputOnly, disabled, placeholder, getStatus, getValue: getValue3, onValueChange, onBlur }) => {
388
697
  const { status, error } = getStatus();
389
- return /* @__PURE__ */ React6.createElement(Input5.Root, {
698
+ return /* @__PURE__ */ React7.createElement(Input5.Root, {
390
699
  validationValence: status
391
- }, !inputOnly && /* @__PURE__ */ React6.createElement(InputHeader, {
700
+ }, !inputOnly && /* @__PURE__ */ React7.createElement(InputHeader, {
392
701
  error
393
- }, /* @__PURE__ */ React6.createElement(Input5.Label, null, label)), /* @__PURE__ */ React6.createElement(Input5.TextInput, {
702
+ }, /* @__PURE__ */ React7.createElement(Input5.Label, null, label)), /* @__PURE__ */ React7.createElement(Input5.TextInput, {
394
703
  disabled,
395
704
  placeholder,
396
705
  value: getValue3() ?? "",
397
706
  onChange: (event) => onValueChange(type, event.target.value),
398
707
  onBlur
399
- }), inputOnly && /* @__PURE__ */ React6.createElement(Input5.Validation, null, error));
708
+ }), inputOnly && /* @__PURE__ */ React7.createElement(Input5.Validation, null, error));
400
709
  };
401
710
  var NumberInput = ({ type, label, inputOnly, disabled, placeholder, getStatus, getValue: getValue3, onValueChange, onBlur }) => {
402
711
  const { status, error } = getStatus();
403
- return /* @__PURE__ */ React6.createElement(Input5.Root, {
712
+ return /* @__PURE__ */ React7.createElement(Input5.Root, {
404
713
  validationValence: status
405
- }, !inputOnly && /* @__PURE__ */ React6.createElement(InputHeader, {
714
+ }, !inputOnly && /* @__PURE__ */ React7.createElement(InputHeader, {
406
715
  error
407
- }, /* @__PURE__ */ React6.createElement(Input5.Label, null, label)), /* @__PURE__ */ React6.createElement(Input5.TextInput, {
716
+ }, /* @__PURE__ */ React7.createElement(Input5.Label, null, label)), /* @__PURE__ */ React7.createElement(Input5.TextInput, {
408
717
  type: "number",
409
718
  disabled,
410
719
  placeholder,
411
720
  value: getValue3() ?? 0,
412
721
  onChange: (event) => onValueChange(type, event.target.value),
413
722
  onBlur
414
- }), inputOnly && /* @__PURE__ */ React6.createElement(Input5.DescriptionAndValidation, null, error));
723
+ }), inputOnly && /* @__PURE__ */ React7.createElement(Input5.DescriptionAndValidation, null, error));
415
724
  };
416
725
  var BooleanInput = ({ type, label, inputOnly, getStatus, getValue: getValue3, onValueChange }) => {
417
726
  const { status, error } = getStatus();
418
- return /* @__PURE__ */ React6.createElement(Input5.Root, {
727
+ const checked = Boolean(getValue3());
728
+ return /* @__PURE__ */ React7.createElement(Input5.Root, {
419
729
  validationValence: status
420
- }, !inputOnly && /* @__PURE__ */ React6.createElement(InputHeader, {
730
+ }, !inputOnly && /* @__PURE__ */ React7.createElement(InputHeader, {
421
731
  error
422
- }, /* @__PURE__ */ React6.createElement(Input5.Label, null, label)), /* @__PURE__ */ React6.createElement(Input5.Switch, {
423
- checked: getValue3(),
732
+ }, /* @__PURE__ */ React7.createElement(Input5.Label, null, label)), /* @__PURE__ */ React7.createElement(Input5.Switch, {
733
+ checked,
424
734
  onCheckedChange: (value) => onValueChange(type, value)
425
- }), inputOnly && /* @__PURE__ */ React6.createElement(Input5.DescriptionAndValidation, null, error));
735
+ }), inputOnly && /* @__PURE__ */ React7.createElement(Input5.DescriptionAndValidation, null, error));
426
736
  };
427
737
  var SelectInput = ({ type, label, inputOnly, disabled, placeholder, options, getStatus, getValue: getValue3, onValueChange }) => {
428
738
  const { status, error } = getStatus();
429
- return /* @__PURE__ */ React6.createElement(Input5.Root, {
739
+ return /* @__PURE__ */ React7.createElement(Input5.Root, {
430
740
  validationValence: status
431
- }, !inputOnly && /* @__PURE__ */ React6.createElement(InputHeader, {
741
+ }, !inputOnly && /* @__PURE__ */ React7.createElement(InputHeader, {
432
742
  error
433
- }, /* @__PURE__ */ React6.createElement(Input5.Label, null, label)), /* @__PURE__ */ React6.createElement(Select.Root, {
743
+ }, /* @__PURE__ */ React7.createElement(Input5.Label, null, label)), /* @__PURE__ */ React7.createElement(Select.Root, {
434
744
  value: getValue3(),
435
745
  onValueChange: (value) => onValueChange(type, value)
436
- }, /* @__PURE__ */ React6.createElement(Select.TriggerButton, {
746
+ }, /* @__PURE__ */ React7.createElement(Select.TriggerButton, {
437
747
  classNames: "is-full",
438
748
  disabled,
439
749
  placeholder
440
- }), /* @__PURE__ */ React6.createElement(Select.Portal, null, /* @__PURE__ */ React6.createElement(Select.Content, null, /* @__PURE__ */ React6.createElement(Select.Viewport, null, options?.map(({ value, label: label2 }) => (
750
+ }), /* @__PURE__ */ React7.createElement(Select.Portal, null, /* @__PURE__ */ React7.createElement(Select.Content, null, /* @__PURE__ */ React7.createElement(Select.Viewport, null, options?.map(({ value, label: label2 }) => (
441
751
  // NOTE: Numeric values are converted to and from strings.
442
- /* @__PURE__ */ React6.createElement(Select.Option, {
752
+ /* @__PURE__ */ React7.createElement(Select.Option, {
443
753
  key: String(value),
444
754
  value: String(value)
445
755
  }, label2 ?? String(value))
446
- )))))), inputOnly && /* @__PURE__ */ React6.createElement(Input5.DescriptionAndValidation, null, error));
756
+ )))))), inputOnly && /* @__PURE__ */ React7.createElement(Input5.DescriptionAndValidation, null, error));
447
757
  };
448
-
449
- // packages/ui/react-ui-form/src/components/Form/Form.tsx
450
- import React11, { useEffect as useEffect3, useMemo as useMemo4 } from "react";
451
- import { mx as mx7 } from "@dxos/react-ui-theme";
452
-
453
- // packages/ui/react-ui-form/src/components/Form/FormActions.tsx
454
- import React8 from "react";
455
- import { IconButton as IconButton2, useTranslation as useTranslation3 } from "@dxos/react-ui";
456
- import { mx as mx4 } from "@dxos/react-ui-theme";
457
-
458
- // packages/ui/react-ui-form/src/components/Form/FormContext.tsx
459
- import React7, { createContext, useContext } from "react";
460
- import { raise } from "@dxos/debug";
461
- import { getValue as getValue2 } from "@dxos/echo-schema";
462
- import { createJsonPath as createJsonPath2 } from "@dxos/effect";
463
-
464
- // packages/ui/react-ui-form/src/hooks/useForm.ts
465
- import { useCallback as useCallback2, useEffect as useEffect2, useMemo, useState as useState2 } from "react";
466
- import { getValue, setValue } from "@dxos/echo-schema";
467
- import { AST, createJsonPath, fromEffectValidationPath } from "@dxos/effect";
468
- import { invariant } from "@dxos/invariant";
469
- import { log } from "@dxos/log";
470
- import { validateSchema } from "@dxos/schema";
471
- var __dxlog_file = "/home/runner/work/dxos/dxos/packages/ui/react-ui-form/src/hooks/useForm.ts";
472
- var useForm = ({ schema, initialValues, onValuesChanged, onValidate, onValid, onSave }) => {
473
- invariant(AST.isTypeLiteral(schema.ast), void 0, {
474
- F: __dxlog_file,
475
- L: 91,
476
- S: void 0,
477
- A: [
478
- "AST.isTypeLiteral(schema.ast)",
479
- ""
480
- ]
481
- });
482
- const [values, setValues] = useState2(initialValues);
483
- useEffect2(() => {
484
- setValues(initialValues);
485
- }, [
486
- initialValues
487
- ]);
488
- const [touched, setTouched] = useState2(createKeySet(initialValues, false));
489
- const [changed, setChanged] = useState2(createKeySet(initialValues, false));
490
- const [errors, setErrors] = useState2({});
491
- const [saving, setSaving] = useState2(false);
492
- const validate = useCallback2((values2) => {
493
- let errors2 = validateSchema(schema, values2) ?? [];
494
- if (errors2.length === 0 && onValidate) {
495
- const validatedValues = values2;
496
- errors2 = onValidate(validatedValues) ?? [];
497
- }
498
- setErrors(flatMap(errors2));
499
- const valid = errors2.length === 0;
500
- return valid;
501
- }, [
502
- schema,
503
- onValidate
504
- ]);
505
- const [schemaDirty, setSchemaDirty] = useState2(false);
506
- useEffect2(() => setSchemaDirty(true), [
507
- schema
508
- ]);
509
- useEffect2(() => {
510
- if (schemaDirty) {
511
- validate(values);
512
- setSchemaDirty(false);
513
- }
514
- }, [
515
- values,
516
- schemaDirty
517
- ]);
518
- const canSave = useMemo(() => !saving && // Check if any error paths that are touched have errors
519
- !Object.entries(touched).some(([path, isTouched]) => isTouched && Object.keys(errors).some((errorPath) => errorPath === path || errorPath.startsWith(`${path}.`) || errorPath.startsWith(`${path}[`))), [
520
- touched,
521
- errors,
522
- saving
523
- ]);
524
- const handleSave = useCallback2(async () => {
525
- if (validate(values)) {
526
- setSaving(true);
527
- try {
528
- await onSave?.(values, {
529
- changed
530
- });
531
- } finally {
532
- setSaving(false);
533
- }
758
+ var MarkdownInput = ({ type, label, inputOnly, disabled, placeholder, getStatus, getValue: getValue3, onValueChange, onBlur }) => {
759
+ const { status, error } = getStatus();
760
+ const textareaRef = useRef2(null);
761
+ const adjustHeight = useCallback4(() => {
762
+ const textarea = textareaRef.current;
763
+ if (textarea) {
764
+ textarea.style.blockSize = "auto";
765
+ textarea.style.blockSize = `${textarea.scrollHeight + 2}px`;
534
766
  }
767
+ }, []);
768
+ useEffect5(() => {
769
+ adjustHeight();
535
770
  }, [
536
- values,
537
- validate,
538
- onSave,
539
- changed
540
- ]);
541
- const getStatus = useCallback2((path) => {
542
- const jsonPath = Array.isArray(path) ? createJsonPath(path) : path;
543
- const matchingError = Object.entries(errors).find(([errorPath]) => errorPath === jsonPath || errorPath.startsWith(`${jsonPath}.`) || errorPath.startsWith(`${jsonPath}[`));
544
- return {
545
- status: matchingError ? "error" : void 0,
546
- error: matchingError ? matchingError[1] : void 0
547
- };
548
- }, [
549
- errors
771
+ adjustHeight
550
772
  ]);
551
- const getFormValue = (path) => {
552
- return getValue(values, createJsonPath(path));
553
- };
554
- const onValueChange = (path, type, value) => {
555
- const jsonPath = createJsonPath(path);
556
- let parsedValue = value;
557
- try {
558
- if (type === "number") {
559
- parsedValue = parseFloat(value) || 0;
560
- }
561
- } catch (err) {
562
- log.catch(err, void 0, {
563
- F: __dxlog_file,
564
- L: 193,
565
- S: void 0,
566
- C: (f, a) => f(...a)
567
- });
568
- parsedValue = void 0;
569
- }
570
- const newValues = {
571
- ...setValue(values, jsonPath, parsedValue)
572
- };
573
- setValues(newValues);
574
- setChanged((prev) => ({
575
- ...prev,
576
- [jsonPath]: true
577
- }));
578
- onValuesChanged?.(newValues);
579
- const isValid = validate(newValues);
580
- if (isValid && onValid) {
581
- onValid(newValues, {
582
- changed
583
- });
584
- }
585
- };
586
- const onTouched = useCallback2((path) => {
587
- const jsonPath = createJsonPath(path);
588
- setTouched((touched2) => ({
589
- ...touched2,
590
- [jsonPath]: true
591
- }));
592
- validate(values);
773
+ useEffect5(() => {
774
+ adjustHeight();
593
775
  }, [
594
- validate,
595
- values
776
+ getValue3(),
777
+ adjustHeight
596
778
  ]);
597
- return {
598
- // State.
599
- values,
600
- errors,
601
- touched,
602
- changed,
603
- canSave,
604
- handleSave,
605
- // Field utils.
606
- getStatus,
607
- getValue: getFormValue,
608
- onValueChange,
609
- onTouched
610
- };
611
- };
612
- var createKeySet = (obj, value) => {
613
- invariant(obj, void 0, {
614
- F: __dxlog_file,
615
- L: 235,
616
- S: void 0,
617
- A: [
618
- "obj",
619
- ""
620
- ]
621
- });
622
- return Object.keys(obj).reduce((acc, key) => ({
623
- ...acc,
624
- [key]: value
625
- }), {});
626
- };
627
- var flatMap = (errors) => {
628
- return errors.reduce((result, { path, message }) => {
629
- const jsonPath = fromEffectValidationPath(path);
630
- if (!(jsonPath in result)) {
631
- result[jsonPath] = message;
632
- }
633
- return result;
634
- }, {});
779
+ return /* @__PURE__ */ React7.createElement(Input5.Root, {
780
+ validationValence: status
781
+ }, !inputOnly && /* @__PURE__ */ React7.createElement(InputHeader, {
782
+ error
783
+ }, /* @__PURE__ */ React7.createElement(Input5.Label, null, label)), /* @__PURE__ */ React7.createElement(Input5.TextArea, {
784
+ ref: textareaRef,
785
+ disabled,
786
+ placeholder,
787
+ value: getValue3() ?? "",
788
+ classNames: "min-bs-auto max-h-40 overflow-auto",
789
+ onChange: (event) => onValueChange(type, event.target.value),
790
+ onBlur,
791
+ style: {
792
+ resize: "none"
793
+ },
794
+ spellCheck: false
795
+ }), inputOnly && /* @__PURE__ */ React7.createElement(Input5.Validation, null, error));
635
796
  };
636
797
 
637
- // packages/ui/react-ui-form/src/components/Form/FormContext.tsx
638
- var FormContext = /* @__PURE__ */ createContext(void 0);
639
- var useFormContext = () => {
640
- return useContext(FormContext) ?? raise(new Error("Missing FormContext"));
641
- };
642
- var useFormValues = (path = []) => {
643
- const { values: formValues } = useFormContext();
644
- const jsonPath = createJsonPath2(path);
645
- return getValue2(formValues, jsonPath);
646
- };
647
- var useInputProps = (path = []) => {
648
- const { getStatus, getValue: getFormValue, onValueChange, onTouched } = useFormContext();
649
- return {
650
- getStatus: () => getStatus(path),
651
- getValue: () => getFormValue(path),
652
- onValueChange: (type, value) => onValueChange(path, type, value),
653
- onBlur: () => onTouched(path)
654
- };
655
- };
656
- var FormProvider = ({ children, ...formOptions }) => {
657
- const formHandler = useForm(formOptions);
658
- return /* @__PURE__ */ React7.createElement(FormContext.Provider, {
659
- value: formHandler
660
- }, children);
661
- };
798
+ // packages/ui/react-ui-form/src/components/Form/Form.tsx
799
+ import React11, { useEffect as useEffect6, useMemo as useMemo6, useRef as useRef3 } from "react";
800
+ import { mx as mx7 } from "@dxos/react-ui-theme";
662
801
 
663
802
  // packages/ui/react-ui-form/src/components/Form/FormActions.tsx
803
+ import React8 from "react";
804
+ import { IconButton as IconButton2, useTranslation as useTranslation3 } from "@dxos/react-ui";
805
+ import { mx as mx4 } from "@dxos/react-ui-theme";
664
806
  var FormActions = ({ onCancel, readonly }) => {
665
807
  const { t } = useTranslation3(translationKey);
666
808
  const { canSave, handleSave } = useFormContext();
667
809
  return /* @__PURE__ */ React8.createElement("div", {
668
810
  role: "none",
669
- className: "flex justify-center"
811
+ className: "mt-2 flex justify-center"
670
812
  }, /* @__PURE__ */ React8.createElement("div", {
671
813
  role: "none",
672
814
  className: mx4(onCancel && !readonly && "grid grid-cols-2 gap-2")
@@ -688,7 +830,7 @@ var FormActions = ({ onCancel, readonly }) => {
688
830
  // packages/ui/react-ui-form/src/components/Form/FormContent.tsx
689
831
  import { pipe as pipe2 } from "effect";
690
832
  import { capitalize as capitalize2 } from "effect/String";
691
- import React10, { useMemo as useMemo3 } from "react";
833
+ import React10, { useMemo as useMemo5 } from "react";
692
834
  import { AST as AST3, S } from "@dxos/echo-schema";
693
835
  import { createJsonPath as createJsonPath3, findNode as findNode2, getDiscriminatedType as getDiscriminatedType2, isDiscriminatedUnion as isDiscriminatedUnion2 } from "@dxos/effect";
694
836
  import { mx as mx6 } from "@dxos/react-ui-theme";
@@ -698,7 +840,7 @@ import { isNotFalsy } from "@dxos/util";
698
840
  // packages/ui/react-ui-form/src/components/Form/ArrayField.tsx
699
841
  import { pipe } from "effect";
700
842
  import { capitalize } from "effect/String";
701
- import React9, { useCallback as useCallback3, useMemo as useMemo2 } from "react";
843
+ import React9, { useCallback as useCallback5, useMemo as useMemo4 } from "react";
702
844
  import { AST as AST2 } from "@dxos/echo-schema";
703
845
  import { findNode, getDiscriminatedType, isDiscriminatedUnion, SimpleType } from "@dxos/effect";
704
846
  import { invariant as invariant2 } from "@dxos/invariant";
@@ -734,7 +876,7 @@ var ArrayField = ({ property, readonly, path, inputProps, Custom, lookupComponen
734
876
  prop.defaultValue
735
877
  ]));
736
878
  };
737
- const newValue = useMemo2(() => {
879
+ const newValue = useMemo4(() => {
738
880
  if (type === "object" && elementType) {
739
881
  return getDefaultObjectValue(elementType);
740
882
  } else {
@@ -744,7 +886,7 @@ var ArrayField = ({ property, readonly, path, inputProps, Custom, lookupComponen
744
886
  type,
745
887
  elementType
746
888
  ]);
747
- const handleAdd = useCallback3(() => {
889
+ const handleAdd = useCallback5(() => {
748
890
  inputProps.onValueChange(type, [
749
891
  ...values,
750
892
  newValue
@@ -756,7 +898,7 @@ var ArrayField = ({ property, readonly, path, inputProps, Custom, lookupComponen
756
898
  newValue,
757
899
  values
758
900
  ]);
759
- const handleRemove = useCallback3((index) => {
901
+ const handleRemove = useCallback5((index) => {
760
902
  const newValues = values.filter((_, i) => i !== index);
761
903
  inputProps.onValueChange(type, newValues);
762
904
  }, [
@@ -814,8 +956,10 @@ var ArrayField = ({ property, readonly, path, inputProps, Custom, lookupComponen
814
956
  import { FormatEnum } from "@dxos/echo-schema";
815
957
  var getInputComponent = (type, format) => {
816
958
  switch (format) {
817
- case FormatEnum.LatLng:
959
+ case FormatEnum.GeoPoint:
818
960
  return GeoPointInput;
961
+ case FormatEnum.Markdown:
962
+ return MarkdownInput;
819
963
  }
820
964
  switch (type) {
821
965
  case "string":
@@ -831,11 +975,11 @@ var getInputComponent = (type, format) => {
831
975
  var FormField = ({ property, path, readonly, inline, lookupComponent, Custom }) => {
832
976
  const inputProps = useInputProps(path);
833
977
  const { ast, name, type, format, title, description, options, examples, array } = property;
834
- const label = useMemo3(() => title ?? pipe2(name, capitalize2), [
978
+ const label = useMemo5(() => title ?? pipe2(name, capitalize2), [
835
979
  title,
836
980
  name
837
981
  ]);
838
- const placeholder = useMemo3(() => examples?.length ? `Example: "${examples[0]}"` : description, [
982
+ const placeholder = useMemo5(() => examples?.length ? `Example: "${examples[0]}"` : description, [
839
983
  examples,
840
984
  description
841
985
  ]);
@@ -859,20 +1003,15 @@ var FormField = ({ property, path, readonly, inline, lookupComponent, Custom })
859
1003
  const jsonPath = createJsonPath3(path ?? []);
860
1004
  const CustomComponent = Custom?.[jsonPath];
861
1005
  if (CustomComponent) {
862
- return (
863
- // TODO(ZaymonFC): We should try to remove this div wrapper.
864
- /* @__PURE__ */ React10.createElement("div", {
865
- role: "none"
866
- }, /* @__PURE__ */ React10.createElement(CustomComponent, {
867
- type,
868
- format,
869
- label,
870
- inputOnly: inline,
871
- placeholder,
872
- disabled: readonly,
873
- ...inputProps
874
- }))
875
- );
1006
+ return /* @__PURE__ */ React10.createElement(CustomComponent, {
1007
+ type,
1008
+ format,
1009
+ label,
1010
+ inputOnly: inline,
1011
+ placeholder,
1012
+ disabled: readonly,
1013
+ ...inputProps
1014
+ });
876
1015
  }
877
1016
  if (array) {
878
1017
  return /* @__PURE__ */ React10.createElement(ArrayField, {
@@ -932,7 +1071,7 @@ var FormField = ({ property, path, readonly, inline, lookupComponent, Custom })
932
1071
  };
933
1072
  var FormFields = ({ schema, path, filter, sort, readonly, lookupComponent, Custom }) => {
934
1073
  const values = useFormValues(path);
935
- const properties = useMemo3(() => {
1074
+ const properties = useMemo5(() => {
936
1075
  const props = getSchemaProperties2(schema.ast, values);
937
1076
  const filtered = filter ? filter(props) : props;
938
1077
  return sort ? filtered.sort((a, b) => sort.indexOf(a.name) - sort.indexOf(b.name)) : filtered;
@@ -944,7 +1083,7 @@ var FormFields = ({ schema, path, filter, sort, readonly, lookupComponent, Custo
944
1083
  ]);
945
1084
  return /* @__PURE__ */ React10.createElement("div", {
946
1085
  role: "form",
947
- className: mx6("flex flex-col w-full gap-2 py-2")
1086
+ className: mx6("flex flex-col w-full gap-2")
948
1087
  }, properties.map((property) => {
949
1088
  return /* @__PURE__ */ React10.createElement(FormField, {
950
1089
  key: property.name,
@@ -962,13 +1101,14 @@ var FormFields = ({ schema, path, filter, sort, readonly, lookupComponent, Custo
962
1101
 
963
1102
  // packages/ui/react-ui-form/src/components/Form/Form.tsx
964
1103
  var Form = ({ classNames, schema, values: initialValues, path = [], autoFocus, readonly, filter, sort, autoSave, testId, onValuesChanged, onValidate, onSave, onCancel, lookupComponent, Custom }) => {
965
- const onValid = useMemo4(() => autoSave ? onSave : void 0, [
1104
+ const formRef = useRef3(null);
1105
+ const onValid = useMemo6(() => autoSave ? onSave : void 0, [
966
1106
  autoSave,
967
1107
  onSave
968
1108
  ]);
969
- useEffect3(() => {
970
- if (autoFocus) {
971
- const input = document.querySelector("input");
1109
+ useEffect6(() => {
1110
+ if (autoFocus && formRef.current) {
1111
+ const input = formRef.current.querySelector("input");
972
1112
  if (input) {
973
1113
  input.focus();
974
1114
  }
@@ -977,13 +1117,16 @@ var Form = ({ classNames, schema, values: initialValues, path = [], autoFocus, r
977
1117
  autoFocus
978
1118
  ]);
979
1119
  return /* @__PURE__ */ React11.createElement(FormProvider, {
1120
+ formRef,
980
1121
  schema,
1122
+ autoSave,
981
1123
  initialValues,
982
1124
  onValuesChanged,
983
1125
  onValidate,
984
1126
  onValid,
985
1127
  onSave
986
1128
  }, /* @__PURE__ */ React11.createElement("div", {
1129
+ ref: formRef,
987
1130
  role: "none",
988
1131
  className: mx7("p-2", classNames),
989
1132
  "data-testid": testId
@@ -1005,13 +1148,13 @@ var Form = ({ classNames, schema, values: initialValues, path = [], autoFocus, r
1005
1148
  var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-form/src/components/FieldEditor/FieldEditor.tsx";
1006
1149
  var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
1007
1150
  const { t } = useTranslation5(translationKey);
1008
- const [props, setProps] = useState3(projection.getFieldProjection(field.id).props);
1009
- useEffect4(() => setProps(projection.getFieldProjection(field.id).props), [
1151
+ const [props, setProps] = useState4(projection.getFieldProjection(field.id).props);
1152
+ useEffect7(() => setProps(projection.getFieldProjection(field.id).props), [
1010
1153
  field,
1011
1154
  projection
1012
1155
  ]);
1013
- const [schemas, setSchemas] = useState3([]);
1014
- useEffect4(() => {
1156
+ const [schemas, setSchemas] = useState4([]);
1157
+ useEffect7(() => {
1015
1158
  if (!registry) {
1016
1159
  return;
1017
1160
  }
@@ -1029,17 +1172,17 @@ var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
1029
1172
  }, [
1030
1173
  registry
1031
1174
  ]);
1032
- const [referenceSchema, setReferenceSchema] = useState3();
1033
- useEffect4(() => {
1175
+ const [referenceSchema, setReferenceSchema] = useState4();
1176
+ useEffect7(() => {
1034
1177
  setReferenceSchema(schemas.find((schema) => schema.typename === props?.referenceSchema));
1035
1178
  }, [
1036
1179
  schemas,
1037
1180
  props?.referenceSchema
1038
1181
  ]);
1039
- const [{ fieldSchema }, setFieldSchema] = useState3({
1182
+ const [{ fieldSchema }, setFieldSchema] = useState4({
1040
1183
  fieldSchema: getFormatSchema(props?.format)
1041
1184
  });
1042
- const handleValuesChanged = useCallback4((_props) => {
1185
+ const handleValuesChanged = useCallback6((_props) => {
1043
1186
  setFieldSchema((prev) => {
1044
1187
  const fieldSchema2 = getFormatSchema(_props.format);
1045
1188
  if (prev.fieldSchema === fieldSchema2) {
@@ -1074,7 +1217,7 @@ var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
1074
1217
  props.format,
1075
1218
  props.referenceSchema
1076
1219
  ]);
1077
- const handleValidate = useCallback4(({ property }) => {
1220
+ const handleValidate = useCallback6(({ property }) => {
1078
1221
  if (property && view.fields.find((f) => f.path === property && f.path !== field.path)) {
1079
1222
  return [
1080
1223
  {
@@ -1087,7 +1230,7 @@ var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
1087
1230
  view.fields,
1088
1231
  field
1089
1232
  ]);
1090
- const handleSave = useCallback4((props2) => {
1233
+ const handleSave = useCallback6((props2) => {
1091
1234
  projection.setFieldProjection({
1092
1235
  field,
1093
1236
  props: props2
@@ -1098,13 +1241,13 @@ var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
1098
1241
  field,
1099
1242
  onSave
1100
1243
  ]);
1101
- const handleCancel = useCallback4(() => {
1244
+ const handleCancel = useCallback6(() => {
1102
1245
  requestAnimationFrame(() => onCancel?.());
1103
1246
  onSave();
1104
1247
  }, [
1105
1248
  onSave
1106
1249
  ]);
1107
- const Custom = useMemo5(() => ({
1250
+ const Custom = useMemo7(() => ({
1108
1251
  ["format"]: (props2) => /* @__PURE__ */ React12.createElement(SelectInput, {
1109
1252
  ...props2,
1110
1253
  options: FormatEnums.filter((value) => value !== FormatEnum2.None).map((value) => ({
@@ -1130,7 +1273,7 @@ var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
1130
1273
  schemas,
1131
1274
  referenceSchema
1132
1275
  ]);
1133
- const propIsNotType = useCallback4((props2) => props2.filter((p) => p.name !== "type"), []);
1276
+ const propIsNotType = useCallback6((props2) => props2.filter((p) => p.name !== "type"), []);
1134
1277
  if (!fieldSchema) {
1135
1278
  log2.warn("invalid format", {
1136
1279
  props
@@ -1161,7 +1304,7 @@ var FieldEditor = ({ view, projection, field, registry, onSave, onCancel }) => {
1161
1304
  };
1162
1305
 
1163
1306
  // packages/ui/react-ui-form/src/components/ViewEditor/ViewEditor.tsx
1164
- import React13, { useCallback as useCallback5, useMemo as useMemo6, useState as useState4 } from "react";
1307
+ import React13, { useCallback as useCallback7, useMemo as useMemo8, useState as useState5 } from "react";
1165
1308
  import { AST as AST4, Format, S as S2 } from "@dxos/echo-schema";
1166
1309
  import { IconButton as IconButton4, useTranslation as useTranslation6 } from "@dxos/react-ui";
1167
1310
  import { List as List2 } from "@dxos/react-ui-list";
@@ -1172,18 +1315,18 @@ var ViewMetaSchema = S2.Struct({
1172
1315
  name: S2.String.annotations({
1173
1316
  [AST4.TitleAnnotationId]: "View"
1174
1317
  }),
1175
- typename: Format.DXN.annotations({
1318
+ typename: Format.URL.annotations({
1176
1319
  [AST4.TitleAnnotationId]: "Typename"
1177
1320
  })
1178
1321
  }).pipe(S2.mutable);
1179
1322
  var ViewEditor = ({ classNames, schema, view, registry, readonly, showHeading = false, onTypenameChanged, onDelete }) => {
1180
1323
  const { t } = useTranslation6(translationKey);
1181
- const projection = useMemo6(() => new ViewProjection(schema, view), [
1324
+ const projection = useMemo8(() => new ViewProjection(schema, view), [
1182
1325
  schema,
1183
1326
  view
1184
1327
  ]);
1185
- const [field, setField] = useState4();
1186
- const viewValues = useMemo6(() => {
1328
+ const [field, setField] = useState5();
1329
+ const viewValues = useMemo8(() => {
1187
1330
  return {
1188
1331
  name: view.name,
1189
1332
  // TODO(burdon): Need to warn user of possible consequences of editing.
@@ -1193,7 +1336,7 @@ var ViewEditor = ({ classNames, schema, view, registry, readonly, showHeading =
1193
1336
  }, [
1194
1337
  view
1195
1338
  ]);
1196
- const handleViewUpdate = useCallback5(({ name, typename }) => {
1339
+ const handleViewUpdate = useCallback7(({ name, typename }) => {
1197
1340
  requestAnimationFrame(() => {
1198
1341
  if (view.name !== name) {
1199
1342
  view.name = name;
@@ -1207,16 +1350,16 @@ var ViewEditor = ({ classNames, schema, view, registry, readonly, showHeading =
1207
1350
  schema,
1208
1351
  onTypenameChanged
1209
1352
  ]);
1210
- const handleSelect = useCallback5((field2) => {
1353
+ const handleSelect = useCallback7((field2) => {
1211
1354
  setField((f) => f === field2 ? void 0 : field2);
1212
1355
  }, []);
1213
- const handleAdd = useCallback5(() => {
1356
+ const handleAdd = useCallback7(() => {
1214
1357
  const field2 = projection.createFieldProjection();
1215
1358
  setField(field2);
1216
1359
  }, [
1217
1360
  view
1218
1361
  ]);
1219
- const handleMove = useCallback5((fromIndex, toIndex) => {
1362
+ const handleMove = useCallback7((fromIndex, toIndex) => {
1220
1363
  const fields = [
1221
1364
  ...view.fields
1222
1365
  ];
@@ -1226,12 +1369,11 @@ var ViewEditor = ({ classNames, schema, view, registry, readonly, showHeading =
1226
1369
  }, [
1227
1370
  view.fields
1228
1371
  ]);
1229
- const handleClose = useCallback5(() => setField(void 0), []);
1372
+ const handleClose = useCallback7(() => setField(void 0), []);
1230
1373
  return /* @__PURE__ */ React13.createElement("div", {
1231
1374
  role: "none",
1232
1375
  className: mx8("flex flex-col w-full divide-y divide-separator", classNames)
1233
1376
  }, /* @__PURE__ */ React13.createElement(Form, {
1234
- autoFocus: true,
1235
1377
  autoSave: true,
1236
1378
  schema: ViewMetaSchema,
1237
1379
  values: viewValues,
@@ -1282,7 +1424,7 @@ var ViewEditor = ({ classNames, schema, view, registry, readonly, showHeading =
1282
1424
  };
1283
1425
 
1284
1426
  // packages/ui/react-ui-form/src/util/field.ts
1285
- import { FormatEnum as FormatEnum3, TypeEnum } from "@dxos/echo-schema";
1427
+ import { FormatEnum as FormatEnum3, GeoLocation as GeoLocation2, TypeEnum } from "@dxos/echo-schema";
1286
1428
  var parseValue = ({ type, format, value }) => {
1287
1429
  if (value === void 0 || value === null || value === "") {
1288
1430
  return void 0;
@@ -1336,6 +1478,26 @@ var parseValue = ({ type, format, value }) => {
1336
1478
  const date = new Date(value);
1337
1479
  return isNaN(date.getTime()) ? null : date;
1338
1480
  }
1481
+ case FormatEnum3.GeoPoint: {
1482
+ if (typeof value === "string") {
1483
+ const cleaned = value.replace(/[^0-9.,-]+/g, "");
1484
+ const parts = cleaned.split(",");
1485
+ if (parts.length === 2) {
1486
+ const lat = parseFloat(parts[0]);
1487
+ const long = parseFloat(parts[1]);
1488
+ if (!isNaN(lat) && !isNaN(long)) {
1489
+ return GeoLocation2.toGeoPoint({
1490
+ latitude: lat,
1491
+ longitude: long
1492
+ });
1493
+ }
1494
+ }
1495
+ }
1496
+ return [
1497
+ 0,
1498
+ 0
1499
+ ];
1500
+ }
1339
1501
  default: {
1340
1502
  return value;
1341
1503
  }
@@ -1394,7 +1556,7 @@ var pathNotUniqueError = (path) => ({
1394
1556
  });
1395
1557
 
1396
1558
  // packages/ui/react-ui-form/src/util/formatting.ts
1397
- import { FormatEnum as FormatEnum4, TypeEnum as TypeEnum2 } from "@dxos/echo-schema";
1559
+ import { FormatEnum as FormatEnum4, GeoLocation as GeoLocation3, TypeEnum as TypeEnum2 } from "@dxos/echo-schema";
1398
1560
  var formatForDisplay = ({ type, format, value, locale = void 0 }) => {
1399
1561
  const formatScalar = (type2) => {
1400
1562
  switch (type2) {
@@ -1447,6 +1609,16 @@ var formatForDisplay = ({ type, format, value, locale = void 0 }) => {
1447
1609
  return date.toLocaleTimeString(locale);
1448
1610
  }
1449
1611
  }
1612
+ case FormatEnum4.GeoPoint: {
1613
+ if (value === null || value === void 0) {
1614
+ return "";
1615
+ }
1616
+ if (Array.isArray(value) && value.length >= 2 && value.every(Number.isFinite)) {
1617
+ const { latitude, longitude } = GeoLocation3.fromGeoPoint(value);
1618
+ return `${latitude},${longitude}`;
1619
+ }
1620
+ return String(value);
1621
+ }
1450
1622
  default: {
1451
1623
  if (value === null || value === "undefined") {
1452
1624
  return "";
@@ -1495,6 +1667,16 @@ var formatForEditing = ({ type, format, value, locale = void 0 }) => {
1495
1667
  const date = new Date(value);
1496
1668
  return date.toISOString().split("T")[1].split(".")[0];
1497
1669
  }
1670
+ case FormatEnum4.GeoPoint: {
1671
+ if (value === null || value === void 0) {
1672
+ return "";
1673
+ }
1674
+ if (Array.isArray(value) && value.length >= 2 && value.every(Number.isFinite)) {
1675
+ const { latitude, longitude } = GeoLocation3.fromGeoPoint(value);
1676
+ return `${latitude},${longitude}`;
1677
+ }
1678
+ return String(value);
1679
+ }
1498
1680
  default: {
1499
1681
  return String(value);
1500
1682
  }
@@ -1508,6 +1690,7 @@ export {
1508
1690
  Form,
1509
1691
  GeoPointInput,
1510
1692
  InputHeader,
1693
+ MarkdownInput,
1511
1694
  NumberInput,
1512
1695
  SelectInput,
1513
1696
  SelectOptionInput,
@@ -1521,6 +1704,7 @@ export {
1521
1704
  parseValue,
1522
1705
  pathNotUniqueError,
1523
1706
  translations_default as translations,
1524
- useForm
1707
+ useForm,
1708
+ useFormValues
1525
1709
  };
1526
1710
  //# sourceMappingURL=index.mjs.map