@uipath/apollo-wind 2.29.0 → 2.31.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.
@@ -255,6 +255,14 @@ export interface FormStep {
255
255
  validation?: 'onChange' | 'onBlur' | 'onSubmit';
256
256
  canSkip?: boolean;
257
257
  conditions?: FieldCondition[];
258
+ /**
259
+ * Message shown (in the `tabs` step variant) when this step has no visible
260
+ * sections. A step that sets this stays in the tab bar even while empty and
261
+ * renders the message in place of its content — e.g. a "Parameters" tab that
262
+ * always shows, reading "No available parameters" for a node with no inputs.
263
+ * Steps without both sections and `emptyState` are hidden from the tab bar.
264
+ */
265
+ emptyState?: string;
258
266
  }
259
267
  export interface FormAction {
260
268
  id: string;
@@ -39,7 +39,7 @@ const external_field_renderer_cjs_namespaceObject = require("./field-renderer.cj
39
39
  const external_rules_engine_cjs_namespaceObject = require("./rules-engine.cjs");
40
40
  const external_validation_converter_cjs_namespaceObject = require("./validation-converter.cjs");
41
41
  const DEFAULT_PLUGINS = [];
42
- function MetadataForm({ schema, plugins = DEFAULT_PLUGINS, onSubmit, className, disabled = false, autoComplete, stepVariant = 'wizard' }) {
42
+ function MetadataForm({ schema, plugins = DEFAULT_PLUGINS, onSubmit, className, disabled = false, autoComplete, stepVariant = 'wizard', sectionVariant = 'card', activeStepId, onActiveStepChange }) {
43
43
  const [currentStep, setCurrentStep] = (0, external_react_namespaceObject.useState)(0);
44
44
  const [customComponents, setCustomComponents] = (0, external_react_namespaceObject.useState)({});
45
45
  const [isInitialized, setIsInitialized] = (0, external_react_namespaceObject.useState)(false);
@@ -131,6 +131,9 @@ function MetadataForm({ schema, plugins = DEFAULT_PLUGINS, onSubmit, className,
131
131
  context: context,
132
132
  customComponents: customComponents,
133
133
  disabled: disabled,
134
+ sectionVariant: sectionVariant,
135
+ activeStepId: activeStepId,
136
+ onActiveStepChange: onActiveStepChange,
134
137
  onReset: ()=>reset()
135
138
  });
136
139
  return /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(MultiStepForm, {
@@ -139,14 +142,16 @@ function MetadataForm({ schema, plugins = DEFAULT_PLUGINS, onSubmit, className,
139
142
  currentStep: currentStep,
140
143
  setCurrentStep: setCurrentStep,
141
144
  customComponents: customComponents,
142
- disabled: disabled
145
+ disabled: disabled,
146
+ sectionVariant: sectionVariant
143
147
  });
144
148
  }
145
149
  return /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(SinglePageForm, {
146
150
  schema: schema,
147
151
  context: context,
148
152
  customComponents: customComponents,
149
- disabled: disabled
153
+ disabled: disabled,
154
+ sectionVariant: sectionVariant
150
155
  });
151
156
  };
152
157
  return /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(external_react_hook_form_namespaceObject.FormProvider, {
@@ -166,20 +171,21 @@ function MetadataForm({ schema, plugins = DEFAULT_PLUGINS, onSubmit, className,
166
171
  })
167
172
  });
168
173
  }
169
- function SinglePageForm({ schema, context, customComponents, disabled }) {
174
+ function SinglePageForm({ schema, context, customComponents, disabled, sectionVariant }) {
170
175
  const sections = schema.sections || [];
171
176
  const visibleSections = sections.filter((section)=>!section.conditions || context.evaluateConditions(section.conditions));
172
177
  return /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)("div", {
173
- className: "space-y-2",
178
+ className: 'plain' === sectionVariant ? void 0 : 'space-y-2',
174
179
  children: visibleSections.map((section)=>/*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(FormSection, {
175
180
  section: section,
176
181
  context: context,
177
182
  customComponents: customComponents,
178
- disabled: disabled
183
+ disabled: disabled,
184
+ sectionVariant: sectionVariant
179
185
  }, section.id))
180
186
  });
181
187
  }
182
- function MultiStepForm({ schema, context, currentStep, setCurrentStep, customComponents, disabled }) {
188
+ function MultiStepForm({ schema, context, currentStep, setCurrentStep, customComponents, disabled, sectionVariant }) {
183
189
  const steps = schema.steps || [];
184
190
  const step = steps[currentStep];
185
191
  if (!step) return null;
@@ -217,12 +223,13 @@ function MultiStepForm({ schema, context, currentStep, setCurrentStep, customCom
217
223
  ]
218
224
  }),
219
225
  /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)("div", {
220
- className: "space-y-2",
226
+ className: 'plain' === sectionVariant ? void 0 : 'space-y-2',
221
227
  children: step.sections.map((section)=>/*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(FormSection, {
222
228
  section: section,
223
229
  context: context,
224
230
  customComponents: customComponents,
225
- disabled: disabled
231
+ disabled: disabled,
232
+ sectionVariant: sectionVariant
226
233
  }, section.id))
227
234
  }),
228
235
  /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsxs)("div", {
@@ -250,15 +257,39 @@ function MultiStepForm({ schema, context, currentStep, setCurrentStep, customCom
250
257
  ]
251
258
  });
252
259
  }
253
- function TabbedStepForm({ schema, context, customComponents, disabled, onReset }) {
260
+ function TabbedStepForm({ schema, context, customComponents, disabled, sectionVariant, onReset, activeStepId, onActiveStepChange }) {
254
261
  const steps = schema.steps || [];
255
- const visibleSteps = steps.filter((step)=>step.sections.length > 0 && (!step.conditions || context.evaluateConditions(step.conditions)));
256
- const [activeTab, setActiveTab] = (0, external_react_namespaceObject.useState)('');
257
- const currentTab = visibleSteps.some((step)=>step.id === activeTab) ? activeTab : visibleSteps[0]?.id ?? '';
262
+ const visibleSteps = steps.filter((step)=>{
263
+ if (step.conditions && !context.evaluateConditions(step.conditions)) return false;
264
+ const hasVisibleSection = step.sections.some((section)=>!section.conditions || context.evaluateConditions(section.conditions));
265
+ return hasVisibleSection || void 0 !== step.emptyState;
266
+ });
267
+ const formState = (0, external_react_hook_form_namespaceObject.useFormState)({
268
+ control: context.form.control
269
+ });
270
+ const errorCountByStepId = {};
271
+ for (const step of visibleSteps){
272
+ let count = 0;
273
+ for (const section of step.sections)if (!section.conditions || context.evaluateConditions(section.conditions)) for (const field of section.fields){
274
+ if (field.rules && !external_rules_engine_cjs_namespaceObject.RulesEngine.isFieldVisible(field.rules, context.values)) continue;
275
+ const fieldError = context.form.getFieldState(field.name, formState).error;
276
+ if (fieldError) count += Array.isArray(fieldError) ? fieldError.filter(Boolean).length : 1;
277
+ }
278
+ errorCountByStepId[step.id] = count;
279
+ }
280
+ const [internalTab, setInternalTab] = (0, external_react_namespaceObject.useState)('');
281
+ const controlled = void 0 !== activeStepId;
282
+ const requestedTab = controlled ? activeStepId : internalTab;
283
+ const currentTab = visibleSteps.some((step)=>step.id === requestedTab) ? requestedTab : visibleSteps[0]?.id ?? '';
284
+ const selectTab = (stepId)=>{
285
+ if (!controlled) setInternalTab(stepId);
286
+ onActiveStepChange?.(stepId);
287
+ };
258
288
  (0, external_react_namespaceObject.useEffect)(()=>{
259
- if (activeTab !== currentTab) setActiveTab(currentTab);
289
+ if (!controlled && internalTab !== currentTab) setInternalTab(currentTab);
260
290
  }, [
261
- activeTab,
291
+ controlled,
292
+ internalTab,
262
293
  currentTab
263
294
  ]);
264
295
  if (0 === visibleSteps.length) return null;
@@ -266,27 +297,53 @@ function TabbedStepForm({ schema, context, customComponents, disabled, onReset }
266
297
  children: [
267
298
  /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsxs)(tabs_cjs_namespaceObject.Tabs, {
268
299
  value: currentTab,
269
- onValueChange: setActiveTab,
270
- className: "flex flex-col gap-4",
300
+ onValueChange: selectTab,
301
+ className: "flex min-h-0 flex-1 flex-col gap-1",
271
302
  children: [
272
- /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(tabs_cjs_namespaceObject.TabsList, {
273
- className: "h-auto justify-start gap-0.5 overflow-x-auto rounded-lg bg-transparent p-0.5 text-muted-foreground [-ms-overflow-style:none] [scrollbar-width:none] [&::-webkit-scrollbar]:hidden",
274
- children: visibleSteps.map((step)=>/*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(tabs_cjs_namespaceObject.TabsTrigger, {
275
- value: step.id,
276
- className: "inline-flex h-6 shrink-0 items-center whitespace-nowrap rounded-md px-2.5 text-xs font-medium text-muted-foreground shadow-none transition-colors hover:text-foreground data-[state=active]:bg-surface-overlay data-[state=active]:text-foreground data-[state=active]:shadow-sm",
277
- children: step.title
278
- }, step.id))
303
+ /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)("div", {
304
+ className: "shrink-0 pt-3 [padding-inline:var(--mf-content-inset,0px)]",
305
+ children: /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(tabs_cjs_namespaceObject.ScrollableTabsList, {
306
+ className: "h-auto justify-start gap-0.5 rounded-lg bg-transparent px-0 py-0.5 text-muted-foreground",
307
+ scrollButtonClassName: "size-6 hover:bg-surface-overlay",
308
+ children: visibleSteps.map((step)=>{
309
+ const errorCount = errorCountByStepId[step.id] ?? 0;
310
+ return /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsxs)(tabs_cjs_namespaceObject.TabsTrigger, {
311
+ value: step.id,
312
+ className: "inline-flex h-6 shrink-0 items-center gap-1.5 whitespace-nowrap rounded-md px-2.5 text-xs font-medium text-muted-foreground shadow-none transition-colors hover:text-foreground data-[state=active]:bg-surface-overlay data-[state=active]:text-foreground data-[state=active]:shadow-sm",
313
+ children: [
314
+ step.title,
315
+ errorCount > 0 && /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)("span", {
316
+ role: "img",
317
+ "aria-label": `${errorCount} ${1 === errorCount ? 'issue' : 'issues'}`,
318
+ title: `${errorCount} ${1 === errorCount ? 'issue' : 'issues'}`,
319
+ className: "grid h-4 min-w-4 place-items-center rounded-full bg-error px-1 text-[10px] font-semibold leading-none text-foreground-on-accent",
320
+ children: errorCount
321
+ })
322
+ ]
323
+ }, step.id);
324
+ })
325
+ })
279
326
  }),
280
- visibleSteps.map((step)=>/*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(tabs_cjs_namespaceObject.TabsContent, {
327
+ visibleSteps.map((step)=>{
328
+ const stepSections = step.sections.filter((section)=>!section.conditions || context.evaluateConditions(section.conditions));
329
+ return /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(tabs_cjs_namespaceObject.TabsContent, {
281
330
  value: step.id,
282
- className: "space-y-2",
283
- children: step.sections.filter((section)=>!section.conditions || context.evaluateConditions(section.conditions)).map((section)=>/*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(FormSection, {
284
- section: section,
285
- context: context,
286
- customComponents: customComponents,
287
- disabled: disabled
288
- }, section.id))
289
- }, step.id))
331
+ className: "mt-0 min-h-0 flex-1 overflow-auto",
332
+ children: 0 === stepSections.length && void 0 !== step.emptyState ? /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)("div", {
333
+ className: "pt-4 text-sm text-muted-foreground [padding-inline:var(--mf-content-inset,0px)]",
334
+ children: step.emptyState
335
+ }) : /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)("div", {
336
+ className: 'plain' === sectionVariant ? 'pb-6 [padding-inline:var(--mf-content-inset,0px)]' : 'space-y-2 pb-6 pt-4 [padding-inline:var(--mf-content-inset,0px)]',
337
+ children: stepSections.map((section)=>/*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(FormSection, {
338
+ section: section,
339
+ context: context,
340
+ customComponents: customComponents,
341
+ disabled: disabled,
342
+ sectionVariant: sectionVariant
343
+ }, section.id))
344
+ })
345
+ }, step.id);
346
+ })
290
347
  ]
291
348
  }),
292
349
  /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(FormActions, {
@@ -297,9 +354,13 @@ function TabbedStepForm({ schema, context, customComponents, disabled, onReset }
297
354
  ]
298
355
  });
299
356
  }
300
- function FormSection({ section, context, customComponents, disabled }) {
357
+ function FormSection({ section, context, customComponents, disabled, sectionVariant = 'card' }) {
301
358
  const gridColumns = context.schema.layout?.columns || 1;
302
359
  const gap = context.schema.layout?.gap || 4;
360
+ const isPlain = 'plain' === sectionVariant;
361
+ const dividerClassName = 'border-t first:border-t-0';
362
+ const wrapperClassName = isPlain ? 'border-b-0' : 'border rounded-lg px-3';
363
+ const triggerClassName = isPlain ? 'justify-start gap-2 py-4 text-sm font-semibold hover:no-underline' : 'text-sm font-medium';
303
364
  const fieldsGrid = /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)("div", {
304
365
  className: "grid",
305
366
  style: {
@@ -313,7 +374,10 @@ function FormSection({ section, context, customComponents, disabled }) {
313
374
  disabled: disabled
314
375
  }, field.name))
315
376
  });
316
- if (!section.title) return fieldsGrid;
377
+ if (!section.title) return isPlain ? /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)("div", {
378
+ className: `${dividerClassName} pb-4 pt-4`,
379
+ children: fieldsGrid
380
+ }) : fieldsGrid;
317
381
  const innerContent = /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsxs)("div", {
318
382
  className: "flex flex-col gap-4",
319
383
  children: [
@@ -331,12 +395,13 @@ function FormSection({ section, context, customComponents, disabled }) {
331
395
  return /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(accordion_cjs_namespaceObject.Accordion, {
332
396
  type: "multiple",
333
397
  defaultValue: defaultValue,
398
+ className: isPlain ? dividerClassName : void 0,
334
399
  children: /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsxs)(accordion_cjs_namespaceObject.AccordionItem, {
335
400
  value: section.id,
336
- className: "border rounded-lg px-3",
401
+ className: wrapperClassName,
337
402
  children: [
338
403
  /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(accordion_cjs_namespaceObject.AccordionTrigger, {
339
- className: "text-sm font-medium",
404
+ className: triggerClassName,
340
405
  children: section.title
341
406
  }),
342
407
  /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(accordion_cjs_namespaceObject.AccordionContent, {
@@ -347,12 +412,12 @@ function FormSection({ section, context, customComponents, disabled }) {
347
412
  });
348
413
  }
349
414
  return /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsxs)("div", {
350
- className: "border rounded-lg px-3",
415
+ className: isPlain ? dividerClassName : wrapperClassName,
351
416
  children: [
352
417
  /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)("div", {
353
418
  className: "flex",
354
419
  children: /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)("div", {
355
- className: "flex flex-1 items-center justify-between py-4 text-sm font-medium",
420
+ className: isPlain ? 'flex flex-1 items-center justify-start gap-2 py-4 text-sm font-semibold' : 'flex flex-1 items-center justify-between py-4 text-sm font-medium',
356
421
  children: section.title
357
422
  })
358
423
  }),
@@ -18,6 +18,30 @@ interface MetadataFormProps {
18
18
  * across every step. Ignored for single-page (`sections`) schemas.
19
19
  */
20
20
  stepVariant?: 'wizard' | 'tabs';
21
+ /**
22
+ * Visual treatment for each titled section. `'card'` (default) wraps every
23
+ * section in a bordered, rounded, horizontally-padded box. `'plain'` drops the
24
+ * border, rounding, and horizontal padding so sections read as flush headers
25
+ * over their content, separated by a full-width hairline divider between
26
+ * consecutive sections — used by hosts (e.g. the canvas properties panel) that
27
+ * already frame the form and want a borderless list. Applies to both
28
+ * collapsible (accordion) and non-collapsible sections across every layout
29
+ * (single-page, wizard, tabs).
30
+ */
31
+ sectionVariant?: 'card' | 'plain';
32
+ /**
33
+ * Controlled active step id for the `tabs` step variant. When provided the
34
+ * caller owns which tab is selected — persist it across remounts to keep the
35
+ * user on the same tab when switching between nodes. If the id isn't one of
36
+ * the currently visible steps, the form shows the first tab without mutating
37
+ * the caller's value. Omit for uncontrolled (internal) tab state.
38
+ */
39
+ activeStepId?: string;
40
+ /**
41
+ * Fires with the step id whenever the user selects a tab, in both controlled
42
+ * and uncontrolled mode. Pair it with `activeStepId` to persist the selection.
43
+ */
44
+ onActiveStepChange?: (stepId: string) => void;
21
45
  }
22
- export declare function MetadataForm({ schema, plugins, onSubmit, className, disabled, autoComplete, stepVariant, }: MetadataFormProps): import("react/jsx-runtime").JSX.Element;
46
+ export declare function MetadataForm({ schema, plugins, onSubmit, className, disabled, autoComplete, stepVariant, sectionVariant, activeStepId, onActiveStepChange, }: MetadataFormProps): import("react/jsx-runtime").JSX.Element;
23
47
  export {};
@@ -1,17 +1,17 @@
1
1
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
2
2
  import { standardSchemaResolver } from "@hookform/resolvers/standard-schema";
3
3
  import { useEffect, useMemo, useRef, useState } from "react";
4
- import { FormProvider, useForm } from "react-hook-form";
4
+ import { FormProvider, useForm, useFormState } from "react-hook-form";
5
5
  import { z } from "zod/v4";
6
6
  import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from "../ui/accordion.js";
7
7
  import { Button } from "../ui/button.js";
8
- import { Tabs, TabsContent, TabsList, TabsTrigger } from "../ui/tabs.js";
8
+ import { ScrollableTabsList, Tabs, TabsContent, TabsTrigger } from "../ui/tabs.js";
9
9
  import { DataFetcher } from "./data-fetcher.js";
10
10
  import { FormFieldRenderer } from "./field-renderer.js";
11
11
  import { RulesEngine } from "./rules-engine.js";
12
12
  import { validationConfigToZod } from "./validation-converter.js";
13
13
  const DEFAULT_PLUGINS = [];
14
- function MetadataForm({ schema, plugins = DEFAULT_PLUGINS, onSubmit, className, disabled = false, autoComplete, stepVariant = 'wizard' }) {
14
+ function MetadataForm({ schema, plugins = DEFAULT_PLUGINS, onSubmit, className, disabled = false, autoComplete, stepVariant = 'wizard', sectionVariant = 'card', activeStepId, onActiveStepChange }) {
15
15
  const [currentStep, setCurrentStep] = useState(0);
16
16
  const [customComponents, setCustomComponents] = useState({});
17
17
  const [isInitialized, setIsInitialized] = useState(false);
@@ -103,6 +103,9 @@ function MetadataForm({ schema, plugins = DEFAULT_PLUGINS, onSubmit, className,
103
103
  context: context,
104
104
  customComponents: customComponents,
105
105
  disabled: disabled,
106
+ sectionVariant: sectionVariant,
107
+ activeStepId: activeStepId,
108
+ onActiveStepChange: onActiveStepChange,
106
109
  onReset: ()=>reset()
107
110
  });
108
111
  return /*#__PURE__*/ jsx(MultiStepForm, {
@@ -111,14 +114,16 @@ function MetadataForm({ schema, plugins = DEFAULT_PLUGINS, onSubmit, className,
111
114
  currentStep: currentStep,
112
115
  setCurrentStep: setCurrentStep,
113
116
  customComponents: customComponents,
114
- disabled: disabled
117
+ disabled: disabled,
118
+ sectionVariant: sectionVariant
115
119
  });
116
120
  }
117
121
  return /*#__PURE__*/ jsx(SinglePageForm, {
118
122
  schema: schema,
119
123
  context: context,
120
124
  customComponents: customComponents,
121
- disabled: disabled
125
+ disabled: disabled,
126
+ sectionVariant: sectionVariant
122
127
  });
123
128
  };
124
129
  return /*#__PURE__*/ jsx(FormProvider, {
@@ -138,20 +143,21 @@ function MetadataForm({ schema, plugins = DEFAULT_PLUGINS, onSubmit, className,
138
143
  })
139
144
  });
140
145
  }
141
- function SinglePageForm({ schema, context, customComponents, disabled }) {
146
+ function SinglePageForm({ schema, context, customComponents, disabled, sectionVariant }) {
142
147
  const sections = schema.sections || [];
143
148
  const visibleSections = sections.filter((section)=>!section.conditions || context.evaluateConditions(section.conditions));
144
149
  return /*#__PURE__*/ jsx("div", {
145
- className: "space-y-2",
150
+ className: 'plain' === sectionVariant ? void 0 : 'space-y-2',
146
151
  children: visibleSections.map((section)=>/*#__PURE__*/ jsx(FormSection, {
147
152
  section: section,
148
153
  context: context,
149
154
  customComponents: customComponents,
150
- disabled: disabled
155
+ disabled: disabled,
156
+ sectionVariant: sectionVariant
151
157
  }, section.id))
152
158
  });
153
159
  }
154
- function MultiStepForm({ schema, context, currentStep, setCurrentStep, customComponents, disabled }) {
160
+ function MultiStepForm({ schema, context, currentStep, setCurrentStep, customComponents, disabled, sectionVariant }) {
155
161
  const steps = schema.steps || [];
156
162
  const step = steps[currentStep];
157
163
  if (!step) return null;
@@ -189,12 +195,13 @@ function MultiStepForm({ schema, context, currentStep, setCurrentStep, customCom
189
195
  ]
190
196
  }),
191
197
  /*#__PURE__*/ jsx("div", {
192
- className: "space-y-2",
198
+ className: 'plain' === sectionVariant ? void 0 : 'space-y-2',
193
199
  children: step.sections.map((section)=>/*#__PURE__*/ jsx(FormSection, {
194
200
  section: section,
195
201
  context: context,
196
202
  customComponents: customComponents,
197
- disabled: disabled
203
+ disabled: disabled,
204
+ sectionVariant: sectionVariant
198
205
  }, section.id))
199
206
  }),
200
207
  /*#__PURE__*/ jsxs("div", {
@@ -222,15 +229,39 @@ function MultiStepForm({ schema, context, currentStep, setCurrentStep, customCom
222
229
  ]
223
230
  });
224
231
  }
225
- function TabbedStepForm({ schema, context, customComponents, disabled, onReset }) {
232
+ function TabbedStepForm({ schema, context, customComponents, disabled, sectionVariant, onReset, activeStepId, onActiveStepChange }) {
226
233
  const steps = schema.steps || [];
227
- const visibleSteps = steps.filter((step)=>step.sections.length > 0 && (!step.conditions || context.evaluateConditions(step.conditions)));
228
- const [activeTab, setActiveTab] = useState('');
229
- const currentTab = visibleSteps.some((step)=>step.id === activeTab) ? activeTab : visibleSteps[0]?.id ?? '';
234
+ const visibleSteps = steps.filter((step)=>{
235
+ if (step.conditions && !context.evaluateConditions(step.conditions)) return false;
236
+ const hasVisibleSection = step.sections.some((section)=>!section.conditions || context.evaluateConditions(section.conditions));
237
+ return hasVisibleSection || void 0 !== step.emptyState;
238
+ });
239
+ const formState = useFormState({
240
+ control: context.form.control
241
+ });
242
+ const errorCountByStepId = {};
243
+ for (const step of visibleSteps){
244
+ let count = 0;
245
+ for (const section of step.sections)if (!section.conditions || context.evaluateConditions(section.conditions)) for (const field of section.fields){
246
+ if (field.rules && !RulesEngine.isFieldVisible(field.rules, context.values)) continue;
247
+ const fieldError = context.form.getFieldState(field.name, formState).error;
248
+ if (fieldError) count += Array.isArray(fieldError) ? fieldError.filter(Boolean).length : 1;
249
+ }
250
+ errorCountByStepId[step.id] = count;
251
+ }
252
+ const [internalTab, setInternalTab] = useState('');
253
+ const controlled = void 0 !== activeStepId;
254
+ const requestedTab = controlled ? activeStepId : internalTab;
255
+ const currentTab = visibleSteps.some((step)=>step.id === requestedTab) ? requestedTab : visibleSteps[0]?.id ?? '';
256
+ const selectTab = (stepId)=>{
257
+ if (!controlled) setInternalTab(stepId);
258
+ onActiveStepChange?.(stepId);
259
+ };
230
260
  useEffect(()=>{
231
- if (activeTab !== currentTab) setActiveTab(currentTab);
261
+ if (!controlled && internalTab !== currentTab) setInternalTab(currentTab);
232
262
  }, [
233
- activeTab,
263
+ controlled,
264
+ internalTab,
234
265
  currentTab
235
266
  ]);
236
267
  if (0 === visibleSteps.length) return null;
@@ -238,27 +269,53 @@ function TabbedStepForm({ schema, context, customComponents, disabled, onReset }
238
269
  children: [
239
270
  /*#__PURE__*/ jsxs(Tabs, {
240
271
  value: currentTab,
241
- onValueChange: setActiveTab,
242
- className: "flex flex-col gap-4",
272
+ onValueChange: selectTab,
273
+ className: "flex min-h-0 flex-1 flex-col gap-1",
243
274
  children: [
244
- /*#__PURE__*/ jsx(TabsList, {
245
- className: "h-auto justify-start gap-0.5 overflow-x-auto rounded-lg bg-transparent p-0.5 text-muted-foreground [-ms-overflow-style:none] [scrollbar-width:none] [&::-webkit-scrollbar]:hidden",
246
- children: visibleSteps.map((step)=>/*#__PURE__*/ jsx(TabsTrigger, {
247
- value: step.id,
248
- className: "inline-flex h-6 shrink-0 items-center whitespace-nowrap rounded-md px-2.5 text-xs font-medium text-muted-foreground shadow-none transition-colors hover:text-foreground data-[state=active]:bg-surface-overlay data-[state=active]:text-foreground data-[state=active]:shadow-sm",
249
- children: step.title
250
- }, step.id))
275
+ /*#__PURE__*/ jsx("div", {
276
+ className: "shrink-0 pt-3 [padding-inline:var(--mf-content-inset,0px)]",
277
+ children: /*#__PURE__*/ jsx(ScrollableTabsList, {
278
+ className: "h-auto justify-start gap-0.5 rounded-lg bg-transparent px-0 py-0.5 text-muted-foreground",
279
+ scrollButtonClassName: "size-6 hover:bg-surface-overlay",
280
+ children: visibleSteps.map((step)=>{
281
+ const errorCount = errorCountByStepId[step.id] ?? 0;
282
+ return /*#__PURE__*/ jsxs(TabsTrigger, {
283
+ value: step.id,
284
+ className: "inline-flex h-6 shrink-0 items-center gap-1.5 whitespace-nowrap rounded-md px-2.5 text-xs font-medium text-muted-foreground shadow-none transition-colors hover:text-foreground data-[state=active]:bg-surface-overlay data-[state=active]:text-foreground data-[state=active]:shadow-sm",
285
+ children: [
286
+ step.title,
287
+ errorCount > 0 && /*#__PURE__*/ jsx("span", {
288
+ role: "img",
289
+ "aria-label": `${errorCount} ${1 === errorCount ? 'issue' : 'issues'}`,
290
+ title: `${errorCount} ${1 === errorCount ? 'issue' : 'issues'}`,
291
+ className: "grid h-4 min-w-4 place-items-center rounded-full bg-error px-1 text-[10px] font-semibold leading-none text-foreground-on-accent",
292
+ children: errorCount
293
+ })
294
+ ]
295
+ }, step.id);
296
+ })
297
+ })
251
298
  }),
252
- visibleSteps.map((step)=>/*#__PURE__*/ jsx(TabsContent, {
299
+ visibleSteps.map((step)=>{
300
+ const stepSections = step.sections.filter((section)=>!section.conditions || context.evaluateConditions(section.conditions));
301
+ return /*#__PURE__*/ jsx(TabsContent, {
253
302
  value: step.id,
254
- className: "space-y-2",
255
- children: step.sections.filter((section)=>!section.conditions || context.evaluateConditions(section.conditions)).map((section)=>/*#__PURE__*/ jsx(FormSection, {
256
- section: section,
257
- context: context,
258
- customComponents: customComponents,
259
- disabled: disabled
260
- }, section.id))
261
- }, step.id))
303
+ className: "mt-0 min-h-0 flex-1 overflow-auto",
304
+ children: 0 === stepSections.length && void 0 !== step.emptyState ? /*#__PURE__*/ jsx("div", {
305
+ className: "pt-4 text-sm text-muted-foreground [padding-inline:var(--mf-content-inset,0px)]",
306
+ children: step.emptyState
307
+ }) : /*#__PURE__*/ jsx("div", {
308
+ className: 'plain' === sectionVariant ? 'pb-6 [padding-inline:var(--mf-content-inset,0px)]' : 'space-y-2 pb-6 pt-4 [padding-inline:var(--mf-content-inset,0px)]',
309
+ children: stepSections.map((section)=>/*#__PURE__*/ jsx(FormSection, {
310
+ section: section,
311
+ context: context,
312
+ customComponents: customComponents,
313
+ disabled: disabled,
314
+ sectionVariant: sectionVariant
315
+ }, section.id))
316
+ })
317
+ }, step.id);
318
+ })
262
319
  ]
263
320
  }),
264
321
  /*#__PURE__*/ jsx(FormActions, {
@@ -269,9 +326,13 @@ function TabbedStepForm({ schema, context, customComponents, disabled, onReset }
269
326
  ]
270
327
  });
271
328
  }
272
- function FormSection({ section, context, customComponents, disabled }) {
329
+ function FormSection({ section, context, customComponents, disabled, sectionVariant = 'card' }) {
273
330
  const gridColumns = context.schema.layout?.columns || 1;
274
331
  const gap = context.schema.layout?.gap || 4;
332
+ const isPlain = 'plain' === sectionVariant;
333
+ const dividerClassName = 'border-t first:border-t-0';
334
+ const wrapperClassName = isPlain ? 'border-b-0' : 'border rounded-lg px-3';
335
+ const triggerClassName = isPlain ? 'justify-start gap-2 py-4 text-sm font-semibold hover:no-underline' : 'text-sm font-medium';
275
336
  const fieldsGrid = /*#__PURE__*/ jsx("div", {
276
337
  className: "grid",
277
338
  style: {
@@ -285,7 +346,10 @@ function FormSection({ section, context, customComponents, disabled }) {
285
346
  disabled: disabled
286
347
  }, field.name))
287
348
  });
288
- if (!section.title) return fieldsGrid;
349
+ if (!section.title) return isPlain ? /*#__PURE__*/ jsx("div", {
350
+ className: `${dividerClassName} pb-4 pt-4`,
351
+ children: fieldsGrid
352
+ }) : fieldsGrid;
289
353
  const innerContent = /*#__PURE__*/ jsxs("div", {
290
354
  className: "flex flex-col gap-4",
291
355
  children: [
@@ -303,12 +367,13 @@ function FormSection({ section, context, customComponents, disabled }) {
303
367
  return /*#__PURE__*/ jsx(Accordion, {
304
368
  type: "multiple",
305
369
  defaultValue: defaultValue,
370
+ className: isPlain ? dividerClassName : void 0,
306
371
  children: /*#__PURE__*/ jsxs(AccordionItem, {
307
372
  value: section.id,
308
- className: "border rounded-lg px-3",
373
+ className: wrapperClassName,
309
374
  children: [
310
375
  /*#__PURE__*/ jsx(AccordionTrigger, {
311
- className: "text-sm font-medium",
376
+ className: triggerClassName,
312
377
  children: section.title
313
378
  }),
314
379
  /*#__PURE__*/ jsx(AccordionContent, {
@@ -319,12 +384,12 @@ function FormSection({ section, context, customComponents, disabled }) {
319
384
  });
320
385
  }
321
386
  return /*#__PURE__*/ jsxs("div", {
322
- className: "border rounded-lg px-3",
387
+ className: isPlain ? dividerClassName : wrapperClassName,
323
388
  children: [
324
389
  /*#__PURE__*/ jsx("div", {
325
390
  className: "flex",
326
391
  children: /*#__PURE__*/ jsx("div", {
327
- className: "flex flex-1 items-center justify-between py-4 text-sm font-medium",
392
+ className: isPlain ? 'flex flex-1 items-center justify-start gap-2 py-4 text-sm font-semibold' : 'flex flex-1 items-center justify-between py-4 text-sm font-medium',
328
393
  children: section.title
329
394
  })
330
395
  }),
@@ -45,6 +45,7 @@ const jsx_runtime_namespaceObject = require("react/jsx-runtime");
45
45
  const react_dropdown_menu_namespaceObject = require("@radix-ui/react-dropdown-menu");
46
46
  const external_lucide_react_namespaceObject = require("lucide-react");
47
47
  const external_react_namespaceObject = require("react");
48
+ const external_portal_container_cjs_namespaceObject = require("./portal-container.cjs");
48
49
  const index_cjs_namespaceObject = require("../../lib/index.cjs");
49
50
  const DropdownMenu = react_dropdown_menu_namespaceObject.Root;
50
51
  const DropdownMenuTrigger = react_dropdown_menu_namespaceObject.Trigger;
@@ -70,14 +71,18 @@ const DropdownMenuSubContent = /*#__PURE__*/ external_react_namespaceObject.forw
70
71
  ...props
71
72
  }));
72
73
  DropdownMenuSubContent.displayName = react_dropdown_menu_namespaceObject.SubContent.displayName;
73
- const DropdownMenuContent = /*#__PURE__*/ external_react_namespaceObject.forwardRef(({ className, sideOffset = 4, ...props }, ref)=>/*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(react_dropdown_menu_namespaceObject.Portal, {
74
+ const DropdownMenuContent = /*#__PURE__*/ external_react_namespaceObject.forwardRef(({ className, sideOffset = 4, container, ...props }, ref)=>{
75
+ const resolvedContainer = (0, external_portal_container_cjs_namespaceObject.useResolvedPortalContainer)(container);
76
+ return /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(react_dropdown_menu_namespaceObject.Portal, {
77
+ container: resolvedContainer,
74
78
  children: /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(react_dropdown_menu_namespaceObject.Content, {
75
79
  ref: ref,
76
80
  sideOffset: sideOffset,
77
81
  className: (0, index_cjs_namespaceObject.cn)('z-50 max-h-[var(--radix-dropdown-menu-content-available-height)] min-w-[8rem] overflow-y-auto overflow-x-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md future:rounded-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-dropdown-menu-content-transform-origin]', className),
78
82
  ...props
79
83
  })
80
- }));
84
+ });
85
+ });
81
86
  DropdownMenuContent.displayName = react_dropdown_menu_namespaceObject.Content.displayName;
82
87
  const DropdownMenuItem = /*#__PURE__*/ external_react_namespaceObject.forwardRef(({ className, inset, ...props }, ref)=>/*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(react_dropdown_menu_namespaceObject.Item, {
83
88
  ref: ref,
@@ -1,5 +1,6 @@
1
1
  import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu';
2
2
  import * as React from 'react';
3
+ import { type PortalContainerOverride } from './portal-container';
3
4
  declare const DropdownMenu: React.FC<DropdownMenuPrimitive.DropdownMenuProps>;
4
5
  declare const DropdownMenuTrigger: React.ForwardRefExoticComponent<DropdownMenuPrimitive.DropdownMenuTriggerProps & React.RefAttributes<HTMLButtonElement>>;
5
6
  declare const DropdownMenuGroup: React.ForwardRefExoticComponent<DropdownMenuPrimitive.DropdownMenuGroupProps & React.RefAttributes<HTMLDivElement>>;
@@ -10,7 +11,9 @@ declare const DropdownMenuSubTrigger: React.ForwardRefExoticComponent<Omit<Dropd
10
11
  inset?: boolean;
11
12
  } & React.RefAttributes<HTMLDivElement>>;
12
13
  declare const DropdownMenuSubContent: React.ForwardRefExoticComponent<Omit<DropdownMenuPrimitive.DropdownMenuSubContentProps & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
13
- declare const DropdownMenuContent: React.ForwardRefExoticComponent<Omit<DropdownMenuPrimitive.DropdownMenuContentProps & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
14
+ declare const DropdownMenuContent: React.ForwardRefExoticComponent<Omit<DropdownMenuPrimitive.DropdownMenuContentProps & React.RefAttributes<HTMLDivElement>, "ref"> & {
15
+ container?: PortalContainerOverride;
16
+ } & React.RefAttributes<HTMLDivElement>>;
14
17
  declare const DropdownMenuItem: React.ForwardRefExoticComponent<Omit<DropdownMenuPrimitive.DropdownMenuItemProps & React.RefAttributes<HTMLDivElement>, "ref"> & {
15
18
  inset?: boolean;
16
19
  } & React.RefAttributes<HTMLDivElement>>;