@overmap-ai/core 1.0.32 → 1.0.33-revamp-forms-builder.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.
Files changed (37) hide show
  1. package/dist/forms/builder/FieldActions.d.ts +8 -7
  2. package/dist/forms/builder/FieldBuilder.d.ts +5 -18
  3. package/dist/forms/builder/FieldSectionWithActions.d.ts +2 -2
  4. package/dist/forms/builder/FieldWithActions.d.ts +1 -1
  5. package/dist/forms/builder/FieldsEditor.d.ts +1 -1
  6. package/dist/forms/builder/FormBuilder.d.ts +1 -5
  7. package/dist/forms/builder/componentConstants.d.ts +8 -0
  8. package/dist/forms/builder/utils.d.ts +13 -1
  9. package/dist/forms/fields/BaseField/BaseField.d.ts +15 -5
  10. package/dist/forms/fields/BaseField/hooks.d.ts +2 -1
  11. package/dist/forms/fields/BaseField/layouts.d.ts +7 -2
  12. package/dist/forms/fields/BooleanField/BooleanField.d.ts +6 -0
  13. package/dist/forms/fields/CustomField/CustomField.d.ts +6 -0
  14. package/dist/forms/fields/DateField/DateField.d.ts +6 -0
  15. package/dist/forms/fields/FieldSection/FieldSection.d.ts +12 -6
  16. package/dist/forms/fields/MultiStringField/MultiStringField.d.ts +8 -0
  17. package/dist/forms/fields/NumberField/NumberField.d.ts +18 -3
  18. package/dist/forms/fields/SelectField/BaseSelectField.d.ts +4 -1
  19. package/dist/forms/fields/SelectField/MultiSelectField.d.ts +7 -0
  20. package/dist/forms/fields/SelectField/SelectField.d.ts +7 -0
  21. package/dist/forms/fields/StringOrTextFields/StringField/StringField.d.ts +8 -0
  22. package/dist/forms/fields/StringOrTextFields/StringOrTextField.d.ts +8 -5
  23. package/dist/forms/fields/StringOrTextFields/TextField/TextField.d.ts +7 -0
  24. package/dist/forms/fields/UploadField/UploadField.d.ts +16 -1
  25. package/dist/forms/fields/constants.d.ts +75 -0
  26. package/dist/forms/fields/typings.d.ts +4 -1
  27. package/dist/forms/fields/utils.d.ts +3 -1
  28. package/dist/forms/renderer/PatchForm/Field.d.ts +3 -1
  29. package/dist/forms/renderer/PatchForm/Provider.d.ts +2 -1
  30. package/dist/forms/utils.d.ts +2 -1
  31. package/dist/overmap-core.js +1395 -1028
  32. package/dist/overmap-core.js.map +1 -1
  33. package/dist/overmap-core.umd.cjs +1391 -1024
  34. package/dist/overmap-core.umd.cjs.map +1 -1
  35. package/dist/style.css +2 -0
  36. package/package.json +2 -2
  37. package/dist/forms/builder/constants.d.ts +0 -1
@@ -8,7 +8,7 @@ var _a;
8
8
  import * as React from "react";
9
9
  import React__default, { useState, useEffect, useRef, memo, useMemo, forwardRef, createElement, useCallback, createContext, useContext, Children, isValidElement, cloneElement, Fragment, useLayoutEffect, useReducer } from "react";
10
10
  import { jsx, jsxs, Fragment as Fragment$1 } from "react/jsx-runtime";
11
- import { unsafeShowToast, AlertDialogProvider, ToastProvider, DefaultTheme, Flex, Text, useSeverityColor, Checkbox, TextArea, Select, IconButton, Badge, MultiSelect, Button, ButtonList, divButtonProps, Tooltip, Separator, useDiscardAlertDialog, Dialog, DropdownItemMenu, useAlertDialog, useToast } from "@overmap-ai/blocks";
11
+ import { unsafeShowToast, AlertDialogProvider, ToastProvider, DefaultTheme, Flex, Text, useSeverityColor, Checkbox, TextArea, Select, useToast, IconButton, Badge, MultiSelect, Button, ButtonList, divButtonProps, Tooltip, DropdownItemMenu, DropdownMenu, DropdownMenuItemGroup, DropdownMenuSubMenuGroup, Popover, Input, useAlertDialog } from "@overmap-ai/blocks";
12
12
  import { DepGraph } from "dependency-graph";
13
13
  import { offline as offline$1 } from "@redux-offline/redux-offline";
14
14
  import offlineConfig from "@redux-offline/redux-offline/lib/defaults";
@@ -23,9 +23,9 @@ import jwtDecode from "jwt-decode";
23
23
  import { RESET_STATE } from "@redux-offline/redux-offline/lib/constants";
24
24
  import { openDB } from "idb";
25
25
  import { useField, useFormikContext, useFormik, FormikProvider } from "formik";
26
+ import get from "lodash.get";
26
27
  import Linkify from "linkify-react";
27
28
  import { DragDropContext, Droppable, Draggable } from "@hello-pangea/dnd";
28
- import get from "lodash.get";
29
29
  import set from "lodash.set";
30
30
  import cloneDeep from "lodash.clonedeep";
31
31
  import { flushSync } from "react-dom";
@@ -375,7 +375,7 @@ function Item(fun, array) {
375
375
  Item.prototype.run = function() {
376
376
  this.fun.apply(null, this.array);
377
377
  };
378
- var title$1 = "browser";
378
+ var title = "browser";
379
379
  var platform = "browser";
380
380
  var browser = true;
381
381
  var env = {};
@@ -431,7 +431,7 @@ function uptime() {
431
431
  }
432
432
  var browser$1 = {
433
433
  nextTick,
434
- title: title$1,
434
+ title,
435
435
  browser,
436
436
  env,
437
437
  argv,
@@ -4394,7 +4394,7 @@ class ComponentService extends BaseApiService {
4394
4394
  });
4395
4395
  return promise;
4396
4396
  }
4397
- async refreshStore(replace2) {
4397
+ async refreshStore(replace) {
4398
4398
  const { store } = this.client;
4399
4399
  const result = await this.enqueueRequest({
4400
4400
  description: "Get components",
@@ -4403,7 +4403,7 @@ class ComponentService extends BaseApiService {
4403
4403
  blockers: [],
4404
4404
  blocks: []
4405
4405
  });
4406
- if (replace2) {
4406
+ if (replace) {
4407
4407
  store.dispatch(setComponents(result));
4408
4408
  } else {
4409
4409
  store.dispatch(addComponentsInBatches(result));
@@ -6116,6 +6116,11 @@ class BaseFormElement {
6116
6116
  };
6117
6117
  }
6118
6118
  }
6119
+ const emptyBaseField = {
6120
+ label: "",
6121
+ required: false,
6122
+ description: ""
6123
+ };
6119
6124
  class BaseField extends BaseFormElement {
6120
6125
  constructor(options) {
6121
6126
  const { label, required, fieldValidators = [], formValidators = [], ...base } = options;
@@ -6180,25 +6185,29 @@ class BaseField extends BaseFormElement {
6180
6185
  __publicField(BaseField, "fieldTypeName");
6181
6186
  __publicField(BaseField, "fieldTypeDescription");
6182
6187
  const description$1 = "_description_17zed_1";
6183
- const styles$4 = {
6188
+ const styles$5 = {
6184
6189
  description: description$1
6185
6190
  };
6186
6191
  const InputWithLabel = (props) => {
6187
- const { label, children, severity, inputId, labelId, flexProps } = props;
6192
+ const { label, children, size, severity, inputId, labelId, flexProps } = props;
6188
6193
  return /* @__PURE__ */ jsx(Flex, { direction: "column", gap: "1", asChild: true, ...flexProps, children: /* @__PURE__ */ jsxs("label", { htmlFor: inputId, children: [
6189
- /* @__PURE__ */ jsx(Text, { severity, id: labelId, children: label }),
6194
+ /* @__PURE__ */ jsx(Text, { size, severity, id: labelId, children: label }),
6190
6195
  children
6191
6196
  ] }) });
6192
6197
  };
6193
- const InputWithLabelAndHelpText = (props) => {
6198
+ const InputWithHelpText = (props) => {
6194
6199
  const { helpText, children, severity } = props;
6195
6200
  return /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: "1", children: [
6196
6201
  children,
6197
- /* @__PURE__ */ jsx(Flex, { direction: "column", children: /* @__PURE__ */ jsx(Text, { size: "1", severity, className: styles$4.description, children: helpText }) })
6202
+ /* @__PURE__ */ jsx(Flex, { direction: "column", children: /* @__PURE__ */ jsx(Text, { size: "1", severity, className: styles$5.description, children: helpText }) })
6198
6203
  ] });
6199
6204
  };
6205
+ const InputWithLabelAndHelpText = (props) => {
6206
+ const { children, ...restProps } = props;
6207
+ return /* @__PURE__ */ jsx(InputWithHelpText, { ...restProps, children });
6208
+ };
6200
6209
  const useFormikInput = (props) => {
6201
- const { id, field, formId: formId2, ...rest } = props;
6210
+ const { id, field, formId: formId2, size, ...rest } = props;
6202
6211
  const [fieldProps, meta, helpers] = useField(field.getId());
6203
6212
  const { touched } = meta;
6204
6213
  const helpText = meta.error ?? field.description;
@@ -6227,6 +6236,7 @@ const useFormikInput = (props) => {
6227
6236
  return [
6228
6237
  {
6229
6238
  helpText,
6239
+ size,
6230
6240
  severity,
6231
6241
  inputId,
6232
6242
  labelId,
@@ -6240,12 +6250,13 @@ const useFormikInput = (props) => {
6240
6250
  };
6241
6251
  const truthyValues = [true, "true"];
6242
6252
  const BooleanInput = memo(function BooleanInput2(props) {
6243
- const [{ inputId, labelId, severity, helpText, label, fieldProps }, rest] = useFormikInput(props);
6253
+ const [{ inputId, labelId, size, severity, helpText, label, fieldProps }, rest] = useFormikInput(props);
6244
6254
  const color = useSeverityColor(severity);
6245
6255
  const value = truthyValues.includes(fieldProps.value);
6246
6256
  return /* @__PURE__ */ jsx(InputWithLabelAndHelpText, { helpText, severity, children: /* @__PURE__ */ jsx(
6247
6257
  InputWithLabel,
6248
6258
  {
6259
+ size,
6249
6260
  severity,
6250
6261
  inputId,
6251
6262
  labelId,
@@ -6261,6 +6272,7 @@ const BooleanInput = memo(function BooleanInput2(props) {
6261
6272
  value: value.toString(),
6262
6273
  checked: value,
6263
6274
  onCheckedChange: fieldProps.onChange,
6275
+ alwaysShow: true,
6264
6276
  onChange: void 0,
6265
6277
  onBlur: void 0
6266
6278
  }
@@ -6282,6 +6294,42 @@ function _objectWithoutPropertiesLoose(source, excluded) {
6282
6294
  }
6283
6295
  return target;
6284
6296
  }
6297
+ var _excluded$e = ["color"];
6298
+ var ArrowDownIcon = /* @__PURE__ */ forwardRef(function(_ref, forwardedRef) {
6299
+ var _ref$color = _ref.color, color = _ref$color === void 0 ? "currentColor" : _ref$color, props = _objectWithoutPropertiesLoose(_ref, _excluded$e);
6300
+ return createElement("svg", Object.assign({
6301
+ width: "15",
6302
+ height: "15",
6303
+ viewBox: "0 0 15 15",
6304
+ fill: "none",
6305
+ xmlns: "http://www.w3.org/2000/svg"
6306
+ }, props, {
6307
+ ref: forwardedRef
6308
+ }), createElement("path", {
6309
+ d: "M7.5 2C7.77614 2 8 2.22386 8 2.5L8 11.2929L11.1464 8.14645C11.3417 7.95118 11.6583 7.95118 11.8536 8.14645C12.0488 8.34171 12.0488 8.65829 11.8536 8.85355L7.85355 12.8536C7.75979 12.9473 7.63261 13 7.5 13C7.36739 13 7.24021 12.9473 7.14645 12.8536L3.14645 8.85355C2.95118 8.65829 2.95118 8.34171 3.14645 8.14645C3.34171 7.95118 3.65829 7.95118 3.85355 8.14645L7 11.2929L7 2.5C7 2.22386 7.22386 2 7.5 2Z",
6310
+ fill: color,
6311
+ fillRule: "evenodd",
6312
+ clipRule: "evenodd"
6313
+ }));
6314
+ });
6315
+ var _excluded$j = ["color"];
6316
+ var ArrowUpIcon = /* @__PURE__ */ forwardRef(function(_ref, forwardedRef) {
6317
+ var _ref$color = _ref.color, color = _ref$color === void 0 ? "currentColor" : _ref$color, props = _objectWithoutPropertiesLoose(_ref, _excluded$j);
6318
+ return createElement("svg", Object.assign({
6319
+ width: "15",
6320
+ height: "15",
6321
+ viewBox: "0 0 15 15",
6322
+ fill: "none",
6323
+ xmlns: "http://www.w3.org/2000/svg"
6324
+ }, props, {
6325
+ ref: forwardedRef
6326
+ }), createElement("path", {
6327
+ d: "M7.14645 2.14645C7.34171 1.95118 7.65829 1.95118 7.85355 2.14645L11.8536 6.14645C12.0488 6.34171 12.0488 6.65829 11.8536 6.85355C11.6583 7.04882 11.3417 7.04882 11.1464 6.85355L8 3.70711L8 12.5C8 12.7761 7.77614 13 7.5 13C7.22386 13 7 12.7761 7 12.5L7 3.70711L3.85355 6.85355C3.65829 7.04882 3.34171 7.04882 3.14645 6.85355C2.95118 6.65829 2.95118 6.34171 3.14645 6.14645L7.14645 2.14645Z",
6328
+ fill: color,
6329
+ fillRule: "evenodd",
6330
+ clipRule: "evenodd"
6331
+ }));
6332
+ });
6285
6333
  var _excluded$I = ["color"];
6286
6334
  var CalendarIcon = /* @__PURE__ */ forwardRef(function(_ref, forwardedRef) {
6287
6335
  var _ref$color = _ref.color, color = _ref$color === void 0 ? "currentColor" : _ref$color, props = _objectWithoutPropertiesLoose(_ref, _excluded$I);
@@ -6390,24 +6438,6 @@ var DotsVerticalIcon = /* @__PURE__ */ forwardRef(function(_ref, forwardedRef) {
6390
6438
  clipRule: "evenodd"
6391
6439
  }));
6392
6440
  });
6393
- var _excluded$1R = ["color"];
6394
- var DragHandleDots2Icon = /* @__PURE__ */ forwardRef(function(_ref, forwardedRef) {
6395
- var _ref$color = _ref.color, color = _ref$color === void 0 ? "currentColor" : _ref$color, props = _objectWithoutPropertiesLoose(_ref, _excluded$1R);
6396
- return createElement("svg", Object.assign({
6397
- width: "15",
6398
- height: "15",
6399
- viewBox: "0 0 15 15",
6400
- fill: "none",
6401
- xmlns: "http://www.w3.org/2000/svg"
6402
- }, props, {
6403
- ref: forwardedRef
6404
- }), createElement("path", {
6405
- d: "M5.5 4.625C6.12132 4.625 6.625 4.12132 6.625 3.5C6.625 2.87868 6.12132 2.375 5.5 2.375C4.87868 2.375 4.375 2.87868 4.375 3.5C4.375 4.12132 4.87868 4.625 5.5 4.625ZM9.5 4.625C10.1213 4.625 10.625 4.12132 10.625 3.5C10.625 2.87868 10.1213 2.375 9.5 2.375C8.87868 2.375 8.375 2.87868 8.375 3.5C8.375 4.12132 8.87868 4.625 9.5 4.625ZM10.625 7.5C10.625 8.12132 10.1213 8.625 9.5 8.625C8.87868 8.625 8.375 8.12132 8.375 7.5C8.375 6.87868 8.87868 6.375 9.5 6.375C10.1213 6.375 10.625 6.87868 10.625 7.5ZM5.5 8.625C6.12132 8.625 6.625 8.12132 6.625 7.5C6.625 6.87868 6.12132 6.375 5.5 6.375C4.87868 6.375 4.375 6.87868 4.375 7.5C4.375 8.12132 4.87868 8.625 5.5 8.625ZM10.625 11.5C10.625 12.1213 10.1213 12.625 9.5 12.625C8.87868 12.625 8.375 12.1213 8.375 11.5C8.375 10.8787 8.87868 10.375 9.5 10.375C10.1213 10.375 10.625 10.8787 10.625 11.5ZM5.5 12.625C6.12132 12.625 6.625 12.1213 6.625 11.5C6.625 10.8787 6.12132 10.375 5.5 10.375C4.87868 10.375 4.375 10.8787 4.375 11.5C4.375 12.1213 4.87868 12.625 5.5 12.625Z",
6406
- fill: color,
6407
- fillRule: "evenodd",
6408
- clipRule: "evenodd"
6409
- }));
6410
- });
6411
6441
  var _excluded$1W = ["color"];
6412
6442
  var DropdownMenuIcon = /* @__PURE__ */ forwardRef(function(_ref, forwardedRef) {
6413
6443
  var _ref$color = _ref.color, color = _ref$color === void 0 ? "currentColor" : _ref$color, props = _objectWithoutPropertiesLoose(_ref, _excluded$1W);
@@ -6442,9 +6472,9 @@ var FontFamilyIcon = /* @__PURE__ */ forwardRef(function(_ref, forwardedRef) {
6442
6472
  fill: color
6443
6473
  }));
6444
6474
  });
6445
- var _excluded$2E = ["color"];
6446
- var InputIcon = /* @__PURE__ */ forwardRef(function(_ref, forwardedRef) {
6447
- var _ref$color = _ref.color, color = _ref$color === void 0 ? "currentColor" : _ref$color, props = _objectWithoutPropertiesLoose(_ref, _excluded$2E);
6475
+ var _excluded$2l = ["color"];
6476
+ var GearIcon = /* @__PURE__ */ forwardRef(function(_ref, forwardedRef) {
6477
+ var _ref$color = _ref.color, color = _ref$color === void 0 ? "currentColor" : _ref$color, props = _objectWithoutPropertiesLoose(_ref, _excluded$2l);
6448
6478
  return createElement("svg", Object.assign({
6449
6479
  width: "15",
6450
6480
  height: "15",
@@ -6454,15 +6484,15 @@ var InputIcon = /* @__PURE__ */ forwardRef(function(_ref, forwardedRef) {
6454
6484
  }, props, {
6455
6485
  ref: forwardedRef
6456
6486
  }), createElement("path", {
6457
- d: "M6.5 1C6.22386 1 6 1.22386 6 1.5C6 1.77614 6.22386 2 6.5 2C7.12671 2 7.45718 2.20028 7.65563 2.47812C7.8781 2.78957 8 3.28837 8 4V11C8 11.7116 7.8781 12.2104 7.65563 12.5219C7.45718 12.7997 7.12671 13 6.5 13C6.22386 13 6 13.2239 6 13.5C6 13.7761 6.22386 14 6.5 14C7.37329 14 8.04282 13.7003 8.46937 13.1031C8.47976 13.0886 8.48997 13.0739 8.5 13.0591C8.51003 13.0739 8.52024 13.0886 8.53063 13.1031C8.95718 13.7003 9.62671 14 10.5 14C10.7761 14 11 13.7761 11 13.5C11 13.2239 10.7761 13 10.5 13C9.87329 13 9.54282 12.7997 9.34437 12.5219C9.1219 12.2104 9 11.7116 9 11V4C9 3.28837 9.1219 2.78957 9.34437 2.47812C9.54282 2.20028 9.87329 2 10.5 2C10.7761 2 11 1.77614 11 1.5C11 1.22386 10.7761 1 10.5 1C9.62671 1 8.95718 1.29972 8.53063 1.89688C8.52024 1.91143 8.51003 1.92611 8.5 1.9409C8.48997 1.92611 8.47976 1.91143 8.46937 1.89688C8.04282 1.29972 7.37329 1 6.5 1ZM14 5H11V4H14C14.5523 4 15 4.44772 15 5V10C15 10.5523 14.5523 11 14 11H11V10H14V5ZM6 4V5H1L1 10H6V11H1C0.447715 11 0 10.5523 0 10V5C0 4.44772 0.447715 4 1 4H6Z",
6487
+ d: "M7.07095 0.650238C6.67391 0.650238 6.32977 0.925096 6.24198 1.31231L6.0039 2.36247C5.6249 2.47269 5.26335 2.62363 4.92436 2.81013L4.01335 2.23585C3.67748 2.02413 3.23978 2.07312 2.95903 2.35386L2.35294 2.95996C2.0722 3.2407 2.0232 3.6784 2.23493 4.01427L2.80942 4.92561C2.62307 5.2645 2.47227 5.62594 2.36216 6.00481L1.31209 6.24287C0.924883 6.33065 0.650024 6.6748 0.650024 7.07183V7.92897C0.650024 8.32601 0.924883 8.67015 1.31209 8.75794L2.36228 8.99603C2.47246 9.375 2.62335 9.73652 2.80979 10.0755L2.2354 10.9867C2.02367 11.3225 2.07267 11.7602 2.35341 12.041L2.95951 12.6471C3.24025 12.9278 3.67795 12.9768 4.01382 12.7651L4.92506 12.1907C5.26384 12.377 5.62516 12.5278 6.0039 12.6379L6.24198 13.6881C6.32977 14.0753 6.67391 14.3502 7.07095 14.3502H7.92809C8.32512 14.3502 8.66927 14.0753 8.75705 13.6881L8.99505 12.6383C9.37411 12.5282 9.73573 12.3773 10.0748 12.1909L10.986 12.7653C11.3218 12.977 11.7595 12.928 12.0403 12.6473L12.6464 12.0412C12.9271 11.7604 12.9761 11.3227 12.7644 10.9869L12.1902 10.076C12.3768 9.73688 12.5278 9.37515 12.638 8.99596L13.6879 8.75794C14.0751 8.67015 14.35 8.32601 14.35 7.92897V7.07183C14.35 6.6748 14.0751 6.33065 13.6879 6.24287L12.6381 6.00488C12.528 5.62578 12.3771 5.26414 12.1906 4.92507L12.7648 4.01407C12.9766 3.6782 12.9276 3.2405 12.6468 2.95975L12.0407 2.35366C11.76 2.07292 11.3223 2.02392 10.9864 2.23565L10.0755 2.80989C9.73622 2.62328 9.37437 2.47229 8.99505 2.36209L8.75705 1.31231C8.66927 0.925096 8.32512 0.650238 7.92809 0.650238H7.07095ZM4.92053 3.81251C5.44724 3.44339 6.05665 3.18424 6.71543 3.06839L7.07095 1.50024H7.92809L8.28355 3.06816C8.94267 3.18387 9.5524 3.44302 10.0794 3.81224L11.4397 2.9547L12.0458 3.56079L11.1882 4.92117C11.5573 5.44798 11.8164 6.0575 11.9321 6.71638L13.5 7.07183V7.92897L11.932 8.28444C11.8162 8.94342 11.557 9.55301 11.1878 10.0798L12.0453 11.4402L11.4392 12.0462L10.0787 11.1886C9.55192 11.5576 8.94241 11.8166 8.28355 11.9323L7.92809 13.5002H7.07095L6.71543 11.932C6.0569 11.8162 5.44772 11.5572 4.92116 11.1883L3.56055 12.046L2.95445 11.4399L3.81213 10.0794C3.4431 9.55266 3.18403 8.94326 3.06825 8.2845L1.50002 7.92897V7.07183L3.06818 6.71632C3.18388 6.05765 3.44283 5.44833 3.81171 4.92165L2.95398 3.561L3.56008 2.95491L4.92053 3.81251ZM9.02496 7.50008C9.02496 8.34226 8.34223 9.02499 7.50005 9.02499C6.65786 9.02499 5.97513 8.34226 5.97513 7.50008C5.97513 6.65789 6.65786 5.97516 7.50005 5.97516C8.34223 5.97516 9.02496 6.65789 9.02496 7.50008ZM9.92496 7.50008C9.92496 8.83932 8.83929 9.92499 7.50005 9.92499C6.1608 9.92499 5.07513 8.83932 5.07513 7.50008C5.07513 6.16084 6.1608 5.07516 7.50005 5.07516C8.83929 5.07516 9.92496 6.16084 9.92496 7.50008Z",
6458
6488
  fill: color,
6459
6489
  fillRule: "evenodd",
6460
6490
  clipRule: "evenodd"
6461
6491
  }));
6462
6492
  });
6463
- var _excluded$2Z = ["color"];
6464
- var ListBulletIcon = /* @__PURE__ */ forwardRef(function(_ref, forwardedRef) {
6465
- var _ref$color = _ref.color, color = _ref$color === void 0 ? "currentColor" : _ref$color, props = _objectWithoutPropertiesLoose(_ref, _excluded$2Z);
6493
+ var _excluded$2E = ["color"];
6494
+ var InputIcon = /* @__PURE__ */ forwardRef(function(_ref, forwardedRef) {
6495
+ var _ref$color = _ref.color, color = _ref$color === void 0 ? "currentColor" : _ref$color, props = _objectWithoutPropertiesLoose(_ref, _excluded$2E);
6466
6496
  return createElement("svg", Object.assign({
6467
6497
  width: "15",
6468
6498
  height: "15",
@@ -6472,15 +6502,15 @@ var ListBulletIcon = /* @__PURE__ */ forwardRef(function(_ref, forwardedRef) {
6472
6502
  }, props, {
6473
6503
  ref: forwardedRef
6474
6504
  }), createElement("path", {
6475
- d: "M1.5 5.25C1.91421 5.25 2.25 4.91421 2.25 4.5C2.25 4.08579 1.91421 3.75 1.5 3.75C1.08579 3.75 0.75 4.08579 0.75 4.5C0.75 4.91421 1.08579 5.25 1.5 5.25ZM4 4.5C4 4.22386 4.22386 4 4.5 4H13.5C13.7761 4 14 4.22386 14 4.5C14 4.77614 13.7761 5 13.5 5H4.5C4.22386 5 4 4.77614 4 4.5ZM4.5 7C4.22386 7 4 7.22386 4 7.5C4 7.77614 4.22386 8 4.5 8H13.5C13.7761 8 14 7.77614 14 7.5C14 7.22386 13.7761 7 13.5 7H4.5ZM4.5 10C4.22386 10 4 10.2239 4 10.5C4 10.7761 4.22386 11 4.5 11H13.5C13.7761 11 14 10.7761 14 10.5C14 10.2239 13.7761 10 13.5 10H4.5ZM2.25 7.5C2.25 7.91421 1.91421 8.25 1.5 8.25C1.08579 8.25 0.75 7.91421 0.75 7.5C0.75 7.08579 1.08579 6.75 1.5 6.75C1.91421 6.75 2.25 7.08579 2.25 7.5ZM1.5 11.25C1.91421 11.25 2.25 10.9142 2.25 10.5C2.25 10.0858 1.91421 9.75 1.5 9.75C1.08579 9.75 0.75 10.0858 0.75 10.5C0.75 10.9142 1.08579 11.25 1.5 11.25Z",
6505
+ d: "M6.5 1C6.22386 1 6 1.22386 6 1.5C6 1.77614 6.22386 2 6.5 2C7.12671 2 7.45718 2.20028 7.65563 2.47812C7.8781 2.78957 8 3.28837 8 4V11C8 11.7116 7.8781 12.2104 7.65563 12.5219C7.45718 12.7997 7.12671 13 6.5 13C6.22386 13 6 13.2239 6 13.5C6 13.7761 6.22386 14 6.5 14C7.37329 14 8.04282 13.7003 8.46937 13.1031C8.47976 13.0886 8.48997 13.0739 8.5 13.0591C8.51003 13.0739 8.52024 13.0886 8.53063 13.1031C8.95718 13.7003 9.62671 14 10.5 14C10.7761 14 11 13.7761 11 13.5C11 13.2239 10.7761 13 10.5 13C9.87329 13 9.54282 12.7997 9.34437 12.5219C9.1219 12.2104 9 11.7116 9 11V4C9 3.28837 9.1219 2.78957 9.34437 2.47812C9.54282 2.20028 9.87329 2 10.5 2C10.7761 2 11 1.77614 11 1.5C11 1.22386 10.7761 1 10.5 1C9.62671 1 8.95718 1.29972 8.53063 1.89688C8.52024 1.91143 8.51003 1.92611 8.5 1.9409C8.48997 1.92611 8.47976 1.91143 8.46937 1.89688C8.04282 1.29972 7.37329 1 6.5 1ZM14 5H11V4H14C14.5523 4 15 4.44772 15 5V10C15 10.5523 14.5523 11 14 11H11V10H14V5ZM6 4V5H1L1 10H6V11H1C0.447715 11 0 10.5523 0 10V5C0 4.44772 0.447715 4 1 4H6Z",
6476
6506
  fill: color,
6477
6507
  fillRule: "evenodd",
6478
6508
  clipRule: "evenodd"
6479
6509
  }));
6480
6510
  });
6481
- var _excluded$3n = ["color"];
6482
- var Pencil1Icon = /* @__PURE__ */ forwardRef(function(_ref, forwardedRef) {
6483
- var _ref$color = _ref.color, color = _ref$color === void 0 ? "currentColor" : _ref$color, props = _objectWithoutPropertiesLoose(_ref, _excluded$3n);
6511
+ var _excluded$2Z = ["color"];
6512
+ var ListBulletIcon = /* @__PURE__ */ forwardRef(function(_ref, forwardedRef) {
6513
+ var _ref$color = _ref.color, color = _ref$color === void 0 ? "currentColor" : _ref$color, props = _objectWithoutPropertiesLoose(_ref, _excluded$2Z);
6484
6514
  return createElement("svg", Object.assign({
6485
6515
  width: "15",
6486
6516
  height: "15",
@@ -6490,7 +6520,7 @@ var Pencil1Icon = /* @__PURE__ */ forwardRef(function(_ref, forwardedRef) {
6490
6520
  }, props, {
6491
6521
  ref: forwardedRef
6492
6522
  }), createElement("path", {
6493
- d: "M11.8536 1.14645C11.6583 0.951184 11.3417 0.951184 11.1465 1.14645L3.71455 8.57836C3.62459 8.66832 3.55263 8.77461 3.50251 8.89155L2.04044 12.303C1.9599 12.491 2.00189 12.709 2.14646 12.8536C2.29103 12.9981 2.50905 13.0401 2.69697 12.9596L6.10847 11.4975C6.2254 11.4474 6.3317 11.3754 6.42166 11.2855L13.8536 3.85355C14.0488 3.65829 14.0488 3.34171 13.8536 3.14645L11.8536 1.14645ZM4.42166 9.28547L11.5 2.20711L12.7929 3.5L5.71455 10.5784L4.21924 11.2192L3.78081 10.7808L4.42166 9.28547Z",
6523
+ d: "M1.5 5.25C1.91421 5.25 2.25 4.91421 2.25 4.5C2.25 4.08579 1.91421 3.75 1.5 3.75C1.08579 3.75 0.75 4.08579 0.75 4.5C0.75 4.91421 1.08579 5.25 1.5 5.25ZM4 4.5C4 4.22386 4.22386 4 4.5 4H13.5C13.7761 4 14 4.22386 14 4.5C14 4.77614 13.7761 5 13.5 5H4.5C4.22386 5 4 4.77614 4 4.5ZM4.5 7C4.22386 7 4 7.22386 4 7.5C4 7.77614 4.22386 8 4.5 8H13.5C13.7761 8 14 7.77614 14 7.5C14 7.22386 13.7761 7 13.5 7H4.5ZM4.5 10C4.22386 10 4 10.2239 4 10.5C4 10.7761 4.22386 11 4.5 11H13.5C13.7761 11 14 10.7761 14 10.5C14 10.2239 13.7761 10 13.5 10H4.5ZM2.25 7.5C2.25 7.91421 1.91421 8.25 1.5 8.25C1.08579 8.25 0.75 7.91421 0.75 7.5C0.75 7.08579 1.08579 6.75 1.5 6.75C1.91421 6.75 2.25 7.08579 2.25 7.5ZM1.5 11.25C1.91421 11.25 2.25 10.9142 2.25 10.5C2.25 10.0858 1.91421 9.75 1.5 9.75C1.08579 9.75 0.75 10.0858 0.75 10.5C0.75 10.9142 1.08579 11.25 1.5 11.25Z",
6494
6524
  fill: color,
6495
6525
  fillRule: "evenodd",
6496
6526
  clipRule: "evenodd"
@@ -6638,6 +6668,10 @@ var UploadIcon = /* @__PURE__ */ forwardRef(function(_ref, forwardedRef) {
6638
6668
  clipRule: "evenodd"
6639
6669
  }));
6640
6670
  });
6671
+ const emptyBooleanField = {
6672
+ ...emptyBaseField,
6673
+ type: "boolean"
6674
+ };
6641
6675
  const _BooleanField = class _BooleanField extends BaseField {
6642
6676
  constructor(options) {
6643
6677
  super({ ...options, type: "boolean" });
@@ -8062,9 +8096,9 @@ const Tabs = Object.assign({}, {
8062
8096
  Content: TabsContent
8063
8097
  });
8064
8098
  const NumberInput$1 = memo(function NumberInput2(props) {
8065
- const [{ inputId, labelId, severity, helpText, label, fieldProps, field }, rest] = useFormikInput(props);
8099
+ const [{ inputId, labelId, size, severity, helpText, label, fieldProps, field }, rest] = useFormikInput(props);
8066
8100
  const color = useSeverityColor(severity);
8067
- return /* @__PURE__ */ jsx(InputWithLabelAndHelpText, { helpText, severity, children: /* @__PURE__ */ jsx(InputWithLabel, { severity, inputId, labelId, label, children: /* @__PURE__ */ jsx(
8101
+ return /* @__PURE__ */ jsx(InputWithLabelAndHelpText, { helpText, severity, children: /* @__PURE__ */ jsx(InputWithLabel, { size, severity, inputId, labelId, label, children: /* @__PURE__ */ jsx(
8068
8102
  TextField$1.Input,
8069
8103
  {
8070
8104
  ...rest,
@@ -8078,144 +8112,6 @@ const NumberInput$1 = memo(function NumberInput2(props) {
8078
8112
  }
8079
8113
  ) }) });
8080
8114
  });
8081
- const _NumberField = class _NumberField extends BaseField {
8082
- constructor(options) {
8083
- const {
8084
- minimum = Number.MIN_SAFE_INTEGER,
8085
- maximum = Number.MAX_SAFE_INTEGER,
8086
- integers = false,
8087
- ...base
8088
- } = options;
8089
- super({ ...base, type: "number" });
8090
- __publicField(this, "minimum");
8091
- __publicField(this, "maximum");
8092
- __publicField(this, "integers");
8093
- this.minimum = minimum;
8094
- this.maximum = maximum;
8095
- this.integers = integers;
8096
- }
8097
- getValueFromChangeEvent(event) {
8098
- const number = Number.parseFloat(event.target.value);
8099
- if (Number.isNaN(number))
8100
- return "";
8101
- return number;
8102
- }
8103
- static getFieldCreationSchema() {
8104
- return [
8105
- new _NumberField({
8106
- label: "Minimum",
8107
- description: "Minimum value",
8108
- integers: true,
8109
- required: false,
8110
- identifier: "minimum",
8111
- formValidators: [this._validateMin]
8112
- }),
8113
- new _NumberField({
8114
- label: "Maximum",
8115
- description: "Maximum value",
8116
- integers: true,
8117
- required: false,
8118
- identifier: "maximum",
8119
- formValidators: [this._validateMax]
8120
- }),
8121
- new BooleanField({
8122
- label: "Integers",
8123
- description: "Whole numbers only",
8124
- required: false,
8125
- identifier: "integers"
8126
- })
8127
- ];
8128
- }
8129
- getFieldValidators() {
8130
- const validators = super.getFieldValidators();
8131
- const min = this.minimum;
8132
- const max = this.maximum;
8133
- if (typeof min === "number") {
8134
- validators.push((value) => {
8135
- if (typeof value === "number" && value < min) {
8136
- return `Must be at least ${this.minimum}.`;
8137
- }
8138
- });
8139
- }
8140
- if (typeof max === "number") {
8141
- validators.push((value) => {
8142
- if (typeof value === "number" && value > max) {
8143
- return `Must be at most ${this.maximum}.`;
8144
- }
8145
- });
8146
- }
8147
- if (this.integers) {
8148
- validators.push((value) => {
8149
- if (typeof value === "number" && !Number.isInteger(value)) {
8150
- return "Must be a whole number.";
8151
- }
8152
- });
8153
- }
8154
- return validators;
8155
- }
8156
- serialize() {
8157
- return {
8158
- ...super._serialize(),
8159
- minimum: this.minimum,
8160
- maximum: this.maximum,
8161
- integers: this.integers
8162
- };
8163
- }
8164
- static deserialize(data) {
8165
- if (data.type !== "number")
8166
- throw new Error("Type mismatch.");
8167
- return new _NumberField(data);
8168
- }
8169
- getInput(props) {
8170
- return /* @__PURE__ */ jsx(NumberInput$1, { field: this, ...props });
8171
- }
8172
- };
8173
- __publicField(_NumberField, "fieldTypeName", "Number");
8174
- __publicField(_NumberField, "fieldTypeDescription", "Allows specifying a number within a given range.");
8175
- __publicField(_NumberField, "Icon", FontFamilyIcon);
8176
- __publicField(_NumberField, "_validateMin", (value, allValues) => {
8177
- if (typeof allValues.maximum === "number" && typeof value === "number" && allValues.maximum < value) {
8178
- return "Minimum cannot be greater than minimum.";
8179
- }
8180
- return null;
8181
- });
8182
- __publicField(_NumberField, "_validateMax", (value, allValues) => {
8183
- if (typeof allValues.minimum === "number" && typeof value === "number" && allValues.minimum > value) {
8184
- return "Maximum cannot be less than minimum.";
8185
- }
8186
- return null;
8187
- });
8188
- let NumberField = _NumberField;
8189
- const DateInput = memo(function DateInput2(props) {
8190
- const [{ inputId, labelId, severity, helpText, label, fieldProps }, rest] = useFormikInput(props);
8191
- const color = useSeverityColor(severity);
8192
- const value = fieldProps.value ? fieldProps.value.split("T")[0] : "";
8193
- return /* @__PURE__ */ jsx(InputWithLabelAndHelpText, { helpText, severity, children: /* @__PURE__ */ jsx(InputWithLabel, { severity, inputId, labelId, label, children: /* @__PURE__ */ jsx(TextField$1.Input, { ...rest, ...fieldProps, type: "date", id: inputId, color, value }) }) });
8194
- });
8195
- const _DateField = class _DateField extends BaseField {
8196
- constructor(options) {
8197
- super({ ...options, type: "date" });
8198
- __publicField(this, "onlyValidateAfterTouched", false);
8199
- }
8200
- serialize() {
8201
- return super._serialize();
8202
- }
8203
- getValueFromChangeEvent(event) {
8204
- return new Date(event.target.value).toISOString();
8205
- }
8206
- static deserialize(data) {
8207
- if (data.type !== "date")
8208
- throw new Error("Type mismatch.");
8209
- return new _DateField(data);
8210
- }
8211
- getInput(props) {
8212
- return /* @__PURE__ */ jsx(DateInput, { field: this, ...props });
8213
- }
8214
- };
8215
- __publicField(_DateField, "fieldTypeName", "Date");
8216
- __publicField(_DateField, "fieldTypeDescription", "Allows specifying a date.");
8217
- __publicField(_DateField, "Icon", CalendarIcon);
8218
- let DateField = _DateField;
8219
8115
  class StringOrTextField extends BaseField {
8220
8116
  constructor(options) {
8221
8117
  const { minLength, maxLength = 5e3, ...base } = options;
@@ -8225,31 +8121,40 @@ class StringOrTextField extends BaseField {
8225
8121
  this.minLength = minLength ? Math.max(minLength, 0) : void 0;
8226
8122
  this.maxLength = maxLength ? Math.max(maxLength, 0) : 5e3;
8227
8123
  }
8228
- static getFieldCreationSchema() {
8124
+ static getFieldCreationSchema(parentPath = "") {
8125
+ const path = parentPath && `${parentPath}.`;
8229
8126
  return [
8230
- // min, max
8231
- new NumberField({
8232
- label: "Minimum length",
8233
- description: "Minimum number of characters",
8234
- required: false,
8235
- identifier: "minimum_length",
8236
- minimum: 0,
8237
- maximum: 100,
8238
- formValidators: [this._validateMin],
8239
- integers: true
8240
- }),
8241
- new NumberField({
8242
- label: "Maximum length",
8243
- description: "Maximum number of characters",
8244
- required: false,
8245
- identifier: "maximum_length",
8246
- minimum: 1,
8247
- maximum: 5e3,
8248
- // TODO: depends on short vs long text
8249
- formValidators: [this._validateMax],
8250
- // TODO: default: 500 (see: "Short text fields can hold up to 500 characters on a single line.")
8251
- integers: true
8252
- })
8127
+ {
8128
+ field: (
8129
+ // min, max
8130
+ new NumberField({
8131
+ label: "Minimum length",
8132
+ description: "Minimum number of characters",
8133
+ required: false,
8134
+ identifier: `${path}minimum_length`,
8135
+ minimum: 0,
8136
+ maximum: 100,
8137
+ formValidators: [this._validateMin(parentPath)],
8138
+ integers: true
8139
+ })
8140
+ ),
8141
+ showDirectly: false
8142
+ },
8143
+ {
8144
+ field: new NumberField({
8145
+ label: "Maximum length",
8146
+ description: "Maximum number of characters",
8147
+ required: false,
8148
+ identifier: `${path}maximum_length`,
8149
+ minimum: 1,
8150
+ maximum: 5e3,
8151
+ // TODO: depends on short vs long text
8152
+ formValidators: [this._validateMax(parentPath)],
8153
+ // TODO: default: 500 (see: "Short text fields can hold up to 500 characters on a single line.")
8154
+ integers: true
8155
+ }),
8156
+ showDirectly: false
8157
+ }
8253
8158
  ];
8254
8159
  }
8255
8160
  getFieldValidators() {
@@ -8284,23 +8189,24 @@ class StringOrTextField extends BaseField {
8284
8189
  }
8285
8190
  }
8286
8191
  /**
8287
- * This function validates that the value given for "minimum length" (when creating a new field) is less than or
8192
+ * This function returns a function that validates that the value given for "minimum length" (when creating a new field) is less than or
8288
8193
  * equal to the value given for "maximum length".
8289
8194
  */
8290
- __publicField(StringOrTextField, "_validateMin", (value, allValues) => {
8291
- if (typeof allValues.maximum_length === "number" && typeof value === "number" && allValues.maximum_length < value) {
8195
+ __publicField(StringOrTextField, "_validateMin", (path) => (value, allValues) => {
8196
+ const field = valueIsFormikUserFormRevision(allValues) ? get(allValues, path) : allValues;
8197
+ if (typeof field.maximum_length === "number" && typeof value === "number" && field.maximum_length < value) {
8292
8198
  return "Minimum cannot be greater than maximum.";
8293
8199
  }
8294
8200
  return null;
8295
8201
  });
8296
8202
  /**
8297
- * This function validates that the value given for "maximum length" (when creating a new field) is greater than or
8203
+ * This function returns a function that validates that the value given for "maximum length" (when creating a new field) is greater than or
8298
8204
  * equal to the value given for "minimum length".
8299
8205
  */
8300
- __publicField(StringOrTextField, "_validateMax", (value, allValues) => {
8206
+ __publicField(StringOrTextField, "_validateMax", (path) => (value, allValues) => {
8301
8207
  if (typeof value !== "number")
8302
8208
  return null;
8303
- const { minimum_length: minimumLength } = allValues;
8209
+ const { minimum_length: minimumLength } = valueIsFormikUserFormRevision(allValues) ? get(allValues, path) : allValues;
8304
8210
  if (typeof minimumLength !== "number") {
8305
8211
  return null;
8306
8212
  }
@@ -8311,20 +8217,20 @@ __publicField(StringOrTextField, "_validateMax", (value, allValues) => {
8311
8217
  });
8312
8218
  const clickableLinkContainer = "_clickableLinkContainer_1ace7_1";
8313
8219
  const TextFieldInputCopy = "_TextFieldInputCopy_1ace7_5";
8314
- const styles$3 = {
8220
+ const styles$4 = {
8315
8221
  clickableLinkContainer,
8316
8222
  TextFieldInputCopy
8317
8223
  };
8318
8224
  const StringInput = memo(function StringInput2(props) {
8319
- const [{ inputId, labelId, severity, helpText, label, fieldProps, field }, rest] = useFormikInput(props);
8225
+ const [{ inputId, labelId, size, severity, helpText, label, fieldProps, field }, rest] = useFormikInput(props);
8320
8226
  const color = useSeverityColor(severity);
8321
- return /* @__PURE__ */ jsx(InputWithLabelAndHelpText, { helpText, severity, children: /* @__PURE__ */ jsx(InputWithLabel, { severity, inputId, labelId, label, children: !rest.disabled ? /* @__PURE__ */ jsx(TextField$1.Input, { ...rest, ...fieldProps, type: field.inputType, id: inputId, color }) : /* @__PURE__ */ jsxs(TextField$1.Root, { className: styles$3.clickableLinkContainer, children: [
8227
+ return /* @__PURE__ */ jsx(InputWithLabelAndHelpText, { helpText, severity, children: /* @__PURE__ */ jsx(InputWithLabel, { size, severity, inputId, labelId, label, children: !rest.disabled ? /* @__PURE__ */ jsx(TextField$1.Input, { ...rest, ...fieldProps, type: field.inputType, id: inputId, color }) : /* @__PURE__ */ jsxs(TextField$1.Root, { className: styles$4.clickableLinkContainer, children: [
8322
8228
  /* @__PURE__ */ jsx(
8323
8229
  "div",
8324
8230
  {
8325
8231
  className: classNames$1(
8326
8232
  "rt-TextFieldInput rt-r-size-2 rt-variant-surface",
8327
- styles$3.TextFieldInputCopy
8233
+ styles$4.TextFieldInputCopy
8328
8234
  ),
8329
8235
  children: /* @__PURE__ */ jsx(
8330
8236
  Linkify,
@@ -8341,6 +8247,12 @@ const StringInput = memo(function StringInput2(props) {
8341
8247
  /* @__PURE__ */ jsx("div", { className: "rt-TextFieldChrome" })
8342
8248
  ] }) }) });
8343
8249
  });
8250
+ const emptyStringField = {
8251
+ ...emptyBaseField,
8252
+ type: "string",
8253
+ maximum_length: 500,
8254
+ input_type: "text"
8255
+ };
8344
8256
  const _StringField = class _StringField extends StringOrTextField {
8345
8257
  constructor(options) {
8346
8258
  const { inputType = "text", ...rest } = options;
@@ -8368,9 +8280,14 @@ __publicField(_StringField, "fieldTypeDescription", "Short text fields can hold
8368
8280
  __publicField(_StringField, "Icon", InputIcon);
8369
8281
  let StringField = _StringField;
8370
8282
  const TextInput = memo(function TextInput2(props) {
8371
- const [{ inputId, labelId, severity, helpText, label, fieldProps }, rest] = useFormikInput(props);
8372
- return /* @__PURE__ */ jsx(InputWithLabelAndHelpText, { helpText, severity, children: /* @__PURE__ */ jsx(InputWithLabel, { severity, inputId, labelId, label, children: /* @__PURE__ */ jsx(TextArea, { ...rest, ...fieldProps, resize: "vertical", id: inputId, severity }) }) });
8283
+ const [{ inputId, labelId, size, severity, helpText, label, fieldProps }, rest] = useFormikInput(props);
8284
+ return /* @__PURE__ */ jsx(InputWithLabelAndHelpText, { helpText, severity, children: /* @__PURE__ */ jsx(InputWithLabel, { size, severity, inputId, labelId, label, children: /* @__PURE__ */ jsx(TextArea, { ...rest, ...fieldProps, resize: "vertical", id: inputId, severity }) }) });
8373
8285
  });
8286
+ const emptyTextField = {
8287
+ ...emptyBaseField,
8288
+ type: "text",
8289
+ maximum_length: 5e3
8290
+ };
8374
8291
  const _TextField = class _TextField extends StringOrTextField {
8375
8292
  constructor(options) {
8376
8293
  const maxLength = options.maxLength ? Math.min(5e3, options.maxLength) : 5e3;
@@ -8394,8 +8311,42 @@ __publicField(_TextField, "fieldTypeName", "Paragraph");
8394
8311
  __publicField(_TextField, "fieldTypeDescription", "Paragraph fields can hold up to 5000 characters and can have multiple lines.");
8395
8312
  __publicField(_TextField, "Icon", RowsIcon);
8396
8313
  let TextField = _TextField;
8314
+ const DateInput = memo(function DateInput2(props) {
8315
+ const [{ inputId, labelId, size, severity, helpText, label, fieldProps }, rest] = useFormikInput(props);
8316
+ const color = useSeverityColor(severity);
8317
+ const value = fieldProps.value ? fieldProps.value.split("T")[0] : "";
8318
+ return /* @__PURE__ */ jsx(InputWithLabelAndHelpText, { helpText, severity, children: /* @__PURE__ */ jsx(InputWithLabel, { size, severity, inputId, labelId, label, children: /* @__PURE__ */ jsx(TextField$1.Input, { ...rest, ...fieldProps, type: "date", id: inputId, color, value }) }) });
8319
+ });
8320
+ const emptyDateField = {
8321
+ ...emptyBaseField,
8322
+ type: "date"
8323
+ };
8324
+ const _DateField = class _DateField extends BaseField {
8325
+ constructor(options) {
8326
+ super({ ...options, type: "date" });
8327
+ __publicField(this, "onlyValidateAfterTouched", false);
8328
+ }
8329
+ serialize() {
8330
+ return super._serialize();
8331
+ }
8332
+ getValueFromChangeEvent(event) {
8333
+ return new Date(event.target.value).toISOString();
8334
+ }
8335
+ static deserialize(data) {
8336
+ if (data.type !== "date")
8337
+ throw new Error("Type mismatch.");
8338
+ return new _DateField(data);
8339
+ }
8340
+ getInput(props) {
8341
+ return /* @__PURE__ */ jsx(DateInput, { field: this, ...props });
8342
+ }
8343
+ };
8344
+ __publicField(_DateField, "fieldTypeName", "Date");
8345
+ __publicField(_DateField, "fieldTypeDescription", "Allows specifying a date.");
8346
+ __publicField(_DateField, "Icon", CalendarIcon);
8347
+ let DateField = _DateField;
8397
8348
  const SelectInput = memo(function SelectInput2(props) {
8398
- const [{ inputId, labelId, severity, helpText, label, fieldProps, field }, rest] = useFormikInput(props);
8349
+ const [{ inputId, labelId, size, severity, helpText, label, fieldProps, field }, rest] = useFormikInput(props);
8399
8350
  const { onChange, onBlur } = fieldProps;
8400
8351
  const options = useMemo(
8401
8352
  () => field.options.map((option) => ({ value: option.value, itemContent: option.label })),
@@ -8408,7 +8359,7 @@ const SelectInput = memo(function SelectInput2(props) {
8408
8359
  },
8409
8360
  [onChange, onBlur]
8410
8361
  );
8411
- return /* @__PURE__ */ jsx(InputWithLabelAndHelpText, { helpText, severity, children: /* @__PURE__ */ jsx(InputWithLabel, { severity, inputId, labelId, label, children: /* @__PURE__ */ jsx(
8362
+ return /* @__PURE__ */ jsx(InputWithLabelAndHelpText, { helpText, severity, children: /* @__PURE__ */ jsx(InputWithLabel, { size, severity, inputId, labelId, label, children: /* @__PURE__ */ jsx(
8412
8363
  Select,
8413
8364
  {
8414
8365
  items: options,
@@ -8459,11 +8410,6 @@ function reorder(list, source, destination) {
8459
8410
  result.splice(destination, 0, removed);
8460
8411
  return result;
8461
8412
  }
8462
- function replace(list, index2, value) {
8463
- const result = Array.from(list);
8464
- result[index2] = value;
8465
- return result;
8466
- }
8467
8413
  function insert(list, index2, value) {
8468
8414
  const result = Array.from(list ?? []);
8469
8415
  result.splice(index2, 0, value);
@@ -8498,9 +8444,7 @@ const makeConditionalSourceFields = (sections, index2) => {
8498
8444
  return sections.filter((_, i) => i < index2).flatMap((field) => field.fields);
8499
8445
  };
8500
8446
  const getTakenFieldLabels = (fields) => {
8501
- return fields.flatMap(
8502
- (field) => field.type === "section" ? [...field.fields.map((f) => f.label), field.label] : field.label
8503
- ).filter((id) => id !== null);
8447
+ return fields.flatMap((field) => [...field.fields.map((f) => f.label), field.label]).filter((id) => id !== null);
8504
8448
  };
8505
8449
  const incrementFieldLabel = (label, takenLabels) => {
8506
8450
  let count = 1;
@@ -8510,8 +8454,90 @@ const incrementFieldLabel = (label, takenLabels) => {
8510
8454
  }
8511
8455
  return newLabel;
8512
8456
  };
8457
+ const createNewField = (parentPath, index2, initialValues2, values, setFieldValue) => {
8458
+ const { label } = initialValues2;
8459
+ const newField = {
8460
+ ...initialValues2,
8461
+ identifier: makeIdentifier(null, label)
8462
+ };
8463
+ const parent = get(values, parentPath);
8464
+ if (parent === void 0) {
8465
+ throw new Error("Parent path must point to an existing field.");
8466
+ }
8467
+ if (!Array.isArray(parent)) {
8468
+ throw new Error("Parent path must point to an array.");
8469
+ }
8470
+ const updatedFields = insert(parent, index2, newField);
8471
+ void setFieldValue(parentPath, updatedFields).then();
8472
+ };
8473
+ const createNewEmptySection = (index2, values, setFieldValue) => {
8474
+ const initialValues2 = {
8475
+ ...emptySection(),
8476
+ label: ""
8477
+ };
8478
+ createNewField("fields", index2, initialValues2, values, setFieldValue);
8479
+ };
8480
+ const useFieldReordering = () => {
8481
+ const { showError } = useToast();
8482
+ const reorderSection = useCallback(
8483
+ (dropState, sectionId, sectionIndex, destinationIndex, values, setFieldValue) => {
8484
+ const state = dropState[sectionId];
8485
+ if (!state)
8486
+ throw new Error("Could not find section context.");
8487
+ let dest = typeof state.conditionIndex !== "undefined" ? (
8488
+ // cannot move a section with a condition before the condition's field
8489
+ Math.max(state.conditionIndex + 1, destinationIndex)
8490
+ ) : destinationIndex;
8491
+ for (const section of Object.values(dropState)) {
8492
+ if (section.conditionIndex === sectionIndex) {
8493
+ dest = Math.min(dest, section.index - 1);
8494
+ }
8495
+ }
8496
+ if (dest !== destinationIndex) {
8497
+ showError({
8498
+ title: "Could not reorder sections",
8499
+ description: "Sections with conditions must be below the fields they reference."
8500
+ });
8501
+ return;
8502
+ }
8503
+ void setFieldValue("fields", reorder(values.fields, sectionIndex, dest));
8504
+ },
8505
+ [showError]
8506
+ );
8507
+ const reorderField = useCallback(
8508
+ (srcSection, srcSectionIndex, srcFieldIndex, destSection, destSectionIndex, destFieldIndex, setFieldValue) => {
8509
+ var _a2;
8510
+ if (!(srcSection == null ? void 0 : srcSection.fields) || !destSection)
8511
+ throw new Error("Could not find section with fields.");
8512
+ if (srcSection.identifier === destSection.identifier) {
8513
+ void setFieldValue(
8514
+ `fields.${srcSectionIndex}.fields`,
8515
+ reorder(srcSection.fields, srcFieldIndex, destFieldIndex)
8516
+ ).then();
8517
+ } else {
8518
+ const removed = srcSection.fields[srcFieldIndex];
8519
+ if (!removed)
8520
+ throw new Error("Could not find field to reorder.");
8521
+ if (((_a2 = destSection.condition) == null ? void 0 : _a2.identifier) === removed.identifier) {
8522
+ showError({
8523
+ title: "Could not reorder field",
8524
+ description: "Field must be above the section whose condition references it."
8525
+ });
8526
+ return;
8527
+ }
8528
+ void setFieldValue(`fields.${srcSectionIndex}.fields`, remove(srcSection.fields, srcFieldIndex)).then();
8529
+ void setFieldValue(
8530
+ `fields.${destSectionIndex}.fields`,
8531
+ insert(destSection.fields, destFieldIndex, removed)
8532
+ ).then();
8533
+ }
8534
+ },
8535
+ [showError]
8536
+ );
8537
+ return { reorderSection, reorderField };
8538
+ };
8513
8539
  const MultiStringInput = memo(function MultiStringInput2(props) {
8514
- const [{ inputId, labelId, severity, helpText, label, fieldProps }, rest] = useFormikInput(props);
8540
+ const [{ inputId, labelId, size, severity, helpText, label, fieldProps }, rest] = useFormikInput(props);
8515
8541
  const color = useSeverityColor(severity);
8516
8542
  const value = useMemo(
8517
8543
  () => Array.isArray(fieldProps.value) ? fieldProps.value : [],
@@ -8581,7 +8607,7 @@ const MultiStringInput = memo(function MultiStringInput2(props) {
8581
8607
  [setValueAndTouched, value]
8582
8608
  );
8583
8609
  return /* @__PURE__ */ jsx(DragDropContext, { onDragEnd: handleDragEnd, children: /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: "2", children: [
8584
- /* @__PURE__ */ jsx(InputWithLabelAndHelpText, { helpText: updatedHelpText, severity, children: /* @__PURE__ */ jsx(InputWithLabel, { severity, inputId, labelId, label, children: (!disabled || value.length === 0) && /* @__PURE__ */ jsxs(Flex, { gap: "2", children: [
8610
+ /* @__PURE__ */ jsx(InputWithLabelAndHelpText, { helpText: updatedHelpText, severity, children: /* @__PURE__ */ jsx(InputWithLabel, { size, severity, inputId, labelId, label, children: (!disabled || value.length === 0) && /* @__PURE__ */ jsxs(Flex, { gap: "2", children: [
8585
8611
  /* @__PURE__ */ jsx(Box, { grow: "1", children: /* @__PURE__ */ jsx(
8586
8612
  TextField$1.Input,
8587
8613
  {
@@ -8652,6 +8678,12 @@ const MultiStringInput = memo(function MultiStringInput2(props) {
8652
8678
  ] }) })
8653
8679
  ] }) });
8654
8680
  });
8681
+ const emptyMultiStringField = {
8682
+ ...emptyBaseField,
8683
+ type: "multi-string",
8684
+ minimum_length: 0,
8685
+ maximum_length: null
8686
+ };
8655
8687
  const _MultiStringField = class _MultiStringField extends BaseField {
8656
8688
  constructor(options) {
8657
8689
  const { minimum_length, maximum_length, ...rest } = options;
@@ -8726,19 +8758,28 @@ class BaseSelectField extends BaseField {
8726
8758
  options: this.options
8727
8759
  };
8728
8760
  }
8729
- static getFieldCreationSchema() {
8761
+ static getFieldCreationSchema(parentPath = "") {
8762
+ const path = parentPath && `${parentPath}.`;
8730
8763
  return [
8731
- new MultiStringField({
8732
- label: "Options",
8733
- description: "List possible options for the user to select from.",
8734
- required: true,
8735
- identifier: "options",
8736
- minimum_length: 2,
8737
- maximum_length: 20
8738
- })
8739
- ];
8740
- }
8764
+ {
8765
+ field: new MultiStringField({
8766
+ label: "Options",
8767
+ description: "List possible options for the user to select from.",
8768
+ required: true,
8769
+ identifier: `${path}options`,
8770
+ minimum_length: 2,
8771
+ maximum_length: 20
8772
+ }),
8773
+ showDirectly: true
8774
+ }
8775
+ ];
8776
+ }
8741
8777
  }
8778
+ const emptySelectField = {
8779
+ ...emptyBaseField,
8780
+ type: "select",
8781
+ options: []
8782
+ };
8742
8783
  const _SelectField = class _SelectField extends BaseSelectField {
8743
8784
  constructor(options) {
8744
8785
  super({ ...options, type: "select" });
@@ -8772,7 +8813,7 @@ const parseValueToArray = (value) => {
8772
8813
  return [value];
8773
8814
  };
8774
8815
  const MultiSelectInput = memo(function MultiSelectInput2(props) {
8775
- const [{ inputId, labelId, severity, helpText, label, fieldProps, field }, rest] = useFormikInput(props);
8816
+ const [{ inputId, labelId, size, severity, helpText, label, fieldProps, field }, rest] = useFormikInput(props);
8776
8817
  const { onChange, onBlur } = fieldProps;
8777
8818
  const value = useMemo(() => parseValueToArray(fieldProps.value), [fieldProps.value]);
8778
8819
  const handleChange = useCallback(
@@ -8782,7 +8823,7 @@ const MultiSelectInput = memo(function MultiSelectInput2(props) {
8782
8823
  },
8783
8824
  [onChange, onBlur]
8784
8825
  );
8785
- return /* @__PURE__ */ jsx(InputWithLabelAndHelpText, { helpText, severity, children: /* @__PURE__ */ jsx(InputWithLabel, { severity, inputId, labelId, label, children: /* @__PURE__ */ jsx(
8826
+ return /* @__PURE__ */ jsx(InputWithLabelAndHelpText, { helpText, severity, children: /* @__PURE__ */ jsx(InputWithLabel, { size, severity, inputId, labelId, label, children: /* @__PURE__ */ jsx(
8786
8827
  MultiSelect,
8787
8828
  {
8788
8829
  value,
@@ -8796,6 +8837,11 @@ const MultiSelectInput = memo(function MultiSelectInput2(props) {
8796
8837
  }
8797
8838
  ) }) });
8798
8839
  });
8840
+ const emptyMultiSelectField = {
8841
+ ...emptyBaseField,
8842
+ type: "multi-select",
8843
+ options: []
8844
+ };
8799
8845
  const _MultiSelectField = class _MultiSelectField extends BaseSelectField {
8800
8846
  constructor(options) {
8801
8847
  super({ ...options, type: "multi-select" });
@@ -8824,16 +8870,10 @@ __publicField(_MultiSelectField, "fieldTypeName", "Multi-select");
8824
8870
  __publicField(_MultiSelectField, "fieldTypeDescription", "Allows the user to select a multiple options from a list of options.");
8825
8871
  __publicField(_MultiSelectField, "Icon", CheckboxIcon);
8826
8872
  let MultiSelectField = _MultiSelectField;
8827
- const FieldInputCloner = memo(function FieldInputCloner2({ field, ...props }) {
8828
- const [{ value: identifier }] = useField(field.options.clonedFieldIdentifier);
8829
- const deserializedField = useMemo(() => {
8830
- const options = field.options.getFieldToClone(identifier);
8831
- if (!options)
8832
- return null;
8833
- return deserialize(options);
8834
- }, [field.options, identifier]);
8835
- return useFieldInput(deserializedField, props);
8836
- });
8873
+ const emptyCustomField = {
8874
+ ...emptyBaseField,
8875
+ type: "custom"
8876
+ };
8837
8877
  class CustomField extends BaseField {
8838
8878
  constructor(options, Component) {
8839
8879
  super({ ...options, type: "custom" });
@@ -8853,13 +8893,8 @@ class CustomField extends BaseField {
8853
8893
  }
8854
8894
  __publicField(CustomField, "fieldTypeName", "Custom");
8855
8895
  __publicField(CustomField, "fieldTypeDescription", "Allows re-rendering of field already in the form");
8856
- class FieldInputClonerField extends CustomField {
8857
- constructor(options) {
8858
- super(options, FieldInputCloner);
8859
- }
8860
- }
8861
8896
  const previewImage = "_previewImage_1ig84_1";
8862
- const styles$2 = {
8897
+ const styles$3 = {
8863
8898
  previewImage
8864
8899
  };
8865
8900
  const convertBytesToLargestUnit = (bytes) => {
@@ -8880,7 +8915,7 @@ const convertBytesToLargestUnit = (bytes) => {
8880
8915
  };
8881
8916
  const NumberInput = memo(function NumberInput22(props) {
8882
8917
  var _a2;
8883
- const [{ inputId, labelId, severity, helpText, label, fieldProps, field }, rest] = useFormikInput(props);
8918
+ const [{ inputId, labelId, size, severity, helpText, label, fieldProps, field }, rest] = useFormikInput(props);
8884
8919
  const { onChange } = fieldProps;
8885
8920
  const color = useSeverityColor(severity);
8886
8921
  const input = useRef(null);
@@ -8910,7 +8945,7 @@ const NumberInput = memo(function NumberInput22(props) {
8910
8945
  const singleButtonText = value ? "Select new file" : "Select a file";
8911
8946
  const buttonText = field.maxFiles > 1 ? multipleButtonText : singleButtonText;
8912
8947
  return /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: "2", children: [
8913
- /* @__PURE__ */ jsx(InputWithLabelAndHelpText, { helpText: updatedHelpText, severity, children: /* @__PURE__ */ jsxs(InputWithLabel, { severity, inputId, labelId, label, children: [
8948
+ /* @__PURE__ */ jsx(InputWithLabelAndHelpText, { helpText: updatedHelpText, severity, children: /* @__PURE__ */ jsxs(InputWithLabel, { size, severity, inputId, labelId, label, children: [
8914
8949
  /* @__PURE__ */ jsx(Flex, { direction: "row", gap: "2", children: /* @__PURE__ */ jsx(Box, { width: "max-content", asChild: true, children: /* @__PURE__ */ jsxs(Button, { ...rest, onClick: handleClick, children: [
8915
8950
  /* @__PURE__ */ jsx(UploadIcon, {}),
8916
8951
  " ",
@@ -8991,9 +9026,16 @@ const DisplayFile = memo(function DisplayFile2({ file, field, onRemove, disabled
8991
9026
  error && /* @__PURE__ */ jsx(Text, { size: "1", severity: "danger", children: error })
8992
9027
  ] })
8993
9028
  ] }),
8994
- url && /* @__PURE__ */ jsx("img", { className: styles$2.previewImage, src: url, alt: name })
9029
+ url && /* @__PURE__ */ jsx("img", { className: styles$3.previewImage, src: url, alt: name })
8995
9030
  ] }) });
8996
9031
  });
9032
+ const emptyUploadField = {
9033
+ ...emptyBaseField,
9034
+ type: "upload",
9035
+ extensions: [],
9036
+ maximum_size: void 0,
9037
+ maximum_files: 1
9038
+ };
8997
9039
  const largestSupportedSize = 50;
8998
9040
  const _UploadField = class _UploadField extends BaseField {
8999
9041
  constructor(options) {
@@ -9013,55 +9055,65 @@ const _UploadField = class _UploadField extends BaseField {
9013
9055
  isBlank(value) {
9014
9056
  return super.isBlank(value) || value.length === 0;
9015
9057
  }
9016
- static getFieldCreationSchema() {
9058
+ static getFieldCreationSchema(parentPath = "") {
9059
+ const path = parentPath && `${parentPath}.`;
9017
9060
  return [
9018
- new NumberField({
9019
- label: "How many files can be uploaded?",
9020
- description: "By default, only one file can be uploaded.",
9021
- required: false,
9022
- minimum: 1,
9023
- maximum: 10,
9024
- identifier: "maximum_files",
9025
- integers: true
9026
- }),
9027
- new NumberField({
9028
- // TODO: Default value
9029
- label: "What is the maximum size of each file?",
9030
- description: `Maximum file size in megabytes (between 1MB–${largestSupportedSize}MB).`,
9031
- required: false,
9032
- identifier: "maximum_size",
9033
- minimum: 1,
9034
- maximum: largestSupportedSize,
9035
- integers: true
9036
- }),
9037
- new MultiSelectField({
9038
- label: "Accepted file types",
9039
- description: "Types of allowed files to upload. If left blank, all files will be accepted.",
9040
- required: false,
9041
- identifier: "extensions",
9042
- options: [
9043
- {
9044
- value: "image/*",
9045
- label: "Images"
9046
- },
9047
- {
9048
- value: "audio/*",
9049
- label: "Audio files"
9050
- },
9051
- {
9052
- value: "video/*",
9053
- label: "Videos"
9054
- },
9055
- {
9056
- value: "text/*",
9057
- label: "Text files"
9058
- },
9059
- {
9060
- value: "application/*",
9061
- label: "Application files (includes PDFs and Word documents)"
9062
- }
9063
- ]
9064
- })
9061
+ {
9062
+ field: new NumberField({
9063
+ label: "How many files can be uploaded?",
9064
+ description: "By default, only one file can be uploaded.",
9065
+ required: false,
9066
+ minimum: 1,
9067
+ maximum: 10,
9068
+ identifier: `${path}maximum_files`,
9069
+ integers: true
9070
+ }),
9071
+ showDirectly: false
9072
+ },
9073
+ {
9074
+ field: new NumberField({
9075
+ // TODO: Default value
9076
+ label: "What is the maximum size of each file?",
9077
+ description: `Maximum file size in megabytes (between 1MB–${largestSupportedSize}MB).`,
9078
+ required: false,
9079
+ identifier: `${path}maximum_size`,
9080
+ minimum: 1,
9081
+ maximum: largestSupportedSize,
9082
+ integers: true
9083
+ }),
9084
+ showDirectly: false
9085
+ },
9086
+ {
9087
+ field: new MultiSelectField({
9088
+ label: "Accepted file types",
9089
+ description: "Types of allowed files to upload. If left blank, all files will be accepted.",
9090
+ required: false,
9091
+ identifier: `${path}extensions`,
9092
+ options: [
9093
+ {
9094
+ value: "image/*",
9095
+ label: "Images"
9096
+ },
9097
+ {
9098
+ value: "audio/*",
9099
+ label: "Audio files"
9100
+ },
9101
+ {
9102
+ value: "video/*",
9103
+ label: "Videos"
9104
+ },
9105
+ {
9106
+ value: "text/*",
9107
+ label: "Text files"
9108
+ },
9109
+ {
9110
+ value: "application/*",
9111
+ label: "Application files (includes PDFs and Word documents)"
9112
+ }
9113
+ ]
9114
+ }),
9115
+ showDirectly: false
9116
+ }
9065
9117
  ];
9066
9118
  }
9067
9119
  getFieldValidators() {
@@ -9115,44 +9167,33 @@ const FieldTypeToClsMapping = {
9115
9167
  "multi-string": MultiStringField,
9116
9168
  "multi-select": MultiSelectField
9117
9169
  };
9118
- const deserializeField = (serializedField) => {
9119
- const fieldType = serializedField.type;
9120
- const fieldCls = FieldTypeToClsMapping[fieldType];
9121
- return fieldCls.deserialize(serializedField);
9122
- };
9123
- const deserialize = (serialized) => {
9124
- if (serialized.type === "section") {
9125
- return FieldSection.deserialize(serialized);
9126
- }
9127
- return deserializeField(serialized);
9170
+ const FieldTypeToEmptyFieldMapping = {
9171
+ date: emptyDateField,
9172
+ number: emptyNumberField,
9173
+ boolean: emptyBooleanField,
9174
+ select: emptySelectField,
9175
+ string: emptyStringField,
9176
+ text: emptyTextField,
9177
+ custom: emptyCustomField,
9178
+ upload: emptyUploadField,
9179
+ // TODO: Underscore
9180
+ "multi-string": emptyMultiStringField,
9181
+ "multi-select": emptyMultiSelectField
9128
9182
  };
9129
- function formRevisionToSchema(formRevision, meta = {}) {
9130
- const { readonly = false } = meta;
9131
- return {
9132
- title: formRevision.title,
9133
- description: formRevision.description,
9134
- fields: formRevision.fields.map((serializedField) => deserialize(serializedField)),
9135
- meta: { readonly }
9136
- };
9137
- }
9138
- function valueIsFile(v) {
9139
- return Array.isArray(v) && v.some((v2) => v2 instanceof File || v2 instanceof Promise);
9140
- }
9141
- function isConditionMet(condition, value) {
9142
- if (!condition)
9143
- return true;
9144
- if (valueIsFile(value) || valueIsFile(condition.value))
9145
- throw new Error("Conditions do not support file uploads");
9146
- const valueAsPrimitive = Array.isArray(value) ? value.map((v) => typeof v === "string" ? v : v.value) : value;
9147
- const valueToCompare = Array.isArray(condition.value) ? condition.value.map((v) => typeof v === "string" ? v : v.value) : condition.value;
9148
- if (Array.isArray(valueToCompare) && Array.isArray(valueAsPrimitive)) {
9149
- for (const v of valueToCompare) {
9150
- if (!valueAsPrimitive.includes(v))
9151
- return false;
9152
- }
9153
- return true;
9183
+ const FieldInputCloner = memo(function FieldInputCloner2({ field, ...props }) {
9184
+ const [{ value: identifier }] = useField(field.options.clonedFieldIdentifier);
9185
+ const deserializedField = useMemo(() => {
9186
+ const options = field.options.getFieldToClone(identifier);
9187
+ if (!options)
9188
+ return null;
9189
+ return deserialize(options);
9190
+ }, [field.options, identifier]);
9191
+ return useFieldInput(deserializedField, props);
9192
+ });
9193
+ class FieldInputClonerField extends CustomField {
9194
+ constructor(options) {
9195
+ super(options, FieldInputCloner);
9154
9196
  }
9155
- return valueToCompare === value;
9156
9197
  }
9157
9198
  const useFieldInput = (field, props) => {
9158
9199
  return useMemo(() => {
@@ -9195,7 +9236,7 @@ const FieldSectionLayout = memo(function FieldSectionLayout2(props) {
9195
9236
  return /* @__PURE__ */ jsx(Card, { children: /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: "3", children: [
9196
9237
  /* @__PURE__ */ jsxs(Flex, { direction: "column", children: [
9197
9238
  /* @__PURE__ */ jsx(Heading, { as: "h3", size: "3", children: label }),
9198
- /* @__PURE__ */ jsx(Text, { className: styles$4.description, children: description2 })
9239
+ /* @__PURE__ */ jsx(Text, { className: styles$5.description, children: description2 })
9199
9240
  ] }),
9200
9241
  inputs
9201
9242
  ] }) });
@@ -9214,85 +9255,89 @@ const _FieldSection = class _FieldSection extends BaseFormElement {
9214
9255
  this.condition = null;
9215
9256
  }
9216
9257
  }
9217
- static getFieldCreationSchema(options) {
9258
+ static getFieldCreationSchema(options, parentPath) {
9218
9259
  if (options.length === 0)
9219
9260
  return [];
9261
+ const path = parentPath ? `${parentPath}.` : "";
9220
9262
  return [
9221
- new BooleanField({
9222
- label: "Conditional",
9223
- description: "Conditionally show or hide this section.",
9224
- identifier: "conditional",
9225
- required: false
9226
- }),
9227
- // Declare a section that will hold options for the condition (if any).
9228
- new _FieldSection({
9229
- label: "Conditional settings",
9230
- identifier: "conditional-settings",
9231
- // This section will only be rendered if the above "Conditional" field is checked.
9232
- condition: {
9233
- identifier: "conditional",
9234
- value: true
9235
- },
9236
- // These are the options of the condition.
9237
- fields: [
9238
- // Declare a select field that will be used to select the field against which we will check the
9239
- // condition. This must be selected before the next field is rendered.
9240
- new SelectField({
9241
- label: "Field",
9242
- description: "The field to use for the condition.",
9243
- // The options (for the field against which we will check the condition) are all the labels of
9244
- // the fields in the previous section(s) (or fields declared before with no section) that
9245
- // support conditions. We pass in both the label and the identifier of each supported field. The
9246
- // identifier becomes the value of the option.
9247
- options: options.map((option) => {
9248
- if (!option.label)
9249
- return null;
9250
- if (option.type === "upload")
9251
- return null;
9252
- return {
9253
- label: option.label,
9254
- value: option.identifier
9255
- };
9256
- }).filter((option) => !!option),
9257
- identifier: "condition.identifier",
9258
- required: true
9259
- }),
9260
- // Declare a custom field that will be used to input a value for the condition. The value of the
9261
- // conditional field selected in the previous step must be equal to the value the user inputs into
9262
- // this field for the section to be rendered.
9263
- new FieldInputClonerField({
9264
- label: "Value",
9265
- identifier: "condition.value",
9266
- required: true,
9267
- clonedFieldIdentifier: "condition.identifier",
9268
- getFieldToClone(identifier) {
9269
- if (!identifier) {
9270
- return null;
9271
- }
9272
- const option = options.find((option2) => option2.identifier === identifier);
9273
- if (!option) {
9274
- console.error("Could not find field with identifier", identifier);
9275
- return null;
9263
+ {
9264
+ field: new BooleanField({
9265
+ label: "Conditionally render section",
9266
+ identifier: `${path}conditional`,
9267
+ required: false
9268
+ }),
9269
+ showDirectly: true
9270
+ },
9271
+ {
9272
+ // Declare a section that will hold options for the condition (if any).
9273
+ field: new _FieldSection({
9274
+ label: "Conditional settings",
9275
+ identifier: `${path}conditional-settings`,
9276
+ // This section will only be rendered if the above "Conditional" field is checked.
9277
+ condition: {
9278
+ identifier: `${path}conditional`,
9279
+ value: true
9280
+ },
9281
+ // These are the options of the condition.
9282
+ fields: [
9283
+ // Declare a select field that will be used to select the field against which we will check the
9284
+ // condition. This must be selected before the next field is rendered.
9285
+ new SelectField({
9286
+ label: "Field",
9287
+ description: "The field to use for the condition.",
9288
+ // The options (for the field against which we will check the condition) are all the labels of
9289
+ // the fields in the previous section(s) (or fields declared before with no section) that
9290
+ // support conditions. We pass in both the label and the identifier of each supported field. The
9291
+ // identifier becomes the value of the option.
9292
+ options: options.map((option) => {
9293
+ if (!option.label)
9294
+ return null;
9295
+ if (option.type === "upload")
9296
+ return null;
9297
+ return {
9298
+ label: option.label,
9299
+ value: option.identifier
9300
+ };
9301
+ }).filter((option) => !!option),
9302
+ identifier: `${path}condition.identifier`,
9303
+ required: true
9304
+ }),
9305
+ // Declare a custom field that will be used to input a value for the condition. The value of the
9306
+ // conditional field selected in the previous step must be equal to the value the user inputs into
9307
+ // this field for the section to be rendered.
9308
+ new FieldInputClonerField({
9309
+ label: "Value",
9310
+ identifier: `${path}condition.value`,
9311
+ required: true,
9312
+ clonedFieldIdentifier: `${path}condition.identifier`,
9313
+ getFieldToClone(identifier) {
9314
+ if (!identifier) {
9315
+ return null;
9316
+ }
9317
+ const option = options.find((option2) => option2.identifier === identifier);
9318
+ if (!option) {
9319
+ console.error("Could not find field with identifier", identifier);
9320
+ return null;
9321
+ }
9322
+ return {
9323
+ ...option,
9324
+ // Override some options to make it make sense in the context and to make it work with the framework.
9325
+ label: "Value",
9326
+ identifier: `${path}condition.value`,
9327
+ description: "The value to compare against.",
9328
+ required: option.type !== "boolean"
9329
+ };
9276
9330
  }
9277
- return {
9278
- ...option,
9279
- // Override some options to make it make sense in the context and to make it work with the framework.
9280
- label: "Value",
9281
- identifier: "condition.value",
9282
- description: "The value to compare against.",
9283
- required: option.type !== "boolean"
9284
- };
9285
- }
9286
- })
9287
- ]
9288
- })
9331
+ })
9332
+ ]
9333
+ }),
9334
+ showDirectly: false
9335
+ }
9289
9336
  ];
9290
9337
  }
9291
9338
  static deserialize(data) {
9292
9339
  if (data.type !== "section")
9293
9340
  throw new Error("Invalid type");
9294
- if (!Array.isArray(data.fields))
9295
- throw new Error(`Invalid fields: ${data.fields} (not an array)`);
9296
9341
  const fields = data.fields.map(deserializeField);
9297
9342
  return new _FieldSection({ ...data, fields });
9298
9343
  }
@@ -9326,6 +9371,175 @@ const _FieldSection = class _FieldSection extends BaseFormElement {
9326
9371
  __publicField(_FieldSection, "fieldTypeName", "Section");
9327
9372
  __publicField(_FieldSection, "fieldTypeDescription", "Sections can be useful for grouping fields together. They can also be conditionally shown or hidden.");
9328
9373
  let FieldSection = _FieldSection;
9374
+ const deserializeField = (serializedField) => {
9375
+ const fieldType = serializedField.type;
9376
+ const fieldCls = FieldTypeToClsMapping[fieldType];
9377
+ return fieldCls.deserialize(serializedField);
9378
+ };
9379
+ const deserialize = (serialized) => {
9380
+ if (serialized.type === "section") {
9381
+ return FieldSection.deserialize(serialized);
9382
+ }
9383
+ return deserializeField(serialized);
9384
+ };
9385
+ function formRevisionToSchema(formRevision, meta = {}) {
9386
+ const { readonly = false } = meta;
9387
+ return {
9388
+ title: formRevision.title,
9389
+ description: formRevision.description,
9390
+ fields: formRevision.fields.map((serializedField) => deserialize(serializedField)),
9391
+ meta: { readonly }
9392
+ };
9393
+ }
9394
+ function valueIsFile(v) {
9395
+ return Array.isArray(v) && v.some((v2) => v2 instanceof File || v2 instanceof Promise);
9396
+ }
9397
+ const valueIsFormikUserFormRevision = (form) => {
9398
+ return "fields" in form;
9399
+ };
9400
+ function isConditionMet(condition, value) {
9401
+ if (!condition)
9402
+ return true;
9403
+ if (valueIsFile(value) || valueIsFile(condition.value))
9404
+ throw new Error("Conditions do not support file uploads");
9405
+ const valueAsPrimitive = Array.isArray(value) ? value.map((v) => typeof v === "string" ? v : v.value) : value;
9406
+ const valueToCompare = Array.isArray(condition.value) ? condition.value.map((v) => typeof v === "string" ? v : v.value) : condition.value;
9407
+ if (Array.isArray(valueToCompare) && Array.isArray(valueAsPrimitive)) {
9408
+ for (const v of valueToCompare) {
9409
+ if (!valueAsPrimitive.includes(v))
9410
+ return false;
9411
+ }
9412
+ return true;
9413
+ }
9414
+ return valueToCompare === value;
9415
+ }
9416
+ const emptyNumberField = {
9417
+ ...emptyBaseField,
9418
+ type: "number",
9419
+ minimum: Number.MIN_SAFE_INTEGER,
9420
+ maximum: Number.MAX_SAFE_INTEGER,
9421
+ integers: false
9422
+ };
9423
+ const _NumberField = class _NumberField extends BaseField {
9424
+ constructor(options) {
9425
+ const {
9426
+ minimum = Number.MIN_SAFE_INTEGER,
9427
+ maximum = Number.MAX_SAFE_INTEGER,
9428
+ integers = false,
9429
+ ...base
9430
+ } = options;
9431
+ super({ ...base, type: "number" });
9432
+ __publicField(this, "minimum");
9433
+ __publicField(this, "maximum");
9434
+ __publicField(this, "integers");
9435
+ this.minimum = minimum;
9436
+ this.maximum = maximum;
9437
+ this.integers = integers;
9438
+ }
9439
+ getValueFromChangeEvent(event) {
9440
+ const number = Number.parseFloat(event.target.value);
9441
+ if (Number.isNaN(number))
9442
+ return "";
9443
+ return number;
9444
+ }
9445
+ static getFieldCreationSchema(parentPath = "") {
9446
+ const path = parentPath && `${parentPath}.`;
9447
+ return [
9448
+ {
9449
+ field: new _NumberField({
9450
+ label: "Minimum",
9451
+ description: "Minimum value",
9452
+ integers: true,
9453
+ required: false,
9454
+ identifier: `${path}minimum`,
9455
+ formValidators: [this._validateMin(parentPath)]
9456
+ }),
9457
+ showDirectly: false
9458
+ },
9459
+ {
9460
+ field: new _NumberField({
9461
+ label: "Maximum",
9462
+ description: "Maximum value",
9463
+ integers: true,
9464
+ required: false,
9465
+ identifier: `${path}maximum`,
9466
+ formValidators: [this._validateMax(parentPath)]
9467
+ }),
9468
+ showDirectly: false
9469
+ },
9470
+ {
9471
+ field: new BooleanField({
9472
+ label: "Integers",
9473
+ description: "Whole numbers only",
9474
+ required: false,
9475
+ identifier: `${path}integers`
9476
+ }),
9477
+ showDirectly: false
9478
+ }
9479
+ ];
9480
+ }
9481
+ getFieldValidators() {
9482
+ const validators = super.getFieldValidators();
9483
+ const min = this.minimum;
9484
+ const max = this.maximum;
9485
+ if (typeof min === "number") {
9486
+ validators.push((value) => {
9487
+ if (typeof value === "number" && value < min) {
9488
+ return `Must be at least ${this.minimum}.`;
9489
+ }
9490
+ });
9491
+ }
9492
+ if (typeof max === "number") {
9493
+ validators.push((value) => {
9494
+ if (typeof value === "number" && value > max) {
9495
+ return `Must be at most ${this.maximum}.`;
9496
+ }
9497
+ });
9498
+ }
9499
+ if (this.integers) {
9500
+ validators.push((value) => {
9501
+ if (typeof value === "number" && !Number.isInteger(value)) {
9502
+ return "Must be a whole number.";
9503
+ }
9504
+ });
9505
+ }
9506
+ return validators;
9507
+ }
9508
+ serialize() {
9509
+ return {
9510
+ ...super._serialize(),
9511
+ minimum: this.minimum,
9512
+ maximum: this.maximum,
9513
+ integers: this.integers
9514
+ };
9515
+ }
9516
+ static deserialize(data) {
9517
+ if (data.type !== "number")
9518
+ throw new Error("Type mismatch.");
9519
+ return new _NumberField(data);
9520
+ }
9521
+ getInput(props) {
9522
+ return /* @__PURE__ */ jsx(NumberInput$1, { field: this, ...props });
9523
+ }
9524
+ };
9525
+ __publicField(_NumberField, "fieldTypeName", "Number");
9526
+ __publicField(_NumberField, "fieldTypeDescription", "Allows specifying a number within a given range.");
9527
+ __publicField(_NumberField, "Icon", FontFamilyIcon);
9528
+ __publicField(_NumberField, "_validateMin", (path) => (value, allValues) => {
9529
+ const field = valueIsFormikUserFormRevision(allValues) ? get(allValues, path) : allValues;
9530
+ if (typeof field.maximum === "number" && typeof value === "number" && field.maximum < value) {
9531
+ return "Minimum cannot be greater than minimum.";
9532
+ }
9533
+ return null;
9534
+ });
9535
+ __publicField(_NumberField, "_validateMax", (path) => (value, allValues) => {
9536
+ const field = valueIsFormikUserFormRevision(allValues) ? get(allValues, path) : allValues;
9537
+ if (typeof field.minimum === "number" && typeof value === "number" && field.minimum > value) {
9538
+ return "Maximum cannot be less than minimum.";
9539
+ }
9540
+ return null;
9541
+ });
9542
+ let NumberField = _NumberField;
9329
9543
  const hasKeys = (errors) => {
9330
9544
  return Object.keys(errors).length > 0;
9331
9545
  };
@@ -9408,7 +9622,7 @@ const FormRenderer = memo(
9408
9622
  [schema.title]
9409
9623
  );
9410
9624
  const Description = useMemo(
9411
- () => typeof schema.description === "string" ? /* @__PURE__ */ jsx(Text, { className: styles$4.description, children: schema.description }) : schema.description,
9625
+ () => typeof schema.description === "string" ? /* @__PURE__ */ jsx(Text, { className: styles$5.description, children: schema.description }) : schema.description,
9412
9626
  [schema.description]
9413
9627
  );
9414
9628
  const inputs = useFieldInputs(schema.fields, { formId: formId2, disabled: readonly });
@@ -9424,12 +9638,25 @@ const FormRenderer = memo(
9424
9638
  !hideDescription && Description
9425
9639
  ] }) }),
9426
9640
  inputs,
9427
- !readonly && /* @__PURE__ */ jsxs(Flex, { justify: "end", gap: "2", children: [
9428
- cancelText && /* @__PURE__ */ jsx(Button, { type: "button", variant: "soft", onClick: onCancel, children: cancelText }),
9429
- /* @__PURE__ */ jsx(Button, { type: "submit", disabled: !formik.isValid, children: submitText })
9430
- ] })
9431
- ] }) }) });
9432
- })
9641
+ !readonly && /* @__PURE__ */ jsxs(
9642
+ Flex,
9643
+ {
9644
+ justify: "end",
9645
+ gap: "2",
9646
+ align: "center",
9647
+ style: {
9648
+ position: "sticky",
9649
+ bottom: "0px",
9650
+ paddingBottom: "10px"
9651
+ },
9652
+ children: [
9653
+ cancelText && /* @__PURE__ */ jsx(Button, { type: "button", variant: "soft", onClick: onCancel, children: cancelText }),
9654
+ /* @__PURE__ */ jsx(Button, { type: "submit", disabled: !formik.isValid, children: submitText })
9655
+ ]
9656
+ }
9657
+ )
9658
+ ] }) }) });
9659
+ })
9433
9660
  );
9434
9661
  const FormSubmissionViewer = memo(
9435
9662
  forwardRef((props, ref) => {
@@ -9472,7 +9699,7 @@ const FormSubmissionViewer = memo(
9472
9699
  );
9473
9700
  const favoriteIcon = "_favoriteIcon_1bixi_1";
9474
9701
  const regularIcon = "_regularIcon_1bixi_9";
9475
- const styles$1 = {
9702
+ const styles$2 = {
9476
9703
  favoriteIcon,
9477
9704
  regularIcon
9478
9705
  };
@@ -9584,7 +9811,7 @@ const FormBrowserEntry = (props) => {
9584
9811
  /* @__PURE__ */ jsx(
9585
9812
  IconButton,
9586
9813
  {
9587
- className: classNames$1(form.favorite ? styles$1.favoriteIcon : styles$1.regularIcon),
9814
+ className: classNames$1(form.favorite ? styles$2.favoriteIcon : styles$2.regularIcon),
9588
9815
  variant: "ghost",
9589
9816
  onClick: handleFavoriteClick,
9590
9817
  "aria-label": form.favorite ? "Favorite form" : "Standard form",
@@ -9610,7 +9837,7 @@ const FormBrowserEntry = (props) => {
9610
9837
  };
9611
9838
  const submissionsContainer = "_submissionsContainer_9iirt_1";
9612
9839
  const stopHorizontalOverflow = "_stopHorizontalOverflow_9iirt_6";
9613
- const styles = {
9840
+ const styles$1 = {
9614
9841
  submissionsContainer,
9615
9842
  stopHorizontalOverflow
9616
9843
  };
@@ -9641,7 +9868,7 @@ const FormSubmissionBrowserEntry = memo(function FormSubmissionBrowserEntry2(pro
9641
9868
  }
9642
9869
  }, [submission, onSubmissionClick]);
9643
9870
  const row = /* @__PURE__ */ jsx(ButtonList.Item, { onClick: handleClick, asChild: true, children: /* @__PURE__ */ jsxs(Flex, { grow: "1", width: "100%", p: "2", gap: "2", justify: "between", children: [
9644
- /* @__PURE__ */ jsxs(Flex, { gap: "2", align: "center", className: styles.stopHorizontalOverflow, children: [
9871
+ /* @__PURE__ */ jsxs(Flex, { gap: "2", align: "center", className: styles$1.stopHorizontalOverflow, children: [
9645
9872
  /* @__PURE__ */ jsx(Avatar, { src: creatorProfileSrc, size: "1", fallback: creatorProfileFallback }),
9646
9873
  /* @__PURE__ */ jsx(Text, { size: "2", noWrap: true, children: labelType === "creator" ? (createdBy || currentUser).username : revision.title })
9647
9874
  ] }),
@@ -9685,7 +9912,7 @@ const FormSubmissionBrowser = memo(function FormSubmissionBrowser2(props) {
9685
9912
  return /* @__PURE__ */ jsx(
9686
9913
  ButtonList.Root,
9687
9914
  {
9688
- className: classNames$1(styles.submissionsContainer, className),
9915
+ className: classNames$1(styles$1.submissionsContainer, className),
9689
9916
  size: "small",
9690
9917
  variant,
9691
9918
  before: !compact && /* @__PURE__ */ jsxs(Text, { severity: "info", children: [
@@ -9709,23 +9936,22 @@ const FormSubmissionBrowser = memo(function FormSubmissionBrowser2(props) {
9709
9936
  );
9710
9937
  });
9711
9938
  const PatchField = memo((props) => {
9712
- console.log("PatchField props:", props);
9713
9939
  const { name, render } = props;
9714
9940
  const { submitForm } = useFormikContext();
9715
9941
  const [fieldProps, _meta, helpers] = useField(name);
9716
- const ret = useMemo(() => {
9942
+ return useMemo(() => {
9717
9943
  const setValue = (value) => {
9718
9944
  void helpers.setValue(value, false);
9719
9945
  };
9720
9946
  return render({
9721
9947
  value: fieldProps.value,
9948
+ meta: _meta,
9722
9949
  setValue,
9723
9950
  patchValue: () => {
9724
9951
  void submitForm();
9725
9952
  }
9726
9953
  });
9727
- }, [submitForm, helpers, fieldProps.value, render]);
9728
- return /* @__PURE__ */ jsx(Fragment$1, { children: ret });
9954
+ }, [render, fieldProps.value, _meta, submitForm, helpers]);
9729
9955
  });
9730
9956
  PatchField.displayName = "PatchField";
9731
9957
  const PatchFormProvider = memo(
@@ -9774,365 +10000,437 @@ const PatchFormProvider = memo(
9774
10000
  return /* @__PURE__ */ jsx(FormikProvider, { value: formik, children: /* @__PURE__ */ jsx("form", { ...rest, ref, onSubmit: formik.handleSubmit, children }) });
9775
10001
  })
9776
10002
  );
9777
- const CompleteFieldTypeToClsMapping = {
9778
- ...FieldTypeToClsMapping,
9779
- section: FieldSection
9780
- };
9781
- const FieldToChoose = memo(function FieldToChoose2(props) {
9782
- const { field, setFieldType } = props;
9783
- const typeName = field.fieldTypeName;
9784
- const description2 = field.fieldTypeDescription;
9785
- const Icon = field.Icon;
9786
- return /* @__PURE__ */ jsxs(Flex, { gap: "4", align: "center", children: [
9787
- /* @__PURE__ */ jsx(Button, { type: "button", variant: "surface", onClick: setFieldType, style: { width: "135px" }, children: /* @__PURE__ */ jsxs(Flex, { gap: "3", align: "center", grow: "1", children: [
9788
- /* @__PURE__ */ jsx(Icon, {}),
9789
- typeName
9790
- ] }) }),
9791
- /* @__PURE__ */ jsx(Text, { children: description2 })
9792
- ] });
9793
- });
10003
+ const formId = "form-builder";
9794
10004
  const fieldsToChoose = [
9795
10005
  ["string", "text"],
9796
10006
  ["select", "multi-select", "upload"],
9797
10007
  ["boolean", "date", "number", "multi-string"]
9798
10008
  ];
9799
- const indexOfLastFieldGroup = fieldsToChoose.length - 1;
9800
- const ChooseFieldToAdd = memo(function ChooseFieldToAdd2(props) {
9801
- const { setFieldType } = props;
9802
- return /* @__PURE__ */ jsx(Flex, { direction: "column", gap: "3", children: fieldsToChoose.map((fieldGroup, index2) => /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: "3", children: [
9803
- /* @__PURE__ */ jsx(Flex, { direction: "column", gap: "2", children: fieldGroup.map((identifier) => /* @__PURE__ */ jsx(
9804
- FieldToChoose,
9805
- {
9806
- field: FieldTypeToClsMapping[identifier],
9807
- setFieldType: () => {
9808
- setFieldType(identifier);
9809
- }
9810
- },
9811
- identifier
9812
- )) }),
9813
- index2 < indexOfLastFieldGroup && /* @__PURE__ */ jsx(Separator, { size: "4" })
9814
- ] }, index2)) });
9815
- });
9816
- const validateNewFieldName = (takenLabels) => {
9817
- return (value) => {
9818
- if (!value || typeof value !== "string")
9819
- return;
9820
- if (takenLabels.includes(value.trim())) {
9821
- return "This name is already taken.";
9822
- }
9823
- };
10009
+ const CompleteFieldTypeToClsMapping = {
10010
+ ...FieldTypeToClsMapping,
10011
+ section: FieldSection
9824
10012
  };
9825
- const commonFields = (takenLabels, type) => {
9826
- const base = [
9827
- new StringField({
9828
- label: "Label",
9829
- required: true,
9830
- maxLength: 200,
9831
- identifier: "label",
9832
- fieldValidators: [validateNewFieldName(takenLabels)]
9833
- }),
9834
- new TextField({
9835
- label: "Description",
9836
- required: false,
9837
- maxLength: 1e3,
9838
- identifier: "description"
9839
- })
9840
- ];
9841
- if (type === "section")
9842
- return base;
9843
- return [
9844
- ...base,
9845
- new BooleanField({ label: "Required", description: null, required: false, identifier: "required" })
9846
- ];
10013
+ const useFieldTypeItems = (onSelect = () => null) => {
10014
+ return useMemo(() => {
10015
+ return fieldsToChoose.map((fieldGroup) => {
10016
+ return fieldGroup.map((identifier) => {
10017
+ const field = FieldTypeToClsMapping[identifier];
10018
+ const Icon = field.Icon;
10019
+ return {
10020
+ content: /* @__PURE__ */ jsxs(Flex, { align: "center", gap: "2", children: [
10021
+ /* @__PURE__ */ jsx(Icon, {}),
10022
+ /* @__PURE__ */ jsx(Text, { children: field.fieldTypeName })
10023
+ ] }, identifier),
10024
+ value: identifier,
10025
+ onSelect: () => {
10026
+ onSelect(identifier);
10027
+ }
10028
+ };
10029
+ });
10030
+ });
10031
+ }, [onSelect]);
9847
10032
  };
9848
- const FieldOptionsForm = memo(function FieldOptionsForm2(props) {
9849
- const { fieldType, handleCancel, handleCreateField, handleDirtyChange, defaultField, conditionalSourceFields } = props;
9850
- const fieldCls = CompleteFieldTypeToClsMapping[fieldType];
9851
- const formik = useFormikContext();
9852
- const schema = useMemo(() => {
9853
- const takenFieldLabels = getTakenFieldLabels(formik.values.fields).filter((id) => id !== (defaultField == null ? void 0 : defaultField.label));
9854
- let fields = commonFields(takenFieldLabels, fieldType);
9855
- if (fieldCls === FieldSection) {
9856
- if (conditionalSourceFields === void 0) {
9857
- throw new Error("Conditional source fields must be provided when changing sections.");
10033
+ const FieldTypeDropdown = memo((props) => {
10034
+ const { setFieldType, children } = props;
10035
+ const fieldTypeItems = useFieldTypeItems(setFieldType);
10036
+ return /* @__PURE__ */ jsx(DropdownItemMenu, { trigger: children, items: fieldTypeItems.flat() });
10037
+ });
10038
+ FieldTypeDropdown.displayName = "FieldTypeDropdown";
10039
+ const forMobile = (mobile, display) => ({
10040
+ initial: mobile ? display : "none",
10041
+ sm: mobile ? "none" : display
10042
+ });
10043
+ const FieldActions = memo((props) => {
10044
+ const { index: index2, sectionIndex, type, remove: remove2, duplicate, addAfter, move } = props;
10045
+ if (type !== "section" && !addAfter) {
10046
+ throw new Error("addAfter is required for non-section fields");
10047
+ }
10048
+ const { values } = useFormikContext();
10049
+ const fieldTypeItems = useFieldTypeItems(addAfter);
10050
+ const [actions, mobileActions] = useMemo(() => {
10051
+ const getActions = (isMobile) => {
10052
+ const actions2 = [
10053
+ {
10054
+ Icon: TrashIcon,
10055
+ buttonProps: { onClick: remove2 },
10056
+ key: "delete",
10057
+ text: "Delete"
10058
+ },
10059
+ {
10060
+ Icon: CopyIcon,
10061
+ key: "duplicate",
10062
+ text: "Duplicate",
10063
+ buttonProps: { onClick: duplicate }
10064
+ }
10065
+ ];
10066
+ if (type !== "section") {
10067
+ actions2.push({
10068
+ // We want to show a dropdown with field types if "Add after" is clicked
10069
+ isComponent: true,
10070
+ Component: isMobile ? /* @__PURE__ */ jsx(DropdownMenuItemGroup, { items: fieldTypeItems.flat() }) : /* @__PURE__ */ jsx(FieldTypeDropdown, { setFieldType: addAfter, children: /* @__PURE__ */ jsx(IconButton, { type: "button", variant: "ghost", "aria-label": "Add after", children: /* @__PURE__ */ jsx(PlusIcon, {}) }) }),
10071
+ Icon: PlusIcon,
10072
+ key: "add",
10073
+ text: "Add after"
10074
+ });
9858
10075
  }
9859
- fields = fields.concat(fieldCls.getFieldCreationSchema(conditionalSourceFields));
9860
- } else {
9861
- if (!(fieldCls.prototype instanceof BaseField)) {
9862
- throw new Error(`Field must be an instance of BaseField. Got ${fieldCls.toString()}.`);
10076
+ if (sectionIndex === void 0 && index2 !== 0 || sectionIndex !== void 0 && (sectionIndex !== 0 || index2 !== 0)) {
10077
+ actions2.push({
10078
+ Icon: ArrowUpIcon,
10079
+ key: "moveUp",
10080
+ text: "Move up",
10081
+ buttonProps: {
10082
+ onClick: () => {
10083
+ move("up");
10084
+ }
10085
+ }
10086
+ });
9863
10087
  }
9864
- fields = [...fields, ...fieldCls.getFieldCreationSchema()];
9865
- }
9866
- return {
9867
- fields,
9868
- meta: { readonly: false },
9869
- // using the dialog title as the form title
9870
- title: null
10088
+ if (sectionIndex === void 0 && index2 !== values.fields.length - 1 || sectionIndex !== void 0 && (sectionIndex < values.fields.length - 1 || index2 !== values.fields[sectionIndex].fields.length - 1)) {
10089
+ actions2.push({
10090
+ Icon: ArrowDownIcon,
10091
+ key: "moveDown",
10092
+ text: "Move down",
10093
+ buttonProps: {
10094
+ onClick: () => {
10095
+ move("down");
10096
+ }
10097
+ }
10098
+ });
10099
+ }
10100
+ return actions2;
9871
10101
  };
9872
- }, [formik.values.fields, fieldType, fieldCls, defaultField == null ? void 0 : defaultField.label, conditionalSourceFields]);
10102
+ return [getActions(false), getActions(true)];
10103
+ }, [addAfter, duplicate, fieldTypeItems, index2, move, remove2, sectionIndex, type, values.fields]);
10104
+ return /* @__PURE__ */ jsxs(Fragment$1, { children: [
10105
+ /* @__PURE__ */ jsx(Flex, { gap: "4", display: forMobile(false, "flex"), children: actions.map((Action) => {
10106
+ if (Action.isComponent) {
10107
+ return Action.Component;
10108
+ }
10109
+ return /* @__PURE__ */ jsx(
10110
+ IconButton,
10111
+ {
10112
+ type: "button",
10113
+ variant: "ghost",
10114
+ severity: Action.key.startsWith("move") ? "info" : "primary",
10115
+ "aria-label": Action.text,
10116
+ ...Action.buttonProps,
10117
+ children: /* @__PURE__ */ jsx(Action.Icon, {})
10118
+ },
10119
+ Action.key
10120
+ );
10121
+ }) }),
10122
+ /* @__PURE__ */ jsx(Box, { display: forMobile(true, "block"), children: /* @__PURE__ */ jsxs(
10123
+ DropdownMenu,
10124
+ {
10125
+ trigger: /* @__PURE__ */ jsx(IconButton, { variant: "ghost", "aria-label": "Actions menu", children: /* @__PURE__ */ jsx(DotsVerticalIcon, {}) }),
10126
+ children: [
10127
+ /* @__PURE__ */ jsx(
10128
+ DropdownMenuItemGroup,
10129
+ {
10130
+ items: mobileActions.filter((Action) => !Action.isComponent).map((Action) => {
10131
+ var _a2;
10132
+ return {
10133
+ content: /* @__PURE__ */ jsxs(Flex, { gap: "2", align: "center", children: [
10134
+ /* @__PURE__ */ jsx(Action.Icon, {}),
10135
+ Action.text
10136
+ ] }, Action.key),
10137
+ value: Action.key,
10138
+ onSelect: (_a2 = Action.buttonProps) == null ? void 0 : _a2.onClick
10139
+ };
10140
+ })
10141
+ }
10142
+ ),
10143
+ /* @__PURE__ */ jsx(
10144
+ DropdownMenuSubMenuGroup,
10145
+ {
10146
+ items: mobileActions.filter((Action) => Action.isComponent).map((Action) => ({
10147
+ content: /* @__PURE__ */ jsxs(Flex, { gap: "2", align: "center", children: [
10148
+ /* @__PURE__ */ jsx(Action.Icon, {}),
10149
+ Action.text
10150
+ ] }, Action.key),
10151
+ subContent: Action.Component,
10152
+ triggerIndicator: null
10153
+ }))
10154
+ }
10155
+ )
10156
+ ]
10157
+ }
10158
+ ) })
10159
+ ] });
10160
+ });
10161
+ FieldActions.displayName = "FieldActions";
10162
+ const description = "_description_17zed_1";
10163
+ const styles = {
10164
+ description
10165
+ };
10166
+ const FieldSettingsPopover = memo((props) => {
10167
+ const { popoverInputs, hasError } = props;
9873
10168
  return /* @__PURE__ */ jsx(
9874
- FormRenderer,
10169
+ Popover,
9875
10170
  {
9876
- schema,
9877
- values: defaultField,
9878
- onSubmit: handleCreateField,
9879
- cancelText: defaultField ? void 0 : "Back",
9880
- onCancel: handleCancel,
9881
- onDirtyChange: handleDirtyChange
10171
+ size: "1",
10172
+ trigger: /* @__PURE__ */ jsxs(
10173
+ Button,
10174
+ {
10175
+ variant: "soft",
10176
+ size: "small",
10177
+ "aria-label": "settings",
10178
+ ...hasError && { severity: "danger" },
10179
+ hoverEffects: ["spin90Clockwise"],
10180
+ children: [
10181
+ /* @__PURE__ */ jsx(GearIcon, {}),
10182
+ /* @__PURE__ */ jsx(Text, { children: "Settings" })
10183
+ ]
10184
+ },
10185
+ "settings"
10186
+ ),
10187
+ children: () => /* @__PURE__ */ jsx(Flex, { direction: "column", style: { maxWidth: "240px" }, children: popoverInputs })
9882
10188
  }
9883
10189
  );
9884
10190
  });
9885
- const FieldBuilder = memo(function FieldBuilder2(props) {
9886
- const { parentPath, index: index2, isOpen, setIsOpen, initial, editing, conditionalSourceFields } = props;
9887
- const [fieldType, setFieldType] = useState();
9888
- const [formIsDirty, setFormIsDirty] = useState(false);
9889
- const type = (initial == null ? void 0 : initial.type) ?? fieldType;
9890
- const typeName = type ? CompleteFieldTypeToClsMapping[type].fieldTypeName : void 0;
9891
- const { setFieldValue, values } = useFormikContext();
9892
- if (editing && !initial)
9893
- throw new Error("Initial field must be provided if editing is true.");
9894
- const openConfirmDiscardChangesDialog = useDiscardAlertDialog();
9895
- const showChooseField = !type && !editing && !initial;
9896
- const title2 = showChooseField ? "Choose a field type" : `${typeName} settings`;
9897
- 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.`;
9898
- const handleCancel = useCallback(() => {
9899
- setFieldType(void 0);
9900
- setFormIsDirty(false);
10191
+ FieldSettingsPopover.displayName = "FieldSettingsPopover";
10192
+ const FieldBuilder = memo((props) => {
10193
+ var _a2, _b, _c, _d, _e, _f;
10194
+ const { parentPath, index: index2, initial, conditionalSourceFields } = props;
10195
+ const RADIX_SM_MIN_WIDTH = 576;
10196
+ const [isLargeScreen, setIsLargeScreen] = useState(
10197
+ window.matchMedia(`(min-width: ${RADIX_SM_MIN_WIDTH}px)`).matches
10198
+ );
10199
+ useEffect(() => {
10200
+ const mediaQuery = window.matchMedia(`(min-width: ${RADIX_SM_MIN_WIDTH}px)`);
10201
+ const handleMediaQueryChange = (event) => {
10202
+ setIsLargeScreen(event.matches);
10203
+ };
10204
+ mediaQuery.addEventListener("change", handleMediaQueryChange);
10205
+ return () => {
10206
+ mediaQuery.removeEventListener("change", handleMediaQueryChange);
10207
+ };
9901
10208
  }, []);
9902
- const handleCloseDialog = useCallback(() => {
9903
- if (!formIsDirty) {
9904
- setFieldType(void 0);
9905
- setIsOpen(false);
9906
- } else {
9907
- openConfirmDiscardChangesDialog({
9908
- onDiscard: () => {
9909
- setFieldType(void 0);
9910
- setIsOpen(false);
9911
- }
9912
- });
10209
+ const { values, setFieldValue, errors } = useFormikContext();
10210
+ const fieldTypeItems = useFieldTypeItems();
10211
+ const isSection = useCallback((field) => {
10212
+ return field.type === "section";
10213
+ }, []);
10214
+ useEffect(() => {
10215
+ if (isSection(initial) && !initial.conditional) {
10216
+ void setFieldValue(`${parentPath}.${index2}.condition`, null).then();
9913
10217
  }
9914
- }, [formIsDirty, openConfirmDiscardChangesDialog, setIsOpen]);
9915
- const handleCreateField = useCallback(
9916
- (form) => {
9917
- const { label } = form;
9918
- if (!type)
9919
- throw new Error("Field type must be selected before creating a field.");
9920
- if (!label || typeof label !== "string")
9921
- throw new Error("Label must be provided before creating a field.");
9922
- const field = deserialize({
9923
- type,
9924
- ...form,
9925
- identifier: makeIdentifier(form.identifier, label)
9926
- }).serialize();
9927
- const parent = get(values, parentPath);
9928
- if (parent === void 0) {
9929
- throw new Error("Parent path must point to an existing field.");
9930
- }
9931
- let newFields;
9932
- if (!Array.isArray(parent))
9933
- throw new Error("Parent path must point to an array.");
9934
- if (editing) {
9935
- newFields = replace(parent, index2, field);
9936
- } else {
9937
- newFields = insert(parent, index2, field);
9938
- }
9939
- void setFieldValue(parentPath, newFields).then();
9940
- setIsOpen(false);
10218
+ }, [index2, initial, isSection, parentPath, setFieldValue]);
10219
+ const conditionLabel = useMemo(
10220
+ () => {
10221
+ var _a3, _b2;
10222
+ return isSection(initial) ? (_b2 = findFieldByIdentifier(values.fields, (_a3 = initial.condition) == null ? void 0 : _a3.identifier)) == null ? void 0 : _b2.label : void 0;
9941
10223
  },
9942
- [type, values, parentPath, editing, setFieldValue, setIsOpen, index2]
10224
+ [initial, isSection, values.fields]
9943
10225
  );
9944
- const handleDirtyChange = useCallback((dirty) => {
9945
- setFormIsDirty(dirty);
9946
- }, []);
9947
- const dialogContent = useCallback(() => {
9948
- if (showChooseField) {
9949
- return /* @__PURE__ */ jsx(ChooseFieldToAdd, { setFieldType });
9950
- }
9951
- return /* @__PURE__ */ jsx(
9952
- FieldOptionsForm,
9953
- {
9954
- conditionalSourceFields,
9955
- handleCancel,
9956
- handleCreateField,
9957
- fieldType: type,
9958
- defaultField: initial,
9959
- handleDirtyChange
10226
+ const conditionComparison = isSection(initial) ? Array.isArray((_a2 = initial.condition) == null ? void 0 : _a2.value) ? "contains all of" : "equals" : void 0;
10227
+ let conditionValue = void 0;
10228
+ if (isSection(initial)) {
10229
+ if (valueIsFile((_b = initial.condition) == null ? void 0 : _b.value)) {
10230
+ throw new Error("File values are not supported for conditions.");
10231
+ }
10232
+ conditionValue = Array.isArray((_c = initial.condition) == null ? void 0 : _c.value) ? initial.condition.value.map((v) => typeof v === "string" ? v : v.label).join(", ") : (_e = (_d = initial.condition) == null ? void 0 : _d.value) == null ? void 0 : _e.toString();
10233
+ }
10234
+ const type = initial.type;
10235
+ const fieldCls = CompleteFieldTypeToClsMapping[type];
10236
+ const [directlyShownFields, popoverFields] = useMemo(() => {
10237
+ let directlyShownFields2 = [];
10238
+ let popoverFields2 = [];
10239
+ if (fieldCls === FieldSection) {
10240
+ if (conditionalSourceFields === void 0) {
10241
+ throw new Error("Conditional source fields must be provided when changing sections.");
9960
10242
  }
9961
- );
9962
- }, [conditionalSourceFields, handleCancel, handleCreateField, handleDirtyChange, initial, showChooseField, type]);
9963
- return /* @__PURE__ */ jsx(
9964
- Dialog,
9965
- {
9966
- title: title2,
9967
- description: description2,
9968
- content: dialogContent,
9969
- open: isOpen,
9970
- onOpenChange: handleCloseDialog
9971
- }
9972
- );
9973
- });
9974
- const forMobile = (mobile, display) => ({
9975
- initial: mobile ? display : "none",
9976
- sm: mobile ? "none" : display
9977
- });
9978
- const FieldActions = memo(function FieldActions2(props) {
9979
- const { remove: remove2, dragHandleProps, editProps, insertAfterProps, duplicateProps } = props;
9980
- const [isEditDialogOpen, setIsEditDialogOpen] = useState(false);
9981
- const [isDuplicateDialogOpen, setIsDuplicateDialogOpen] = useState(false);
9982
- const [isAddDialogOpen, setIsAddDialogOpen] = useState(false);
9983
- const actions = useMemo(
9984
- () => [
9985
- {
9986
- SelectedContent: FieldBuilder,
9987
- selectedContentProps: { ...editProps, isOpen: isEditDialogOpen, setIsOpen: setIsEditDialogOpen },
9988
- Icon: Pencil1Icon,
9989
- text: "Edit",
9990
- buttonProps: {
9991
- onClick: () => {
9992
- setIsEditDialogOpen(true);
9993
- }
9994
- }
9995
- },
9996
- {
9997
- Icon: TrashIcon,
9998
- buttonProps: {
9999
- onClick: remove2
10000
- },
10001
- text: "Delete"
10002
- },
10003
- {
10004
- SelectedContent: FieldBuilder,
10005
- selectedContentProps: {
10006
- ...duplicateProps,
10007
- isOpen: isDuplicateDialogOpen,
10008
- setIsOpen: setIsDuplicateDialogOpen
10009
- },
10010
- Icon: CopyIcon,
10011
- text: "Duplicate",
10012
- buttonProps: {
10013
- onClick: () => {
10014
- setIsDuplicateDialogOpen(true);
10015
- }
10016
- }
10017
- },
10018
- {
10019
- SelectedContent: FieldBuilder,
10020
- selectedContentProps: {
10021
- ...insertAfterProps,
10022
- isOpen: isAddDialogOpen,
10023
- setIsOpen: setIsAddDialogOpen
10024
- },
10025
- Icon: PlusIcon,
10026
- text: "Add after",
10027
- buttonProps: {
10028
- onClick: () => {
10029
- setIsAddDialogOpen(true);
10030
- }
10031
- }
10032
- },
10033
- {
10034
- // Wrapping icon in a div so that the asChild turns the button into a div
10035
- // so that the drag handle props are not applied to the icon
10036
- // Note: b/c the <button> does not handle the space-press event correctly
10037
- Icon: (props2) => /* @__PURE__ */ jsx("div", { ...props2, children: /* @__PURE__ */ jsx(DragHandleDots2Icon, {}) }),
10038
- text: "Reorder",
10039
- disableOnMobile: true,
10040
- buttonProps: { ...dragHandleProps, asChild: true }
10243
+ const fieldObject = fieldCls.getFieldCreationSchema(conditionalSourceFields, `${parentPath}.${index2}`);
10244
+ directlyShownFields2 = directlyShownFields2.concat(
10245
+ fieldObject.filter((field) => field.showDirectly).map((field) => field.field)
10246
+ );
10247
+ popoverFields2 = popoverFields2.concat(
10248
+ fieldObject.filter((field) => !field.showDirectly).map((field) => field.field)
10249
+ );
10250
+ } else {
10251
+ if (!(fieldCls.prototype instanceof BaseField)) {
10252
+ throw new Error(`Field must be an instance of BaseField. Got ${fieldCls.toString()}.`);
10041
10253
  }
10042
- ],
10043
- [
10044
- dragHandleProps,
10045
- duplicateProps,
10046
- editProps,
10047
- insertAfterProps,
10048
- isAddDialogOpen,
10049
- isDuplicateDialogOpen,
10050
- isEditDialogOpen,
10051
- remove2
10052
- ]
10053
- );
10054
- return /* @__PURE__ */ jsxs(Fragment$1, { children: [
10055
- /* @__PURE__ */ jsx(Flex, { gap: "4", display: forMobile(false, "flex"), children: actions.map((action) => {
10056
- return /* @__PURE__ */ jsxs(Fragment, { children: [
10254
+ const fieldObject = fieldCls.getFieldCreationSchema(
10255
+ `${parentPath}.${index2}`
10256
+ );
10257
+ if (isLargeScreen) {
10258
+ directlyShownFields2 = [
10259
+ ...directlyShownFields2,
10260
+ ...fieldObject.filter((field) => field.showDirectly).map((field) => field.field)
10261
+ ];
10262
+ popoverFields2 = [
10263
+ ...popoverFields2,
10264
+ ...fieldObject.filter((field) => !field.showDirectly).map((field) => field.field)
10265
+ ];
10266
+ } else {
10267
+ popoverFields2 = [...popoverFields2, ...fieldObject.map((field) => field.field)];
10268
+ }
10269
+ }
10270
+ return [directlyShownFields2, popoverFields2];
10271
+ }, [fieldCls, conditionalSourceFields, parentPath, index2, isLargeScreen]);
10272
+ const directlyShownInputs = useFieldInputs(directlyShownFields, {
10273
+ formId,
10274
+ disabled: false,
10275
+ ...fieldCls === FieldSection && { size: "2" }
10276
+ });
10277
+ const popoverInputs = useFieldInputs(popoverFields, {
10278
+ formId,
10279
+ disabled: false
10280
+ });
10281
+ let showPopoverInputs = popoverFields.length > 0;
10282
+ if (isSection(initial) && popoverFields.length > 0) {
10283
+ showPopoverInputs = initial.conditional;
10284
+ }
10285
+ const popoverHasErrors = popoverFields.some((field) => {
10286
+ const error = get(errors, fieldCls === FieldSection ? `${parentPath}.${index2}.condition` : field.getId());
10287
+ return error && (typeof error !== "object" || hasKeys(error));
10288
+ });
10289
+ return /* @__PURE__ */ jsxs(Flex, { align: "center", grow: "1", children: [
10290
+ /* @__PURE__ */ jsxs(Flex, { direction: "column", children: [
10291
+ fieldCls === FieldSection && /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: "1", children: [
10292
+ directlyShownFields.length > 0 && directlyShownInputs,
10293
+ /* @__PURE__ */ jsxs(Flex, { align: "center", gap: "2", children: [
10294
+ showPopoverInputs && /* @__PURE__ */ jsx(FieldSettingsPopover, { popoverInputs, hasError: popoverHasErrors }),
10295
+ isSection(initial) && initial.conditional && /* @__PURE__ */ jsx(Text, { size: "1", severity: popoverHasErrors ? "danger" : "primary", children: /* @__PURE__ */ jsxs(Em, { children: [
10296
+ "Display only if ",
10297
+ /* @__PURE__ */ jsx(Strong, { children: conditionLabel }),
10298
+ " ",
10299
+ conditionComparison,
10300
+ " ",
10301
+ /* @__PURE__ */ jsx(Strong, { children: conditionValue })
10302
+ ] }) })
10303
+ ] })
10304
+ ] }),
10305
+ fieldCls !== FieldSection && /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: "2", children: [
10057
10306
  /* @__PURE__ */ jsx(
10058
- IconButton,
10307
+ PatchField,
10059
10308
  {
10060
- type: "button",
10061
- variant: "ghost",
10062
- "aria-label": action.text,
10063
- ...action.buttonProps,
10064
- children: /* @__PURE__ */ jsx(action.Icon, {})
10309
+ name: `${parentPath}.${index2}.required`,
10310
+ render: ({ setValue, value }) => /* @__PURE__ */ jsx(
10311
+ Checkbox,
10312
+ {
10313
+ checked: value,
10314
+ onCheckedChange: setValue,
10315
+ label: /* @__PURE__ */ jsx(Text, { size: "2", children: "Required field" }),
10316
+ alwaysShow: true
10317
+ }
10318
+ )
10065
10319
  }
10066
10320
  ),
10067
- action.SelectedContent && /* @__PURE__ */ jsx(action.SelectedContent, { ...action.selectedContentProps })
10068
- ] }, action.text);
10069
- }) }),
10070
- /* @__PURE__ */ jsx(Box, { display: forMobile(true, "block"), children: /* @__PURE__ */ jsx(
10071
- DropdownItemMenu,
10072
- {
10073
- trigger: /* @__PURE__ */ jsx(IconButton, { variant: "ghost", "aria-label": "Actions menu", children: /* @__PURE__ */ jsx(DotsVerticalIcon, {}) }),
10074
- items: actions.map((action) => {
10075
- if (action.disableOnMobile)
10076
- return null;
10077
- return {
10078
- ...action.buttonProps,
10079
- onSelect: (event) => {
10080
- var _a2, _b;
10081
- (_b = (_a2 = action.buttonProps) == null ? void 0 : _a2.onClick) == null ? void 0 : _b.call(
10082
- _a2,
10083
- // TODO: Clean up types
10084
- event
10085
- );
10086
- },
10087
- content: /* @__PURE__ */ jsxs(Fragment, { children: [
10088
- /* @__PURE__ */ jsxs(Flex, { gap: "2", align: "center", children: [
10089
- /* @__PURE__ */ jsx(action.Icon, {}),
10090
- action.text
10091
- ] }),
10092
- action.SelectedContent && /* @__PURE__ */ jsx(action.SelectedContent, { ...action.selectedContentProps })
10093
- ] }, action.text)
10094
- };
10095
- }).filter((x) => x !== null)
10096
- }
10097
- ) })
10321
+ /* @__PURE__ */ jsxs(Flex, { align: "center", gap: "3", children: [
10322
+ /* @__PURE__ */ jsx(Badge, { style: { width: "fit-content", height: "24px" }, children: (_f = fieldTypeItems.flat().find((item) => item.value === type)) == null ? void 0 : _f.content }),
10323
+ showPopoverInputs && /* @__PURE__ */ jsx(FieldSettingsPopover, { popoverInputs, hasError: popoverHasErrors })
10324
+ ] })
10325
+ ] }),
10326
+ /* @__PURE__ */ jsx(
10327
+ PatchField,
10328
+ {
10329
+ name: `${parentPath}.${index2}.label`,
10330
+ render: ({ setValue, value }) => /* @__PURE__ */ jsx(
10331
+ Input,
10332
+ {
10333
+ className: styles.Input,
10334
+ placeholder: `Enter a ${type === "section" ? "section" : "field"} label`,
10335
+ value,
10336
+ onChange: (event) => {
10337
+ setValue(event.target.value);
10338
+ },
10339
+ maxLength: 200,
10340
+ showInputLength: false,
10341
+ variant: "ghost",
10342
+ size: "large"
10343
+ }
10344
+ )
10345
+ }
10346
+ ),
10347
+ /* @__PURE__ */ jsx(
10348
+ PatchField,
10349
+ {
10350
+ name: `${parentPath}.${index2}.description`,
10351
+ render: ({ setValue, value }) => /* @__PURE__ */ jsx(
10352
+ TextArea,
10353
+ {
10354
+ style: { minHeight: "max-content" },
10355
+ placeholder: `Enter a ${type === "section" ? "section" : "field"} description`,
10356
+ value,
10357
+ onChange: (event) => {
10358
+ setValue(event.target.value);
10359
+ },
10360
+ resize: "vertical",
10361
+ maxLength: 1e3,
10362
+ showInputLength: false,
10363
+ variant: "ghost"
10364
+ }
10365
+ )
10366
+ }
10367
+ )
10368
+ ] }),
10369
+ fieldCls !== FieldSection && directlyShownFields.length > 0 && directlyShownInputs
10098
10370
  ] });
10099
10371
  });
10100
- const formId = "form-builder";
10101
- const FieldWithActions = memo(function FieldWithActions2(props) {
10372
+ FieldBuilder.displayName = "FieldBuilder";
10373
+ const FieldWithActions = memo((props) => {
10102
10374
  const { field, index: index2, sectionIndex, takenLabels, remove: remove2 } = props;
10103
- const deserializedField = useMemo(() => deserialize(field), [field]);
10104
- const input = useFieldInput(deserializedField, { formId, disabled: true });
10105
- const duplicateField = useCallback(
10106
- (field2) => {
10107
- const fieldLabel = field2.label ?? "Untitled field";
10108
- return { ...field2, label: incrementFieldLabel(fieldLabel, takenLabels), identifier: "" };
10109
- },
10110
- [takenLabels]
10111
- );
10375
+ const { setFieldValue, values } = useFormikContext();
10376
+ const { reorderField } = useFieldReordering();
10377
+ const parentPath = `fields.${sectionIndex}.fields`;
10112
10378
  const editFieldProps = useMemo(
10113
10379
  () => ({
10114
10380
  index: index2,
10115
- parentPath: `fields.${sectionIndex}.fields`,
10116
- initial: field,
10117
- editing: true
10381
+ parentPath,
10382
+ initial: field
10118
10383
  }),
10119
- [field, index2, sectionIndex]
10384
+ [field, index2, parentPath]
10120
10385
  );
10121
- const duplicateFieldProps = useMemo(
10122
- () => ({
10123
- parentPath: `fields.${sectionIndex}.fields`,
10124
- index: index2 + 1,
10125
- initial: duplicateField(field)
10126
- }),
10127
- [duplicateField, field, index2, sectionIndex]
10386
+ const duplicateField = useCallback(() => {
10387
+ const label = field.label ?? "Unlabelled field";
10388
+ const duplicatedField = {
10389
+ ...field,
10390
+ label: incrementFieldLabel(label, takenLabels)
10391
+ };
10392
+ createNewField(parentPath, index2 + 1, duplicatedField, values, setFieldValue);
10393
+ }, [field, takenLabels, parentPath, index2, values, setFieldValue]);
10394
+ const createFieldAfter = useCallback(
10395
+ (type) => {
10396
+ if (type === "section") {
10397
+ throw new Error("Section type unexpected");
10398
+ }
10399
+ createNewField(
10400
+ parentPath,
10401
+ index2 + 1,
10402
+ FieldTypeToEmptyFieldMapping[type],
10403
+ values,
10404
+ setFieldValue
10405
+ );
10406
+ },
10407
+ [parentPath, index2, values, setFieldValue]
10128
10408
  );
10129
- const insertAfterProps = useMemo(
10130
- () => ({
10131
- parentPath: `fields.${sectionIndex}.fields`,
10132
- index: index2 + 1,
10133
- initial: void 0
10134
- }),
10135
- [index2, sectionIndex]
10409
+ const moveField = useCallback(
10410
+ (direction) => {
10411
+ const srcSectionIndex = sectionIndex;
10412
+ const srcSection = values.fields[srcSectionIndex];
10413
+ let destSectionIndex = sectionIndex;
10414
+ let destFieldIndex = direction === "up" ? index2 - 1 : index2 + 1;
10415
+ if (direction === "up" && index2 === 0) {
10416
+ destSectionIndex = sectionIndex - 1;
10417
+ destFieldIndex = values.fields[destSectionIndex].fields.length;
10418
+ } else if (direction === "down" && index2 === srcSection.fields.length - 1) {
10419
+ destSectionIndex = sectionIndex + 1;
10420
+ destFieldIndex = 0;
10421
+ }
10422
+ const destSection = values.fields[destSectionIndex];
10423
+ reorderField(
10424
+ srcSection,
10425
+ srcSectionIndex,
10426
+ index2,
10427
+ destSection,
10428
+ destSectionIndex,
10429
+ destFieldIndex,
10430
+ setFieldValue
10431
+ );
10432
+ },
10433
+ [sectionIndex, values.fields, index2, reorderField, setFieldValue]
10136
10434
  );
10137
10435
  return /* @__PURE__ */ jsx(Draggable, { draggableId: field.identifier, index: index2, children: (draggableProvided) => /* @__PURE__ */ jsx(
10138
10436
  Card,
@@ -10140,30 +10438,38 @@ const FieldWithActions = memo(function FieldWithActions2(props) {
10140
10438
  ref: draggableProvided.innerRef,
10141
10439
  ...draggableProvided.draggableProps,
10142
10440
  ...draggableProvided.dragHandleProps,
10441
+ style: {
10442
+ ...draggableProvided.draggableProps.style,
10443
+ backgroundColor: "var(--accent-1)",
10444
+ borderColor: "var(--accent-3)"
10445
+ },
10143
10446
  mb: "4",
10144
10447
  children: /* @__PURE__ */ jsxs(Flex, { gap: "4", justify: "between", align: "center", children: [
10145
- input,
10448
+ /* @__PURE__ */ jsx(FieldBuilder, { ...editFieldProps }),
10146
10449
  /* @__PURE__ */ jsx(
10147
10450
  FieldActions,
10148
10451
  {
10452
+ index: index2,
10453
+ sectionIndex,
10454
+ type: field.type,
10149
10455
  remove: remove2,
10150
- editProps: editFieldProps,
10151
- duplicateProps: duplicateFieldProps,
10152
- insertAfterProps,
10153
- dragHandleProps: draggableProvided.dragHandleProps
10456
+ duplicate: duplicateField,
10457
+ addAfter: createFieldAfter,
10458
+ move: moveField
10154
10459
  }
10155
10460
  )
10156
10461
  ] })
10157
10462
  }
10158
10463
  ) });
10159
10464
  });
10160
- const FieldSectionWithActions = memo(function FieldSectionWithActions2(props) {
10161
- var _a2, _b, _c, _d, _e, _f, _g;
10465
+ FieldWithActions.displayName = "FieldWithActions";
10466
+ const FieldSectionWithActions = memo((props) => {
10467
+ var _a2;
10162
10468
  const { field, index: sectionIndex, dropState } = props;
10163
10469
  const isDropDisabled = (_a2 = dropState[field.identifier]) == null ? void 0 : _a2.disabled;
10164
- const [isAddFieldDialogOpen, setIsAddFieldDialogOpen] = useState(false);
10165
10470
  const { setFieldValue, values } = useFormikContext();
10166
10471
  const alertDialog = useAlertDialog();
10472
+ const { reorderSection } = useFieldReordering();
10167
10473
  const takenFieldLabels = getTakenFieldLabels(values.fields);
10168
10474
  const removeSectionConditions = useCallback(
10169
10475
  (sectionsToUpdate, allSections) => {
@@ -10250,152 +10556,113 @@ const FieldSectionWithActions = memo(function FieldSectionWithActions2(props) {
10250
10556
  alertDialog,
10251
10557
  removeSectionConditions
10252
10558
  ]);
10253
- const duplicateSection = useCallback(
10254
- (field2) => {
10255
- const fieldLabel = field2.label ?? "Untitled section";
10256
- const newSectionLabel = incrementFieldLabel(fieldLabel, takenFieldLabels);
10257
- const newFields = field2.fields.map((f) => {
10258
- const newLabel = incrementFieldLabel(f.label || "Untitled field", takenFieldLabels);
10259
- return {
10260
- ...f,
10261
- label: newLabel,
10262
- identifier: makeIdentifier(void 0, newLabel)
10263
- };
10264
- });
10265
- return { ...field2, label: newSectionLabel, fields: newFields, identifier: "" };
10559
+ const moveSection = useCallback(
10560
+ (direction) => {
10561
+ const destinationIndex = direction === "up" ? sectionIndex - 1 : sectionIndex + 1;
10562
+ reorderSection(dropState, field.identifier, sectionIndex, destinationIndex, values, setFieldValue);
10266
10563
  },
10267
- [takenFieldLabels]
10564
+ [sectionIndex, reorderSection, dropState, field.identifier, values, setFieldValue]
10268
10565
  );
10269
10566
  const editSectionProps = useMemo(
10270
10567
  () => ({
10271
10568
  index: sectionIndex,
10272
10569
  parentPath: "fields",
10273
10570
  initial: field,
10274
- editing: true,
10275
10571
  conditionalSourceFields: makeConditionalSourceFields(values.fields, sectionIndex)
10276
10572
  }),
10277
10573
  [field, sectionIndex, values.fields]
10278
10574
  );
10279
- const insertSectionProps = useMemo(
10280
- () => ({
10281
- index: sectionIndex + 1,
10282
- parentPath: "fields",
10283
- initial: emptySection(),
10284
- conditionalSourceFields: makeConditionalSourceFields(values.fields, sectionIndex + 1)
10285
- }),
10286
- [sectionIndex, values.fields]
10287
- );
10288
- const insertFieldAtEndOfSection = useMemo(
10289
- () => ({
10290
- parentPath: `fields.${sectionIndex}.fields`,
10291
- index: field.fields.length,
10292
- initial: void 0
10293
- }),
10294
- [field.fields.length, sectionIndex]
10295
- );
10296
- const duplicateSectionProps = useMemo(
10297
- () => ({
10298
- index: sectionIndex + 1,
10299
- parentPath: "fields",
10300
- initial: duplicateSection(field),
10301
- conditionalSourceFields: makeConditionalSourceFields(values.fields, sectionIndex + 1)
10302
- }),
10303
- [duplicateSection, field, sectionIndex, values.fields]
10304
- );
10305
- const conditionLabel = useMemo(
10306
- () => {
10307
- var _a3, _b2;
10308
- return (_b2 = findFieldByIdentifier(values.fields, (_a3 = field.condition) == null ? void 0 : _a3.identifier)) == null ? void 0 : _b2.label;
10575
+ const duplicateSection = useCallback(() => {
10576
+ const fieldLabel = field.label ?? "Untitled section";
10577
+ const newSectionLabel = incrementFieldLabel(fieldLabel, takenFieldLabels);
10578
+ const newFields = field.fields.map((f) => {
10579
+ const newLabel = incrementFieldLabel(f.label, takenFieldLabels);
10580
+ return {
10581
+ ...f,
10582
+ label: newLabel,
10583
+ identifier: makeIdentifier(null, newLabel)
10584
+ };
10585
+ });
10586
+ const duplicatedField = { ...field, label: newSectionLabel, fields: newFields };
10587
+ createNewField("fields", sectionIndex + 1, duplicatedField, values, setFieldValue);
10588
+ }, [field, takenFieldLabels, sectionIndex, values, setFieldValue]);
10589
+ const handleCreateField = useCallback(
10590
+ (type) => {
10591
+ createNewField(
10592
+ `fields.${sectionIndex}.fields`,
10593
+ field.fields.length,
10594
+ FieldTypeToEmptyFieldMapping[type],
10595
+ values,
10596
+ setFieldValue
10597
+ );
10309
10598
  },
10310
- [(_b = field.condition) == null ? void 0 : _b.identifier, values.fields]
10599
+ [sectionIndex, field.fields.length, values, setFieldValue]
10311
10600
  );
10312
- const conditionComparison = Array.isArray((_c = field.condition) == null ? void 0 : _c.value) ? "contains all of" : "equals";
10313
- if (valueIsFile((_d = field.condition) == null ? void 0 : _d.value))
10314
- throw new Error("File values are not supported for conditions.");
10315
- const conditionValue = Array.isArray((_e = field.condition) == null ? void 0 : _e.value) ? field.condition.value.map((v) => typeof v === "string" ? v : v.label).join(", ") : (_g = (_f = field.condition) == null ? void 0 : _f.value) == null ? void 0 : _g.toString();
10316
- return /* @__PURE__ */ jsx(Draggable, { draggableId: field.identifier, index: sectionIndex, children: (draggableProvided) => /* @__PURE__ */ jsx(
10317
- Card,
10318
- {
10319
- ref: draggableProvided.innerRef,
10320
- ...draggableProvided.draggableProps,
10321
- ...draggableProvided.dragHandleProps,
10322
- mb: "4",
10323
- children: /* @__PURE__ */ jsxs(Flex, { gap: "3", justify: "between", align: "center", children: [
10324
- /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: "2", grow: "1", children: [
10325
- /* @__PURE__ */ jsxs(Flex, { direction: "column", children: [
10326
- /* @__PURE__ */ jsx(Heading, { as: "h3", size: "3", children: field.label }),
10327
- /* @__PURE__ */ jsx(Text, { className: styles$4.description, children: field.description })
10328
- ] }),
10329
- field.condition && /* @__PURE__ */ jsx(Text, { size: "1", children: /* @__PURE__ */ jsxs(Em, { children: [
10330
- "Display only if ",
10331
- /* @__PURE__ */ jsx(Strong, { children: conditionLabel }),
10332
- " ",
10333
- conditionComparison,
10334
- " ",
10335
- /* @__PURE__ */ jsx(Strong, { children: conditionValue })
10336
- ] }) }),
10337
- /* @__PURE__ */ jsx(Droppable, { droppableId: field.identifier, type: "SECTION", isDropDisabled, children: (droppableProvided) => /* @__PURE__ */ jsxs(
10338
- Flex,
10339
- {
10340
- ref: droppableProvided.innerRef,
10341
- ...droppableProvided.droppableProps,
10342
- direction: "column",
10343
- gap: "0",
10344
- children: [
10345
- field.fields.map((child, i) => /* @__PURE__ */ jsx(
10346
- FieldWithActions,
10347
- {
10348
- field: child,
10349
- index: i,
10350
- sectionIndex,
10351
- remove: () => {
10352
- removeField(i);
10353
- },
10354
- takenLabels: takenFieldLabels
10355
- },
10356
- child.identifier
10357
- )),
10358
- droppableProvided.placeholder,
10359
- /* @__PURE__ */ jsxs(
10360
- Button,
10601
+ return /* @__PURE__ */ jsx(Draggable, { draggableId: field.identifier, index: sectionIndex, children: (draggableProvided) => {
10602
+ return /* @__PURE__ */ jsx(
10603
+ Card,
10604
+ {
10605
+ ref: draggableProvided.innerRef,
10606
+ ...draggableProvided.draggableProps,
10607
+ ...draggableProvided.dragHandleProps,
10608
+ mb: "4",
10609
+ children: /* @__PURE__ */ jsxs(Flex, { gap: "3", justify: "between", align: "center", children: [
10610
+ /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: "2", grow: "1", children: [
10611
+ /* @__PURE__ */ jsx(FieldBuilder, { ...editSectionProps }),
10612
+ /* @__PURE__ */ jsx(
10613
+ Droppable,
10614
+ {
10615
+ droppableId: field.identifier,
10616
+ type: "SECTION",
10617
+ isDropDisabled,
10618
+ children: (droppableProvided) => /* @__PURE__ */ jsxs(
10619
+ Flex,
10361
10620
  {
10362
- type: "button",
10363
- variant: "outline",
10364
- onClick: () => {
10365
- setIsAddFieldDialogOpen(true);
10366
- },
10621
+ ref: droppableProvided.innerRef,
10622
+ ...droppableProvided.droppableProps,
10623
+ direction: "column",
10624
+ gap: "0",
10367
10625
  children: [
10368
- /* @__PURE__ */ jsx(PlusIcon, {}),
10369
- " Add a field"
10626
+ field.fields.map((child, i) => /* @__PURE__ */ jsx(
10627
+ FieldWithActions,
10628
+ {
10629
+ field: child,
10630
+ index: i,
10631
+ sectionIndex,
10632
+ remove: () => {
10633
+ removeField(i);
10634
+ },
10635
+ takenLabels: takenFieldLabels
10636
+ },
10637
+ child.identifier
10638
+ )),
10639
+ droppableProvided.placeholder,
10640
+ /* @__PURE__ */ jsx(FieldTypeDropdown, { setFieldType: handleCreateField, children: /* @__PURE__ */ jsxs(Button, { type: "button", variant: "soft", children: [
10641
+ /* @__PURE__ */ jsx(PlusIcon, {}),
10642
+ " Add field"
10643
+ ] }) })
10370
10644
  ]
10371
10645
  }
10372
- ),
10373
- /* @__PURE__ */ jsx(
10374
- FieldBuilder,
10375
- {
10376
- ...insertFieldAtEndOfSection,
10377
- isOpen: isAddFieldDialogOpen,
10378
- setIsOpen: setIsAddFieldDialogOpen
10379
- }
10380
10646
  )
10381
- ]
10647
+ }
10648
+ )
10649
+ ] }),
10650
+ /* @__PURE__ */ jsx(
10651
+ FieldActions,
10652
+ {
10653
+ index: sectionIndex,
10654
+ type: field.type,
10655
+ remove: removeSection,
10656
+ duplicate: duplicateSection,
10657
+ move: moveSection
10382
10658
  }
10383
- ) })
10384
- ] }),
10385
- /* @__PURE__ */ jsx(
10386
- FieldActions,
10387
- {
10388
- remove: removeSection,
10389
- insertAfterProps: insertSectionProps,
10390
- dragHandleProps: draggableProvided.dragHandleProps,
10391
- editProps: editSectionProps,
10392
- duplicateProps: duplicateSectionProps
10393
- }
10394
- )
10395
- ] })
10396
- }
10397
- ) });
10659
+ )
10660
+ ] })
10661
+ }
10662
+ );
10663
+ } });
10398
10664
  });
10665
+ FieldSectionWithActions.displayName = "FieldSectionWithActions";
10399
10666
  const reducer = (state, action) => {
10400
10667
  var _a2;
10401
10668
  const next = { ...state };
@@ -10457,11 +10724,40 @@ const findSection = (fields, sectionId) => {
10457
10724
  return [section, i];
10458
10725
  }
10459
10726
  };
10460
- const FieldsEditor = memo(function FieldsEditor2() {
10727
+ const BasicFieldSection = memo((props) => {
10728
+ const { field, provided } = props;
10729
+ return /* @__PURE__ */ jsx(
10730
+ Card,
10731
+ {
10732
+ ref: provided == null ? void 0 : provided.innerRef,
10733
+ ...provided == null ? void 0 : provided.draggableProps,
10734
+ ...provided == null ? void 0 : provided.dragHandleProps,
10735
+ style: { ...provided == null ? void 0 : provided.draggableProps.style, height: "80px" },
10736
+ children: /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: "2", children: [
10737
+ /* @__PURE__ */ jsxs(Flex, { direction: "row", gap: "2", children: [
10738
+ /* @__PURE__ */ jsx(Text, { size: "4", children: field.label }),
10739
+ /* @__PURE__ */ jsx(Badge, { style: { width: "fit-content" }, children: /* @__PURE__ */ jsxs(Text, { children: [
10740
+ field.fields.length,
10741
+ " Fields"
10742
+ ] }) })
10743
+ ] }),
10744
+ /* @__PURE__ */ jsx(Flex, { direction: "row", gap: "2", children: field.fields.map((child) => {
10745
+ const childInfo = FieldTypeToClsMapping[child.type];
10746
+ const Icon = childInfo.Icon;
10747
+ return /* @__PURE__ */ jsx(Flex, { gap: "3", children: /* @__PURE__ */ jsxs(Badge, { style: { width: "fit-content" }, children: [
10748
+ /* @__PURE__ */ jsx(Icon, {}),
10749
+ /* @__PURE__ */ jsx(Text, { children: childInfo.fieldTypeName })
10750
+ ] }) }, child.identifier);
10751
+ }) })
10752
+ ] })
10753
+ }
10754
+ );
10755
+ });
10756
+ BasicFieldSection.displayName = "BasicFieldSection";
10757
+ const FieldsEditor = memo(() => {
10461
10758
  const { values, setFieldValue } = useFormikContext();
10462
10759
  const [dropState, dispatch] = useReducer(reducer, values.fields, initializer);
10463
- const [isAddSectionDialogOpen, setIsAddSectionDialogOpen] = useState(false);
10464
- const { showInfo } = useToast();
10760
+ const { reorderSection, reorderField } = useFieldReordering();
10465
10761
  useEffect(() => {
10466
10762
  dispatch({ type: "update", state: initializer(values.fields) });
10467
10763
  }, [dispatch, values.fields]);
@@ -10477,58 +10773,30 @@ const FieldsEditor = memo(function FieldsEditor2() {
10477
10773
  if (!destination || reason === "CANCEL")
10478
10774
  return;
10479
10775
  if (type === "ROOT") {
10480
- const state = dropState[draggableId];
10481
- if (!state)
10482
- throw new Error("Could not find section context.");
10483
- let dest = typeof state.conditionIndex !== "undefined" ? (
10484
- // cannot move a section with a condition before the condition's field
10485
- Math.max(state.conditionIndex + 1, destination.index)
10486
- ) : destination.index;
10487
- for (const section of Object.values(dropState)) {
10488
- if (section.conditionIndex === source.index) {
10489
- dest = Math.min(dest, section.index - 1);
10490
- }
10491
- }
10492
- if (dest != destination.index) {
10493
- showInfo({
10494
- title: "Reordered sections",
10495
- description: "Sections with conditions must be below the fields they reference."
10496
- });
10497
- }
10498
- return setFieldValue("fields", reorder(values.fields, source.index, dest));
10776
+ reorderSection(dropState, draggableId, source.index, destination.index, values, setFieldValue);
10777
+ return;
10499
10778
  }
10500
10779
  if (type !== "SECTION")
10501
10780
  throw new Error("Unexpected droppable type.");
10502
10781
  const [sourceSection, srcIndex] = findSection(values.fields, source.droppableId) ?? [];
10503
10782
  const [destinationSection, destIndex] = findSection(values.fields, destination.droppableId) ?? [];
10504
- if (!(sourceSection == null ? void 0 : sourceSection.fields) || !destinationSection)
10505
- throw new Error("Could not find section with fields.");
10506
- if (sourceSection.identifier === destinationSection.identifier) {
10507
- void setFieldValue(
10508
- `fields.${srcIndex}.fields`,
10509
- reorder(sourceSection.fields, source.index, destination.index)
10510
- ).then();
10511
- } else {
10512
- const removed = sourceSection.fields[source.index];
10513
- if (!removed)
10514
- throw new Error("Could not find field to reorder.");
10515
- void setFieldValue(`fields.${srcIndex}.fields`, remove(sourceSection.fields, source.index)).then();
10516
- void setFieldValue(
10517
- `fields.${destIndex}.fields`,
10518
- insert(destinationSection.fields, destination.index, removed)
10519
- ).then();
10520
- }
10783
+ reorderField(
10784
+ sourceSection,
10785
+ srcIndex,
10786
+ source.index,
10787
+ destinationSection,
10788
+ destIndex,
10789
+ destination.index,
10790
+ setFieldValue
10791
+ );
10521
10792
  },
10522
- [values.fields, setFieldValue, dropState, showInfo]
10793
+ [values, reorderField, setFieldValue, reorderSection, dropState]
10523
10794
  );
10524
- const makeFieldSectionProps = useMemo(
10525
- () => ({
10526
- index: values.fields.length,
10527
- parentPath: "fields",
10528
- initial: emptySection(),
10529
- conditionalSourceFields: makeConditionalSourceFields(values.fields, values.fields.length)
10530
- }),
10531
- [values.fields]
10795
+ const handleCreateEmptySection = useCallback(
10796
+ (index2) => {
10797
+ createNewEmptySection(index2 + 1, values, setFieldValue);
10798
+ },
10799
+ [values, setFieldValue]
10532
10800
  );
10533
10801
  return /* @__PURE__ */ jsx(DragDropContext, { onDragStart: handleDragStart, onDragEnd: handleDragEnd, children: /* @__PURE__ */ jsx(Droppable, { droppableId: "droppable", type: "ROOT", children: (droppableProvided) => /* @__PURE__ */ jsxs(
10534
10802
  Flex,
@@ -10538,123 +10806,200 @@ const FieldsEditor = memo(function FieldsEditor2() {
10538
10806
  direction: "column",
10539
10807
  gap: "0",
10540
10808
  children: [
10541
- values.fields.map((field, index2) => /* @__PURE__ */ jsx(
10542
- FieldSectionWithActions,
10543
- {
10544
- field,
10545
- index: index2,
10546
- dropState
10547
- },
10548
- field.label
10549
- )),
10550
- droppableProvided.placeholder,
10551
- /* @__PURE__ */ jsxs(
10552
- Button,
10553
- {
10554
- type: "button",
10555
- variant: "outline",
10556
- onClick: () => {
10557
- setIsAddSectionDialogOpen(true);
10558
- },
10559
- children: [
10560
- /* @__PURE__ */ jsx(PlusIcon, {}),
10561
- " Add a section"
10562
- ]
10563
- }
10564
- ),
10565
- /* @__PURE__ */ jsx(
10566
- FieldBuilder,
10567
- {
10568
- ...makeFieldSectionProps,
10569
- isOpen: isAddSectionDialogOpen,
10570
- setIsOpen: setIsAddSectionDialogOpen
10571
- }
10572
- )
10809
+ values.fields.map((field, index2) => /* @__PURE__ */ jsxs(Fragment, { children: [
10810
+ /* @__PURE__ */ jsx(FieldSectionWithActions, { field, index: index2, dropState }),
10811
+ /* @__PURE__ */ jsxs(
10812
+ Button,
10813
+ {
10814
+ type: "button",
10815
+ variant: "surface",
10816
+ severity: "info",
10817
+ onClick: () => {
10818
+ handleCreateEmptySection(index2);
10819
+ },
10820
+ style: { marginBottom: "4px" },
10821
+ children: [
10822
+ /* @__PURE__ */ jsx(PlusIcon, {}),
10823
+ " Add section"
10824
+ ]
10825
+ }
10826
+ )
10827
+ ] }, field.identifier)),
10828
+ droppableProvided.placeholder
10573
10829
  ]
10574
10830
  }
10575
10831
  ) }) });
10576
10832
  });
10833
+ FieldsEditor.displayName = "FieldsEditor";
10577
10834
  const initialValues = {
10578
10835
  title: "",
10579
10836
  description: "",
10580
- fields: []
10581
- };
10582
- const title = new StringField({
10583
- label: "Title",
10584
- minLength: 0,
10585
- maxLength: 100,
10586
- required: true,
10587
- identifier: "title"
10588
- });
10589
- const titleProps = { formId, placeholder: "Give your form a title." };
10590
- const description = new TextField({
10591
- label: "Description",
10592
- minLength: 0,
10593
- maxLength: 1e3,
10594
- required: false,
10595
- identifier: "description"
10596
- });
10597
- const descriptionProps = { formId, placeholder: "Explain the purpose of this form." };
10837
+ fields: [{ ...emptySection(makeIdentifier(null, "")), label: "" }]
10838
+ };
10598
10839
  const previewSubmit = () => {
10599
10840
  alert("This is a form preview, your data will not be saved.");
10600
10841
  };
10601
10842
  const FormBuilder = memo(
10602
10843
  forwardRef((props, ref) => {
10603
10844
  const { onCancel, onSave, revision } = props;
10604
- const { heading = revision ? "Edit form" : "Create a new form" } = props;
10605
- const validate = useCallback((form) => {
10606
- const errors = {};
10607
- if (!form.title) {
10608
- errors.title = "Title is required.";
10609
- }
10610
- if (!form.fields || form.fields.length === 0) {
10611
- errors.fields = "At least one field is required.";
10612
- }
10613
- if (hasKeys(errors)) {
10614
- return errors;
10615
- }
10616
- }, []);
10845
+ const { showError } = useToast();
10846
+ const validate = useCallback(
10847
+ (form) => {
10848
+ const errors = {};
10849
+ if (!form.title) {
10850
+ errors.title = "Title is required.";
10851
+ }
10852
+ if (form.fields.length === 0) {
10853
+ errors.fields = "At least one field is required.";
10854
+ }
10855
+ let fieldsToValidate = [];
10856
+ for (const [sectionIndex, section] of form.fields.entries()) {
10857
+ const fieldCls = CompleteFieldTypeToClsMapping.section;
10858
+ const sectionSettings = fieldCls.getFieldCreationSchema(
10859
+ makeConditionalSourceFields(form.fields, sectionIndex),
10860
+ `fields.${sectionIndex}`
10861
+ ).map((field) => field.field);
10862
+ fieldsToValidate = [...fieldsToValidate, ...sectionSettings];
10863
+ for (const [fieldIndex, field] of section.fields.entries()) {
10864
+ const fieldCls2 = CompleteFieldTypeToClsMapping[field.type];
10865
+ const fieldSettings = fieldCls2.getFieldCreationSchema(`fields.${sectionIndex}.fields.${fieldIndex}`).map((field2) => field2.field);
10866
+ fieldsToValidate = [...fieldsToValidate, ...fieldSettings];
10867
+ }
10868
+ }
10869
+ const fieldErrors = validateForm(
10870
+ {
10871
+ title: "Validate form builder",
10872
+ fields: fieldsToValidate,
10873
+ meta: { readonly: true }
10874
+ },
10875
+ form
10876
+ );
10877
+ if (fieldErrors) {
10878
+ errors.fields = fieldErrors.fields;
10879
+ }
10880
+ if (hasKeys(errors)) {
10881
+ showError({
10882
+ title: "Some form settings are invalid",
10883
+ description: "Please check settings highlighted in red."
10884
+ });
10885
+ return errors;
10886
+ }
10887
+ },
10888
+ [showError]
10889
+ );
10617
10890
  const formik = useFormik({
10618
10891
  initialValues: wrapRootFieldsWithFieldSection(revision) ?? initialValues,
10619
10892
  validate,
10620
- onSubmit: onSave,
10621
- // only validate the entire for on submit
10893
+ // onSubmit: (form) => console.log("SUBMITTED", form),
10894
+ onSubmit: (form) => {
10895
+ onSave(form);
10896
+ },
10897
+ // only validate the entire form on submit
10622
10898
  validateOnChange: false,
10623
10899
  validateOnBlur: false
10624
10900
  });
10625
10901
  const previewSchema = useMemo(() => formRevisionToSchema(formik.values), [formik.values]);
10626
- const titleInput = useFieldInput(title, titleProps);
10627
- const descriptionInput = useFieldInput(description, descriptionProps);
10628
- const FormBuilderHeading = useMemo(
10629
- () => typeof heading === "object" ? heading : /* @__PURE__ */ jsx(Heading, { children: heading }),
10630
- [heading]
10631
- );
10632
10902
  return /* @__PURE__ */ jsx(Tabs.Root, { ref, defaultValue: "edit", children: /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: "2", children: [
10633
- /* @__PURE__ */ jsxs(Tabs.List, { children: [
10634
- /* @__PURE__ */ jsx(Tabs.Trigger, { value: "edit", children: "Edit" }),
10635
- /* @__PURE__ */ jsx(Tabs.Trigger, { value: "preview", children: "Preview" })
10636
- ] }),
10903
+ /* @__PURE__ */ jsxs(
10904
+ Tabs.List,
10905
+ {
10906
+ style: {
10907
+ display: "flex",
10908
+ position: "sticky",
10909
+ top: 0,
10910
+ zIndex: 2e3,
10911
+ backgroundColor: "var(--color-background)"
10912
+ },
10913
+ children: [
10914
+ /* @__PURE__ */ jsx(Tabs.Trigger, { style: { flex: 1 }, value: "edit", children: "Edit" }),
10915
+ /* @__PURE__ */ jsx(Tabs.Trigger, { style: { flex: 1 }, value: "preview", children: "Preview" })
10916
+ ]
10917
+ }
10918
+ ),
10637
10919
  /* @__PURE__ */ jsxs(Tabs.Content, { value: "edit", children: [
10638
- FormBuilderHeading,
10639
10920
  /* @__PURE__ */ jsxs(Text, { children: [
10640
- "Add a new form field by clicking a + button. Specify options for each field, then drag and drop to rearrange them. You can see what a submitted form might look like in the",
10921
+ "Create your form using various field types. Sections can be",
10641
10922
  " ",
10642
- /* @__PURE__ */ jsx("em", { children: "Preview" }),
10643
- " tab, but",
10923
+ /* @__PURE__ */ jsx("strong", { children: "conditionally rendered" }),
10924
+ " based on",
10644
10925
  " ",
10645
- /* @__PURE__ */ jsx("strong", { children: "field values entered on this page will not be saved." })
10926
+ /* @__PURE__ */ jsx("strong", { children: "answers to fields in preceding sections. " })
10646
10927
  ] }),
10647
10928
  /* @__PURE__ */ jsx(Flex, { asChild: true, direction: "column", gap: "2", mt: "3", children: /* @__PURE__ */ jsxs("form", { id: formId, onSubmit: formik.handleSubmit, children: [
10648
10929
  /* @__PURE__ */ jsxs(FormikProvider, { value: formik, children: [
10649
- titleInput,
10650
- descriptionInput,
10930
+ /* @__PURE__ */ jsx(
10931
+ PatchField,
10932
+ {
10933
+ name: "title",
10934
+ render: ({ setValue, value, meta }) => /* @__PURE__ */ jsx(InputWithHelpText, { severity: "danger", helpText: meta.error ?? null, children: /* @__PURE__ */ jsx(
10935
+ Input,
10936
+ {
10937
+ style: {
10938
+ // var(--accent-a11) for red and var(--accent-1) for gray
10939
+ border: meta.error ? "1px solid #ff9592" : "1px solid #5a6169",
10940
+ paddingLeft: "8px",
10941
+ fontWeight: "bold"
10942
+ },
10943
+ placeholder: "Form title",
10944
+ value,
10945
+ onChange: (event) => {
10946
+ setValue(event.target.value);
10947
+ },
10948
+ maxLength: 100,
10949
+ showInputLength: false,
10950
+ variant: "ghost",
10951
+ size: "large"
10952
+ }
10953
+ ) })
10954
+ }
10955
+ ),
10956
+ /* @__PURE__ */ jsx(
10957
+ PatchField,
10958
+ {
10959
+ name: "description",
10960
+ render: ({ setValue, value }) => /* @__PURE__ */ jsx(
10961
+ TextArea,
10962
+ {
10963
+ style: {
10964
+ minHeight: "max-content",
10965
+ border: "1px solid #5a6169",
10966
+ paddingLeft: "8px",
10967
+ paddingTop: "8px"
10968
+ },
10969
+ placeholder: "Explain the purpose of this form",
10970
+ value,
10971
+ onChange: (event) => {
10972
+ setValue(event.target.value);
10973
+ },
10974
+ resize: "vertical",
10975
+ maxLength: 1e3,
10976
+ showInputLength: false,
10977
+ variant: "ghost"
10978
+ }
10979
+ )
10980
+ }
10981
+ ),
10651
10982
  /* @__PURE__ */ jsx(FieldsEditor, {}),
10652
10983
  /* @__PURE__ */ jsx(Text, { severity: "danger", size: "1", children: typeof formik.errors.fields === "string" && formik.errors.fields })
10653
10984
  ] }),
10654
- /* @__PURE__ */ jsxs(Flex, { justify: "end", gap: "2", children: [
10655
- /* @__PURE__ */ jsx(Button, { type: "button", variant: "soft", onClick: onCancel, children: "Cancel" }),
10656
- /* @__PURE__ */ jsx(Button, { type: "submit", disabled: !formik.isValid, children: "Save" })
10657
- ] })
10985
+ /* @__PURE__ */ jsxs(
10986
+ Flex,
10987
+ {
10988
+ justify: "end",
10989
+ align: "center",
10990
+ gap: "2",
10991
+ style: {
10992
+ position: "sticky",
10993
+ bottom: 0,
10994
+ paddingBottom: "10px",
10995
+ paddingRight: "10px"
10996
+ },
10997
+ children: [
10998
+ /* @__PURE__ */ jsx(Button, { type: "button", variant: "solid", severity: "info", onClick: onCancel, children: "Cancel" }),
10999
+ /* @__PURE__ */ jsx(Button, { type: "submit", children: "Save form" })
11000
+ ]
11001
+ }
11002
+ )
10658
11003
  ] }) })
10659
11004
  ] }),
10660
11005
  /* @__PURE__ */ jsx(Tabs.Content, { value: "preview", children: /* @__PURE__ */ jsx(FormRenderer, { schema: previewSchema, onSubmit: previewSubmit }) })
@@ -10675,6 +11020,7 @@ const index = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.definePropert
10675
11020
  FormRenderer,
10676
11021
  FormSubmissionBrowser,
10677
11022
  FormSubmissionViewer,
11023
+ InputWithHelpText,
10678
11024
  InputWithLabel,
10679
11025
  InputWithLabelAndHelpText,
10680
11026
  MultiSelectField,
@@ -10693,12 +11039,22 @@ const index = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.definePropert
10693
11039
  TextInput,
10694
11040
  deserialize,
10695
11041
  deserializeField,
11042
+ emptyBaseField,
11043
+ emptyBooleanField,
11044
+ emptyDateField,
11045
+ emptyMultiSelectField,
11046
+ emptyMultiStringField,
11047
+ emptyNumberField,
11048
+ emptySelectField,
11049
+ emptyStringField,
11050
+ emptyTextField,
10696
11051
  formRevisionToSchema,
10697
11052
  isConditionMet,
10698
11053
  useFieldInput,
10699
11054
  useFieldInputs,
10700
11055
  useFormikInput,
10701
- valueIsFile
11056
+ valueIsFile,
11057
+ valueIsFormikUserFormRevision
10702
11058
  }, Symbol.toStringTag, { value: "Module" }));
10703
11059
  export {
10704
11060
  APIError,
@@ -10731,6 +11087,7 @@ export {
10731
11087
  FormSubmissionViewer,
10732
11088
  GREEN,
10733
11089
  HttpMethod,
11090
+ InputWithHelpText,
10734
11091
  InputWithLabel,
10735
11092
  InputWithLabelAndHelpText,
10736
11093
  IssueCommentService,
@@ -10845,6 +11202,15 @@ export {
10845
11202
  emailDomainsReducer,
10846
11203
  emailDomainsSlice,
10847
11204
  emailRegex,
11205
+ emptyBaseField,
11206
+ emptyBooleanField,
11207
+ emptyDateField,
11208
+ emptyMultiSelectField,
11209
+ emptyMultiStringField,
11210
+ emptyNumberField,
11211
+ emptySelectField,
11212
+ emptyStringField,
11213
+ emptyTextField,
10848
11214
  enqueue,
10849
11215
  enqueueRequest,
10850
11216
  errorColor,
@@ -11130,6 +11496,7 @@ export {
11130
11496
  userReducer,
11131
11497
  userSlice,
11132
11498
  valueIsFile,
11499
+ valueIsFormikUserFormRevision,
11133
11500
  warningColor,
11134
11501
  workspaceReducer,
11135
11502
  workspaceSlice,