@parallelworks/ui 0.64.1 → 0.65.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -44,6 +44,7 @@ function heldSendArgs(held) {
44
44
  preceding.length > 0 ? preceding : void 0
45
45
  ];
46
46
  }
47
+ var NO_TOOLS = [];
47
48
  var ChatContext = createContext(void 0);
48
49
  var ChatStreamContext = createContext(void 0);
49
50
  function useChat() {
@@ -51,6 +52,11 @@ function useChat() {
51
52
  if (!context) throw new Error("useChat must be used within a ChatProvider");
52
53
  return context;
53
54
  }
55
+ /** True while the adapter lists tools of its own, which the composer's +
56
+ * menu offers; false outside a ChatProvider. */
57
+ function useHasChatTools() {
58
+ return (useContext(ChatContext)?.tools.length ?? 0) > 0;
59
+ }
54
60
  /** The reply being streamed. A component that reads it re-renders on every
55
61
  * token, so read it only where the reply is drawn. */
56
62
  function useChatStream() {
@@ -66,6 +72,30 @@ function ChatProvider({ adapter, currentUser, navigation, activeConversationId =
66
72
  const [storedModel, storeModel] = usePersistedState("aiChat.model", null);
67
73
  const storedModelRef = useRef(storedModel);
68
74
  storedModelRef.current = storedModel;
75
+ const [tools, setTools] = useState(null);
76
+ const [disabledToolIds, storeDisabledToolIds] = usePersistedState(`aiChat.disabledTools.${currentUser.id}`, []);
77
+ useEffect(() => {
78
+ if (!adapter.tools) {
79
+ setTools(null);
80
+ return;
81
+ }
82
+ let current = true;
83
+ adapter.tools.list().then((listed) => {
84
+ if (current) setTools(listed);
85
+ }, (error) => {
86
+ console.error("Failed to load tools:", error);
87
+ });
88
+ return () => {
89
+ current = false;
90
+ };
91
+ }, [adapter]);
92
+ const enabledToolIds = useMemo(() => (tools ?? []).filter((t) => !disabledToolIds.includes(t.id)).map((t) => t.id), [tools, disabledToolIds]);
93
+ const setToolEnabled = useCallback((id, enabled) => {
94
+ storeDisabledToolIds((previous) => {
95
+ const others = previous.filter((other) => other !== id);
96
+ return enabled ? others : [...others, id];
97
+ });
98
+ }, [storeDisabledToolIds]);
69
99
  const selectedProviderRef = useRef(state.selectedProvider);
70
100
  useEffect(() => {
71
101
  selectedProviderRef.current = state.selectedProvider;
@@ -437,7 +467,8 @@ function ChatProvider({ adapter, currentUser, navigation, activeConversationId =
437
467
  parentMessageId: userMessage.parentId ?? null,
438
468
  userMessageId,
439
469
  allocation: state.selectedAllocation,
440
- useResponses
470
+ useResponses,
471
+ ...tools ? { tools: enabledToolIds } : {}
441
472
  }, {
442
473
  onContent: (chunk) => {
443
474
  markStreamStart();
@@ -544,6 +575,8 @@ function ChatProvider({ adapter, currentUser, navigation, activeConversationId =
544
575
  state.selectedAllocation,
545
576
  state.currentConversation,
546
577
  state.models,
578
+ tools,
579
+ enabledToolIds,
547
580
  currentUser,
548
581
  createConversation,
549
582
  loadConversations,
@@ -752,6 +785,8 @@ function ChatProvider({ adapter, currentUser, navigation, activeConversationId =
752
785
  selectedProvider: state.selectedProvider,
753
786
  isSelectedModelAvailable,
754
787
  selectedAllocation: state.selectedAllocation,
788
+ tools: tools ?? NO_TOOLS,
789
+ enabledToolIds,
755
790
  isLoading: state.isLoading,
756
791
  isLoadingConversation: state.isLoadingConversation,
757
792
  isLoadingModels: state.isLoadingModels,
@@ -774,6 +809,7 @@ function ChatProvider({ adapter, currentUser, navigation, activeConversationId =
774
809
  retryMessage,
775
810
  setSelectedProvider,
776
811
  setSelectedAllocation,
812
+ setToolEnabled,
777
813
  stopStreaming,
778
814
  removeQueuedMessage,
779
815
  flushQueuedMessages,
@@ -796,6 +832,8 @@ function ChatProvider({ adapter, currentUser, navigation, activeConversationId =
796
832
  state.providerIssues,
797
833
  state.selectedProvider,
798
834
  state.selectedAllocation,
835
+ tools,
836
+ enabledToolIds,
799
837
  state.isLoading,
800
838
  state.isLoadingConversation,
801
839
  state.isLoadingModels,
@@ -818,6 +856,7 @@ function ChatProvider({ adapter, currentUser, navigation, activeConversationId =
818
856
  retryMessage,
819
857
  setSelectedProvider,
820
858
  setSelectedAllocation,
859
+ setToolEnabled,
821
860
  stopStreaming,
822
861
  removeQueuedMessage,
823
862
  flushQueuedMessages,
@@ -856,4 +895,4 @@ function ChatProvider({ adapter, currentUser, navigation, activeConversationId =
856
895
  });
857
896
  }
858
897
  //#endregion
859
- export { ChatProvider, useChat, useChatStream };
898
+ export { ChatProvider, useChat, useChatStream, useHasChatTools };
@@ -47,6 +47,27 @@ export interface ChatStrings {
47
47
  /** Sending before a model is chosen. */
48
48
  selectFirst: string;
49
49
  };
50
+ composerMenu: {
51
+ /** Names the composer's + button while it opens a menu of files and tools. */
52
+ label: string;
53
+ /** Opens the attachments panel from the menu. */
54
+ addFiles: string;
55
+ /** Heads the host's tools in the menu, and names the + when it holds only tools. */
56
+ tools: string;
57
+ /** Beside the + while the reader has turned some of the host's tools off. */
58
+ someToolsOff: string;
59
+ /** Beside Tools: how many of the host's tools are on. */
60
+ toolsOn: (enabled: number, total: number) => string;
61
+ /** Under the title of the modal that lists every tool. */
62
+ toolsDescription: string;
63
+ searchTools: string;
64
+ /** The modal's search matched no tool. */
65
+ noToolsMatch: string;
66
+ turnAllOn: string;
67
+ turnAllOff: string;
68
+ /** Closes the tools modal; each switch takes effect as it is flipped. */
69
+ done: string;
70
+ };
50
71
  allocationPicker: {
51
72
  choose: string;
52
73
  placeholder: string;
@@ -53,6 +53,19 @@ var defaultChatStrings = {
53
53
  manageProvider: "Manage provider",
54
54
  selectFirst: "Select a model first"
55
55
  },
56
+ composerMenu: {
57
+ label: "Add files and tools",
58
+ addFiles: "Add files",
59
+ tools: "Tools",
60
+ someToolsOff: "Some tools are off",
61
+ toolsOn: (enabled, total) => `${enabled.toLocaleString()}/${total.toLocaleString()}`,
62
+ toolsDescription: "What the assistant may look up for you.",
63
+ searchTools: "Search tools",
64
+ noToolsMatch: "No tools match",
65
+ turnAllOn: "Turn all on",
66
+ turnAllOff: "Turn all off",
67
+ done: "Done"
68
+ },
56
69
  allocationPicker: {
57
70
  choose: "Allocation",
58
71
  placeholder: "Select allocation",
@@ -5,8 +5,8 @@ import { useRender } from "@base-ui/react/use-render";
5
5
  //#region src/components/Card.tsx
6
6
  var sizeClasses = {
7
7
  sm: "max-w-[400px] p-6",
8
- md: "max-w-[520px] p-10",
9
- lg: "max-w-[560px] p-8"
8
+ md: "max-w-[520px] p-6 sm:p-10",
9
+ lg: "max-w-[560px] p-6 sm:p-8"
10
10
  };
11
11
  /** A raised surface holding one task, such as a sign-in form or a choice among
12
12
  * a few options. */
@@ -61,9 +61,11 @@ export interface FieldProps {
61
61
  group?: boolean | undefined;
62
62
  /** Puts a checkbox, a switch or a lone radio before its label, as such a control reads: the
63
63
  * control, then its label and ?, with the description and error under the label. A click on
64
- * the label sets the control. Inline, or in a row of fields, it sits in the control column,
65
- * its first line on the line of the labels beside it. Not for a `group`, whose options are
66
- * each a `FieldOption`. */
64
+ * the label sets the control. A checkbox or a radio sits on the label's first line; a switch
65
+ * centers on the text's first two lines, such as the label and its description, and stays
66
+ * there under longer text. Inline it sits in the control column, under the controls above
67
+ * it; in a row of fields, its first line centers on the controls beside it, a switch's too.
68
+ * Not for a `group`, whose options are each a `FieldOption`. */
67
69
  controlFirst?: boolean | undefined;
68
70
  /** The control's id; one is made up when left out. */
69
71
  id?: string | undefined;
@@ -38,18 +38,27 @@ var labelSizes = {
38
38
  text: "text-xs text-(--theme-muted-text-color)",
39
39
  inlineHeight: "min-h-7",
40
40
  stackGap: "gap-1",
41
- inlineLine: "py-1.5"
41
+ narrowStack: "max-sm:flex-col max-sm:items-stretch max-sm:gap-1",
42
+ inlineLine: "pt-1",
43
+ controlFirstHeight: "min-h-5",
44
+ controlFirstStackedHeight: "min-h-6"
42
45
  },
43
46
  md: {
44
47
  text: "text-sm text-(--theme-app)",
45
48
  inlineHeight: "min-h-8",
46
49
  stackGap: "gap-1.5",
47
- inlineLine: "py-1.5"
50
+ narrowStack: "max-sm:flex-col max-sm:items-stretch max-sm:gap-1.5",
51
+ inlineLine: "pt-1",
52
+ controlFirstHeight: "min-h-6",
53
+ controlFirstStackedHeight: "min-h-7"
48
54
  }
49
55
  };
50
56
  var labelClassName = "flex items-center gap-1 font-medium";
51
57
  var actionsClassName = "ml-auto flex shrink-0 items-center gap-1";
52
58
  var controlFirstExtrasClassName = "ms-1 inline-flex items-center gap-1 align-[-0.125em]";
59
+ var switchOnTwoLines = "has-[[role=switch]]:max-h-[2lh]";
60
+ var switchOnLabelAndDescription = "has-[[role=switch]]:max-h-[calc(1lh+1rem)]";
61
+ var switchRowStartsAtText = "has-[[role=switch]]:-mt-1";
53
62
  var errorTextClassName = "flex items-center gap-1.5 text-xs text-(--theme-error-text)";
54
63
  /** An error in the look a Field gives its own, for a control outside a Field, or for a part of
55
64
  * one rather than the whole of it, such as a row of a list editor. Give it an `id` and name it
@@ -127,7 +136,7 @@ function Field$1({ label, hint, help, actions, description, error, invalid, requ
127
136
  }
128
137
  }
129
138
  } : {};
130
- const labelBox = cx(labelClassName, labelSize.text, inline && cx(labelSize.inlineHeight, "shrink-0", compact ? "mr-2 w-fit" : "w-52 pr-3"), inRow && "row-start-1 self-end");
139
+ const labelBox = cx(labelClassName, labelSize.text, inline && cx(labelSize.inlineHeight, "shrink-0", compact ? "mr-2 w-fit" : "w-52 pr-3 max-sm:min-h-0 max-sm:w-full max-sm:pr-0"), inRow && "row-start-1 self-end");
131
140
  const nameContent = /* @__PURE__ */ jsxs(Fragment, { children: [label, required && /* @__PURE__ */ jsx(RequiredMark, {})] });
132
141
  const labelExtras = /* @__PURE__ */ jsxs(Fragment, { children: [
133
142
  helpTip,
@@ -148,7 +157,7 @@ function Field$1({ label, hint, help, actions, description, error, invalid, requ
148
157
  const messages = /* @__PURE__ */ jsxs(Fragment, { children: [
149
158
  description && /* @__PURE__ */ jsx(Field.Description, {
150
159
  id: descriptionId,
151
- className: "text-xs leading-relaxed text-(--theme-muted-text-color)",
160
+ className: cx("text-xs text-(--theme-muted-text-color)", controlFirst && !group ? "leading-4" : "leading-relaxed"),
152
161
  children: description
153
162
  }),
154
163
  help && /* @__PURE__ */ jsx(Field.Description, {
@@ -177,47 +186,47 @@ function Field$1({ label, hint, help, actions, description, error, invalid, requ
177
186
  "data-field-label": true,
178
187
  children: nameContent
179
188
  });
180
- if (controlFirst && !group) {
181
- const lined = inline || inRow;
182
- return /* @__PURE__ */ jsxs(Field.Root, {
183
- invalid: isInvalid,
184
- disabled,
185
- className: inRow ? cx("contents", className) : cx("flex w-full items-start", className),
186
- "data-field-row": inRow || void 0,
187
- children: [inline && !compact && /* @__PURE__ */ jsx("div", {
188
- "aria-hidden": "true",
189
- className: "w-52 shrink-0"
190
- }), /* @__PURE__ */ jsxs("div", {
191
- ref: help ? setControlBox : void 0,
192
- className: cx("flex w-fit max-w-full min-w-0 items-start gap-2", lined ? labelSize.inlineLine : "py-0.5", inRow && "row-start-2"),
193
- children: [/* @__PURE__ */ jsx("div", {
194
- className: cx("flex h-lh shrink-0 items-center", labelSize.text),
195
- ...helpFocus,
189
+ if (controlFirst && !group) return /* @__PURE__ */ jsxs(Field.Root, {
190
+ invalid: isInvalid,
191
+ disabled,
192
+ className: inRow ? cx("contents", className) : cx("flex w-full items-start", inline ? labelSize.controlFirstHeight : labelSize.controlFirstStackedHeight, className),
193
+ "data-field-row": inRow || void 0,
194
+ children: [inline && !compact && /* @__PURE__ */ jsx("div", {
195
+ "aria-hidden": "true",
196
+ className: "w-52 shrink-0 max-sm:hidden"
197
+ }), /* @__PURE__ */ jsxs("div", {
198
+ ref: help ? setControlBox : void 0,
199
+ className: cx("flex w-fit max-w-full min-w-0 items-start gap-2", inRow ? labelSize.inlineLine : !inline && "pt-1", inRow && "row-start-2", !inRow && (description || error) && switchRowStartsAtText),
200
+ children: [/* @__PURE__ */ jsx("div", {
201
+ className: cx("box-content flex shrink-0 items-center", inRow ? "h-lh py-0.5" : cx("min-h-lh max-h-lh self-stretch pt-0.5", description ? switchOnLabelAndDescription : switchOnTwoLines), labelSize.text),
202
+ ...helpFocus,
203
+ children: /* @__PURE__ */ jsx("div", {
204
+ className: "flex h-0 items-center",
196
205
  children: controlInContext
197
- }), /* @__PURE__ */ jsxs("div", {
198
- className: "flex min-w-0 flex-col gap-1",
199
- children: [/* @__PURE__ */ jsxs("div", {
200
- className: cx("font-medium", labelSize.text, disabled && "opacity-60"),
201
- children: [
202
- fieldLabel(disabled ? "cursor-not-allowed" : "cursor-pointer"),
203
- helpTip && /* @__PURE__ */ jsx("span", {
204
- className: controlFirstExtrasClassName,
205
- children: helpTip
206
- }),
207
- hint && /* @__PURE__ */ jsx("span", {
208
- className: "ms-1",
209
- children: hint
210
- }),
211
- actions && /* @__PURE__ */ jsx("span", {
212
- className: controlFirstExtrasClassName,
213
- children: actions
214
- })
215
- ]
216
- }), messages]
217
- })]
206
+ })
207
+ }), /* @__PURE__ */ jsxs("div", {
208
+ className: "flex min-w-0 flex-col pt-0.5",
209
+ children: [/* @__PURE__ */ jsxs("div", {
210
+ className: cx("font-medium", labelSize.text, disabled && "opacity-60"),
211
+ children: [
212
+ fieldLabel(disabled ? "cursor-not-allowed" : "cursor-pointer"),
213
+ helpTip && /* @__PURE__ */ jsx("span", {
214
+ className: controlFirstExtrasClassName,
215
+ children: helpTip
216
+ }),
217
+ hint && /* @__PURE__ */ jsx("span", {
218
+ className: "ms-1",
219
+ children: hint
220
+ }),
221
+ actions && /* @__PURE__ */ jsx("span", {
222
+ className: controlFirstExtrasClassName,
223
+ children: actions
224
+ })
225
+ ]
226
+ }), messages]
218
227
  })]
219
- });
220
- }
228
+ })]
229
+ });
221
230
  const body = /* @__PURE__ */ jsxs("div", {
222
231
  ref: help ? setControlBox : void 0,
223
232
  className: cx("flex w-full min-w-0 flex-col gap-1", inRow && "row-start-2"),
@@ -227,10 +236,11 @@ function Field$1({ label, hint, help, actions, description, error, invalid, requ
227
236
  children: controlInContext
228
237
  }) : controlInContext, messages]
229
238
  });
230
- const frame = inRow ? cx("contents", className) : cx("flex w-full", inline ? "items-start" : cx("flex-col", labelSize.stackGap), className);
239
+ const frame = inRow ? cx("contents", className) : cx("flex w-full", inline ? cx("items-start", !compact && labelSize.narrowStack) : cx("flex-col", labelSize.stackGap), className);
231
240
  if (group) return /* @__PURE__ */ jsx(Field.Root, {
232
241
  invalid: isInvalid,
233
242
  disabled,
243
+ className: "w-full min-w-0",
234
244
  render: /* @__PURE__ */ jsx(Fieldset.Root, {
235
245
  "aria-describedby": control["aria-describedby"],
236
246
  "aria-invalid": control["aria-invalid"]
@@ -1,5 +1,6 @@
1
1
  import { type ReactNode } from 'react';
2
2
  export type SectionVariant = 'plain' | 'card';
3
+ export type SectionSpacing = 'regular' | 'tight';
3
4
  export interface SectionProps {
4
5
  title: ReactNode;
5
6
  /** Under the title in muted text, saying what the section holds; it describes
@@ -12,6 +13,10 @@ export interface SectionProps {
12
13
  /** `plain` rules the title off from the content under it; `card` frames the
13
14
  * section as a panel. */
14
15
  variant?: SectionVariant | undefined;
16
+ /** The room between a `plain` section's rule and its content. `tight` suits content that
17
+ * spaces itself tightly, such as a form with its labels over its fields, so the first row
18
+ * sits as far under the rule as the rows under it sit under one another. */
19
+ spacing?: SectionSpacing | undefined;
15
20
  /** False shows the content always, under a title that doesn't fold. */
16
21
  collapsible?: boolean | undefined;
17
22
  /** Hold the state, such as a remembered preference, with `open` and
@@ -30,4 +35,4 @@ export interface SectionProps {
30
35
  * that can fold away. Folding keeps the content mounted, so fields hold their
31
36
  * values and validation while closed. For a line inside content that reveals
32
37
  * more detail, use Disclosure. */
33
- export declare function Section({ title, description, beside, actions, variant, collapsible, open, onOpenChange, defaultOpen, headingLevel, id, className, children, }: SectionProps): import("react").JSX.Element;
38
+ export declare function Section({ title, description, beside, actions, variant, spacing, collapsible, open, onOpenChange, defaultOpen, headingLevel, id, className, children, }: SectionProps): import("react").JSX.Element;
@@ -10,9 +10,13 @@ var rootClasses = {
10
10
  card: "panel mb-1 flex w-full flex-col"
11
11
  };
12
12
  var headerClasses = {
13
- plain: "mb-4 flex w-full items-center gap-2 border-b border-(--theme-border) pb-1",
13
+ plain: "flex w-full items-center gap-2 border-b border-(--theme-border) pb-1",
14
14
  card: "flex w-full items-center gap-2 p-4"
15
15
  };
16
+ var ruleGaps = {
17
+ regular: "mb-4",
18
+ tight: "mb-1.5"
19
+ };
16
20
  var cardBodyClassName = "px-4 pb-4";
17
21
  var titleClasses = {
18
22
  plain: "text-base font-semibold",
@@ -27,14 +31,15 @@ var chevronIndent = "pl-6";
27
31
  * that can fold away. Folding keeps the content mounted, so fields hold their
28
32
  * values and validation while closed. For a line inside content that reveals
29
33
  * more detail, use Disclosure. */
30
- function Section({ title, description, beside, actions, variant = "plain", collapsible = true, open, onOpenChange, defaultOpen = true, headingLevel = 3, id, className, children }) {
34
+ function Section({ title, description, beside, actions, variant = "plain", spacing = "regular", collapsible = true, open, onOpenChange, defaultOpen = true, headingLevel = 3, id, className, children }) {
31
35
  const Heading = `h${headingLevel}`;
32
36
  const descriptionId = useId();
33
37
  const describedBy = description ? descriptionId : void 0;
34
38
  const titleProps = { "data-section-title": "" };
35
39
  const fill = !beside && !actions;
36
40
  const header = (heading) => /* @__PURE__ */ jsxs("div", {
37
- className: headerClasses[variant],
41
+ className: cx(headerClasses[variant], variant === "plain" && ruleGaps[spacing]),
42
+ "data-section-header": true,
38
43
  children: [/* @__PURE__ */ jsxs("div", {
39
44
  className: "flex min-w-0 flex-1 flex-col gap-0.5",
40
45
  children: [/* @__PURE__ */ jsxs("div", {
@@ -1,6 +1,6 @@
1
1
  import { InfoTip } from "../../components/InfoTip.js";
2
2
  import { Section } from "../../components/Section.js";
3
- import { FieldsFromOptions, resolveMetaOverrides } from "../Form.js";
3
+ import { FieldsFromOptions, resolveMetaOverrides, sectionSpacing } from "../Form.js";
4
4
  import { jsx } from "react/jsx-runtime";
5
5
  import { useMemo } from "react";
6
6
  //#region src/form/Fields/ObjectField.tsx
@@ -13,6 +13,7 @@ function ObjectField({ field, label, help, labelPosition, spaceCompact }) {
13
13
  beside: help && /* @__PURE__ */ jsx(InfoTip, { text: help }),
14
14
  collapsible: !field.noCollapse,
15
15
  defaultOpen: !field.collapsed,
16
+ spacing: sectionSpacing(meta.labelPosition),
16
17
  children: /* @__PURE__ */ jsx(FieldsFromOptions, {
17
18
  options: field.options,
18
19
  labelPosition: meta.labelPosition,
@@ -1,4 +1,5 @@
1
1
  import { type UseFormReturn } from 'react-hook-form';
2
+ import { type SectionSpacing } from '../components/Section.js';
2
3
  import type { WorkflowVariables } from '../engine.js';
3
4
  import { type FieldComponent } from './fieldRegistry.js';
4
5
  import { type ServerError } from './validation.js';
@@ -45,6 +46,9 @@ export interface ParentInfo {
45
46
  arrayIndex?: number | undefined;
46
47
  onChange?: RowFlagChange | undefined;
47
48
  }
49
+ /** A section's rule sits as far over its first row as the form's rows sit apart: tight with the
50
+ * labels over the fields, and the regular gap, close to the 15px between side-labeled rows. */
51
+ export declare function sectionSpacing(labelPosition: 'left' | 'top' | undefined): SectionSpacing;
48
52
  /** Renders a schema's fields. Inside another field, `parentInfo` says where their values sit. */
49
53
  export declare function FieldsFromOptions({ options, parentInfo, labelPosition, spaceCompact, }: {
50
54
  options: Record<string, unknown>;
package/dist/form/Form.js CHANGED
@@ -341,6 +341,8 @@ var FormField = memo(function FormField({ fieldName, optionsField, nested, field
341
341
  title: field.label,
342
342
  collapsible: !field.noCollapse,
343
343
  defaultOpen: !field.collapsed,
344
+ spacing: sectionSpacing(meta.labelPosition),
345
+ className: sectionAbove,
344
346
  children: /* @__PURE__ */ jsx(EditingScope, {
345
347
  editing,
346
348
  path,
@@ -389,7 +391,7 @@ var FormField = memo(function FormField({ fieldName, optionsField, nested, field
389
391
  }
390
392
  const required = !fieldObj.optional && !fieldObj.disabled && fieldObj.type !== "boolean" && !editing;
391
393
  const input = /* @__PURE__ */ jsx("div", {
392
- className: inRow ? "grid grid-rows-subgrid [&>:not([data-field-row])]:row-span-2" : cx("flex w-full", labelPosition === "left" ? "mb-[15px]" : "mb-[5px]"),
394
+ className: inRow ? "grid grid-rows-subgrid [&>:not([data-field-row])]:row-span-2" : cx("flex w-full", labelPosition === "left" ? "mb-[15px]" : "mb-[5px]", fieldObj.type === "object" && sectionAbove),
393
395
  children: /* @__PURE__ */ jsx(RequiredFieldContext, {
394
396
  value: required ? {
395
397
  name,
@@ -420,6 +422,12 @@ var FormField = memo(function FormField({ fieldName, optionsField, nested, field
420
422
  })
421
423
  });
422
424
  });
425
+ var sectionAbove = "not-first:pt-3";
426
+ /** A section's rule sits as far over its first row as the form's rows sit apart: tight with the
427
+ * labels over the fields, and the regular gap, close to the 15px between side-labeled rows. */
428
+ function sectionSpacing(labelPosition) {
429
+ return labelPosition === "top" ? "tight" : "regular";
430
+ }
423
431
  /** The message under a field for its error, if it has one of its own rather than errors in fields
424
432
  * inside it. */
425
433
  function errorMessage(error, strings) {
@@ -742,4 +750,4 @@ function clearServerErrors(form, paths) {
742
750
  for (const path of paths) if (form.getFieldState(path).error?.type === "server") form.clearErrors(path);
743
751
  }
744
752
  //#endregion
745
- export { DynamicDefaultsSync, DynamicForm, FieldsFromOptions, collectFieldsWithDefaults, defaultReferencesField, findSelfReferencingFieldNames, listLengthsSignature, resolveMetaOverrides, useDynamicDefaultsSync };
753
+ export { DynamicDefaultsSync, DynamicForm, FieldsFromOptions, collectFieldsWithDefaults, defaultReferencesField, findSelfReferencingFieldNames, listLengthsSignature, resolveMetaOverrides, sectionSpacing, useDynamicDefaultsSync };
package/dist/icons.d.ts CHANGED
@@ -235,6 +235,7 @@ export declare const TagIcon: IconType;
235
235
  export declare const TerminalIcon: IconType;
236
236
  export declare const ThinkingIcon: IconType;
237
237
  export declare const TodoIcon: IconType;
238
+ export declare const ToolsIcon: IconType;
238
239
  export declare const TrashIcon: IconType;
239
240
  export declare const TunnelIcon: IconType;
240
241
  export declare const UndoIcon: IconType;
package/dist/icons.js CHANGED
@@ -267,6 +267,7 @@ var TagIcon = /* @__PURE__ */ icon(Tag);
267
267
  var TerminalIcon = /* @__PURE__ */ icon(Terminal);
268
268
  var ThinkingIcon = /* @__PURE__ */ icon(Brain);
269
269
  var TodoIcon = /* @__PURE__ */ icon(ClipboardPen);
270
+ var ToolsIcon = /* @__PURE__ */ icon(Wrench);
270
271
  var TrashIcon = /* @__PURE__ */ icon(Trash2);
271
272
  var TunnelIcon = /* @__PURE__ */ icon(Route);
272
273
  var UndoIcon = /* @__PURE__ */ icon(Undo2);
@@ -285,4 +286,4 @@ var ZipIcon = /* @__PURE__ */ icon(FileArchive);
285
286
  var ZoomInIcon = /* @__PURE__ */ icon(ZoomIn);
286
287
  var ZoomOutIcon = /* @__PURE__ */ icon(ZoomOut);
287
288
  //#endregion
288
- export { APIIcon, AccessIcon, AddAllocationIcon, AddIcon, AddProjectIcon, AddUserIcon, AgentIcon, AllocationIcon, ArchiveIcon, ArrowDownIcon, ArrowLeftIcon, ArrowRightIcon, ArrowUpIcon, ArticleIcon, AttachmentIcon, AuthenticationIcon, BillingIcon, BriefcaseIcon, BucketIcon, BuildWorkflowIcon, CalendarIcon, CancelIcon, CelebrateIcon, CertificateIcon, ChangesRequestedIcon, ChartIcon, ChatIcon, CheckIcon, ChevronDoubleDownIcon, ChevronDoubleUpIcon, ChevronDownIcon, ChevronLeftIcon, ChevronRightIcon, ChevronUpIcon, ClipboardCheckIcon, ClockIcon, CloseIcon, CloudIcon, ClusterIcon, CodeIcon, CollapseIcon, ColumnsIcon, CommentIcon, CommitIcon, ComputeIcon, ConnectIcon, ContractIcon, CopyIcon, CustomizeIcon, DesktopIcon, DestroyIcon, DeviceIcon, DirectoryIcon, DisableCostIcon, DisableUserIcon, DisconnectIcon, DiskIcon, DisplayIcon, DownloadIcon, DragHandleIcon, DuplicateIcon, EditIcon, EditorIcon, EducationIcon, EnableCostIcon, EnableUserIcon, EndpointIcon, ErrorCheckmark, ErrorIcon, EventsIcon, ExpandIcon, ExpandVerticalIcon, ExpiredIcon, ExpiringIcon, ExpressionIcon, ExternalLinkIcon, EyeIcon, EyeOffIcon, FailIcon, FavoriteIcon, FavoriteOutlineIcon, FeaturedIcon, FileIcon, FileTextIcon, FilesIcon, FilesystemIcon, FilterClearIcon, FilterIcon, FlaggedIcon, FlaskIcon, FolderIcon, FolderOpenIcon, FolderTreeIcon, ForbiddenIcon, ForkIcon, GearsIcon, GlobeIcon, GovernmentIcon, GraphIcon, GridIcon, HealthMonitoringIcon, HelpIcon, HistoryIcon, HomeIcon, IdCardIcon, ImageIcon, ImpersonateIcon, InboxIcon, IndexIcon, InfoIcon, InfrastructureLayersIcon, InputFormIcon, InstallIcon, InstanceIcon, InstanceTypeIcon, IpAddressIcon, IssueIcon, JobIcon, JsonIcon, KeyIcon, KeyboardIcon, KubernetesNamespaceIcon, LanguageIcon, LegalIcon, LibraryIcon, LicenseIcon, LinkIcon, ListViewIcon, LockIcon, MFAIcon, MachineImageIcon, MailFailedIcon, MailIcon, MailVerifiedIcon, MapPinIcon, MarketplaceIcon, MatrixIcon, MegaphoneIcon, MigrationIcon, MinimizeIcon, MinusIcon, MlIcon, MoneyIcon, MoonIcon, MoreIcon, MusicIcon, MuteIcon, NavigationIcon, NetworkInterfaceIcon, NewChatIcon, NodeIcon, NotRunningIcon, NotebookIcon, NotificationIcon, OnboardingIcon, OpenInNewGraphIcon, OrganizationIcon, PartnerIcon, PasswordIcon, PauseIcon, PdfIcon, PendingIcon, PhoneIcon, PieChartIcon, PinFilledIcon, PinIcon, PowerIcon, PowershellIcon, PreviewIcon, PrintIcon, ProjectIcon, PublishIcon, PullRequestIcon, QRCodeIcon, QueueIcon, QuotaIcon, RedoIcon, RefreshIcon, RemoveIcon, RemoveUserIcon, RenameIcon, RenewIcon, ResetLayoutIcon, ResourceGroupIcon, ResourceIcon, RetryIcon, RoleIcon, RollbackIcon, RunWorkflowIcon, RunningIcon, RunsIcon, SaveIcon, SchedulerIcon, ScriptIcon, SearchIcon, SendIcon, ServiceIcon, SessionIcon, SettingsIcon, ShareIcon, ShieldIcon, ShieldOffIcon, ShrinkIcon, SidebarCloseIcon, SidebarIcon, SidebarOpenIcon, SignInIcon, SignOutIcon, SkipIcon, SnapshotIcon, SortDownIcon, SortUnsortedIcon, SortUpIcon, SparklesIcon, SplitIcon, SpreadsheetIcon, StartIcon, StopIcon, StorageIcon, SubdomainIcon, SuccessCheckmark, SuccessIcon, SummaryIcon, SunIcon, SupportIcon, SwapIcon, TagIcon, TerminalIcon, ThinkingIcon, TodoIcon, TrashIcon, TunnelIcon, UndoIcon, UnfavoriteIcon, UnlinkIcon, UnmuteIcon, UploadIcon, UserIcon, UserWorkspaceIcon, UsersIcon, VideoIcon, WarningIcon, WebhookIcon, ZapIcon, ZipIcon, ZoomInIcon, ZoomOutIcon };
289
+ export { APIIcon, AccessIcon, AddAllocationIcon, AddIcon, AddProjectIcon, AddUserIcon, AgentIcon, AllocationIcon, ArchiveIcon, ArrowDownIcon, ArrowLeftIcon, ArrowRightIcon, ArrowUpIcon, ArticleIcon, AttachmentIcon, AuthenticationIcon, BillingIcon, BriefcaseIcon, BucketIcon, BuildWorkflowIcon, CalendarIcon, CancelIcon, CelebrateIcon, CertificateIcon, ChangesRequestedIcon, ChartIcon, ChatIcon, CheckIcon, ChevronDoubleDownIcon, ChevronDoubleUpIcon, ChevronDownIcon, ChevronLeftIcon, ChevronRightIcon, ChevronUpIcon, ClipboardCheckIcon, ClockIcon, CloseIcon, CloudIcon, ClusterIcon, CodeIcon, CollapseIcon, ColumnsIcon, CommentIcon, CommitIcon, ComputeIcon, ConnectIcon, ContractIcon, CopyIcon, CustomizeIcon, DesktopIcon, DestroyIcon, DeviceIcon, DirectoryIcon, DisableCostIcon, DisableUserIcon, DisconnectIcon, DiskIcon, DisplayIcon, DownloadIcon, DragHandleIcon, DuplicateIcon, EditIcon, EditorIcon, EducationIcon, EnableCostIcon, EnableUserIcon, EndpointIcon, ErrorCheckmark, ErrorIcon, EventsIcon, ExpandIcon, ExpandVerticalIcon, ExpiredIcon, ExpiringIcon, ExpressionIcon, ExternalLinkIcon, EyeIcon, EyeOffIcon, FailIcon, FavoriteIcon, FavoriteOutlineIcon, FeaturedIcon, FileIcon, FileTextIcon, FilesIcon, FilesystemIcon, FilterClearIcon, FilterIcon, FlaggedIcon, FlaskIcon, FolderIcon, FolderOpenIcon, FolderTreeIcon, ForbiddenIcon, ForkIcon, GearsIcon, GlobeIcon, GovernmentIcon, GraphIcon, GridIcon, HealthMonitoringIcon, HelpIcon, HistoryIcon, HomeIcon, IdCardIcon, ImageIcon, ImpersonateIcon, InboxIcon, IndexIcon, InfoIcon, InfrastructureLayersIcon, InputFormIcon, InstallIcon, InstanceIcon, InstanceTypeIcon, IpAddressIcon, IssueIcon, JobIcon, JsonIcon, KeyIcon, KeyboardIcon, KubernetesNamespaceIcon, LanguageIcon, LegalIcon, LibraryIcon, LicenseIcon, LinkIcon, ListViewIcon, LockIcon, MFAIcon, MachineImageIcon, MailFailedIcon, MailIcon, MailVerifiedIcon, MapPinIcon, MarketplaceIcon, MatrixIcon, MegaphoneIcon, MigrationIcon, MinimizeIcon, MinusIcon, MlIcon, MoneyIcon, MoonIcon, MoreIcon, MusicIcon, MuteIcon, NavigationIcon, NetworkInterfaceIcon, NewChatIcon, NodeIcon, NotRunningIcon, NotebookIcon, NotificationIcon, OnboardingIcon, OpenInNewGraphIcon, OrganizationIcon, PartnerIcon, PasswordIcon, PauseIcon, PdfIcon, PendingIcon, PhoneIcon, PieChartIcon, PinFilledIcon, PinIcon, PowerIcon, PowershellIcon, PreviewIcon, PrintIcon, ProjectIcon, PublishIcon, PullRequestIcon, QRCodeIcon, QueueIcon, QuotaIcon, RedoIcon, RefreshIcon, RemoveIcon, RemoveUserIcon, RenameIcon, RenewIcon, ResetLayoutIcon, ResourceGroupIcon, ResourceIcon, RetryIcon, RoleIcon, RollbackIcon, RunWorkflowIcon, RunningIcon, RunsIcon, SaveIcon, SchedulerIcon, ScriptIcon, SearchIcon, SendIcon, ServiceIcon, SessionIcon, SettingsIcon, ShareIcon, ShieldIcon, ShieldOffIcon, ShrinkIcon, SidebarCloseIcon, SidebarIcon, SidebarOpenIcon, SignInIcon, SignOutIcon, SkipIcon, SnapshotIcon, SortDownIcon, SortUnsortedIcon, SortUpIcon, SparklesIcon, SplitIcon, SpreadsheetIcon, StartIcon, StopIcon, StorageIcon, SubdomainIcon, SuccessCheckmark, SuccessIcon, SummaryIcon, SunIcon, SupportIcon, SwapIcon, TagIcon, TerminalIcon, ThinkingIcon, TodoIcon, ToolsIcon, TrashIcon, TunnelIcon, UndoIcon, UnfavoriteIcon, UnlinkIcon, UnmuteIcon, UploadIcon, UserIcon, UserWorkspaceIcon, UsersIcon, VideoIcon, WarningIcon, WebhookIcon, ZapIcon, ZipIcon, ZoomInIcon, ZoomOutIcon };