@overmap-ai/forms 1.0.9 → 1.0.10-conditional-arrows-2.1

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,39 @@ 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
+ const actionItems = actions.map((Action) => {
2106
+ var _a;
2107
+ const Wrapper = Action.Wrapper ?? DefaultWrapper;
2108
+ return {
2109
+ ...Action.buttonProps,
2110
+ onSelect: (_a = Action.buttonProps) == null ? void 0 : _a.onClick,
2111
+ content: /* @__PURE__ */ jsx(Wrapper, { ...Action.wrapperProps, children: /* @__PURE__ */ jsxs(Flex, { gap: "2", align: "center", children: [
2112
+ /* @__PURE__ */ jsx(Action.Icon, {}),
2113
+ Action.text
2114
+ ] }) })
2115
+ };
2116
+ });
2117
+ console.log(actionItems);
2118
+ return /* @__PURE__ */ jsx(Box, { display: "block", children: /* @__PURE__ */ jsx(
2119
+ DropdownMenu,
2120
+ {
2121
+ trigger: /* @__PURE__ */ jsx(IconButton, { variant: "ghost", "aria-label": "Actions menu", children: /* @__PURE__ */ jsx(DotsVerticalIcon, {}) }),
2122
+ closeOnSelect: false,
2123
+ items: actionItems
2124
+ }
2125
+ ) });
2142
2126
  });
2143
2127
  const formId = "form-builder";
2144
2128
  const FieldWithActions = memo(function FieldWithActions2(props) {
2145
2129
  const { field, index, sectionIndex, takenLabels, remove: remove2 } = props;
2146
2130
  const deserializedField = useMemo(() => deserialize(field), [field]);
2147
2131
  const input = useFieldInput(deserializedField, { formId, disabled: true });
2132
+ const updateXarrow = useXarrow();
2148
2133
  const duplicateField = useCallback(
2149
2134
  (field2) => {
2150
2135
  if (field2.label === null) {
@@ -2185,6 +2170,8 @@ const FieldWithActions = memo(function FieldWithActions2(props) {
2185
2170
  ref: draggableProvided.innerRef,
2186
2171
  ...draggableProvided.draggableProps,
2187
2172
  ...draggableProvided.dragHandleProps,
2173
+ onDragStart: updateXarrow,
2174
+ id: `${field.identifier}-card`,
2188
2175
  mb: "4",
2189
2176
  children: /* @__PURE__ */ jsxs(Flex, { gap: "4", justify: "between", align: "center", children: [
2190
2177
  input,
@@ -2194,20 +2181,91 @@ const FieldWithActions = memo(function FieldWithActions2(props) {
2194
2181
  remove: remove2,
2195
2182
  editProps: editFieldProps,
2196
2183
  duplicateProps: duplicateFieldProps,
2197
- insertAfterProps,
2198
- dragHandleProps: draggableProvided.dragHandleProps
2184
+ insertAfterProps
2199
2185
  }
2200
2186
  )
2201
2187
  ] })
2202
2188
  }
2203
2189
  ) });
2204
2190
  });
2191
+ const ArrowSpacingDiv = memo(function ArrowSpacingDiv2(props) {
2192
+ const { identifier, index, conditionalFieldCounts } = props;
2193
+ const HORIZONTAL_SPACE = 3;
2194
+ const totalConditionals = conditionalFieldCounts.filter((count) => count !== null).length;
2195
+ const conditionalNum = conditionalFieldCounts[index] ?? 0;
2196
+ const marginLeft = HORIZONTAL_SPACE / totalConditionals * conditionalNum;
2197
+ return /* @__PURE__ */ jsx(
2198
+ "div",
2199
+ {
2200
+ id: `${identifier}-floating-point`,
2201
+ style: {
2202
+ width: `${HORIZONTAL_SPACE - marginLeft}%`,
2203
+ marginLeft: `${marginLeft}%`
2204
+ }
2205
+ }
2206
+ );
2207
+ });
2208
+ const ConditionalArrow = (props) => {
2209
+ const { identifier, condition } = props;
2210
+ const primaryColor = "var(--gray-a4)";
2211
+ const hoverColor = "var(--primary-color)";
2212
+ const [color, setColor] = useState(primaryColor);
2213
+ const [zIndex, setZIndex] = useState(0);
2214
+ const handleMouseEnter = useCallback(() => {
2215
+ setColor(hoverColor);
2216
+ setZIndex(1);
2217
+ }, [hoverColor]);
2218
+ const handleMouseLeave = useCallback(() => {
2219
+ setColor(primaryColor);
2220
+ setZIndex(0);
2221
+ }, [primaryColor]);
2222
+ const settings = useMemo(() => {
2223
+ return {
2224
+ strokeWidth: 1,
2225
+ showHead: false,
2226
+ color,
2227
+ zIndex,
2228
+ arrowBodyProps: {
2229
+ onMouseEnter: handleMouseEnter,
2230
+ onMouseLeave: handleMouseLeave
2231
+ }
2232
+ };
2233
+ }, [color, handleMouseEnter, handleMouseLeave, zIndex]);
2234
+ if (!condition)
2235
+ return null;
2236
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
2237
+ /* @__PURE__ */ jsx(
2238
+ Xarrow,
2239
+ {
2240
+ start: `${identifier}-card`,
2241
+ end: `${identifier}-floating-point`,
2242
+ startAnchor: "right",
2243
+ endAnchor: "left",
2244
+ path: "straight",
2245
+ ...settings
2246
+ }
2247
+ ),
2248
+ /* @__PURE__ */ jsx(
2249
+ Xarrow,
2250
+ {
2251
+ start: `${identifier}-floating-point`,
2252
+ end: `${condition.identifier}-card`,
2253
+ startAnchor: "left",
2254
+ endAnchor: "right",
2255
+ path: "grid",
2256
+ gridBreak: "0",
2257
+ ...settings
2258
+ }
2259
+ )
2260
+ ] });
2261
+ };
2205
2262
  const FieldSectionWithActions = memo(function FieldSectionWithActions2(props) {
2206
2263
  var _a, _b, _c, _d, _e, _f, _g, _h, _i;
2207
- const { field, index: sectionIndex, dropState } = props;
2264
+ const { field, index: sectionIndex, dropState, conditionalFieldCounts } = props;
2208
2265
  const isDropDisabled = (_a = dropState[field.identifier]) == null ? void 0 : _a.disabled;
2209
2266
  const { setFieldValue, values } = useFormikContext();
2210
2267
  const alertDialog = useAlertDialog();
2268
+ const updateXarrow = useXarrow();
2211
2269
  const takenFieldLabels = getTakenFieldLabels(values.fields);
2212
2270
  const removeSectionConditions = useCallback(
2213
2271
  (sectionsToUpdate, allSections) => {
@@ -2358,64 +2416,95 @@ const FieldSectionWithActions = memo(function FieldSectionWithActions2(props) {
2358
2416
  throw new Error("File values are not supported for conditions.");
2359
2417
  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
2418
  return /* @__PURE__ */ jsx(Draggable, { draggableId: field.identifier, index: sectionIndex, children: (draggableProvided) => /* @__PURE__ */ jsx(
2361
- Card,
2419
+ Flex,
2362
2420
  {
2421
+ className: styles$3.sectionContainer,
2363
2422
  ref: draggableProvided.innerRef,
2364
2423
  ...draggableProvided.draggableProps,
2365
- ...draggableProvided.dragHandleProps,
2424
+ direction: "row",
2425
+ justify: "center",
2426
+ align: "center",
2366
2427
  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
- ] }),
2428
+ children: /* @__PURE__ */ jsxs(Xwrapper, { children: [
2409
2429
  /* @__PURE__ */ jsx(
2410
- FieldActions,
2430
+ Card,
2411
2431
  {
2412
- remove: removeSection,
2413
- insertAfterProps: insertSectionProps,
2414
- dragHandleProps: draggableProvided.dragHandleProps,
2415
- editProps: editSectionProps,
2416
- duplicateProps: duplicateSectionProps
2432
+ ...draggableProvided.dragHandleProps,
2433
+ onDragStart: updateXarrow,
2434
+ id: `${field.identifier}-card`,
2435
+ style: { flexGrow: "1" },
2436
+ children: /* @__PURE__ */ jsxs(Flex, { gap: "3", justify: "between", align: "center", children: [
2437
+ /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: "2", grow: "1", children: [
2438
+ /* @__PURE__ */ jsxs(Flex, { direction: "column", children: [
2439
+ /* @__PURE__ */ jsx(Heading, { as: "h3", size: "3", children: field.label }),
2440
+ /* @__PURE__ */ jsx(Text, { className: styles$3.description, children: field.description })
2441
+ ] }),
2442
+ field.condition && /* @__PURE__ */ jsx(Text, { size: "1", children: /* @__PURE__ */ jsxs(Em, { children: [
2443
+ "Display only if ",
2444
+ /* @__PURE__ */ jsx(Strong, { children: conditionLabel }),
2445
+ " ",
2446
+ conditionComparison,
2447
+ " ",
2448
+ /* @__PURE__ */ jsx(Strong, { children: conditionValue })
2449
+ ] }) }),
2450
+ /* @__PURE__ */ jsx(
2451
+ Droppable,
2452
+ {
2453
+ droppableId: field.identifier,
2454
+ type: "SECTION",
2455
+ isDropDisabled,
2456
+ children: (droppableProvided) => /* @__PURE__ */ jsxs(
2457
+ Flex,
2458
+ {
2459
+ ref: droppableProvided.innerRef,
2460
+ ...droppableProvided.droppableProps,
2461
+ direction: "column",
2462
+ gap: "0",
2463
+ children: [
2464
+ field.fields.map((child, i) => /* @__PURE__ */ jsx(
2465
+ FieldWithActions,
2466
+ {
2467
+ field: child,
2468
+ index: i,
2469
+ sectionIndex,
2470
+ remove: () => removeField(i),
2471
+ takenLabels: takenFieldLabels
2472
+ },
2473
+ child.identifier
2474
+ )),
2475
+ droppableProvided.placeholder,
2476
+ /* @__PURE__ */ jsx(FieldBuilder, { ...insertFieldAtEndOfSection, children: /* @__PURE__ */ jsxs(Button, { type: "button", variant: "outline", children: [
2477
+ /* @__PURE__ */ jsx(PlusIcon, {}),
2478
+ " Add a field"
2479
+ ] }) })
2480
+ ]
2481
+ }
2482
+ )
2483
+ }
2484
+ )
2485
+ ] }),
2486
+ /* @__PURE__ */ jsx(
2487
+ FieldActions,
2488
+ {
2489
+ remove: removeSection,
2490
+ insertAfterProps: insertSectionProps,
2491
+ editProps: editSectionProps,
2492
+ duplicateProps: duplicateSectionProps,
2493
+ type: "section"
2494
+ }
2495
+ )
2496
+ ] })
2417
2497
  }
2418
- )
2498
+ ),
2499
+ conditionalFieldCounts.some((count) => count !== null) && /* @__PURE__ */ jsx(
2500
+ ArrowSpacingDiv,
2501
+ {
2502
+ identifier: field.identifier,
2503
+ index: sectionIndex,
2504
+ conditionalFieldCounts
2505
+ }
2506
+ ),
2507
+ field.condition && /* @__PURE__ */ jsx(ConditionalArrow, { identifier: field.identifier, condition: field.condition })
2419
2508
  ] })
2420
2509
  }
2421
2510
  ) });
@@ -2553,6 +2642,12 @@ const FieldsEditor = memo(function FieldsEditor2() {
2553
2642
  }),
2554
2643
  [values.fields]
2555
2644
  );
2645
+ const conditionalFieldCounts = () => {
2646
+ let conditionalCount = 1;
2647
+ return values.fields.map((field) => {
2648
+ return field.conditional ? conditionalCount++ : null;
2649
+ });
2650
+ };
2556
2651
  return /* @__PURE__ */ jsx(DragDropContext, { onDragStart: handleDragStart, onDragEnd: handleDragEnd, children: /* @__PURE__ */ jsx(Droppable, { droppableId: "droppable", type: "ROOT", children: (droppableProvided) => /* @__PURE__ */ jsxs(
2557
2652
  Flex,
2558
2653
  {
@@ -2566,7 +2661,8 @@ const FieldsEditor = memo(function FieldsEditor2() {
2566
2661
  {
2567
2662
  field,
2568
2663
  index,
2569
- dropState
2664
+ dropState,
2665
+ conditionalFieldCounts: conditionalFieldCounts()
2570
2666
  },
2571
2667
  field.label
2572
2668
  )),