@parallelworks/ui 0.34.0 → 0.35.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 (84) hide show
  1. package/README.md +201 -0
  2. package/dist/ai/components/ChatEmptyState.js +71 -86
  3. package/dist/ai/components/ChatInput.d.ts +11 -3
  4. package/dist/ai/components/ChatInput.js +19 -11
  5. package/dist/ai/components/ChatSidebar.js +12 -130
  6. package/dist/ai/components/ChatStage.d.ts +11 -0
  7. package/dist/ai/components/ChatStage.js +26 -0
  8. package/dist/ai/components/ComposerChrome.d.ts +3 -0
  9. package/dist/ai/components/ComposerChrome.js +21 -2
  10. package/dist/ai/components/conversationActions.d.ts +23 -0
  11. package/dist/ai/components/conversationActions.js +108 -0
  12. package/dist/ai/index.d.ts +4 -3
  13. package/dist/ai/index.js +6 -5
  14. package/dist/ai/strings.d.ts +1 -0
  15. package/dist/ai/strings.js +2 -1
  16. package/dist/ai/ui/ConversationSidebar.d.ts +3 -2
  17. package/dist/ai/ui/ConversationSidebar.js +2 -1
  18. package/dist/ai/ui/sidebar.d.ts +6 -0
  19. package/dist/ai/ui/sidebar.js +10 -1
  20. package/dist/components/Dropdown.js +3 -1
  21. package/dist/components/FilterPill.js +1 -0
  22. package/dist/components/Provider.d.ts +14 -0
  23. package/dist/components/Provider.js +14 -3
  24. package/dist/components/SegmentedControl.d.ts +24 -0
  25. package/dist/components/SegmentedControl.js +69 -0
  26. package/dist/editing.d.ts +32 -0
  27. package/dist/editor/FormCodePanel.js +1 -1
  28. package/dist/engine.d.ts +3 -0
  29. package/dist/form/FieldWrapper.js +1 -1
  30. package/dist/form/Fields/CheckboxGroupField.d.ts +3 -3
  31. package/dist/form/Fields/CheckboxGroupField.js +10 -4
  32. package/dist/form/Fields/RadioField.d.ts +5 -3
  33. package/dist/form/Fields/RadioField.js +25 -17
  34. package/dist/form/Fields/fieldOption.d.ts +12 -0
  35. package/dist/form/Fields/fieldOption.js +17 -0
  36. package/dist/form/Form.d.ts +4 -2
  37. package/dist/form/Form.js +170 -68
  38. package/dist/form/FormLayout.d.ts +7 -0
  39. package/dist/form/FormLayout.js +144 -0
  40. package/dist/form/SpecialTypes/FormikCustomDropdown.js +1 -1
  41. package/dist/form/SpecialTypes/FormikCustomInput.js +7 -0
  42. package/dist/form/Wizard/WizardContainer.d.ts +1 -1
  43. package/dist/form/Wizard/WizardContainer.js +244 -49
  44. package/dist/form/Wizard/WizardNavigation.js +4 -4
  45. package/dist/form/Wizard/WizardStepContent.d.ts +1 -1
  46. package/dist/form/Wizard/WizardStepContent.js +19 -10
  47. package/dist/form/Wizard/WizardStepIndicator.js +35 -7
  48. package/dist/form/Wizard/types.d.ts +19 -6
  49. package/dist/form/Wizard/useWizardState.d.ts +1 -0
  50. package/dist/form/Wizard/useWizardState.js +5 -1
  51. package/dist/form/Wizard/utils.d.ts +7 -0
  52. package/dist/form/Wizard/utils.js +18 -1
  53. package/dist/form/index.d.ts +2 -0
  54. package/dist/form/index.js +4 -2
  55. package/dist/form/layout.d.ts +50 -0
  56. package/dist/form/layout.js +125 -0
  57. package/dist/form/layoutCSS.d.ts +10 -0
  58. package/dist/form/layoutCSS.js +234 -0
  59. package/dist/form/lib.d.ts +2 -0
  60. package/dist/form/lib.js +17 -2
  61. package/dist/form/types/fieldTypes.d.ts +8 -23
  62. package/dist/graph/DependencyGraph.d.ts +20 -1
  63. package/dist/graph/DependencyGraph.js +437 -142
  64. package/dist/graph/MatrixGroup.d.ts +3 -1
  65. package/dist/graph/MatrixGroup.js +31 -28
  66. package/dist/graph/TreeView.js +6 -6
  67. package/dist/graph/gridSpacing.d.ts +7 -0
  68. package/dist/graph/gridSpacing.js +10 -0
  69. package/dist/graph/util.d.ts +2 -0
  70. package/dist/graph/util.js +2 -2
  71. package/dist/index.d.ts +1 -0
  72. package/dist/index.js +2 -1
  73. package/dist/list/ListViewControls.d.ts +15 -0
  74. package/dist/list/ListViewControls.js +9 -3
  75. package/dist/list/index.d.ts +1 -1
  76. package/dist/list/index.js +2 -2
  77. package/dist/styles/base.css +3 -1
  78. package/dist/styles/theme.css +5 -0
  79. package/dist/styles.css +1 -1
  80. package/dist/theme/index.d.ts +2 -0
  81. package/dist/theme/index.js +3 -2
  82. package/package.json +4 -2
  83. package/dist/ai/components/ComposerFrame.d.ts +0 -16
  84. package/dist/ai/components/ComposerFrame.js +0 -33
package/dist/form/Form.js CHANGED
@@ -7,17 +7,19 @@ import CustomListbox from "../components/Listbox.js";
7
7
  import Loader from "../components/Loader.js";
8
8
  import SectionHeader from "../components/SectionHeader.js";
9
9
  import { Table } from "../components/Table.js";
10
+ import { parseWizardConfig } from "./Wizard/utils.js";
11
+ import { inputWidth, resolvedFlag } from "./lib.js";
10
12
  import { useFieldControlProps, useFieldRequired } from "./fieldContext.js";
11
- import { resolvedFlag } from "./lib.js";
13
+ import { resolveFormLayout } from "./layout.js";
14
+ import { FormLayout, LayoutCSSContext } from "./FormLayout.js";
12
15
  import { getValueUsingPath } from "./utils/getValueUsingPath.js";
13
16
  import { FieldRegistryContext, Registry } from "./fieldRegistry.js";
14
17
  import { useParsedOpts } from "./useParsedOpts.js";
15
18
  import { usePrevious } from "./usePrevious.js";
16
19
  import { getParentValue } from "./utils/getParentValue.js";
17
- import { parseWizardConfig } from "./Wizard/utils.js";
18
20
  import { WizardContainer } from "./Wizard/WizardContainer.js";
19
21
  import cx from "classnames";
20
- import React, { useCallback, useEffect, useMemo, useRef, useState } from "react";
22
+ import React, { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState } from "react";
21
23
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
22
24
  import deepEqual from "fast-deep-equal";
23
25
  import { Form, Formik, useField, useFormikContext } from "formik";
@@ -31,6 +33,13 @@ function asRecord(value) {
31
33
  function flagValue(value, fallback) {
32
34
  return value && (typeof value === "string" || typeof value === "boolean") ? value : fallback;
33
35
  }
36
+ /** The `$meta.labelPosition` a workflow set, which nested lists inherit; undefined when none did. */
37
+ var ChosenLabelPosition = createContext(void 0);
38
+ function useChosenLabelPosition(options) {
39
+ const inherited = useContext(ChosenLabelPosition);
40
+ const position = asRecord(options["$meta"])["labelPosition"];
41
+ return position === "left" || position === "top" ? position : inherited;
42
+ }
34
43
  /** Applies `$meta` overrides for `labelPosition` / `spaceCompact`. */
35
44
  function resolveMetaOverrides(options, labelPosition, spaceCompact) {
36
45
  const meta = options?.["$meta"];
@@ -47,7 +56,7 @@ function listLengthsSignature(options, values = {}, prefix = "") {
47
56
  const field = asSchemaField(rawField);
48
57
  if (fieldName === "$meta" || !field) continue;
49
58
  const fullName = prefix ? `${prefix}${fieldName}` : fieldName;
50
- if (field.type === "list") {
59
+ if (field.type === "list" || repeatsPage(field)) {
51
60
  const items = values?.[fieldName];
52
61
  const len = Array.isArray(items) ? items.length : 0;
53
62
  parts.push(`${fullName}:${len}`);
@@ -87,7 +96,7 @@ function collectFieldsWithDefaults(options, values = {}, prefix = "") {
87
96
  }
88
97
  continue;
89
98
  }
90
- if (field.type === "list") {
99
+ if (field.type === "list" || repeatsPage(field)) {
91
100
  const listTemplate = field.template || field.options;
92
101
  const listValues = values?.[fieldName];
93
102
  if (listTemplate && Array.isArray(listValues)) for (let i = 0; i < listValues.length; i++) {
@@ -510,7 +519,31 @@ var FormField = React.memo(function FormField({ optionsField, fieldName, values,
510
519
  return true;
511
520
  });
512
521
  function FieldsFromOptions({ options = {}, values, setFormDirty, setFieldValue, setFieldTouched, parentInfo, labelPosition = "left", missingFields = [], spaceCompact = false, workflowForm = false }) {
513
- return Object.keys(options).map((fieldName) => /* @__PURE__ */ jsx(FormField, {
522
+ const chosen = useChosenLabelPosition(options);
523
+ const wizard = parseWizardConfig(options);
524
+ if (wizard) return /* @__PURE__ */ jsx(ChosenLabelPosition.Provider, {
525
+ value: chosen,
526
+ children: /* @__PURE__ */ jsx(WizardContainer, {
527
+ wizardConfig: wizard,
528
+ values,
529
+ className: "w-full",
530
+ labelPosition,
531
+ missingFields,
532
+ spaceCompact,
533
+ workflowForm,
534
+ nested: true,
535
+ fieldNamePrefix: parentInfo?.fieldNamePrefix,
536
+ setFieldValue,
537
+ setFieldTouched
538
+ })
539
+ });
540
+ const names = Object.keys(options);
541
+ const flows = names.some((name) => {
542
+ const field = asRecord(options[name]);
543
+ return inputWidth(field["width"]) !== void 0 || field["anchor-below"] === true;
544
+ });
545
+ const columns = flows ? columnsOf(options, names) : [];
546
+ const fieldOf = (fieldName, compactLabels = false) => /* @__PURE__ */ jsx(FormField, {
514
547
  optionsField: options[fieldName],
515
548
  fieldName,
516
549
  values,
@@ -518,55 +551,121 @@ function FieldsFromOptions({ options = {}, values, setFormDirty, setFieldValue,
518
551
  setFieldValue,
519
552
  setFieldTouched,
520
553
  parentInfo,
521
- labelPosition,
554
+ labelPosition: compactLabels ? chosen ?? "top" : labelPosition,
522
555
  missingFields,
523
556
  spaceCompact,
524
557
  workflowForm
525
- }, fieldName));
558
+ }, fieldName);
559
+ const layout = resolveFormLayout(asRecord(options["$meta"])["layout"], names.filter((name) => !name.startsWith("$") && asSchemaField(options[name])));
560
+ if (layout.layout) return /* @__PURE__ */ jsx(ChosenLabelPosition.Provider, {
561
+ value: chosen,
562
+ children: /* @__PURE__ */ jsxs("div", {
563
+ className: "flex min-w-0 flex-col gap-4",
564
+ children: [/* @__PURE__ */ jsx(FormLayout, {
565
+ layout: layout.layout,
566
+ renderField: (name) => fieldOf(name, true)
567
+ }), layout.remaining.map((name) => fieldOf(name, true))]
568
+ })
569
+ });
570
+ return /* @__PURE__ */ jsx(ChosenLabelPosition.Provider, {
571
+ value: chosen,
572
+ children: flows ? /* @__PURE__ */ jsx("div", {
573
+ className: "@container/inputs -mx-2 flex flex-wrap items-start",
574
+ children: columns.map((column) => {
575
+ const width = inputWidth(asRecord(options[column.head])["width"]);
576
+ return /* @__PURE__ */ jsx("div", {
577
+ "data-input-cell": true,
578
+ className: "flex w-(--input-narrow) max-w-full flex-col px-2 empty:hidden @min-[24rem]/inputs:w-(--input-width) [&:not(:has(>:not([data-input-hidden])))]:order-1 [&:not(:has(>:not([data-input-hidden])))]:w-full",
579
+ style: widthVars(width, width),
580
+ children: column.names.map((name) => {
581
+ const own = name === column.head ? void 0 : inputWidth(asRecord(options[name])["width"]);
582
+ return own === void 0 ? fieldOf(name, width !== void 0 && width !== "100%") : /* @__PURE__ */ jsx("div", {
583
+ "data-input-member": true,
584
+ className: "w-(--input-narrow) max-w-full @min-[24rem]/inputs:w-(--input-width)",
585
+ style: widthVars(own, own.endsWith("%") ? `calc(${parseFloat(own)}cqw - 1rem)` : own),
586
+ children: fieldOf(name, width !== void 0 && width !== "100%")
587
+ }, name);
588
+ })
589
+ }, column.head);
590
+ })
591
+ }) : names.map((name) => fieldOf(name))
592
+ });
526
593
  }
527
594
  var noop = () => {};
595
+ function repeatsPage(field) {
596
+ return field.type === "step" && field.multi === true;
597
+ }
598
+ function columnsOf(options, names) {
599
+ const columns = [];
600
+ let shown;
601
+ for (const name of names) {
602
+ const field = asRecord(options[name]);
603
+ const hidden = name.startsWith("$") || field["hidden"] === true;
604
+ if (shown && !hidden && field["anchor-below"] === true) {
605
+ shown.names.push(name);
606
+ continue;
607
+ }
608
+ const column = {
609
+ head: name,
610
+ names: [name]
611
+ };
612
+ columns.push(column);
613
+ if (!hidden) shown = column;
614
+ }
615
+ return columns;
616
+ }
617
+ function widthVars(width, wide) {
618
+ return {
619
+ "--input-width": wide ?? "100%",
620
+ "--input-narrow": width?.endsWith("px") ? width : "100%"
621
+ };
622
+ }
528
623
  function DynamicFormContent({ options, setValues, setFormDirty, labelPosition, missingFields, spaceCompact, organizationVariables, remoteVars, workflowForm, onSubmit, submitLabel, values, contextKey }) {
529
624
  const { setFieldValue, setFieldTouched } = useFormikContext();
530
625
  const opts = useParsedOpts(options, values, organizationVariables, void 0, void 0, remoteVars);
531
626
  const handleChange = useCallback((state) => setValues?.(state), [setValues]);
532
627
  const wizardConfig = parseWizardConfig(opts);
533
628
  const meta = resolveMetaOverrides(options, labelPosition, spaceCompact);
534
- return /* @__PURE__ */ jsxs(Fragment$1, { children: [
535
- /* @__PURE__ */ jsx(DirtyStateBridge, { setFormDirty }),
536
- /* @__PURE__ */ jsx(FormikStateBridge, { onChange: handleChange }),
537
- /* @__PURE__ */ jsx(DynamicDefaultsSync, { options: opts }, contextKey ?? ""),
538
- wizardConfig ? /* @__PURE__ */ jsx(WizardContainer, {
539
- wizardConfig,
540
- values,
541
- onChange: handleChange,
542
- onSubmit,
543
- className: "w-full",
544
- ...meta,
545
- missingFields,
546
- workflowForm,
547
- setFieldValue,
548
- setFieldTouched
549
- }) : /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(FieldsFromOptions, {
550
- ...meta,
551
- options: opts,
552
- values,
553
- setFormDirty,
554
- setFieldValue,
555
- setFieldTouched,
556
- missingFields,
557
- workflowForm
558
- }), onSubmit !== void 0 && !workflowForm && /* @__PURE__ */ jsx("div", {
559
- className: "mt-4",
560
- children: /* @__PURE__ */ jsx("input", {
561
- type: "submit",
562
- className: "btn btn-info",
563
- value: submitLabel
564
- })
565
- })] })
566
- ] });
629
+ const chosen = useChosenLabelPosition(options);
630
+ return /* @__PURE__ */ jsxs(ChosenLabelPosition.Provider, {
631
+ value: chosen,
632
+ children: [
633
+ /* @__PURE__ */ jsx(DirtyStateBridge, { setFormDirty }),
634
+ /* @__PURE__ */ jsx(FormikStateBridge, { onChange: handleChange }),
635
+ /* @__PURE__ */ jsx(DynamicDefaultsSync, { options: opts }, contextKey ?? ""),
636
+ wizardConfig ? /* @__PURE__ */ jsx(WizardContainer, {
637
+ wizardConfig,
638
+ values,
639
+ onChange: handleChange,
640
+ onSubmit,
641
+ className: "w-full",
642
+ ...meta,
643
+ missingFields,
644
+ workflowForm,
645
+ setFieldValue,
646
+ setFieldTouched
647
+ }) : /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(FieldsFromOptions, {
648
+ ...meta,
649
+ options: opts,
650
+ values,
651
+ setFormDirty,
652
+ setFieldValue,
653
+ setFieldTouched,
654
+ missingFields,
655
+ workflowForm
656
+ }), onSubmit !== void 0 && !workflowForm && /* @__PURE__ */ jsx("div", {
657
+ className: "mt-4",
658
+ children: /* @__PURE__ */ jsx("input", {
659
+ type: "submit",
660
+ className: "btn btn-info",
661
+ value: submitLabel
662
+ })
663
+ })] })
664
+ ]
665
+ });
567
666
  }
568
667
  var NO_FIELDS = {};
569
- function DynamicForm({ formJSONs: options = {}, reinitialize = false, initialValues, setValues, setFormDirty = noop, formikRef, labelPosition = "left", missingFields = [], spaceCompact = false, organizationVariables, remoteVars, needsOrganizationVariables = false, onSubmit, submitLabel = "Submit", className = "w-full", workflowForm = false, contextKey, skipValueParse = false, fields = NO_FIELDS }) {
668
+ function DynamicForm({ formJSONs: options = {}, reinitialize = false, initialValues, setValues, setFormDirty = noop, formikRef, labelPosition = "left", missingFields = [], spaceCompact = false, organizationVariables, remoteVars, needsOrganizationVariables = false, onSubmit, submitLabel = "Submit", className = "w-full", workflowForm = false, contextKey, skipValueParse = false, fields = NO_FIELDS, allowLayoutCSS = false }) {
570
669
  const engine = useWorkflowEngine();
571
670
  const [parseReady, setParseReady] = useState(() => engine.isReady());
572
671
  useEffect(() => {
@@ -582,32 +681,35 @@ function DynamicForm({ formJSONs: options = {}, reinitialize = false, initialVal
582
681
  });
583
682
  return /* @__PURE__ */ jsx(FieldRegistryContext.Provider, {
584
683
  value: fields,
585
- children: /* @__PURE__ */ jsx("div", {
586
- className,
587
- children: (!needsOrganizationVariables || organizationVariables) && initialValues && /* @__PURE__ */ jsx(Formik, {
588
- enableReinitialize: reinitialize,
589
- initialValues: parsedInitVals,
590
- onSubmit: onSubmit ?? (() => {}),
591
- onReset: () => {
592
- setFormDirty(false);
593
- },
594
- ...formikRef ? { innerRef: formikRef } : {},
595
- children: ({ values }) => /* @__PURE__ */ jsx(Form, {
596
- className: "w-full text-[13px]",
597
- children: /* @__PURE__ */ jsx(DynamicFormContent, {
598
- values,
599
- options,
600
- setValues,
601
- setFormDirty,
602
- labelPosition,
603
- missingFields,
604
- spaceCompact,
605
- organizationVariables,
606
- remoteVars,
607
- workflowForm,
608
- onSubmit,
609
- submitLabel,
610
- contextKey
684
+ children: /* @__PURE__ */ jsx(LayoutCSSContext.Provider, {
685
+ value: allowLayoutCSS,
686
+ children: /* @__PURE__ */ jsx("div", {
687
+ className,
688
+ children: (!needsOrganizationVariables || organizationVariables) && initialValues && /* @__PURE__ */ jsx(Formik, {
689
+ enableReinitialize: reinitialize,
690
+ initialValues: parsedInitVals,
691
+ onSubmit: onSubmit ?? (() => {}),
692
+ onReset: () => {
693
+ setFormDirty(false);
694
+ },
695
+ ...formikRef ? { innerRef: formikRef } : {},
696
+ children: ({ values }) => /* @__PURE__ */ jsx(Form, {
697
+ className: "w-full text-[13px]",
698
+ children: /* @__PURE__ */ jsx(DynamicFormContent, {
699
+ values,
700
+ options,
701
+ setValues,
702
+ setFormDirty,
703
+ labelPosition,
704
+ missingFields,
705
+ spaceCompact,
706
+ organizationVariables,
707
+ remoteVars,
708
+ workflowForm,
709
+ onSubmit,
710
+ submitLabel,
711
+ contextKey
712
+ })
611
713
  })
612
714
  })
613
715
  })
@@ -0,0 +1,7 @@
1
+ import type { ReactNode } from 'react';
2
+ import { type FormLayoutNode } from './layout.js';
3
+ export declare const LayoutCSSContext: import("react").Context<boolean>;
4
+ export declare function FormLayout({ layout, renderField, }: {
5
+ layout: FormLayoutNode;
6
+ renderField: (name: string) => ReactNode;
7
+ }): import("react").JSX.Element;
@@ -0,0 +1,144 @@
1
+ import { layoutBreakpoints, responsiveLayoutValues } from "./layout.js";
2
+ import { resolveLayoutCSS } from "./layoutCSS.js";
3
+ import cx from "classnames";
4
+ import { createContext, useContext, useId, useMemo } from "react";
5
+ import { jsx, jsxs } from "react/jsx-runtime";
6
+ //#region src/form/FormLayout.tsx
7
+ var LayoutCSSContext = createContext(false);
8
+ var gaps = {
9
+ none: "0px",
10
+ sm: "0.5rem",
11
+ md: "1rem",
12
+ lg: "1.5rem"
13
+ };
14
+ var visible = "[&:not(:has([data-layout-field]:not(:empty)))]:hidden";
15
+ var sharedRowsClass = "grid grid-rows-(--layout-shared-base) row-(--layout-row-span-base) @min-[24rem]/layout:grid-rows-(--layout-shared-sm) @min-[24rem]/layout:row-(--layout-row-span-sm) @min-[40rem]/layout:grid-rows-(--layout-shared-md) @min-[40rem]/layout:row-(--layout-row-span-md) @min-[64rem]/layout:grid-rows-(--layout-shared-lg) @min-[64rem]/layout:row-(--layout-row-span-lg)";
16
+ var slotClass = "row-start-(--layout-slot-base) @min-[24rem]/layout:row-start-(--layout-slot-sm) @min-[40rem]/layout:row-start-(--layout-slot-md) @min-[64rem]/layout:row-start-(--layout-slot-lg)";
17
+ var trackCount = (tracks) => Array.isArray(tracks) ? tracks.length : tracks;
18
+ var trackStyle = (tracks) => Array.isArray(tracks) ? tracks.map((weight) => `minmax(0, ${weight}fr)`).join(" ") : `repeat(${tracks}, minmax(0, 1fr))`;
19
+ function FormLayout({ layout, renderField }) {
20
+ const allowCSS = useContext(LayoutCSSContext);
21
+ return /* @__PURE__ */ jsx("div", {
22
+ "data-layout-boundary": true,
23
+ className: cx("min-w-0 max-w-full", allowCSS && "isolate [contain:paint] p-0.5"),
24
+ children: /* @__PURE__ */ jsx(LayoutNode, {
25
+ node: layout,
26
+ renderField
27
+ })
28
+ });
29
+ }
30
+ function LayoutNode({ node, renderField, sharedRows }) {
31
+ const labelId = useId();
32
+ const descriptionId = useId();
33
+ const allowCSS = useContext(LayoutCSSContext);
34
+ const customStyle = useMemo(() => allowCSS ? resolveLayoutCSS(node.css).style : {}, [allowCSS, node.css]);
35
+ if (node.type === "field") return /* @__PURE__ */ jsx("div", {
36
+ "data-layout-field": node.field,
37
+ className: "min-w-0 max-w-full empty:hidden [&>div]:mb-0",
38
+ style: customStyle,
39
+ children: renderField(node.field)
40
+ });
41
+ const columns = responsiveLayoutValues(node.type === "grid" ? node.columns : 1, 1);
42
+ const alignRows = node.type === "grid" && node.align === "rows";
43
+ const childSharedRows = alignRows ? Object.fromEntries(layoutBreakpoints.map((key) => [key, trackCount(columns[key]) > 1])) : void 0;
44
+ const rowCount = alignRows ? Math.max(0, ...node.children.map((child) => child.type === "section" ? child.children.length : 0)) + 1 : 1;
45
+ const children = node.children.map((child, index) => {
46
+ const spans = responsiveLayoutValues(child.span, 1);
47
+ const style = Object.fromEntries(layoutBreakpoints.flatMap((key) => [[`--layout-span-${key}`, Math.min(spans[key], trackCount(columns[key]))], [`--layout-slot-${key}`, sharedRows?.[key] ? index + 2 : "auto"]]));
48
+ return /* @__PURE__ */ jsx("div", {
49
+ "data-layout-item": true,
50
+ className: cx("min-w-0 text-sm", visible, sharedRows && slotClass, alignRows && sharedRowsClass, node.type === "grid" && "col-span-(--layout-span-base) @min-[24rem]/layout:col-span-(--layout-span-sm) @min-[40rem]/layout:col-span-(--layout-span-md) @min-[64rem]/layout:col-span-(--layout-span-lg)"),
51
+ style,
52
+ children: /* @__PURE__ */ jsx(LayoutNode, {
53
+ node: child,
54
+ renderField,
55
+ sharedRows: childSharedRows
56
+ })
57
+ }, child.type === "field" ? `field:${child.field}` : `container:${index}`);
58
+ });
59
+ const gap = { "--layout-gap": gaps[node.gap ?? "md"] };
60
+ const headingStyle = {
61
+ color: customStyle.color,
62
+ fontSize: customStyle.fontSize,
63
+ fontWeight: customStyle.fontWeight,
64
+ lineHeight: customStyle.lineHeight
65
+ };
66
+ if (node.type === "grid") {
67
+ const style = {
68
+ ...gap,
69
+ ...Object.fromEntries(layoutBreakpoints.flatMap((key) => [
70
+ [`--layout-columns-${key}`, trackStyle(columns[key])],
71
+ [`--layout-shared-${key}`, childSharedRows?.[key] ? "subgrid" : "none"],
72
+ [`--layout-row-span-${key}`, childSharedRows?.[key] ? `span ${rowCount}` : "auto"]
73
+ ])),
74
+ ...customStyle
75
+ };
76
+ return /* @__PURE__ */ jsx("div", {
77
+ "data-layout-grid": true,
78
+ className: cx("@container/layout min-w-0 max-w-full", visible),
79
+ children: /* @__PURE__ */ jsx("div", {
80
+ className: cx("grid gap-(--layout-gap) grid-cols-(--layout-columns-base) @min-[24rem]/layout:grid-cols-(--layout-columns-sm) @min-[40rem]/layout:grid-cols-(--layout-columns-md) @min-[64rem]/layout:grid-cols-(--layout-columns-lg)", !alignRows && "items-start"),
81
+ style,
82
+ children
83
+ })
84
+ });
85
+ }
86
+ if (node.type === "section" && sharedRows) return /* @__PURE__ */ jsxs("div", {
87
+ role: "group",
88
+ "aria-labelledby": labelId,
89
+ "aria-describedby": node.description ? descriptionId : void 0,
90
+ "data-layout-section": true,
91
+ className: cx("min-w-0 max-w-full text-sm gap-(--layout-gap)", sharedRowsClass, visible),
92
+ style: customStyle,
93
+ children: [/* @__PURE__ */ jsxs("div", {
94
+ "data-layout-header": true,
95
+ className: "self-start",
96
+ children: [/* @__PURE__ */ jsx("div", {
97
+ id: labelId,
98
+ className: "text-sm font-semibold theme-text",
99
+ style: headingStyle,
100
+ children: node.label
101
+ }), node.description && /* @__PURE__ */ jsx("p", {
102
+ id: descriptionId,
103
+ className: "mt-2 text-sm theme-muted-text",
104
+ children: node.description
105
+ })]
106
+ }), children]
107
+ });
108
+ const body = /* @__PURE__ */ jsx("div", {
109
+ className: "flex min-w-0 flex-col text-sm gap-(--layout-gap)",
110
+ style: {
111
+ ...gap,
112
+ ...node.type === "stack" ? customStyle : {
113
+ gap: customStyle.gap,
114
+ rowGap: customStyle.rowGap
115
+ }
116
+ },
117
+ children
118
+ });
119
+ if (node.type === "section") return /* @__PURE__ */ jsxs("fieldset", {
120
+ "data-layout-section": true,
121
+ className: cx("min-w-0 max-w-full border-0 p-0", visible),
122
+ "aria-describedby": node.description ? descriptionId : void 0,
123
+ style: customStyle,
124
+ children: [/* @__PURE__ */ jsx("legend", {
125
+ className: "float-left mb-2 w-full p-0 text-sm font-semibold theme-text",
126
+ style: headingStyle,
127
+ children: node.label
128
+ }), /* @__PURE__ */ jsxs("div", {
129
+ className: "clear-both",
130
+ children: [node.description && /* @__PURE__ */ jsx("p", {
131
+ id: descriptionId,
132
+ className: "mb-4 text-sm theme-muted-text",
133
+ children: node.description
134
+ }), body]
135
+ })]
136
+ });
137
+ return /* @__PURE__ */ jsx("div", {
138
+ "data-layout-stack": true,
139
+ className: cx("min-w-0 max-w-full", visible),
140
+ children: body
141
+ });
142
+ }
143
+ //#endregion
144
+ export { FormLayout, LayoutCSSContext };
@@ -1,7 +1,7 @@
1
1
  import { isCategory } from "../../components/dropdownUtils.js";
2
2
  import Dropdown from "../../components/Dropdown.js";
3
- import { useFieldControlProps, useFieldRequired } from "../fieldContext.js";
4
3
  import { applySecondaryField, findSecondaryOption } from "../utils/secondaryField.js";
4
+ import { useFieldControlProps, useFieldRequired } from "../fieldContext.js";
5
5
  import cx from "classnames";
6
6
  import { memo, useEffect, useEffectEvent, useRef } from "react";
7
7
  import { jsx } from "react/jsx-runtime";
@@ -17,6 +17,7 @@ function FormikCustomInput({ name, type, step, placeholder, onChange, disabled,
17
17
  const [localValue, setLocalValue] = useState(value ?? field.value);
18
18
  const isFocused = useRef(false);
19
19
  const debounceRef = useRef(null);
20
+ const pendingRef = useRef(null);
20
21
  useEffect(() => {
21
22
  if (!isFocused.current) setLocalValue(value ?? field.value);
22
23
  }, [field.value, value]);
@@ -34,6 +35,7 @@ function FormikCustomInput({ name, type, step, placeholder, onChange, disabled,
34
35
  return sanitizeRegexp ? cased.replace(sanitizeRegexp, "") : cased;
35
36
  }, [sanitizeRegexp, lowercase]);
36
37
  const flushToFormik = useCallback((val) => {
38
+ pendingRef.current = null;
37
39
  onChange?.(val);
38
40
  setFieldTouched(name, true);
39
41
  setFieldValue(name, val);
@@ -43,6 +45,10 @@ function FormikCustomInput({ name, type, step, placeholder, onChange, disabled,
43
45
  setFieldTouched,
44
46
  setFieldValue
45
47
  ]);
48
+ useEffect(() => () => {
49
+ clearTimeout(debounceRef.current ?? void 0);
50
+ if (pendingRef.current) flushToFormik(pendingRef.current.value);
51
+ }, [flushToFormik]);
46
52
  const handleChange = (e) => {
47
53
  const text = sanitizeName(e.target.value);
48
54
  let val = text;
@@ -53,6 +59,7 @@ function FormikCustomInput({ name, type, step, placeholder, onChange, disabled,
53
59
  if (type === "password" && val === "") val = defaultValue;
54
60
  setLocalValue(val);
55
61
  clearTimeout(debounceRef.current ?? void 0);
62
+ pendingRef.current = { value: val };
56
63
  debounceRef.current = setTimeout(() => flushToFormik(val), DEBOUNCE_MS);
57
64
  };
58
65
  const handleFocus = () => {
@@ -1,5 +1,5 @@
1
1
  import type { WizardContainerProps } from './types.js';
2
- export declare function WizardContainer({ wizardConfig, values, onChange, onSubmit, className, labelPosition, missingFields, spaceCompact, workflowForm, setFieldValue, setFieldTouched, }: WizardContainerProps & {
2
+ export declare function WizardContainer({ wizardConfig, values, onChange, onSubmit, className, labelPosition, missingFields, spaceCompact, workflowForm, nested, fieldNamePrefix, setFieldValue, setFieldTouched, }: WizardContainerProps & {
3
3
  setFieldValue: (field: string, value: unknown, shouldValidate?: boolean) => void;
4
4
  setFieldTouched: (field: string, touched?: boolean, shouldValidate?: boolean) => void;
5
5
  }): import("react").JSX.Element;