@dxos/react-ui-form 0.7.5-labs.f5080a1 → 0.7.5-labs.ff2ff30

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.
@@ -48,7 +48,8 @@ __export(node_exports, {
48
48
  parseValue: () => parseValue,
49
49
  pathNotUniqueError: () => pathNotUniqueError,
50
50
  translations: () => translations_default,
51
- useForm: () => useForm
51
+ useForm: () => useForm,
52
+ useFormValues: () => useFormValues
52
53
  });
53
54
  module.exports = __toCommonJS(node_exports);
54
55
  var import_react = __toESM(require("react"));
@@ -60,38 +61,38 @@ var import_log = require("@dxos/log");
60
61
  var import_react_ui2 = require("@dxos/react-ui");
61
62
  var import_schema = require("@dxos/schema");
62
63
  var import_react3 = __toESM(require("react"));
64
+ var import_debug = require("@dxos/debug");
65
+ var import_echo_schema2 = require("@dxos/echo-schema");
66
+ var import_effect = require("@dxos/effect");
67
+ var import_react4 = require("react");
68
+ var import_echo_schema3 = require("@dxos/echo-schema");
69
+ var import_effect2 = require("@dxos/effect");
70
+ var import_invariant = require("@dxos/invariant");
71
+ var import_log2 = require("@dxos/log");
72
+ var import_schema2 = require("@dxos/schema");
73
+ var import_react5 = __toESM(require("react"));
63
74
  var import_react_ui3 = require("@dxos/react-ui");
64
75
  var import_util = require("@dxos/util");
65
- var import_react4 = __toESM(require("react"));
76
+ var import_react6 = __toESM(require("react"));
66
77
  var import_react_ui4 = require("@dxos/react-ui");
67
78
  var import_react_ui_theme2 = require("@dxos/react-ui-theme");
68
- var import_react5 = __toESM(require("react"));
79
+ var import_react7 = __toESM(require("react"));
69
80
  var import_keys = require("@dxos/keys");
70
81
  var import_react_ui5 = require("@dxos/react-ui");
71
82
  var import_react_ui_list = require("@dxos/react-ui-list");
72
83
  var import_react_ui_pickers = require("@dxos/react-ui-pickers");
73
84
  var import_react_ui_theme3 = require("@dxos/react-ui-theme");
74
- var import_react6 = __toESM(require("react"));
85
+ var import_react8 = __toESM(require("react"));
75
86
  var import_react_ui6 = require("@dxos/react-ui");
76
87
  var import_react_ui_theme4 = require("@dxos/react-ui-theme");
77
88
  var import_util2 = require("@dxos/util");
78
- var import_react7 = __toESM(require("react"));
89
+ var import_react9 = __toESM(require("react"));
79
90
  var import_react_ui7 = require("@dxos/react-ui");
80
- var import_react8 = __toESM(require("react"));
91
+ var import_react10 = __toESM(require("react"));
81
92
  var import_react_ui_theme5 = require("@dxos/react-ui-theme");
82
- var import_react9 = __toESM(require("react"));
93
+ var import_react11 = __toESM(require("react"));
83
94
  var import_react_ui8 = require("@dxos/react-ui");
84
95
  var import_react_ui_theme6 = require("@dxos/react-ui-theme");
85
- var import_react10 = __toESM(require("react"));
86
- var import_debug = require("@dxos/debug");
87
- var import_echo_schema2 = require("@dxos/echo-schema");
88
- var import_effect = require("@dxos/effect");
89
- var import_react11 = require("react");
90
- var import_echo_schema3 = require("@dxos/echo-schema");
91
- var import_effect2 = require("@dxos/effect");
92
- var import_invariant = require("@dxos/invariant");
93
- var import_log2 = require("@dxos/log");
94
- var import_schema2 = require("@dxos/schema");
95
96
  var import_effect3 = require("effect");
96
97
  var import_String = require("effect/String");
97
98
  var import_react12 = __toESM(require("react"));
@@ -211,31 +212,220 @@ var DeprecatedFormInput = ({ label, description, secondary, children }) => {
211
212
  }
212
213
  return primary;
213
214
  };
215
+ var __dxlog_file = "/home/runner/work/dxos/dxos/packages/ui/react-ui-form/src/hooks/useForm.ts";
216
+ var useForm = ({ schema, initialValues, onValuesChanged, onValidate, onValid, onSave }) => {
217
+ (0, import_invariant.invariant)(import_effect2.AST.isTypeLiteral(schema.ast), void 0, {
218
+ F: __dxlog_file,
219
+ L: 91,
220
+ S: void 0,
221
+ A: [
222
+ "AST.isTypeLiteral(schema.ast)",
223
+ ""
224
+ ]
225
+ });
226
+ const [values, setValues] = (0, import_react4.useState)(initialValues);
227
+ (0, import_react4.useEffect)(() => {
228
+ setValues(initialValues);
229
+ }, [
230
+ initialValues
231
+ ]);
232
+ const [touched, setTouched] = (0, import_react4.useState)(createKeySet(initialValues, false));
233
+ const [changed, setChanged] = (0, import_react4.useState)(createKeySet(initialValues, false));
234
+ const [errors, setErrors] = (0, import_react4.useState)({});
235
+ const [saving, setSaving] = (0, import_react4.useState)(false);
236
+ const validate = (0, import_react4.useCallback)((values2) => {
237
+ let errors2 = (0, import_schema2.validateSchema)(schema, values2) ?? [];
238
+ if (errors2.length === 0 && onValidate) {
239
+ const validatedValues = values2;
240
+ errors2 = onValidate(validatedValues) ?? [];
241
+ }
242
+ setErrors(flatMap(errors2));
243
+ const valid = errors2.length === 0;
244
+ return valid;
245
+ }, [
246
+ schema,
247
+ onValidate
248
+ ]);
249
+ const [schemaDirty, setSchemaDirty] = (0, import_react4.useState)(false);
250
+ (0, import_react4.useEffect)(() => setSchemaDirty(true), [
251
+ schema
252
+ ]);
253
+ (0, import_react4.useEffect)(() => {
254
+ if (schemaDirty) {
255
+ validate(values);
256
+ setSchemaDirty(false);
257
+ }
258
+ }, [
259
+ values,
260
+ schemaDirty
261
+ ]);
262
+ const canSave = (0, import_react4.useMemo)(() => !saving && // Check if any error paths that are touched have errors
263
+ !Object.entries(touched).some(([path, isTouched]) => isTouched && Object.keys(errors).some((errorPath) => errorPath === path || errorPath.startsWith(`${path}.`) || errorPath.startsWith(`${path}[`))), [
264
+ touched,
265
+ errors,
266
+ saving
267
+ ]);
268
+ const handleSave = (0, import_react4.useCallback)(async () => {
269
+ if (validate(values)) {
270
+ setSaving(true);
271
+ try {
272
+ await onSave?.(values, {
273
+ changed
274
+ });
275
+ } finally {
276
+ setSaving(false);
277
+ }
278
+ }
279
+ }, [
280
+ values,
281
+ validate,
282
+ onSave,
283
+ changed
284
+ ]);
285
+ const getStatus = (0, import_react4.useCallback)((path) => {
286
+ const jsonPath = Array.isArray(path) ? (0, import_effect2.createJsonPath)(path) : path;
287
+ const matchingError = Object.entries(errors).find(([errorPath]) => errorPath === jsonPath || errorPath.startsWith(`${jsonPath}.`) || errorPath.startsWith(`${jsonPath}[`));
288
+ return {
289
+ status: matchingError ? "error" : void 0,
290
+ error: matchingError ? matchingError[1] : void 0
291
+ };
292
+ }, [
293
+ errors
294
+ ]);
295
+ const getFormValue = (path) => {
296
+ return (0, import_echo_schema3.getValue)(values, (0, import_effect2.createJsonPath)(path));
297
+ };
298
+ const onValueChange = (path, type, value) => {
299
+ const jsonPath = (0, import_effect2.createJsonPath)(path);
300
+ let parsedValue = value;
301
+ try {
302
+ if (type === "number") {
303
+ parsedValue = parseFloat(value) || 0;
304
+ }
305
+ } catch (err) {
306
+ import_log2.log.catch(err, void 0, {
307
+ F: __dxlog_file,
308
+ L: 193,
309
+ S: void 0,
310
+ C: (f, a) => f(...a)
311
+ });
312
+ parsedValue = void 0;
313
+ }
314
+ const newValues = {
315
+ ...(0, import_echo_schema3.setValue)(values, jsonPath, parsedValue)
316
+ };
317
+ setValues(newValues);
318
+ setChanged((prev) => ({
319
+ ...prev,
320
+ [jsonPath]: true
321
+ }));
322
+ onValuesChanged?.(newValues);
323
+ const isValid = validate(newValues);
324
+ if (isValid && onValid) {
325
+ onValid(newValues, {
326
+ changed
327
+ });
328
+ }
329
+ };
330
+ const onTouched = (0, import_react4.useCallback)((path) => {
331
+ const jsonPath = (0, import_effect2.createJsonPath)(path);
332
+ setTouched((touched2) => ({
333
+ ...touched2,
334
+ [jsonPath]: true
335
+ }));
336
+ validate(values);
337
+ }, [
338
+ validate,
339
+ values
340
+ ]);
341
+ return {
342
+ // State.
343
+ values,
344
+ errors,
345
+ touched,
346
+ changed,
347
+ canSave,
348
+ handleSave,
349
+ // Field utils.
350
+ getStatus,
351
+ getValue: getFormValue,
352
+ onValueChange,
353
+ onTouched
354
+ };
355
+ };
356
+ var createKeySet = (obj, value) => {
357
+ (0, import_invariant.invariant)(obj, void 0, {
358
+ F: __dxlog_file,
359
+ L: 235,
360
+ S: void 0,
361
+ A: [
362
+ "obj",
363
+ ""
364
+ ]
365
+ });
366
+ return Object.keys(obj).reduce((acc, key) => ({
367
+ ...acc,
368
+ [key]: value
369
+ }), {});
370
+ };
371
+ var flatMap = (errors) => {
372
+ return errors.reduce((result, { path, message }) => {
373
+ const jsonPath = (0, import_effect2.fromEffectValidationPath)(path);
374
+ if (!(jsonPath in result)) {
375
+ result[jsonPath] = message;
376
+ }
377
+ return result;
378
+ }, {});
379
+ };
380
+ var FormContext = /* @__PURE__ */ (0, import_react3.createContext)(void 0);
381
+ var useFormContext = () => {
382
+ return (0, import_react3.useContext)(FormContext) ?? (0, import_debug.raise)(new Error("Missing FormContext"));
383
+ };
384
+ var useFormValues = (path = []) => {
385
+ const { values: formValues } = useFormContext();
386
+ const jsonPath = (0, import_effect.createJsonPath)(path);
387
+ return (0, import_echo_schema2.getValue)(formValues, jsonPath);
388
+ };
389
+ var useInputProps = (path = []) => {
390
+ const { getStatus, getValue: getFormValue, onValueChange, onTouched } = useFormContext();
391
+ return {
392
+ getStatus: () => getStatus(path),
393
+ getValue: () => getFormValue(path),
394
+ onValueChange: (type, value) => onValueChange(path, type, value),
395
+ onBlur: () => onTouched(path)
396
+ };
397
+ };
398
+ var FormProvider = ({ children, ...formOptions }) => {
399
+ const formHandler = useForm(formOptions);
400
+ return /* @__PURE__ */ import_react3.default.createElement(FormContext.Provider, {
401
+ value: formHandler
402
+ }, children);
403
+ };
214
404
  var InputHeader = ({ children, error }) => {
215
- return /* @__PURE__ */ import_react4.default.createElement("div", {
405
+ return /* @__PURE__ */ import_react6.default.createElement("div", {
216
406
  role: "none",
217
407
  className: "flex justify-between items-center mb-1"
218
- }, children, error && /* @__PURE__ */ import_react4.default.createElement(import_react_ui4.Tooltip.Root, null, /* @__PURE__ */ import_react4.default.createElement(import_react_ui4.Tooltip.Trigger, {
408
+ }, children, error && /* @__PURE__ */ import_react6.default.createElement(import_react_ui4.Tooltip.Root, null, /* @__PURE__ */ import_react6.default.createElement(import_react_ui4.Tooltip.Trigger, {
219
409
  asChild: true
220
- }, /* @__PURE__ */ import_react4.default.createElement(import_react_ui4.Icon, {
410
+ }, /* @__PURE__ */ import_react6.default.createElement(import_react_ui4.Icon, {
221
411
  icon: "ph--warning--regular",
222
412
  size: 4,
223
413
  classNames: import_react_ui_theme2.errorText
224
- })), /* @__PURE__ */ import_react4.default.createElement(import_react_ui4.Tooltip.Content, {
414
+ })), /* @__PURE__ */ import_react6.default.createElement(import_react_ui4.Tooltip.Content, {
225
415
  side: "bottom"
226
- }, /* @__PURE__ */ import_react4.default.createElement(import_react_ui4.Tooltip.Arrow, null), error)));
416
+ }, /* @__PURE__ */ import_react6.default.createElement(import_react_ui4.Tooltip.Arrow, null), error)));
227
417
  };
228
418
  var GeoPointInput = ({ type, label, disabled, getStatus, getValue: getValue3, onValueChange, onBlur }) => {
229
419
  const { t } = (0, import_react_ui3.useTranslation)(translationKey);
230
420
  const { status, error } = getStatus();
231
421
  const [lng = 0, lat = 0] = getValue3() ?? [];
232
- return /* @__PURE__ */ import_react3.default.createElement(import_react_ui3.Input.Root, {
422
+ return /* @__PURE__ */ import_react5.default.createElement(import_react_ui3.Input.Root, {
233
423
  validationValence: status
234
- }, /* @__PURE__ */ import_react3.default.createElement(InputHeader, {
424
+ }, /* @__PURE__ */ import_react5.default.createElement(InputHeader, {
235
425
  error
236
- }, /* @__PURE__ */ import_react3.default.createElement(import_react_ui3.Input.Label, null, label)), /* @__PURE__ */ import_react3.default.createElement("div", {
426
+ }, /* @__PURE__ */ import_react5.default.createElement(import_react_ui3.Input.Label, null, label)), /* @__PURE__ */ import_react5.default.createElement("div", {
237
427
  className: "grid grid-cols-2 gap-2"
238
- }, /* @__PURE__ */ import_react3.default.createElement(import_react_ui3.Input.TextInput, {
428
+ }, /* @__PURE__ */ import_react5.default.createElement(import_react_ui3.Input.TextInput, {
239
429
  type: "number",
240
430
  disabled,
241
431
  placeholder: t("placeholder longitude"),
@@ -245,7 +435,7 @@ var GeoPointInput = ({ type, label, disabled, getStatus, getValue: getValue3, on
245
435
  (0, import_util.safeParseFloat)(event.target.value, 0)
246
436
  ]),
247
437
  onBlur
248
- }), /* @__PURE__ */ import_react3.default.createElement(import_react_ui3.Input.TextInput, {
438
+ }), /* @__PURE__ */ import_react5.default.createElement(import_react_ui3.Input.TextInput, {
249
439
  type: "number",
250
440
  disabled,
251
441
  placeholder: t("placeholder latitude"),
@@ -258,13 +448,13 @@ var GeoPointInput = ({ type, label, disabled, getStatus, getValue: getValue3, on
258
448
  })));
259
449
  };
260
450
  var SelectOptionInput = ({ type, label, disabled, getStatus, getValue: getValue3, onValueChange }) => {
261
- const [selected, setSelectedId] = (0, import_react5.useState)(null);
262
- const [isNewOption, setIsNewOption] = (0, import_react5.useState)(false);
263
- const inputRef = (0, import_react5.useRef)(null);
451
+ const [selected, setSelectedId] = (0, import_react7.useState)(null);
452
+ const [isNewOption, setIsNewOption] = (0, import_react7.useState)(false);
453
+ const inputRef = (0, import_react7.useRef)(null);
264
454
  const { t } = (0, import_react_ui5.useTranslation)(translationKey);
265
455
  const { status, error } = getStatus();
266
456
  const options = getValue3();
267
- (0, import_react5.useEffect)(() => {
457
+ (0, import_react7.useEffect)(() => {
268
458
  if (options === void 0) {
269
459
  onValueChange(type, []);
270
460
  }
@@ -284,7 +474,7 @@ var SelectOptionInput = ({ type, label, disabled, getStatus, getValue: getValue3
284
474
  const availableHues = hueKeys.filter((hue) => !lastThree.has(hue));
285
475
  return availableHues[Math.floor(Math.random() * availableHues.length)] ?? hueKeys[Math.floor(Math.random() * hueKeys.length)];
286
476
  };
287
- const handleAdd = (0, import_react5.useCallback)(() => {
477
+ const handleAdd = (0, import_react7.useCallback)(() => {
288
478
  const newId = import_keys.PublicKey.random().truncate();
289
479
  const newOption = {
290
480
  id: newId,
@@ -302,7 +492,7 @@ var SelectOptionInput = ({ type, label, disabled, getStatus, getValue: getValue3
302
492
  type,
303
493
  onValueChange
304
494
  ]);
305
- const handleDelete = (0, import_react5.useCallback)((id) => {
495
+ const handleDelete = (0, import_react7.useCallback)((id) => {
306
496
  const newOptions = options?.filter((option) => option.id !== id) ?? [];
307
497
  onValueChange(type, newOptions);
308
498
  setSelectedId(null);
@@ -311,7 +501,7 @@ var SelectOptionInput = ({ type, label, disabled, getStatus, getValue: getValue3
311
501
  type,
312
502
  onValueChange
313
503
  ]);
314
- const handleMove = (0, import_react5.useCallback)((from, to) => {
504
+ const handleMove = (0, import_react7.useCallback)((from, to) => {
315
505
  if (!options) {
316
506
  return;
317
507
  }
@@ -326,10 +516,10 @@ var SelectOptionInput = ({ type, label, disabled, getStatus, getValue: getValue3
326
516
  type,
327
517
  onValueChange
328
518
  ]);
329
- const handleClick = (0, import_react5.useCallback)((id) => {
519
+ const handleClick = (0, import_react7.useCallback)((id) => {
330
520
  setSelectedId((current) => current === id ? null : id);
331
521
  }, []);
332
- const handleTitleChange = (0, import_react5.useCallback)((id) => (e) => {
522
+ const handleTitleChange = (0, import_react7.useCallback)((id) => (e) => {
333
523
  const newOptions = options?.map((o) => o.id === id ? {
334
524
  ...o,
335
525
  title: e.target.value
@@ -340,12 +530,12 @@ var SelectOptionInput = ({ type, label, disabled, getStatus, getValue: getValue3
340
530
  type,
341
531
  onValueChange
342
532
  ]);
343
- const handleKeyDown = (0, import_react5.useCallback)((e) => {
533
+ const handleKeyDown = (0, import_react7.useCallback)((e) => {
344
534
  if (e.key === "Enter") {
345
535
  setSelectedId(null);
346
536
  }
347
537
  }, []);
348
- const handleColorChange = (0, import_react5.useCallback)((id) => (hue) => {
538
+ const handleColorChange = (0, import_react7.useCallback)((id) => (hue) => {
349
539
  const newOptions = options?.map((o) => o.id === id ? {
350
540
  ...o,
351
541
  color: hue
@@ -356,7 +546,7 @@ var SelectOptionInput = ({ type, label, disabled, getStatus, getValue: getValue3
356
546
  type,
357
547
  onValueChange
358
548
  ]);
359
- (0, import_react5.useEffect)(() => {
549
+ (0, import_react7.useEffect)(() => {
360
550
  if (selected && isNewOption && inputRef.current) {
361
551
  inputRef.current.focus();
362
552
  setIsNewOption(false);
@@ -365,70 +555,70 @@ var SelectOptionInput = ({ type, label, disabled, getStatus, getValue: getValue3
365
555
  selected,
366
556
  isNewOption
367
557
  ]);
368
- return /* @__PURE__ */ import_react5.default.createElement(import_react_ui5.Input.Root, {
558
+ return /* @__PURE__ */ import_react7.default.createElement(import_react_ui5.Input.Root, {
369
559
  validationValence: status
370
- }, /* @__PURE__ */ import_react5.default.createElement(InputHeader, {
560
+ }, /* @__PURE__ */ import_react7.default.createElement(InputHeader, {
371
561
  error
372
- }, /* @__PURE__ */ import_react5.default.createElement(import_react_ui5.Input.Label, null, label)), /* @__PURE__ */ import_react5.default.createElement("div", {
562
+ }, /* @__PURE__ */ import_react7.default.createElement(import_react_ui5.Input.Label, null, label)), /* @__PURE__ */ import_react7.default.createElement("div", {
373
563
  role: "none"
374
- }, options && /* @__PURE__ */ import_react5.default.createElement(import_react_ui_list.List.Root, {
564
+ }, options && /* @__PURE__ */ import_react7.default.createElement(import_react_ui_list.List.Root, {
375
565
  items: options,
376
566
  isItem: (item) => true,
377
567
  onMove: handleMove
378
- }, ({ items }) => /* @__PURE__ */ import_react5.default.createElement("div", {
568
+ }, ({ items }) => /* @__PURE__ */ import_react7.default.createElement("div", {
379
569
  role: "list",
380
570
  className: "w-full overflow-auto"
381
- }, items?.map((item) => /* @__PURE__ */ import_react5.default.createElement("div", {
571
+ }, items?.map((item) => /* @__PURE__ */ import_react7.default.createElement("div", {
382
572
  key: item.id
383
- }, /* @__PURE__ */ import_react5.default.createElement(import_react_ui_list.List.Item, {
573
+ }, /* @__PURE__ */ import_react7.default.createElement(import_react_ui_list.List.Item, {
384
574
  role: "button",
385
575
  item,
386
576
  classNames: (0, import_react_ui_theme3.mx)("p-1 plb-2", "flex flex-col", "cursor-pointer", "hover:bg-hoverOverlay"),
387
577
  "aria-expanded": selected === item.id
388
- }, /* @__PURE__ */ import_react5.default.createElement("div", {
578
+ }, /* @__PURE__ */ import_react7.default.createElement("div", {
389
579
  className: "flex items-center"
390
- }, /* @__PURE__ */ import_react5.default.createElement(import_react_ui_list.List.ItemDragHandle, null), /* @__PURE__ */ import_react5.default.createElement(import_react_ui_list.List.ItemTitle, {
580
+ }, /* @__PURE__ */ import_react7.default.createElement(import_react_ui_list.List.ItemDragHandle, null), /* @__PURE__ */ import_react7.default.createElement(import_react_ui_list.List.ItemTitle, {
391
581
  onClick: () => handleClick(item.id),
392
582
  classNames: "flex-1"
393
- }, /* @__PURE__ */ import_react5.default.createElement(import_react_ui5.Tag, {
583
+ }, /* @__PURE__ */ import_react7.default.createElement(import_react_ui5.Tag, {
394
584
  palette: item.color
395
- }, item.title || "\u200B")), /* @__PURE__ */ import_react5.default.createElement(import_react_ui5.Icon, {
585
+ }, item.title || "\u200B")), /* @__PURE__ */ import_react7.default.createElement(import_react_ui5.Icon, {
396
586
  icon: selected === item.id ? "ph--caret-down--regular" : "ph--caret-right--regular",
397
587
  onClick: () => handleClick(item.id)
398
- })), selected === item.id && /* @__PURE__ */ import_react5.default.createElement("div", {
588
+ })), selected === item.id && /* @__PURE__ */ import_react7.default.createElement("div", {
399
589
  className: "mis-4 mbs-2 flex flex-col gap-1"
400
- }, /* @__PURE__ */ import_react5.default.createElement(import_react_ui5.Input.Label, {
590
+ }, /* @__PURE__ */ import_react7.default.createElement(import_react_ui5.Input.Label, {
401
591
  classNames: "text-xs"
402
- }, t("select option label")), /* @__PURE__ */ import_react5.default.createElement("div", {
592
+ }, t("select option label")), /* @__PURE__ */ import_react7.default.createElement("div", {
403
593
  className: "flex flex-row items-center gap-1"
404
- }, /* @__PURE__ */ import_react5.default.createElement(import_react_ui5.Input.TextInput, {
594
+ }, /* @__PURE__ */ import_react7.default.createElement(import_react_ui5.Input.TextInput, {
405
595
  placeholder: t("select option label placeholder"),
406
596
  ref: selected === item.id ? inputRef : void 0,
407
597
  value: item.title,
408
598
  onChange: handleTitleChange(item.id),
409
599
  onKeyDown: handleKeyDown,
410
600
  classNames: "flex-1"
411
- }), /* @__PURE__ */ import_react5.default.createElement(import_react_ui5.Toolbar.Root, {
601
+ }), /* @__PURE__ */ import_react7.default.createElement(import_react_ui5.Toolbar.Root, {
412
602
  classNames: "p-0 m-0 !is-auto"
413
- }, /* @__PURE__ */ import_react5.default.createElement(import_react_ui_pickers.HuePickerToolbarButton, {
603
+ }, /* @__PURE__ */ import_react7.default.createElement(import_react_ui_pickers.HuePickerToolbarButton, {
414
604
  hue: item.color,
415
605
  onChangeHue: handleColorChange(item.id)
416
- })), /* @__PURE__ */ import_react5.default.createElement(import_react_ui5.IconButton, {
606
+ })), /* @__PURE__ */ import_react7.default.createElement(import_react_ui5.IconButton, {
417
607
  icon: "ph--trash--fill",
418
608
  iconOnly: true,
419
609
  label: t("select option delete"),
420
610
  onClick: () => handleDelete(item.id)
421
- })))))), /* @__PURE__ */ import_react5.default.createElement("div", {
611
+ })))))), /* @__PURE__ */ import_react7.default.createElement("div", {
422
612
  role: "listitem"
423
- }, /* @__PURE__ */ import_react5.default.createElement("div", {
613
+ }, /* @__PURE__ */ import_react7.default.createElement("div", {
424
614
  role: "button",
425
615
  className: (0, import_react_ui_theme3.mx)("p-1 plb-2", "flex flex-col", "cursor-pointer", "hover:bg-hoverOverlay"),
426
616
  onClick: handleAdd
427
- }, /* @__PURE__ */ import_react5.default.createElement("div", {
617
+ }, /* @__PURE__ */ import_react7.default.createElement("div", {
428
618
  className: "flex items-center gap-1"
429
- }, /* @__PURE__ */ import_react5.default.createElement(import_react_ui5.Icon, {
619
+ }, /* @__PURE__ */ import_react7.default.createElement(import_react_ui5.Icon, {
430
620
  icon: "ph--plus--regular"
431
- }), /* @__PURE__ */ import_react5.default.createElement("span", {
621
+ }), /* @__PURE__ */ import_react7.default.createElement("span", {
432
622
  className: "text-sm"
433
623
  }, t("select option add")))))))));
434
624
  };
@@ -441,13 +631,13 @@ var gridCols = [
441
631
  var TupleInput = ({ binding, type, label, disabled, getStatus, getValue: getValue3, onValueChange, onBlur }) => {
442
632
  const { status, error } = getStatus();
443
633
  const values = getValue3() ?? {};
444
- return /* @__PURE__ */ import_react6.default.createElement(import_react_ui6.Input.Root, {
634
+ return /* @__PURE__ */ import_react8.default.createElement(import_react_ui6.Input.Root, {
445
635
  validationValence: status
446
- }, /* @__PURE__ */ import_react6.default.createElement(InputHeader, {
636
+ }, /* @__PURE__ */ import_react8.default.createElement(InputHeader, {
447
637
  error
448
- }, /* @__PURE__ */ import_react6.default.createElement(import_react_ui6.Input.Label, null, label)), /* @__PURE__ */ import_react6.default.createElement("div", {
638
+ }, /* @__PURE__ */ import_react8.default.createElement(import_react_ui6.Input.Label, null, label)), /* @__PURE__ */ import_react8.default.createElement("div", {
449
639
  className: (0, import_react_ui_theme4.mx)("grid gap-2", gridCols[binding.length - 1])
450
- }, binding.map((prop) => /* @__PURE__ */ import_react6.default.createElement(import_react_ui6.Input.TextInput, {
640
+ }, binding.map((prop) => /* @__PURE__ */ import_react8.default.createElement(import_react_ui6.Input.TextInput, {
451
641
  key: prop,
452
642
  type: "number",
453
643
  disabled,
@@ -461,269 +651,81 @@ var TupleInput = ({ binding, type, label, disabled, getStatus, getValue: getValu
461
651
  };
462
652
  var TextInput = ({ type, label, inputOnly, disabled, placeholder, getStatus, getValue: getValue3, onValueChange, onBlur }) => {
463
653
  const { status, error } = getStatus();
464
- return /* @__PURE__ */ import_react7.default.createElement(import_react_ui7.Input.Root, {
654
+ return /* @__PURE__ */ import_react9.default.createElement(import_react_ui7.Input.Root, {
465
655
  validationValence: status
466
- }, !inputOnly && /* @__PURE__ */ import_react7.default.createElement(InputHeader, {
656
+ }, !inputOnly && /* @__PURE__ */ import_react9.default.createElement(InputHeader, {
467
657
  error
468
- }, /* @__PURE__ */ import_react7.default.createElement(import_react_ui7.Input.Label, null, label)), /* @__PURE__ */ import_react7.default.createElement(import_react_ui7.Input.TextInput, {
658
+ }, /* @__PURE__ */ import_react9.default.createElement(import_react_ui7.Input.Label, null, label)), /* @__PURE__ */ import_react9.default.createElement(import_react_ui7.Input.TextInput, {
469
659
  disabled,
470
660
  placeholder,
471
661
  value: getValue3() ?? "",
472
662
  onChange: (event) => onValueChange(type, event.target.value),
473
663
  onBlur
474
- }), inputOnly && /* @__PURE__ */ import_react7.default.createElement(import_react_ui7.Input.Validation, null, error));
664
+ }), inputOnly && /* @__PURE__ */ import_react9.default.createElement(import_react_ui7.Input.Validation, null, error));
475
665
  };
476
666
  var NumberInput = ({ type, label, inputOnly, disabled, placeholder, getStatus, getValue: getValue3, onValueChange, onBlur }) => {
477
667
  const { status, error } = getStatus();
478
- return /* @__PURE__ */ import_react7.default.createElement(import_react_ui7.Input.Root, {
668
+ return /* @__PURE__ */ import_react9.default.createElement(import_react_ui7.Input.Root, {
479
669
  validationValence: status
480
- }, !inputOnly && /* @__PURE__ */ import_react7.default.createElement(InputHeader, {
670
+ }, !inputOnly && /* @__PURE__ */ import_react9.default.createElement(InputHeader, {
481
671
  error
482
- }, /* @__PURE__ */ import_react7.default.createElement(import_react_ui7.Input.Label, null, label)), /* @__PURE__ */ import_react7.default.createElement(import_react_ui7.Input.TextInput, {
672
+ }, /* @__PURE__ */ import_react9.default.createElement(import_react_ui7.Input.Label, null, label)), /* @__PURE__ */ import_react9.default.createElement(import_react_ui7.Input.TextInput, {
483
673
  type: "number",
484
674
  disabled,
485
675
  placeholder,
486
676
  value: getValue3() ?? 0,
487
677
  onChange: (event) => onValueChange(type, event.target.value),
488
678
  onBlur
489
- }), inputOnly && /* @__PURE__ */ import_react7.default.createElement(import_react_ui7.Input.DescriptionAndValidation, null, error));
679
+ }), inputOnly && /* @__PURE__ */ import_react9.default.createElement(import_react_ui7.Input.DescriptionAndValidation, null, error));
490
680
  };
491
681
  var BooleanInput = ({ type, label, inputOnly, getStatus, getValue: getValue3, onValueChange }) => {
492
682
  const { status, error } = getStatus();
493
- return /* @__PURE__ */ import_react7.default.createElement(import_react_ui7.Input.Root, {
683
+ const checked = Boolean(getValue3());
684
+ return /* @__PURE__ */ import_react9.default.createElement(import_react_ui7.Input.Root, {
494
685
  validationValence: status
495
- }, !inputOnly && /* @__PURE__ */ import_react7.default.createElement(InputHeader, {
686
+ }, !inputOnly && /* @__PURE__ */ import_react9.default.createElement(InputHeader, {
496
687
  error
497
- }, /* @__PURE__ */ import_react7.default.createElement(import_react_ui7.Input.Label, null, label)), /* @__PURE__ */ import_react7.default.createElement(import_react_ui7.Input.Switch, {
498
- checked: getValue3(),
688
+ }, /* @__PURE__ */ import_react9.default.createElement(import_react_ui7.Input.Label, null, label)), /* @__PURE__ */ import_react9.default.createElement(import_react_ui7.Input.Switch, {
689
+ checked,
499
690
  onCheckedChange: (value) => onValueChange(type, value)
500
- }), inputOnly && /* @__PURE__ */ import_react7.default.createElement(import_react_ui7.Input.DescriptionAndValidation, null, error));
691
+ }), inputOnly && /* @__PURE__ */ import_react9.default.createElement(import_react_ui7.Input.DescriptionAndValidation, null, error));
501
692
  };
502
693
  var SelectInput = ({ type, label, inputOnly, disabled, placeholder, options, getStatus, getValue: getValue3, onValueChange }) => {
503
694
  const { status, error } = getStatus();
504
- return /* @__PURE__ */ import_react7.default.createElement(import_react_ui7.Input.Root, {
695
+ return /* @__PURE__ */ import_react9.default.createElement(import_react_ui7.Input.Root, {
505
696
  validationValence: status
506
- }, !inputOnly && /* @__PURE__ */ import_react7.default.createElement(InputHeader, {
697
+ }, !inputOnly && /* @__PURE__ */ import_react9.default.createElement(InputHeader, {
507
698
  error
508
- }, /* @__PURE__ */ import_react7.default.createElement(import_react_ui7.Input.Label, null, label)), /* @__PURE__ */ import_react7.default.createElement(import_react_ui7.Select.Root, {
699
+ }, /* @__PURE__ */ import_react9.default.createElement(import_react_ui7.Input.Label, null, label)), /* @__PURE__ */ import_react9.default.createElement(import_react_ui7.Select.Root, {
509
700
  value: getValue3(),
510
701
  onValueChange: (value) => onValueChange(type, value)
511
- }, /* @__PURE__ */ import_react7.default.createElement(import_react_ui7.Select.TriggerButton, {
702
+ }, /* @__PURE__ */ import_react9.default.createElement(import_react_ui7.Select.TriggerButton, {
512
703
  classNames: "is-full",
513
704
  disabled,
514
705
  placeholder
515
- }), /* @__PURE__ */ import_react7.default.createElement(import_react_ui7.Select.Portal, null, /* @__PURE__ */ import_react7.default.createElement(import_react_ui7.Select.Content, null, /* @__PURE__ */ import_react7.default.createElement(import_react_ui7.Select.Viewport, null, options?.map(({ value, label: label2 }) => (
706
+ }), /* @__PURE__ */ import_react9.default.createElement(import_react_ui7.Select.Portal, null, /* @__PURE__ */ import_react9.default.createElement(import_react_ui7.Select.Content, null, /* @__PURE__ */ import_react9.default.createElement(import_react_ui7.Select.Viewport, null, options?.map(({ value, label: label2 }) => (
516
707
  // NOTE: Numeric values are converted to and from strings.
517
- /* @__PURE__ */ import_react7.default.createElement(import_react_ui7.Select.Option, {
708
+ /* @__PURE__ */ import_react9.default.createElement(import_react_ui7.Select.Option, {
518
709
  key: String(value),
519
710
  value: String(value)
520
711
  }, label2 ?? String(value))
521
- )))))), inputOnly && /* @__PURE__ */ import_react7.default.createElement(import_react_ui7.Input.DescriptionAndValidation, null, error));
522
- };
523
- var __dxlog_file = "/home/runner/work/dxos/dxos/packages/ui/react-ui-form/src/hooks/useForm.ts";
524
- var useForm = ({ schema, initialValues, onValuesChanged, onValidate, onValid, onSave }) => {
525
- (0, import_invariant.invariant)(import_effect2.AST.isTypeLiteral(schema.ast), void 0, {
526
- F: __dxlog_file,
527
- L: 91,
528
- S: void 0,
529
- A: [
530
- "AST.isTypeLiteral(schema.ast)",
531
- ""
532
- ]
533
- });
534
- const [values, setValues] = (0, import_react11.useState)(initialValues);
535
- (0, import_react11.useEffect)(() => {
536
- setValues(initialValues);
537
- }, [
538
- initialValues
539
- ]);
540
- const [touched, setTouched] = (0, import_react11.useState)(createKeySet(initialValues, false));
541
- const [changed, setChanged] = (0, import_react11.useState)(createKeySet(initialValues, false));
542
- const [errors, setErrors] = (0, import_react11.useState)({});
543
- const [saving, setSaving] = (0, import_react11.useState)(false);
544
- const validate = (0, import_react11.useCallback)((values2) => {
545
- let errors2 = (0, import_schema2.validateSchema)(schema, values2) ?? [];
546
- if (errors2.length === 0 && onValidate) {
547
- const validatedValues = values2;
548
- errors2 = onValidate(validatedValues) ?? [];
549
- }
550
- setErrors(flatMap(errors2));
551
- const valid = errors2.length === 0;
552
- return valid;
553
- }, [
554
- schema,
555
- onValidate
556
- ]);
557
- const [schemaDirty, setSchemaDirty] = (0, import_react11.useState)(false);
558
- (0, import_react11.useEffect)(() => setSchemaDirty(true), [
559
- schema
560
- ]);
561
- (0, import_react11.useEffect)(() => {
562
- if (schemaDirty) {
563
- validate(values);
564
- setSchemaDirty(false);
565
- }
566
- }, [
567
- values,
568
- schemaDirty
569
- ]);
570
- const canSave = (0, import_react11.useMemo)(() => !saving && // Check if any error paths that are touched have errors
571
- !Object.entries(touched).some(([path, isTouched]) => isTouched && Object.keys(errors).some((errorPath) => errorPath === path || errorPath.startsWith(`${path}.`) || errorPath.startsWith(`${path}[`))), [
572
- touched,
573
- errors,
574
- saving
575
- ]);
576
- const handleSave = (0, import_react11.useCallback)(async () => {
577
- if (validate(values)) {
578
- setSaving(true);
579
- try {
580
- await onSave?.(values, {
581
- changed
582
- });
583
- } finally {
584
- setSaving(false);
585
- }
586
- }
587
- }, [
588
- values,
589
- validate,
590
- onSave,
591
- changed
592
- ]);
593
- const getStatus = (0, import_react11.useCallback)((path) => {
594
- const jsonPath = Array.isArray(path) ? (0, import_effect2.createJsonPath)(path) : path;
595
- const matchingError = Object.entries(errors).find(([errorPath]) => errorPath === jsonPath || errorPath.startsWith(`${jsonPath}.`) || errorPath.startsWith(`${jsonPath}[`));
596
- return {
597
- status: matchingError ? "error" : void 0,
598
- error: matchingError ? matchingError[1] : void 0
599
- };
600
- }, [
601
- errors
602
- ]);
603
- const getFormValue = (path) => {
604
- return (0, import_echo_schema3.getValue)(values, (0, import_effect2.createJsonPath)(path));
605
- };
606
- const onValueChange = (path, type, value) => {
607
- const jsonPath = (0, import_effect2.createJsonPath)(path);
608
- let parsedValue = value;
609
- try {
610
- if (type === "number") {
611
- parsedValue = parseFloat(value) || 0;
612
- }
613
- } catch (err) {
614
- import_log2.log.catch(err, void 0, {
615
- F: __dxlog_file,
616
- L: 193,
617
- S: void 0,
618
- C: (f, a) => f(...a)
619
- });
620
- parsedValue = void 0;
621
- }
622
- const newValues = {
623
- ...(0, import_echo_schema3.setValue)(values, jsonPath, parsedValue)
624
- };
625
- setValues(newValues);
626
- setChanged((prev) => ({
627
- ...prev,
628
- [jsonPath]: true
629
- }));
630
- onValuesChanged?.(newValues);
631
- const isValid = validate(newValues);
632
- if (isValid && onValid) {
633
- onValid(newValues, {
634
- changed
635
- });
636
- }
637
- };
638
- const onTouched = (0, import_react11.useCallback)((path) => {
639
- const jsonPath = (0, import_effect2.createJsonPath)(path);
640
- setTouched((touched2) => ({
641
- ...touched2,
642
- [jsonPath]: true
643
- }));
644
- validate(values);
645
- }, [
646
- validate,
647
- values
648
- ]);
649
- return {
650
- // State.
651
- values,
652
- errors,
653
- touched,
654
- changed,
655
- canSave,
656
- handleSave,
657
- // Field utils.
658
- getStatus,
659
- getValue: getFormValue,
660
- onValueChange,
661
- onTouched
662
- };
663
- };
664
- var createKeySet = (obj, value) => {
665
- (0, import_invariant.invariant)(obj, void 0, {
666
- F: __dxlog_file,
667
- L: 235,
668
- S: void 0,
669
- A: [
670
- "obj",
671
- ""
672
- ]
673
- });
674
- return Object.keys(obj).reduce((acc, key) => ({
675
- ...acc,
676
- [key]: value
677
- }), {});
678
- };
679
- var flatMap = (errors) => {
680
- return errors.reduce((result, { path, message }) => {
681
- const jsonPath = (0, import_effect2.fromEffectValidationPath)(path);
682
- if (!(jsonPath in result)) {
683
- result[jsonPath] = message;
684
- }
685
- return result;
686
- }, {});
687
- };
688
- var FormContext = /* @__PURE__ */ (0, import_react10.createContext)(void 0);
689
- var useFormContext = () => {
690
- return (0, import_react10.useContext)(FormContext) ?? (0, import_debug.raise)(new Error("Missing FormContext"));
691
- };
692
- var useFormValues = (path = []) => {
693
- const { values: formValues } = useFormContext();
694
- const jsonPath = (0, import_effect.createJsonPath)(path);
695
- return (0, import_echo_schema2.getValue)(formValues, jsonPath);
696
- };
697
- var useInputProps = (path = []) => {
698
- const { getStatus, getValue: getFormValue, onValueChange, onTouched } = useFormContext();
699
- return {
700
- getStatus: () => getStatus(path),
701
- getValue: () => getFormValue(path),
702
- onValueChange: (type, value) => onValueChange(path, type, value),
703
- onBlur: () => onTouched(path)
704
- };
705
- };
706
- var FormProvider = ({ children, ...formOptions }) => {
707
- const formHandler = useForm(formOptions);
708
- return /* @__PURE__ */ import_react10.default.createElement(FormContext.Provider, {
709
- value: formHandler
710
- }, children);
712
+ )))))), inputOnly && /* @__PURE__ */ import_react9.default.createElement(import_react_ui7.Input.DescriptionAndValidation, null, error));
711
713
  };
712
714
  var FormActions = ({ onCancel, readonly }) => {
713
715
  const { t } = (0, import_react_ui8.useTranslation)(translationKey);
714
716
  const { canSave, handleSave } = useFormContext();
715
- return /* @__PURE__ */ import_react9.default.createElement("div", {
717
+ return /* @__PURE__ */ import_react11.default.createElement("div", {
716
718
  role: "none",
717
- className: "flex justify-center"
718
- }, /* @__PURE__ */ import_react9.default.createElement("div", {
719
+ className: "mt-2 flex justify-center"
720
+ }, /* @__PURE__ */ import_react11.default.createElement("div", {
719
721
  role: "none",
720
722
  className: (0, import_react_ui_theme6.mx)(onCancel && !readonly && "grid grid-cols-2 gap-2")
721
- }, onCancel && !readonly && /* @__PURE__ */ import_react9.default.createElement(import_react_ui8.IconButton, {
723
+ }, onCancel && !readonly && /* @__PURE__ */ import_react11.default.createElement(import_react_ui8.IconButton, {
722
724
  "data-testid": "cancel-button",
723
725
  icon: "ph--x--regular",
724
726
  label: t("button cancel"),
725
727
  onClick: onCancel
726
- }), handleSave && /* @__PURE__ */ import_react9.default.createElement(import_react_ui8.IconButton, {
728
+ }), handleSave && /* @__PURE__ */ import_react11.default.createElement(import_react_ui8.IconButton, {
727
729
  type: "submit",
728
730
  "data-testid": "save-button",
729
731
  disabled: !canSave,
@@ -966,7 +968,7 @@ var FormFields = ({ schema, path, filter, sort, readonly, lookupComponent, Custo
966
968
  ]);
967
969
  return /* @__PURE__ */ import_react12.default.createElement("div", {
968
970
  role: "form",
969
- className: (0, import_react_ui_theme7.mx)("flex flex-col w-full gap-2 py-2")
971
+ className: (0, import_react_ui_theme7.mx)("flex flex-col w-full gap-2")
970
972
  }, properties.map((property) => {
971
973
  return /* @__PURE__ */ import_react12.default.createElement(FormField, {
972
974
  key: property.name,
@@ -982,11 +984,11 @@ var FormFields = ({ schema, path, filter, sort, readonly, lookupComponent, Custo
982
984
  }).filter(import_util3.isNotFalsy));
983
985
  };
984
986
  var Form = ({ classNames, schema, values: initialValues, path = [], autoFocus, readonly, filter, sort, autoSave, testId, onValuesChanged, onValidate, onSave, onCancel, lookupComponent, Custom }) => {
985
- const onValid = (0, import_react8.useMemo)(() => autoSave ? onSave : void 0, [
987
+ const onValid = (0, import_react10.useMemo)(() => autoSave ? onSave : void 0, [
986
988
  autoSave,
987
989
  onSave
988
990
  ]);
989
- (0, import_react8.useEffect)(() => {
991
+ (0, import_react10.useEffect)(() => {
990
992
  if (autoFocus) {
991
993
  const input = document.querySelector("input");
992
994
  if (input) {
@@ -996,18 +998,18 @@ var Form = ({ classNames, schema, values: initialValues, path = [], autoFocus, r
996
998
  }, [
997
999
  autoFocus
998
1000
  ]);
999
- return /* @__PURE__ */ import_react8.default.createElement(FormProvider, {
1001
+ return /* @__PURE__ */ import_react10.default.createElement(FormProvider, {
1000
1002
  schema,
1001
1003
  initialValues,
1002
1004
  onValuesChanged,
1003
1005
  onValidate,
1004
1006
  onValid,
1005
1007
  onSave
1006
- }, /* @__PURE__ */ import_react8.default.createElement("div", {
1008
+ }, /* @__PURE__ */ import_react10.default.createElement("div", {
1007
1009
  role: "none",
1008
1010
  className: (0, import_react_ui_theme5.mx)("p-2", classNames),
1009
1011
  "data-testid": testId
1010
- }, /* @__PURE__ */ import_react8.default.createElement(FormFields, {
1012
+ }, /* @__PURE__ */ import_react10.default.createElement(FormFields, {
1011
1013
  schema,
1012
1014
  path,
1013
1015
  readonly,
@@ -1015,7 +1017,7 @@ var Form = ({ classNames, schema, values: initialValues, path = [], autoFocus, r
1015
1017
  sort,
1016
1018
  lookupComponent,
1017
1019
  Custom
1018
- }), (onCancel || onSave) && !autoSave && /* @__PURE__ */ import_react8.default.createElement(FormActions, {
1020
+ }), (onCancel || onSave) && !autoSave && /* @__PURE__ */ import_react10.default.createElement(FormActions, {
1019
1021
  onCancel,
1020
1022
  readonly
1021
1023
  })));
@@ -1526,6 +1528,7 @@ var formatForEditing = ({ type, format, value, locale = void 0 }) => {
1526
1528
  parseValue,
1527
1529
  pathNotUniqueError,
1528
1530
  translations,
1529
- useForm
1531
+ useForm,
1532
+ useFormValues
1530
1533
  });
1531
1534
  //# sourceMappingURL=index.cjs.map