@dxos/react-ui-form 0.7.3-staging.cc8dd3e → 0.7.3-staging.d887a4b

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.
@@ -91,7 +91,7 @@ import { pipe } from "effect";
91
91
  import { capitalize } from "effect/String";
92
92
  import React5, { useEffect as useEffect2, useMemo as useMemo2 } from "react";
93
93
  import { AST, S } from "@dxos/echo-schema";
94
- import { findNode, getDiscriminatedType, isDiscriminatedUnion } from "@dxos/effect";
94
+ import { findNode, getDiscriminatedType, isDiscriminatedUnion, SimpleType } from "@dxos/effect";
95
95
  import { log as log2 } from "@dxos/log";
96
96
  import { IconButton, useTranslation as useTranslation2 } from "@dxos/react-ui";
97
97
  import { mx } from "@dxos/react-ui-theme";
@@ -122,11 +122,11 @@ var InputHeader = ({ children, error }) => {
122
122
  };
123
123
 
124
124
  // packages/ui/react-ui-form/src/components/Form/Defaults.tsx
125
- var TextInput = ({ property, type, label, disabled, placeholder, getStatus, getValue, onValueChange, onBlur }) => {
125
+ var TextInput = ({ property, type, label, inputOnly, disabled, placeholder, getStatus, getValue, onValueChange, onBlur }) => {
126
126
  const { status, error } = getStatus?.(property);
127
127
  return /* @__PURE__ */ React3.createElement(Input2.Root, {
128
128
  validationValence: status
129
- }, /* @__PURE__ */ React3.createElement(InputHeader, {
129
+ }, !inputOnly && /* @__PURE__ */ React3.createElement(InputHeader, {
130
130
  error
131
131
  }, /* @__PURE__ */ React3.createElement(Input2.Label, null, label)), /* @__PURE__ */ React3.createElement(Input2.TextInput, {
132
132
  disabled,
@@ -134,13 +134,13 @@ var TextInput = ({ property, type, label, disabled, placeholder, getStatus, getV
134
134
  value: getValue(property) ?? "",
135
135
  onChange: (event) => onValueChange(property, type, event.target.value),
136
136
  onBlur
137
- }));
137
+ }), inputOnly && /* @__PURE__ */ React3.createElement(Input2.Validation, null, error));
138
138
  };
139
- var NumberInput = ({ property, type, label, disabled, placeholder, getStatus, getValue, onValueChange, onBlur }) => {
139
+ var NumberInput = ({ property, type, label, inputOnly, disabled, placeholder, getStatus, getValue, onValueChange, onBlur }) => {
140
140
  const { status, error } = getStatus?.(property);
141
141
  return /* @__PURE__ */ React3.createElement(Input2.Root, {
142
142
  validationValence: status
143
- }, /* @__PURE__ */ React3.createElement(InputHeader, {
143
+ }, !inputOnly && /* @__PURE__ */ React3.createElement(InputHeader, {
144
144
  error
145
145
  }, /* @__PURE__ */ React3.createElement(Input2.Label, null, label)), /* @__PURE__ */ React3.createElement(Input2.TextInput, {
146
146
  type: "number",
@@ -149,24 +149,24 @@ var NumberInput = ({ property, type, label, disabled, placeholder, getStatus, ge
149
149
  value: getValue(property) ?? 0,
150
150
  onChange: (event) => onValueChange(property, type, event.target.value),
151
151
  onBlur
152
- }));
152
+ }), inputOnly && /* @__PURE__ */ React3.createElement(Input2.DescriptionAndValidation, null, error));
153
153
  };
154
- var BooleanInput = ({ property, type, label, getStatus, getValue, onValueChange }) => {
154
+ var BooleanInput = ({ property, type, label, inputOnly, getStatus, getValue, onValueChange }) => {
155
155
  const { status, error } = getStatus?.(property);
156
156
  return /* @__PURE__ */ React3.createElement(Input2.Root, {
157
157
  validationValence: status
158
- }, /* @__PURE__ */ React3.createElement(InputHeader, {
158
+ }, !inputOnly && /* @__PURE__ */ React3.createElement(InputHeader, {
159
159
  error
160
160
  }, /* @__PURE__ */ React3.createElement(Input2.Label, null, label)), /* @__PURE__ */ React3.createElement(Input2.Switch, {
161
161
  checked: getValue(property),
162
162
  onCheckedChange: (value) => onValueChange(property, type, value)
163
- }));
163
+ }), inputOnly && /* @__PURE__ */ React3.createElement(Input2.DescriptionAndValidation, null, error));
164
164
  };
165
- var SelectInput = ({ property, type, label, disabled, placeholder, options, getStatus, getValue, onValueChange }) => {
165
+ var SelectInput = ({ property, type, label, inputOnly, disabled, placeholder, options, getStatus, getValue, onValueChange }) => {
166
166
  const { status, error } = getStatus?.(property);
167
167
  return /* @__PURE__ */ React3.createElement(Input2.Root, {
168
168
  validationValence: status
169
- }, /* @__PURE__ */ React3.createElement(InputHeader, {
169
+ }, !inputOnly && /* @__PURE__ */ React3.createElement(InputHeader, {
170
170
  error
171
171
  }, /* @__PURE__ */ React3.createElement(Input2.Label, null, label)), /* @__PURE__ */ React3.createElement(Select.Root, {
172
172
  value: getValue(property),
@@ -181,7 +181,7 @@ var SelectInput = ({ property, type, label, disabled, placeholder, options, getS
181
181
  key: String(value),
182
182
  value: String(value)
183
183
  }, label2 ?? String(value))
184
- )))))));
184
+ )))))), inputOnly && /* @__PURE__ */ React3.createElement(Input2.DescriptionAndValidation, null, error));
185
185
  };
186
186
 
187
187
  // packages/ui/react-ui-form/src/components/Form/factory.tsx
@@ -317,7 +317,7 @@ var useForm = ({ schema, initialValues, onValuesChanged, onValidate, onValid, on
317
317
  errors
318
318
  ]);
319
319
  const getValue = (property) => {
320
- return values[property];
320
+ return getByPath(values, property);
321
321
  };
322
322
  const onValueChange = (property, type, value) => {
323
323
  let parsedValue = value;
@@ -328,16 +328,13 @@ var useForm = ({ schema, initialValues, onValuesChanged, onValidate, onValid, on
328
328
  } catch (err) {
329
329
  log.catch(err, void 0, {
330
330
  F: __dxlog_file,
331
- L: 180,
331
+ L: 183,
332
332
  S: void 0,
333
333
  C: (f, a) => f(...a)
334
334
  });
335
335
  parsedValue = void 0;
336
336
  }
337
- const newValues = {
338
- ...values,
339
- [property]: parsedValue
340
- };
337
+ const newValues = setByPath(values, property, parsedValue);
341
338
  setValues(newValues);
342
339
  setChanged((prev) => ({
343
340
  ...prev,
@@ -383,7 +380,7 @@ var useForm = ({ schema, initialValues, onValuesChanged, onValidate, onValid, on
383
380
  var createKeySet = (obj, value) => {
384
381
  invariant(obj, void 0, {
385
382
  F: __dxlog_file,
386
- L: 231,
383
+ L: 234,
387
384
  S: void 0,
388
385
  A: [
389
386
  "obj",
@@ -403,12 +400,25 @@ var flatMap = (errors) => {
403
400
  return result;
404
401
  }, {});
405
402
  };
403
+ var getByPath = (obj, path) => {
404
+ const [key, index] = path.split(".");
405
+ return index === void 0 ? obj[key] : obj[key][parseInt(index)];
406
+ };
407
+ var setByPath = (obj, path, value) => {
408
+ const [key, index] = path.split(".");
409
+ const newValue = index === void 0 ? value : [
410
+ ...obj[key]
411
+ ].map((v, i) => i === parseInt(index) ? value : v);
412
+ return {
413
+ ...obj,
414
+ [key]: newValue
415
+ };
416
+ };
406
417
 
407
418
  // packages/ui/react-ui-form/src/components/Form/Form.tsx
408
419
  var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-form/src/components/Form/Form.tsx";
409
420
  var padding = "px-2";
410
421
  var Form = ({ classNames, schema, values: initialValues, path = [], readonly, filter, sort, autoSave, testId, onValuesChanged, onValidate, onSave, onCancel, Custom }) => {
411
- const { t } = useTranslation2(translationKey);
412
422
  const onValid = useMemo2(() => autoSave ? onSave : void 0, [
413
423
  autoSave,
414
424
  onSave
@@ -440,7 +450,7 @@ var Form = ({ classNames, schema, values: initialValues, path = [], readonly, fi
440
450
  errors
441
451
  }, {
442
452
  F: __dxlog_file2,
443
- L: 101,
453
+ L: 100,
444
454
  S: void 0,
445
455
  C: (f, a) => f(...a)
446
456
  });
@@ -453,7 +463,7 @@ var Form = ({ classNames, schema, values: initialValues, path = [], readonly, fi
453
463
  className: mx("flex flex-col w-full gap-2 py-2", classNames),
454
464
  "data-testid": testId
455
465
  }, properties.map((property) => {
456
- const { ast, name, type, format, title, description, examples, options } = property;
466
+ const { ast, name, type, format, title, description, examples, options, array } = property;
457
467
  const key = [
458
468
  ...path,
459
469
  name
@@ -482,6 +492,22 @@ var Form = ({ classNames, schema, values: initialValues, path = [], readonly, fi
482
492
  }));
483
493
  }
484
494
  InputComponent = getInputComponent(type, format);
495
+ if (array) {
496
+ return /* @__PURE__ */ React5.createElement(ArrayField, {
497
+ key: name,
498
+ name,
499
+ type,
500
+ array: true,
501
+ label,
502
+ ast,
503
+ values,
504
+ format,
505
+ readonly,
506
+ placeholder,
507
+ inputProps,
508
+ Custom
509
+ });
510
+ }
485
511
  }
486
512
  if (!InputComponent) {
487
513
  if (type === "object") {
@@ -510,7 +536,7 @@ var Form = ({ classNames, schema, values: initialValues, path = [], readonly, fi
510
536
  type
511
537
  }, {
512
538
  F: __dxlog_file2,
513
- L: 165,
539
+ L: 185,
514
540
  S: void 0,
515
541
  C: (f, a) => f(...a)
516
542
  });
@@ -529,7 +555,140 @@ var Form = ({ classNames, schema, values: initialValues, path = [], readonly, fi
529
555
  placeholder,
530
556
  ...inputProps
531
557
  }));
532
- }).filter(isNotFalsy), (onCancel || onSave) && !autoSave && /* @__PURE__ */ React5.createElement("div", {
558
+ }).filter(isNotFalsy), (onCancel || onSave) && !autoSave && /* @__PURE__ */ React5.createElement(FormActions, {
559
+ onCancel,
560
+ onSubmit: handleSave,
561
+ canSubmit: canSave,
562
+ readonly
563
+ }));
564
+ };
565
+ var ArrayField = ({ name, type, label, ast, values, format, readonly, placeholder, inputProps, Custom }) => {
566
+ const { t } = useTranslation2(translationKey);
567
+ const arrayValues = values[name] ?? [];
568
+ const key = [
569
+ name
570
+ ];
571
+ const tupleType = findNode(ast, AST.isTupleType);
572
+ const elementType = tupleType?.rest[0]?.type;
573
+ if (type === "object" && elementType) {
574
+ const baseNode = findNode(elementType, isDiscriminatedUnion);
575
+ const typeLiteral = baseNode ? getDiscriminatedType(baseNode, values[name]) : findNode(elementType, AST.isTypeLiteral);
576
+ if (typeLiteral) {
577
+ const schema = S.make(typeLiteral);
578
+ return /* @__PURE__ */ React5.createElement("div", {
579
+ key: name,
580
+ role: "none",
581
+ className: mx(padding)
582
+ }, /* @__PURE__ */ React5.createElement(InputHeader, null, label), /* @__PURE__ */ React5.createElement("div", {
583
+ role: "none",
584
+ className: "flex flex-col gap-1"
585
+ }, arrayValues.map((value, index) => {
586
+ return /* @__PURE__ */ React5.createElement("div", {
587
+ key: index,
588
+ role: "none",
589
+ className: "flex items-center gap-1"
590
+ }, /* @__PURE__ */ React5.createElement("div", {
591
+ role: "none",
592
+ className: "flex-1"
593
+ }, /* @__PURE__ */ React5.createElement(Form, {
594
+ schema,
595
+ path: [
596
+ ...key,
597
+ index.toString()
598
+ ],
599
+ values: value,
600
+ onValuesChanged: (childValues) => {
601
+ const newValues = [
602
+ ...arrayValues
603
+ ];
604
+ newValues[index] = childValues;
605
+ inputProps.onValueChange(name, "object", newValues);
606
+ },
607
+ Custom
608
+ })), /* @__PURE__ */ React5.createElement(IconButton, {
609
+ icon: "ph--trash--regular",
610
+ iconOnly: true,
611
+ label: t("button remove"),
612
+ onClick: () => {
613
+ const newValues = arrayValues.filter((_, i) => i !== index);
614
+ inputProps.onValueChange(name, type, newValues);
615
+ }
616
+ }));
617
+ })), /* @__PURE__ */ React5.createElement("div", {
618
+ role: "none",
619
+ className: "flex justify-between items-center plb-1"
620
+ }, /* @__PURE__ */ React5.createElement(IconButton, {
621
+ icon: "ph--plus--regular",
622
+ iconOnly: true,
623
+ label: t("button add"),
624
+ onClick: () => {
625
+ const newValues = [
626
+ ...arrayValues,
627
+ {}
628
+ ];
629
+ inputProps.onValueChange(name, type, newValues);
630
+ }
631
+ })));
632
+ }
633
+ return /* @__PURE__ */ React5.createElement("div", {
634
+ key: name,
635
+ role: "none"
636
+ }, "Nested form not supported in arrays, yet.");
637
+ }
638
+ const InputComponent = getInputComponent(type, format);
639
+ if (!InputComponent) {
640
+ return null;
641
+ }
642
+ return /* @__PURE__ */ React5.createElement("div", {
643
+ role: "none",
644
+ key: "meta-input",
645
+ className: mx(padding)
646
+ }, /* @__PURE__ */ React5.createElement(InputHeader, null, label), /* @__PURE__ */ React5.createElement("div", {
647
+ role: "none",
648
+ className: "flex flex-col gap-1"
649
+ }, arrayValues.map((_, index) => /* @__PURE__ */ React5.createElement("div", {
650
+ key: index,
651
+ role: "none",
652
+ className: "flex items-start gap-1"
653
+ }, /* @__PURE__ */ React5.createElement("div", {
654
+ role: "none",
655
+ className: "flex-1"
656
+ }, /* @__PURE__ */ React5.createElement(InputComponent, {
657
+ type,
658
+ format,
659
+ label,
660
+ inputOnly: true,
661
+ property: `${name}.${index}`,
662
+ disabled: readonly,
663
+ placeholder,
664
+ ...inputProps
665
+ })), /* @__PURE__ */ React5.createElement(IconButton, {
666
+ icon: "ph--trash--regular",
667
+ iconOnly: true,
668
+ label: t("button remove"),
669
+ onClick: () => {
670
+ const newValues = arrayValues.filter((_2, i) => i !== index);
671
+ inputProps.onValueChange(name, type, newValues);
672
+ }
673
+ })))), /* @__PURE__ */ React5.createElement("div", {
674
+ role: "none",
675
+ className: "flex justify-between items-center plb-1"
676
+ }, /* @__PURE__ */ React5.createElement(IconButton, {
677
+ icon: "ph--plus--regular",
678
+ iconOnly: true,
679
+ label: t("button add"),
680
+ onClick: () => {
681
+ const newValues = [
682
+ ...arrayValues,
683
+ SimpleType.getDefaultValue(type)
684
+ ];
685
+ inputProps.onValueChange(name, type, newValues);
686
+ }
687
+ })));
688
+ };
689
+ var FormActions = ({ onCancel, onSubmit, canSubmit, readonly }) => {
690
+ const { t } = useTranslation2(translationKey);
691
+ return /* @__PURE__ */ React5.createElement("div", {
533
692
  role: "none",
534
693
  className: "flex justify-center"
535
694
  }, /* @__PURE__ */ React5.createElement("div", {
@@ -540,14 +699,14 @@ var Form = ({ classNames, schema, values: initialValues, path = [], readonly, fi
540
699
  icon: "ph--x--regular",
541
700
  label: t("button cancel"),
542
701
  onClick: onCancel
543
- }), onSave && /* @__PURE__ */ React5.createElement(IconButton, {
702
+ }), onSubmit && /* @__PURE__ */ React5.createElement(IconButton, {
544
703
  type: "submit",
545
704
  "data-testid": "save-button",
546
- disabled: !canSave,
705
+ disabled: !canSubmit,
547
706
  icon: "ph--check--regular",
548
707
  label: t("button save"),
549
- onClick: handleSave
550
- }))));
708
+ onClick: onSubmit
709
+ })));
551
710
  };
552
711
 
553
712
  // packages/ui/react-ui-form/src/components/FieldEditor/FieldEditor.tsx
@@ -718,7 +877,7 @@ var ViewEditor = ({ classNames, schema, view, registry, readonly, showHeading =
718
877
  name: view.name,
719
878
  // TODO(burdon): Need to warn user of possible consequences of editing.
720
879
  // TODO(burdon): Settings should have domain name owned by user.
721
- typename: view.query.typename
880
+ typename: view.query.type
722
881
  };
723
882
  }, [
724
883
  view
@@ -726,7 +885,7 @@ var ViewEditor = ({ classNames, schema, view, registry, readonly, showHeading =
726
885
  const handleViewUpdate = useCallback3(({ name, typename }) => {
727
886
  requestAnimationFrame(() => {
728
887
  view.name = name;
729
- view.query.typename = typename;
888
+ view.query.type = typename;
730
889
  schema.updateTypename(typename);
731
890
  });
732
891
  }, [
@@ -1026,6 +1185,7 @@ export {
1026
1185
  DeprecatedFormInput,
1027
1186
  FieldEditor,
1028
1187
  Form,
1188
+ FormActions,
1029
1189
  GeiPointInput,
1030
1190
  InputHeader,
1031
1191
  NumberInput,