@overmap-ai/forms 1.0.9 → 1.0.10-conditional-arrows-2.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.
@@ -1,12 +1,11 @@
1
1
  /// <reference types="react" />
2
- import { DraggableProvidedDragHandleProps } from "@hello-pangea/dnd";
3
2
  import { FieldBuilderArgs } from "./FieldBuilder";
4
3
  interface FieldActionsProps {
5
4
  remove: () => void;
6
- dragHandleProps: DraggableProvidedDragHandleProps | null | undefined;
7
5
  editProps: FieldBuilderArgs;
8
6
  insertAfterProps: FieldBuilderArgs;
9
7
  duplicateProps: FieldBuilderArgs;
8
+ type?: string;
10
9
  }
11
10
  export declare const FieldActions: import("react").NamedExoticComponent<FieldActionsProps>;
12
11
  export {};
@@ -4,6 +4,7 @@ import { DropState } from "./DropDispatch";
4
4
  interface FieldSectionWithActionsProps {
5
5
  field: SerializedFieldSection;
6
6
  index: number;
7
+ conditionalFieldCounts: (number | null)[];
7
8
  dropState: DropState;
8
9
  }
9
10
  export declare const FieldSectionWithActions: import("react").NamedExoticComponent<FieldSectionWithActionsProps>;
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, useDiscardAlertDialog, 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, Separator, useDiscardAlertDialog, Dialog, Pencil1Icon, TrashIcon, CopyIcon, DropdownMenu, DotsVerticalIcon, useAlertDialog, Em, Strong, useToast, 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";
@@ -13,6 +13,7 @@ import { slugify, useAppSelector, selectFormRevision, useSDK, selectSubmissionAt
13
13
  import get from "lodash.get";
14
14
  import set from "lodash.set";
15
15
  import cloneDeep from "lodash.clonedeep";
16
+ import Xarrow, { useXarrow, Xwrapper } from "react-xarrows";
16
17
  class BaseFormElement {
17
18
  constructor(options) {
18
19
  __publicField(this, "type");
@@ -103,9 +104,11 @@ class BaseField extends BaseFormElement {
103
104
  }
104
105
  __publicField(BaseField, "fieldTypeName");
105
106
  __publicField(BaseField, "fieldTypeDescription");
106
- const description$1 = "_description_17zed_1";
107
+ const description$1 = "_description_1se5r_1";
108
+ const sectionContainer = "_sectionContainer_1se5r_5";
107
109
  const styles$3 = {
108
- description: description$1
110
+ description: description$1,
111
+ sectionContainer
109
112
  };
110
113
  const InputWithLabel = (props) => {
111
114
  const { label, children, severity, inputId, labelId, flexProps } = props;
@@ -2067,12 +2070,8 @@ const FieldBuilder = memo(function FieldBuilder2(props) {
2067
2070
  return /* @__PURE__ */ jsx(Dialog, { onCloseInterrupt: handleCloseInterrupt, title: title2, description: description2, content: dialogContent, children });
2068
2071
  });
2069
2072
  const DefaultWrapper = ({ children }) => /* @__PURE__ */ jsx(Fragment, { children });
2070
- const forMobile = (mobile, display) => ({
2071
- initial: mobile ? display : "none",
2072
- sm: mobile ? "none" : display
2073
- });
2074
2073
  const FieldActions = memo(function FieldActions2(props) {
2075
- const { remove: remove2, dragHandleProps, editProps, insertAfterProps, duplicateProps } = props;
2074
+ const { remove: remove2, editProps, insertAfterProps, duplicateProps, type } = props;
2076
2075
  const actions = useMemo(
2077
2076
  () => [
2078
2077
  {
@@ -2098,53 +2097,37 @@ const FieldActions = memo(function FieldActions2(props) {
2098
2097
  Wrapper: FieldBuilder,
2099
2098
  wrapperProps: insertAfterProps,
2100
2099
  Icon: PlusIcon,
2101
- text: "Add after"
2102
- },
2103
- {
2104
- // Wrapping icon in a div so that the asChild turns the button into a div
2105
- // so that the drag handle props are not applied to the icon
2106
- // Note: b/c the <button> does not handle the space-press event correctly
2107
- Icon: (props2) => /* @__PURE__ */ jsx("div", { ...props2, children: /* @__PURE__ */ jsx(DragHandleDots2Icon, {}) }),
2108
- text: "Reorder",
2109
- disableOnMobile: true,
2110
- buttonProps: { ...dragHandleProps, asChild: true }
2100
+ text: `Add ${type === "section" ? "section" : "field"}`
2111
2101
  }
2112
2102
  ],
2113
- [dragHandleProps, duplicateProps, editProps, insertAfterProps, remove2]
2103
+ [duplicateProps, editProps, insertAfterProps, remove2, type]
2114
2104
  );
2115
- return /* @__PURE__ */ jsxs(Fragment, { children: [
2116
- /* @__PURE__ */ jsx(Flex, { gap: "4", display: forMobile(false, "flex"), children: actions.map((Action) => {
2117
- const Wrapper = Action.Wrapper ?? DefaultWrapper;
2118
- return /* @__PURE__ */ jsx(Wrapper, { ...Action.wrapperProps, children: /* @__PURE__ */ jsx(IconButton, { type: "button", variant: "ghost", "aria-label": Action.text, ...Action.buttonProps, children: /* @__PURE__ */ jsx(Action.Icon, {}) }) }, Action.text);
2119
- }) }),
2120
- /* @__PURE__ */ jsx(Box, { display: forMobile(true, "block"), children: /* @__PURE__ */ jsx(
2121
- DropdownMenu,
2122
- {
2123
- trigger: /* @__PURE__ */ jsx(IconButton, { variant: "ghost", "aria-label": "Actions menu", children: /* @__PURE__ */ jsx(DotsVerticalIcon, {}) }),
2124
- closeOnSelect: false,
2125
- items: actions.map((Action) => {
2126
- var _a;
2127
- if (Action.disableOnMobile)
2128
- return null;
2129
- const Wrapper = Action.Wrapper ?? DefaultWrapper;
2130
- return {
2131
- ...Action.buttonProps,
2132
- onSelect: (_a = Action.buttonProps) == null ? void 0 : _a.onClick,
2133
- content: /* @__PURE__ */ jsx(Wrapper, { ...Action.wrapperProps, children: /* @__PURE__ */ jsxs(Flex, { gap: "2", align: "center", children: [
2134
- /* @__PURE__ */ jsx(Action.Icon, {}),
2135
- Action.text
2136
- ] }) })
2137
- };
2138
- }).filter((x) => x !== null)
2139
- }
2140
- ) })
2141
- ] });
2105
+ return /* @__PURE__ */ jsx(Box, { display: "block", children: /* @__PURE__ */ jsx(
2106
+ DropdownMenu,
2107
+ {
2108
+ trigger: /* @__PURE__ */ jsx(IconButton, { variant: "ghost", "aria-label": "Actions menu", children: /* @__PURE__ */ jsx(DotsVerticalIcon, {}) }),
2109
+ closeOnSelect: false,
2110
+ items: actions.map((Action) => {
2111
+ var _a;
2112
+ const Wrapper = Action.Wrapper ?? DefaultWrapper;
2113
+ return {
2114
+ ...Action.buttonProps,
2115
+ onSelect: (_a = Action.buttonProps) == null ? void 0 : _a.onClick,
2116
+ content: /* @__PURE__ */ jsx(Wrapper, { ...Action.wrapperProps, children: /* @__PURE__ */ jsxs(Flex, { gap: "2", align: "center", children: [
2117
+ /* @__PURE__ */ jsx(Action.Icon, {}),
2118
+ Action.text
2119
+ ] }) })
2120
+ };
2121
+ })
2122
+ }
2123
+ ) });
2142
2124
  });
2143
2125
  const formId = "form-builder";
2144
2126
  const FieldWithActions = memo(function FieldWithActions2(props) {
2145
2127
  const { field, index, sectionIndex, takenLabels, remove: remove2 } = props;
2146
2128
  const deserializedField = useMemo(() => deserialize(field), [field]);
2147
2129
  const input = useFieldInput(deserializedField, { formId, disabled: true });
2130
+ const updateXarrow = useXarrow();
2148
2131
  const duplicateField = useCallback(
2149
2132
  (field2) => {
2150
2133
  if (field2.label === null) {
@@ -2185,6 +2168,8 @@ const FieldWithActions = memo(function FieldWithActions2(props) {
2185
2168
  ref: draggableProvided.innerRef,
2186
2169
  ...draggableProvided.draggableProps,
2187
2170
  ...draggableProvided.dragHandleProps,
2171
+ onDragStart: updateXarrow,
2172
+ id: `${field.identifier}-card`,
2188
2173
  mb: "4",
2189
2174
  children: /* @__PURE__ */ jsxs(Flex, { gap: "4", justify: "between", align: "center", children: [
2190
2175
  input,
@@ -2194,20 +2179,91 @@ const FieldWithActions = memo(function FieldWithActions2(props) {
2194
2179
  remove: remove2,
2195
2180
  editProps: editFieldProps,
2196
2181
  duplicateProps: duplicateFieldProps,
2197
- insertAfterProps,
2198
- dragHandleProps: draggableProvided.dragHandleProps
2182
+ insertAfterProps
2199
2183
  }
2200
2184
  )
2201
2185
  ] })
2202
2186
  }
2203
2187
  ) });
2204
2188
  });
2189
+ const ArrowSpacingDiv = memo(function ArrowSpacingDiv2(props) {
2190
+ const { identifier, index, conditionalFieldCounts } = props;
2191
+ const HORIZONTAL_SPACE = 3;
2192
+ const totalConditionals = conditionalFieldCounts.filter((count) => count !== null).length;
2193
+ const conditionalNum = conditionalFieldCounts[index] ?? 0;
2194
+ const marginLeft = HORIZONTAL_SPACE / totalConditionals * conditionalNum;
2195
+ return /* @__PURE__ */ jsx(
2196
+ "div",
2197
+ {
2198
+ id: `${identifier}-floating-point`,
2199
+ style: {
2200
+ width: `${HORIZONTAL_SPACE - marginLeft}%`,
2201
+ marginLeft: `${marginLeft}%`
2202
+ }
2203
+ }
2204
+ );
2205
+ });
2206
+ const ConditionalArrow = (props) => {
2207
+ const { identifier, condition } = props;
2208
+ const primaryColor = "var(--gray-a4)";
2209
+ const hoverColor = "var(--primary-color)";
2210
+ const [color, setColor] = useState(primaryColor);
2211
+ const [zIndex, setZIndex] = useState(0);
2212
+ const handleMouseEnter = useCallback(() => {
2213
+ setColor(hoverColor);
2214
+ setZIndex(1);
2215
+ }, [hoverColor]);
2216
+ const handleMouseLeave = useCallback(() => {
2217
+ setColor(primaryColor);
2218
+ setZIndex(0);
2219
+ }, [primaryColor]);
2220
+ const settings = useMemo(() => {
2221
+ return {
2222
+ strokeWidth: 1,
2223
+ showHead: false,
2224
+ color,
2225
+ zIndex,
2226
+ arrowBodyProps: {
2227
+ onMouseEnter: handleMouseEnter,
2228
+ onMouseLeave: handleMouseLeave
2229
+ }
2230
+ };
2231
+ }, [color, handleMouseEnter, handleMouseLeave, zIndex]);
2232
+ if (!condition)
2233
+ return null;
2234
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
2235
+ /* @__PURE__ */ jsx(
2236
+ Xarrow,
2237
+ {
2238
+ start: `${identifier}-card`,
2239
+ end: `${identifier}-floating-point`,
2240
+ startAnchor: "right",
2241
+ endAnchor: "left",
2242
+ path: "straight",
2243
+ ...settings
2244
+ }
2245
+ ),
2246
+ /* @__PURE__ */ jsx(
2247
+ Xarrow,
2248
+ {
2249
+ start: `${identifier}-floating-point`,
2250
+ end: `${condition.identifier}-card`,
2251
+ startAnchor: "left",
2252
+ endAnchor: "right",
2253
+ path: "grid",
2254
+ gridBreak: "0",
2255
+ ...settings
2256
+ }
2257
+ )
2258
+ ] });
2259
+ };
2205
2260
  const FieldSectionWithActions = memo(function FieldSectionWithActions2(props) {
2206
2261
  var _a, _b, _c, _d, _e, _f, _g, _h, _i;
2207
- const { field, index: sectionIndex, dropState } = props;
2262
+ const { field, index: sectionIndex, dropState, conditionalFieldCounts } = props;
2208
2263
  const isDropDisabled = (_a = dropState[field.identifier]) == null ? void 0 : _a.disabled;
2209
2264
  const { setFieldValue, values } = useFormikContext();
2210
2265
  const alertDialog = useAlertDialog();
2266
+ const updateXarrow = useXarrow();
2211
2267
  const takenFieldLabels = getTakenFieldLabels(values.fields);
2212
2268
  const removeSectionConditions = useCallback(
2213
2269
  (sectionsToUpdate, allSections) => {
@@ -2358,64 +2414,95 @@ const FieldSectionWithActions = memo(function FieldSectionWithActions2(props) {
2358
2414
  throw new Error("File values are not supported for conditions.");
2359
2415
  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();
2360
2416
  return /* @__PURE__ */ jsx(Draggable, { draggableId: field.identifier, index: sectionIndex, children: (draggableProvided) => /* @__PURE__ */ jsx(
2361
- Card,
2417
+ Flex,
2362
2418
  {
2419
+ className: styles$3.sectionContainer,
2363
2420
  ref: draggableProvided.innerRef,
2364
2421
  ...draggableProvided.draggableProps,
2365
- ...draggableProvided.dragHandleProps,
2422
+ direction: "row",
2423
+ justify: "center",
2424
+ align: "center",
2366
2425
  mb: "4",
2367
- children: /* @__PURE__ */ jsxs(Flex, { gap: "3", justify: "between", align: "center", children: [
2368
- /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: "2", grow: "1", children: [
2369
- /* @__PURE__ */ jsxs(Flex, { direction: "column", children: [
2370
- /* @__PURE__ */ jsx(Heading, { as: "h3", size: "3", children: field.label }),
2371
- /* @__PURE__ */ jsx(Text, { className: styles$3.description, children: field.description })
2372
- ] }),
2373
- field.condition && /* @__PURE__ */ jsx(Text, { size: "1", children: /* @__PURE__ */ jsxs(Em, { children: [
2374
- "Display only if ",
2375
- /* @__PURE__ */ jsx(Strong, { children: conditionLabel }),
2376
- " ",
2377
- conditionComparison,
2378
- " ",
2379
- /* @__PURE__ */ jsx(Strong, { children: conditionValue })
2380
- ] }) }),
2381
- /* @__PURE__ */ jsx(Droppable, { droppableId: field.identifier, type: "SECTION", isDropDisabled, children: (droppableProvided) => /* @__PURE__ */ jsxs(
2382
- Flex,
2383
- {
2384
- ref: droppableProvided.innerRef,
2385
- ...droppableProvided.droppableProps,
2386
- direction: "column",
2387
- gap: "0",
2388
- children: [
2389
- field.fields.map((child, i) => /* @__PURE__ */ jsx(
2390
- FieldWithActions,
2391
- {
2392
- field: child,
2393
- index: i,
2394
- sectionIndex,
2395
- remove: () => removeField(i),
2396
- takenLabels: takenFieldLabels
2397
- },
2398
- child.identifier
2399
- )),
2400
- droppableProvided.placeholder,
2401
- /* @__PURE__ */ jsx(FieldBuilder, { ...insertFieldAtEndOfSection, children: /* @__PURE__ */ jsxs(Button, { type: "button", variant: "outline", children: [
2402
- /* @__PURE__ */ jsx(PlusIcon, {}),
2403
- " Add a field"
2404
- ] }) })
2405
- ]
2406
- }
2407
- ) })
2408
- ] }),
2426
+ children: /* @__PURE__ */ jsxs(Xwrapper, { children: [
2409
2427
  /* @__PURE__ */ jsx(
2410
- FieldActions,
2428
+ Card,
2429
+ {
2430
+ ...draggableProvided.dragHandleProps,
2431
+ onDragStart: updateXarrow,
2432
+ id: `${field.identifier}-card`,
2433
+ style: { flexGrow: "1" },
2434
+ children: /* @__PURE__ */ jsxs(Flex, { gap: "3", justify: "between", align: "center", children: [
2435
+ /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: "2", grow: "1", children: [
2436
+ /* @__PURE__ */ jsxs(Flex, { direction: "column", children: [
2437
+ /* @__PURE__ */ jsx(Heading, { as: "h3", size: "3", children: field.label }),
2438
+ /* @__PURE__ */ jsx(Text, { className: styles$3.description, children: field.description })
2439
+ ] }),
2440
+ field.condition && /* @__PURE__ */ jsx(Text, { size: "1", children: /* @__PURE__ */ jsxs(Em, { children: [
2441
+ "Display only if ",
2442
+ /* @__PURE__ */ jsx(Strong, { children: conditionLabel }),
2443
+ " ",
2444
+ conditionComparison,
2445
+ " ",
2446
+ /* @__PURE__ */ jsx(Strong, { children: conditionValue })
2447
+ ] }) }),
2448
+ /* @__PURE__ */ jsx(
2449
+ Droppable,
2450
+ {
2451
+ droppableId: field.identifier,
2452
+ type: "SECTION",
2453
+ isDropDisabled,
2454
+ children: (droppableProvided) => /* @__PURE__ */ jsxs(
2455
+ Flex,
2456
+ {
2457
+ ref: droppableProvided.innerRef,
2458
+ ...droppableProvided.droppableProps,
2459
+ direction: "column",
2460
+ gap: "0",
2461
+ children: [
2462
+ field.fields.map((child, i) => /* @__PURE__ */ jsx(
2463
+ FieldWithActions,
2464
+ {
2465
+ field: child,
2466
+ index: i,
2467
+ sectionIndex,
2468
+ remove: () => removeField(i),
2469
+ takenLabels: takenFieldLabels
2470
+ },
2471
+ child.identifier
2472
+ )),
2473
+ droppableProvided.placeholder,
2474
+ /* @__PURE__ */ jsx(FieldBuilder, { ...insertFieldAtEndOfSection, children: /* @__PURE__ */ jsxs(Button, { type: "button", variant: "outline", children: [
2475
+ /* @__PURE__ */ jsx(PlusIcon, {}),
2476
+ " Add a field"
2477
+ ] }) })
2478
+ ]
2479
+ }
2480
+ )
2481
+ }
2482
+ )
2483
+ ] }),
2484
+ /* @__PURE__ */ jsx(
2485
+ FieldActions,
2486
+ {
2487
+ remove: removeSection,
2488
+ insertAfterProps: insertSectionProps,
2489
+ editProps: editSectionProps,
2490
+ duplicateProps: duplicateSectionProps,
2491
+ type: "section"
2492
+ }
2493
+ )
2494
+ ] })
2495
+ }
2496
+ ),
2497
+ conditionalFieldCounts.some((count) => count !== null) && /* @__PURE__ */ jsx(
2498
+ ArrowSpacingDiv,
2411
2499
  {
2412
- remove: removeSection,
2413
- insertAfterProps: insertSectionProps,
2414
- dragHandleProps: draggableProvided.dragHandleProps,
2415
- editProps: editSectionProps,
2416
- duplicateProps: duplicateSectionProps
2500
+ identifier: field.identifier,
2501
+ index: sectionIndex,
2502
+ conditionalFieldCounts
2417
2503
  }
2418
- )
2504
+ ),
2505
+ field.condition && /* @__PURE__ */ jsx(ConditionalArrow, { identifier: field.identifier, condition: field.condition })
2419
2506
  ] })
2420
2507
  }
2421
2508
  ) });
@@ -2553,6 +2640,12 @@ const FieldsEditor = memo(function FieldsEditor2() {
2553
2640
  }),
2554
2641
  [values.fields]
2555
2642
  );
2643
+ const conditionalFieldCounts = () => {
2644
+ let conditionalCount = 1;
2645
+ return values.fields.map((field) => {
2646
+ return field.conditional ? conditionalCount++ : null;
2647
+ });
2648
+ };
2556
2649
  return /* @__PURE__ */ jsx(DragDropContext, { onDragStart: handleDragStart, onDragEnd: handleDragEnd, children: /* @__PURE__ */ jsx(Droppable, { droppableId: "droppable", type: "ROOT", children: (droppableProvided) => /* @__PURE__ */ jsxs(
2557
2650
  Flex,
2558
2651
  {
@@ -2566,7 +2659,8 @@ const FieldsEditor = memo(function FieldsEditor2() {
2566
2659
  {
2567
2660
  field,
2568
2661
  index,
2569
- dropState
2662
+ dropState,
2663
+ conditionalFieldCounts: conditionalFieldCounts()
2570
2664
  },
2571
2665
  field.label
2572
2666
  )),