@overmap-ai/forms 1.0.6 → 1.0.9-handle-patchform-errors.0

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.
@@ -8,6 +8,7 @@ interface FieldOptionsFormProps {
8
8
  /** fields that can be used as a condition */
9
9
  conditionalSourceFields?: ISerializedField[];
10
10
  handleCancel: () => void;
11
+ handleDirtyChange: (dirty: boolean) => void;
11
12
  handleCreateField: (form: Form) => void;
12
13
  }
13
14
  interface FieldBuilderProps extends Pick<FieldOptionsFormProps, "conditionalSourceFields"> {
package/dist/forms.js CHANGED
@@ -5,7 +5,7 @@ var __publicField = (obj, key, value) => {
5
5
  return value;
6
6
  };
7
7
  import { jsx, jsxs, Fragment } from "react/jsx-runtime";
8
- import { Flex, Text, useSeverityColor, Checkbox, CheckCircledIcon, TextField as TextField$1, FontFamilyIcon, CalendarIcon, InputIcon, TextArea, RowsIcon, Select, Box, IconButton, PlusIcon, Badge, Cross1Icon, ListBulletIcon, DropdownMenuIcon, MultiSelect, CheckboxIcon, Card, Heading, Button, UploadIcon, ButtonList, divButtonProps, StarFilledIcon, StarIcon, QuestionMarkCircledIcon, PersonIcon, Tooltip, Avatar, Separator, Dialog, Pencil1Icon, TrashIcon, CopyIcon, DragHandleDots2Icon, DropdownMenu, DotsVerticalIcon, useAlertDialog, Em, Strong, useToast, Tabs } from "@overmap-ai/blocks";
8
+ import { Flex, Text, useSeverityColor, Checkbox, CheckCircledIcon, TextField as TextField$1, FontFamilyIcon, CalendarIcon, InputIcon, TextArea, RowsIcon, Select, Box, IconButton, PlusIcon, Badge, Cross1Icon, ListBulletIcon, DropdownMenuIcon, MultiSelect, CheckboxIcon, Card, Heading, Button, UploadIcon, ButtonList, divButtonProps, StarFilledIcon, StarIcon, QuestionMarkCircledIcon, PersonIcon, Tooltip, Avatar, useToast, Separator, useDiscardAlertDialog, Dialog, Pencil1Icon, TrashIcon, CopyIcon, DragHandleDots2Icon, DropdownMenu, DotsVerticalIcon, useAlertDialog, Em, Strong, Tabs } from "@overmap-ai/blocks";
9
9
  import { useField, useFormikContext, useFormik, FormikProvider } from "formik";
10
10
  import React, { useMemo, memo, useCallback, useState, useEffect, useRef, forwardRef, useReducer } from "react";
11
11
  import { DragDropContext, Droppable, Draggable } from "@hello-pangea/dnd";
@@ -1503,6 +1503,7 @@ const FormRenderer = memo(
1503
1503
  cancelText,
1504
1504
  onCancel,
1505
1505
  onDirty,
1506
+ onDirtyChange,
1506
1507
  // if the title isn't provided, hide it by default
1507
1508
  hideTitle = !schema.title,
1508
1509
  hideDescription,
@@ -1531,7 +1532,9 @@ const FormRenderer = memo(
1531
1532
  useEffect(() => {
1532
1533
  if (dirty && onDirty)
1533
1534
  onDirty();
1534
- }, [dirty, onDirty]);
1535
+ if (onDirtyChange)
1536
+ onDirtyChange(dirty);
1537
+ }, [dirty, onDirty, onDirtyChange]);
1535
1538
  return /* @__PURE__ */ jsx(FormikProvider, { value: formik, children: /* @__PURE__ */ jsx(Flex, { ref, direction: "column", gap: "2", className, asChild: true, children: /* @__PURE__ */ jsxs("form", { id: formId2, onSubmit: formik.handleSubmit, children: [
1536
1539
  !hideTitle && /* @__PURE__ */ jsx(Card, { children: /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: "1", children: [
1537
1540
  Title,
@@ -1830,6 +1833,7 @@ const PatchField = memo(function PatchField2(props) {
1830
1833
  const PatchFormProvider = memo(
1831
1834
  forwardRef((props, ref) => {
1832
1835
  const { children, schema, values, onPatch, onError, ...rest } = props;
1836
+ const { showError } = useToast();
1833
1837
  const initialValues2 = useMemo(() => initialFormValues(schema.fields, values), [schema.fields, values]);
1834
1838
  const handlePatch = useCallback(
1835
1839
  (values2) => {
@@ -1842,6 +1846,7 @@ const PatchFormProvider = memo(
1842
1846
  }
1843
1847
  if (!hasKeys(diff))
1844
1848
  return;
1849
+ console.log("onpatch runs", diff);
1845
1850
  onPatch(diff);
1846
1851
  },
1847
1852
  [initialValues2, onPatch]
@@ -1867,9 +1872,13 @@ const PatchFormProvider = memo(
1867
1872
  const { errors, resetForm } = formik;
1868
1873
  useEffect(() => {
1869
1874
  if (hasKeys(errors)) {
1870
- resetForm({ values: initialValues2, errors: {} });
1875
+ console.log(errors);
1876
+ showError({
1877
+ title: "test title",
1878
+ description: "Sections with conditions must be below the fields they reference."
1879
+ });
1871
1880
  }
1872
- }, [errors, initialValues2, resetForm]);
1881
+ }, [showError, errors, initialValues2, resetForm]);
1873
1882
  return /* @__PURE__ */ jsx(FormikProvider, { value: formik, children: /* @__PURE__ */ jsx("form", { ...rest, ref, onSubmit: formik.handleSubmit, children }) });
1874
1883
  })
1875
1884
  );
@@ -1943,7 +1952,7 @@ const commonFields = (takenLabels, type) => {
1943
1952
  ];
1944
1953
  };
1945
1954
  const FieldOptionsForm = memo(function FieldOptionsForm2(props) {
1946
- const { fieldType, handleCancel, handleCreateField, defaultField, conditionalSourceFields } = props;
1955
+ const { fieldType, handleCancel, handleCreateField, handleDirtyChange, defaultField, conditionalSourceFields } = props;
1947
1956
  const fieldCls = CompleteFieldTypeToClsMapping[fieldType];
1948
1957
  const formik = useFormikContext();
1949
1958
  const schema = useMemo(() => {
@@ -1974,26 +1983,44 @@ const FieldOptionsForm = memo(function FieldOptionsForm2(props) {
1974
1983
  values: defaultField,
1975
1984
  onSubmit: handleCreateField,
1976
1985
  cancelText: defaultField ? void 0 : "Back",
1977
- onCancel: handleCancel
1986
+ onCancel: handleCancel,
1987
+ onDirtyChange: handleDirtyChange
1978
1988
  }
1979
1989
  );
1980
1990
  });
1981
1991
  const FieldBuilder = memo(function FieldBuilder2(props) {
1982
1992
  const { parentPath, index, children, initial, editing, conditionalSourceFields } = props;
1983
1993
  const [fieldType, setFieldType] = useState();
1994
+ const [formIsDirty, setFormIsDirty] = useState(false);
1984
1995
  const type = (initial == null ? void 0 : initial.type) ?? fieldType;
1985
1996
  const typeName = type ? CompleteFieldTypeToClsMapping[type].fieldTypeName : void 0;
1986
1997
  const { setFieldValue, values } = useFormikContext();
1987
1998
  if (editing && !initial)
1988
1999
  throw new Error("Initial field must be provided if editing is true.");
2000
+ const openConfirmDiscardChangesDialog = useDiscardAlertDialog();
1989
2001
  const showChooseField = !type && !editing && !initial;
1990
2002
  const title2 = showChooseField ? "Choose a field type" : `${typeName} settings`;
1991
2003
  const description2 = showChooseField ? "Select a field type to add to this section." : (typeName == null ? void 0 : typeName.toLowerCase()) === "section" ? "Customize your section" : `Customize your ${typeName == null ? void 0 : typeName.toLowerCase()} field.`;
1992
- const handleCancel = useCallback(() => setFieldType(void 0), []);
1993
- const handleCloseInterrupt = useCallback((confirmClose) => {
2004
+ const handleCancel = useCallback(() => {
1994
2005
  setFieldType(void 0);
1995
- confirmClose();
2006
+ setFormIsDirty(false);
1996
2007
  }, []);
2008
+ const handleCloseInterrupt = useCallback(
2009
+ (confirmClose) => {
2010
+ if (formIsDirty) {
2011
+ openConfirmDiscardChangesDialog({
2012
+ onDiscard: () => {
2013
+ setFieldType(void 0);
2014
+ confirmClose();
2015
+ }
2016
+ });
2017
+ } else {
2018
+ setFieldType(void 0);
2019
+ confirmClose();
2020
+ }
2021
+ },
2022
+ [formIsDirty, openConfirmDiscardChangesDialog]
2023
+ );
1997
2024
  const handleCreateField = useCallback(
1998
2025
  (form, closeDialog) => {
1999
2026
  const { label } = form;
@@ -2019,10 +2046,11 @@ const FieldBuilder = memo(function FieldBuilder2(props) {
2019
2046
  newFields = insert(parent, index, field);
2020
2047
  }
2021
2048
  setFieldValue(parentPath, newFields).then();
2022
- closeDialog();
2049
+ closeDialog({ force: true });
2023
2050
  },
2024
2051
  [editing, type, values, parentPath, setFieldValue, index]
2025
2052
  );
2053
+ const handleDirtyChange = useCallback((dirty) => setFormIsDirty(dirty), []);
2026
2054
  const dialogContent = useCallback(
2027
2055
  (closeDialog) => {
2028
2056
  if (showChooseField) {
@@ -2035,11 +2063,12 @@ const FieldBuilder = memo(function FieldBuilder2(props) {
2035
2063
  handleCancel,
2036
2064
  handleCreateField: (form) => handleCreateField(form, closeDialog),
2037
2065
  fieldType: type,
2038
- defaultField: initial
2066
+ defaultField: initial,
2067
+ handleDirtyChange
2039
2068
  }
2040
2069
  );
2041
2070
  },
2042
- [conditionalSourceFields, handleCancel, handleCreateField, initial, showChooseField, type]
2071
+ [conditionalSourceFields, handleCancel, handleCreateField, handleDirtyChange, initial, showChooseField, type]
2043
2072
  );
2044
2073
  return /* @__PURE__ */ jsx(Dialog, { onCloseInterrupt: handleCloseInterrupt, title: title2, description: description2, content: dialogContent, children });
2045
2074
  });
@@ -2180,7 +2209,7 @@ const FieldWithActions = memo(function FieldWithActions2(props) {
2180
2209
  ) });
2181
2210
  });
2182
2211
  const FieldSectionWithActions = memo(function FieldSectionWithActions2(props) {
2183
- var _a, _b, _c, _d, _e, _f, _g;
2212
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i;
2184
2213
  const { field, index: sectionIndex, dropState } = props;
2185
2214
  const isDropDisabled = (_a = dropState[field.identifier]) == null ? void 0 : _a.disabled;
2186
2215
  const { setFieldValue, values } = useFormikContext();
@@ -2333,7 +2362,7 @@ const FieldSectionWithActions = memo(function FieldSectionWithActions2(props) {
2333
2362
  const conditionComparison = Array.isArray((_c = field.condition) == null ? void 0 : _c.value) ? "contains all of" : "equals";
2334
2363
  if (valueIsFile((_d = field.condition) == null ? void 0 : _d.value))
2335
2364
  throw new Error("File values are not supported for conditions.");
2336
- const conditionValue = Array.isArray((_e = field.condition) == null ? void 0 : _e.value) ? (_f = field.condition) == null ? void 0 : _f.value.map((v) => typeof v === "string" ? v : v.label).join(", ") : (_g = field.condition) == null ? void 0 : _g.value.toString();
2365
+ const conditionValue = Array.isArray((_e = field.condition) == null ? void 0 : _e.value) ? (_g = (_f = field.condition) == null ? void 0 : _f.value) == null ? void 0 : _g.map((v) => typeof v === "string" ? v : v.label).join(", ") : (_i = (_h = field.condition) == null ? void 0 : _h.value) == null ? void 0 : _i.toString();
2337
2366
  return /* @__PURE__ */ jsx(Draggable, { draggableId: field.identifier, index: sectionIndex, children: (draggableProvided) => /* @__PURE__ */ jsx(
2338
2367
  Card,
2339
2368
  {