@uipath/apollo-wind 2.50.0 → 2.51.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.
- package/dist/components/forms/field-renderer.cjs +80 -6
- package/dist/components/forms/field-renderer.js +80 -6
- package/dist/components/forms/form-designer.cjs +10 -10
- package/dist/components/forms/form-designer.js +10 -10
- package/dist/components/forms/form-schema.d.ts +38 -2
- package/dist/components/forms/index.cjs +15 -5
- package/dist/components/forms/index.d.ts +7 -6
- package/dist/components/forms/index.js +6 -5
- package/dist/components/forms/metadata-form.cjs +97 -37
- package/dist/components/forms/metadata-form.d.ts +11 -3
- package/dist/components/forms/metadata-form.js +94 -37
- package/dist/components/forms/rules-engine.cjs +14 -3
- package/dist/components/forms/rules-engine.d.ts +16 -0
- package/dist/components/forms/rules-engine.js +14 -3
- package/dist/components/forms/schema-serializer.cjs +10 -0
- package/dist/components/forms/schema-serializer.js +10 -0
- package/dist/components/forms/string-list-field.cjs +154 -0
- package/dist/components/forms/string-list-field.d.ts +29 -0
- package/dist/components/forms/string-list-field.js +117 -0
- package/dist/components/forms/validation-converter.cjs +68 -23
- package/dist/components/forms/validation-converter.d.ts +23 -2
- package/dist/components/forms/validation-converter.js +64 -22
- package/dist/components/ui/datetime-picker.cjs +3 -1
- package/dist/components/ui/datetime-picker.d.ts +4 -0
- package/dist/components/ui/datetime-picker.js +3 -1
- package/dist/components/ui/form-field.cjs +17 -2
- package/dist/components/ui/form-field.d.ts +7 -0
- package/dist/components/ui/form-field.js +17 -2
- package/dist/components/ui/index.cjs +127 -117
- package/dist/components/ui/index.d.ts +3 -2
- package/dist/components/ui/index.js +2 -1
- package/dist/components/ui/info-tooltip.cjs +61 -0
- package/dist/components/ui/info-tooltip.d.ts +10 -0
- package/dist/components/ui/info-tooltip.js +27 -0
- package/dist/components/ui/select.cjs +1 -1
- package/dist/components/ui/select.js +1 -1
- package/dist/components/ui/textarea.cjs +1 -1
- package/dist/components/ui/textarea.js +1 -1
- package/dist/index.cjs +14 -0
- package/dist/index.d.ts +7 -2
- package/dist/index.js +4 -2
- package/dist/styles.css +13 -0
- package/package.json +1 -1
|
@@ -6,13 +6,14 @@ 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
8
|
import { ScrollableTabsList, Tabs, TabsContent, TabsTrigger } from "../ui/tabs.js";
|
|
9
|
+
import { TooltipProvider } from "../ui/tooltip.js";
|
|
9
10
|
import { deepEqual, get } from "../../lib/index.js";
|
|
10
11
|
import { DataFetcher } from "./data-fetcher.js";
|
|
11
12
|
import { FormFieldRenderer } from "./field-renderer.js";
|
|
12
13
|
import { RulesEngine } from "./rules-engine.js";
|
|
13
|
-
import { validationConfigToZod } from "./validation-converter.js";
|
|
14
|
+
import { isEmptyFieldValue, validationConfigToZod } from "./validation-converter.js";
|
|
14
15
|
const DEFAULT_PLUGINS = [];
|
|
15
|
-
function MetadataForm({ schema, plugins = DEFAULT_PLUGINS, onSubmit, className, disabled = false, autoComplete, stepVariant = 'wizard', sectionVariant = 'card', activeStepId, onActiveStepChange }) {
|
|
16
|
+
function MetadataForm({ schema, plugins = DEFAULT_PLUGINS, onSubmit, className, disabled = false, autoComplete, stepVariant = 'wizard', sectionVariant = 'card', activeStepId, onActiveStepChange, container = 'form' }) {
|
|
16
17
|
const [currentStep, setCurrentStep] = useState(0);
|
|
17
18
|
const [customComponents, setCustomComponents] = useState({});
|
|
18
19
|
const [isInitialized, setIsInitialized] = useState(false);
|
|
@@ -24,6 +25,15 @@ function MetadataForm({ schema, plugins = DEFAULT_PLUGINS, onSubmit, className,
|
|
|
24
25
|
}, [
|
|
25
26
|
schema
|
|
26
27
|
]);
|
|
28
|
+
const hasFieldTooltip = useMemo(()=>{
|
|
29
|
+
const sections = [
|
|
30
|
+
...stableSchema.sections ?? [],
|
|
31
|
+
...(stableSchema.steps ?? []).flatMap((step)=>step.sections)
|
|
32
|
+
];
|
|
33
|
+
return sections.some((section)=>section.fields.some((field)=>void 0 !== field.tooltip));
|
|
34
|
+
}, [
|
|
35
|
+
stableSchema
|
|
36
|
+
]);
|
|
27
37
|
const zodSchema = useMemo(()=>buildZodSchema(stableSchema), [
|
|
28
38
|
stableSchema
|
|
29
39
|
]);
|
|
@@ -73,12 +83,12 @@ function MetadataForm({ schema, plugins = DEFAULT_PLUGINS, onSubmit, className,
|
|
|
73
83
|
]);
|
|
74
84
|
const contextRef = useRef(context);
|
|
75
85
|
contextRef.current = context;
|
|
76
|
-
const
|
|
77
|
-
isInitializedRef.current = isInitialized;
|
|
86
|
+
const initializingRef = useRef(false);
|
|
78
87
|
useEffect(()=>{
|
|
79
88
|
const subscription = watch((value, { name })=>{
|
|
80
89
|
valuesRef.current = value;
|
|
81
|
-
if (!name
|
|
90
|
+
if (!name) return;
|
|
91
|
+
if (initializingRef.current) return;
|
|
82
92
|
pluginsRef.current.forEach((plugin)=>{
|
|
83
93
|
plugin.onValueChange?.(name, get(value, name), contextRef.current);
|
|
84
94
|
});
|
|
@@ -92,9 +102,17 @@ function MetadataForm({ schema, plugins = DEFAULT_PLUGINS, onSubmit, className,
|
|
|
92
102
|
const initializeForm = async ()=>{
|
|
93
103
|
if (stableSchema.initialData) {
|
|
94
104
|
const data = await loadInitialData(stableSchema.initialData, contextRef.current);
|
|
95
|
-
|
|
105
|
+
initializingRef.current = true;
|
|
106
|
+
try {
|
|
107
|
+
reset(data);
|
|
108
|
+
} finally{
|
|
109
|
+
initializingRef.current = false;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
for (const plugin of plugins){
|
|
113
|
+
const result = plugin.onFormInit?.(contextRef.current);
|
|
114
|
+
if (result instanceof Promise) await result;
|
|
96
115
|
}
|
|
97
|
-
for (const plugin of plugins)await plugin.onFormInit?.(contextRef.current);
|
|
98
116
|
setIsInitialized(true);
|
|
99
117
|
};
|
|
100
118
|
initializeForm();
|
|
@@ -111,51 +129,89 @@ function MetadataForm({ schema, plugins = DEFAULT_PLUGINS, onSubmit, className,
|
|
|
111
129
|
const handleReset = useCallback(()=>reset(), [
|
|
112
130
|
reset
|
|
113
131
|
]);
|
|
132
|
+
const allCustomComponents = useMemo(()=>{
|
|
133
|
+
const fromPlugins = {};
|
|
134
|
+
for (const plugin of plugins)Object.assign(fromPlugins, plugin.components);
|
|
135
|
+
return {
|
|
136
|
+
...fromPlugins,
|
|
137
|
+
...customComponents
|
|
138
|
+
};
|
|
139
|
+
}, [
|
|
140
|
+
plugins,
|
|
141
|
+
customComponents
|
|
142
|
+
]);
|
|
143
|
+
const enterSwallowRef = useRef(null);
|
|
144
|
+
useEffect(()=>{
|
|
145
|
+
const node = enterSwallowRef.current;
|
|
146
|
+
if (!node) return;
|
|
147
|
+
const swallowEnter = (event)=>{
|
|
148
|
+
if ('Enter' !== event.key || event.defaultPrevented) return;
|
|
149
|
+
const target = event.target;
|
|
150
|
+
if (target instanceof HTMLInputElement && 'button' !== target.type) event.preventDefault();
|
|
151
|
+
};
|
|
152
|
+
node.addEventListener('keydown', swallowEnter);
|
|
153
|
+
return ()=>node.removeEventListener('keydown', swallowEnter);
|
|
154
|
+
}, [
|
|
155
|
+
container
|
|
156
|
+
]);
|
|
114
157
|
const renderContent = ()=>{
|
|
115
158
|
if (stableSchema.steps) {
|
|
116
159
|
if ('tabs' === stepVariant) return /*#__PURE__*/ jsx(TabbedStepForm, {
|
|
117
160
|
schema: stableSchema,
|
|
118
161
|
context: context,
|
|
119
|
-
customComponents:
|
|
162
|
+
customComponents: allCustomComponents,
|
|
120
163
|
disabled: disabled,
|
|
121
164
|
sectionVariant: sectionVariant,
|
|
122
165
|
activeStepId: activeStepId,
|
|
123
166
|
onActiveStepChange: onActiveStepChange,
|
|
124
|
-
onReset: handleReset
|
|
167
|
+
onReset: handleReset,
|
|
168
|
+
onSubmit: 'div' === container ? handleFormSubmit : void 0
|
|
125
169
|
});
|
|
126
170
|
return /*#__PURE__*/ jsx(metadata_form_MultiStepForm, {
|
|
127
171
|
schema: stableSchema,
|
|
128
172
|
context: context,
|
|
129
173
|
currentStep: currentStep,
|
|
130
174
|
setCurrentStep: setCurrentStep,
|
|
131
|
-
customComponents:
|
|
175
|
+
customComponents: allCustomComponents,
|
|
132
176
|
disabled: disabled,
|
|
133
|
-
sectionVariant: sectionVariant
|
|
177
|
+
sectionVariant: sectionVariant,
|
|
178
|
+
onSubmit: 'div' === container ? handleFormSubmit : void 0
|
|
134
179
|
});
|
|
135
180
|
}
|
|
136
181
|
return /*#__PURE__*/ jsx(metadata_form_SinglePageForm, {
|
|
137
182
|
schema: stableSchema,
|
|
138
183
|
context: context,
|
|
139
|
-
customComponents:
|
|
184
|
+
customComponents: allCustomComponents,
|
|
140
185
|
disabled: disabled,
|
|
141
186
|
sectionVariant: sectionVariant
|
|
142
187
|
});
|
|
143
188
|
};
|
|
189
|
+
const content = /*#__PURE__*/ jsxs(Fragment, {
|
|
190
|
+
children: [
|
|
191
|
+
renderContent(),
|
|
192
|
+
!stableSchema.steps && /*#__PURE__*/ jsx(metadata_form_FormActions, {
|
|
193
|
+
schema: stableSchema,
|
|
194
|
+
context: context,
|
|
195
|
+
onReset: handleReset,
|
|
196
|
+
onSubmit: 'div' === container ? handleFormSubmit : void 0
|
|
197
|
+
})
|
|
198
|
+
]
|
|
199
|
+
});
|
|
200
|
+
const body = 'div' === container ? /*#__PURE__*/ jsx("div", {
|
|
201
|
+
className: className,
|
|
202
|
+
ref: enterSwallowRef,
|
|
203
|
+
children: content
|
|
204
|
+
}) : /*#__PURE__*/ jsx("form", {
|
|
205
|
+
onSubmit: handleFormSubmit,
|
|
206
|
+
className: className,
|
|
207
|
+
autoComplete: autoComplete,
|
|
208
|
+
children: content
|
|
209
|
+
});
|
|
144
210
|
return /*#__PURE__*/ jsx(FormProvider, {
|
|
145
211
|
...form,
|
|
146
|
-
children: /*#__PURE__*/
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
autoComplete: autoComplete,
|
|
150
|
-
children: [
|
|
151
|
-
renderContent(),
|
|
152
|
-
!stableSchema.steps && /*#__PURE__*/ jsx(metadata_form_FormActions, {
|
|
153
|
-
schema: stableSchema,
|
|
154
|
-
context: context,
|
|
155
|
-
onReset: handleReset
|
|
156
|
-
})
|
|
157
|
-
]
|
|
158
|
-
})
|
|
212
|
+
children: hasFieldTooltip ? /*#__PURE__*/ jsx(TooltipProvider, {
|
|
213
|
+
children: body
|
|
214
|
+
}) : body
|
|
159
215
|
});
|
|
160
216
|
}
|
|
161
217
|
function conditionDependencies(conditionGroups) {
|
|
@@ -187,7 +243,7 @@ const metadata_form_SinglePageForm = /*#__PURE__*/ react.memo(function({ schema,
|
|
|
187
243
|
}, section.id))
|
|
188
244
|
});
|
|
189
245
|
});
|
|
190
|
-
const metadata_form_MultiStepForm = /*#__PURE__*/ react.memo(function({ schema, context, currentStep, setCurrentStep, customComponents, disabled, sectionVariant }) {
|
|
246
|
+
const metadata_form_MultiStepForm = /*#__PURE__*/ react.memo(function({ schema, context, currentStep, setCurrentStep, customComponents, disabled, sectionVariant, onSubmit }) {
|
|
191
247
|
const steps = schema.steps || [];
|
|
192
248
|
const conditionFields = useMemo(()=>conditionDependencies(schema.steps?.map((step)=>step.conditions) ?? []), [
|
|
193
249
|
schema
|
|
@@ -265,7 +321,8 @@ const metadata_form_MultiStepForm = /*#__PURE__*/ react.memo(function({ schema,
|
|
|
265
321
|
variant: "default",
|
|
266
322
|
children: "Next"
|
|
267
323
|
}) : /*#__PURE__*/ jsx(Button, {
|
|
268
|
-
type:
|
|
324
|
+
type: onSubmit ? 'button' : 'submit',
|
|
325
|
+
onClick: onSubmit,
|
|
269
326
|
variant: "default",
|
|
270
327
|
children: "Submit"
|
|
271
328
|
})
|
|
@@ -274,7 +331,7 @@ const metadata_form_MultiStepForm = /*#__PURE__*/ react.memo(function({ schema,
|
|
|
274
331
|
]
|
|
275
332
|
});
|
|
276
333
|
});
|
|
277
|
-
function TabbedStepForm({ schema, context, customComponents, disabled, sectionVariant, onReset, activeStepId, onActiveStepChange }) {
|
|
334
|
+
function TabbedStepForm({ schema, context, customComponents, disabled, sectionVariant, onReset, activeStepId, onActiveStepChange, onSubmit }) {
|
|
278
335
|
const steps = schema.steps || [];
|
|
279
336
|
const conditionFields = useMemo(()=>conditionDependencies(schema.steps?.flatMap((step)=>[
|
|
280
337
|
step.conditions,
|
|
@@ -340,7 +397,7 @@ function TabbedStepForm({ schema, context, customComponents, disabled, sectionVa
|
|
|
340
397
|
role: "img",
|
|
341
398
|
"aria-label": `${errorCount} ${1 === errorCount ? 'issue' : 'issues'}`,
|
|
342
399
|
title: `${errorCount} ${1 === errorCount ? 'issue' : 'issues'}`,
|
|
343
|
-
className: "grid h-4 min-w-4 place-items-center rounded-full bg-error px-1 text-[10px] font-semibold leading-none text-
|
|
400
|
+
className: "grid h-4 min-w-4 place-items-center rounded-full bg-error px-1 text-[10px] font-semibold leading-none text-error-background",
|
|
344
401
|
children: errorCount
|
|
345
402
|
})
|
|
346
403
|
]
|
|
@@ -373,7 +430,8 @@ function TabbedStepForm({ schema, context, customComponents, disabled, sectionVa
|
|
|
373
430
|
/*#__PURE__*/ jsx(metadata_form_FormActions, {
|
|
374
431
|
schema: schema,
|
|
375
432
|
context: context,
|
|
376
|
-
onReset: onReset
|
|
433
|
+
onReset: onReset,
|
|
434
|
+
onSubmit: onSubmit
|
|
377
435
|
})
|
|
378
436
|
]
|
|
379
437
|
});
|
|
@@ -455,7 +513,7 @@ const metadata_form_FormSection = /*#__PURE__*/ react.memo(function({ section, c
|
|
|
455
513
|
]
|
|
456
514
|
});
|
|
457
515
|
});
|
|
458
|
-
const metadata_form_FormActions = /*#__PURE__*/ react.memo(function({ schema, context, onReset }) {
|
|
516
|
+
const metadata_form_FormActions = /*#__PURE__*/ react.memo(function({ schema, context, onReset, onSubmit }) {
|
|
459
517
|
const { isSubmitting } = useFormState({
|
|
460
518
|
control: context.form.control
|
|
461
519
|
});
|
|
@@ -484,7 +542,8 @@ const metadata_form_FormActions = /*#__PURE__*/ react.memo(function({ schema, co
|
|
|
484
542
|
children: action.label
|
|
485
543
|
}, action.id);
|
|
486
544
|
return /*#__PURE__*/ jsx(Button, {
|
|
487
|
-
type: 'submit'
|
|
545
|
+
type: 'submit' !== action.type || onSubmit ? 'button' : 'submit',
|
|
546
|
+
onClick: 'submit' === action.type && onSubmit ? onSubmit : void 0,
|
|
488
547
|
variant: action.variant || 'default',
|
|
489
548
|
disabled: action.disabled || 'submit' === action.type && isSubmitting,
|
|
490
549
|
children: action.loading && isSubmitting ? 'Loading...' : action.label
|
|
@@ -515,7 +574,7 @@ function buildZodSchema(schema) {
|
|
|
515
574
|
} : shouldIncludeRequiredInBase ? {
|
|
516
575
|
required: true
|
|
517
576
|
} : void 0;
|
|
518
|
-
shape[field.name] = validationConfigToZod(validationConfig, field.type);
|
|
577
|
+
shape[field.name] = validationConfigToZod(validationConfig, field.type, 'custom' === field.type ? field.valueType : void 0);
|
|
519
578
|
});
|
|
520
579
|
const baseSchema = z.object(shape);
|
|
521
580
|
if (0 === dynamicValidationFields.length) return baseSchema;
|
|
@@ -527,9 +586,7 @@ function buildZodSchema(schema) {
|
|
|
527
586
|
const ruleResult = RulesEngine.applyRules(rules, values, {});
|
|
528
587
|
const isRequired = true === ruleResult.required || staticRequired;
|
|
529
588
|
if (isRequired) {
|
|
530
|
-
|
|
531
|
-
const isEmpty = null == value || '' === value || Array.isArray(value) && 0 === value.length;
|
|
532
|
-
if (isEmpty) ctx.addIssue({
|
|
589
|
+
if (isEmptyFieldValue(values[name])) ctx.addIssue({
|
|
533
590
|
code: z.ZodIssueCode.custom,
|
|
534
591
|
message: customRequiredMessage || 'This field is required',
|
|
535
592
|
path: [
|
|
@@ -544,4 +601,4 @@ async function loadInitialData(initialData, _context) {
|
|
|
544
601
|
if (!initialData) return {};
|
|
545
602
|
return initialData;
|
|
546
603
|
}
|
|
547
|
-
export { MetadataForm };
|
|
604
|
+
export { MetadataForm, useWatch };
|
|
@@ -76,12 +76,23 @@ class RulesEngine {
|
|
|
76
76
|
return state;
|
|
77
77
|
}
|
|
78
78
|
static evaluateExpression(expression, values) {
|
|
79
|
+
const result = RulesEngine.tryEvaluateExpression(expression, values);
|
|
80
|
+
if (result.ok) return result.value;
|
|
81
|
+
console.error('Expression evaluation error:', result.error);
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
static tryEvaluateExpression(expression, values) {
|
|
79
85
|
try {
|
|
80
86
|
const ast = external_jsep_default()(expression);
|
|
81
|
-
return
|
|
87
|
+
return {
|
|
88
|
+
ok: true,
|
|
89
|
+
value: RulesEngine.evaluateNode(ast, values)
|
|
90
|
+
};
|
|
82
91
|
} catch (error) {
|
|
83
|
-
|
|
84
|
-
|
|
92
|
+
return {
|
|
93
|
+
ok: false,
|
|
94
|
+
error
|
|
95
|
+
};
|
|
85
96
|
}
|
|
86
97
|
}
|
|
87
98
|
static evaluateNode(node, values) {
|
|
@@ -33,6 +33,22 @@ export declare class RulesEngine {
|
|
|
33
33
|
* - "total >= 100 ? 'discount' : 'regular'"
|
|
34
34
|
*/
|
|
35
35
|
static evaluateExpression(expression: string, values: Record<string, unknown>): unknown;
|
|
36
|
+
/**
|
|
37
|
+
* Like `evaluateExpression`, but reports *why* there is no value.
|
|
38
|
+
*
|
|
39
|
+
* `evaluateExpression` returns `false` both for an expression that legitimately evaluates
|
|
40
|
+
* to false and for one the evaluator cannot handle at all — `value.some(x)` parses fine and
|
|
41
|
+
* then throws on the unsupported `CallExpression`. Callers that treat falsey as "failed the
|
|
42
|
+
* check" would turn an unsupported expression into a permanently failing one, so they need
|
|
43
|
+
* to tell the two apart.
|
|
44
|
+
*/
|
|
45
|
+
static tryEvaluateExpression(expression: string, values: Record<string, unknown>): {
|
|
46
|
+
ok: true;
|
|
47
|
+
value: unknown;
|
|
48
|
+
} | {
|
|
49
|
+
ok: false;
|
|
50
|
+
error: unknown;
|
|
51
|
+
};
|
|
36
52
|
/**
|
|
37
53
|
* Minimal AST evaluator - only supports operators needed for form rules
|
|
38
54
|
*/
|
|
@@ -36,12 +36,23 @@ class RulesEngine {
|
|
|
36
36
|
return state;
|
|
37
37
|
}
|
|
38
38
|
static evaluateExpression(expression, values) {
|
|
39
|
+
const result = RulesEngine.tryEvaluateExpression(expression, values);
|
|
40
|
+
if (result.ok) return result.value;
|
|
41
|
+
console.error('Expression evaluation error:', result.error);
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
static tryEvaluateExpression(expression, values) {
|
|
39
45
|
try {
|
|
40
46
|
const ast = jsep(expression);
|
|
41
|
-
return
|
|
47
|
+
return {
|
|
48
|
+
ok: true,
|
|
49
|
+
value: RulesEngine.evaluateNode(ast, values)
|
|
50
|
+
};
|
|
42
51
|
} catch (error) {
|
|
43
|
-
|
|
44
|
-
|
|
52
|
+
return {
|
|
53
|
+
ok: false,
|
|
54
|
+
error
|
|
55
|
+
};
|
|
45
56
|
}
|
|
46
57
|
}
|
|
47
58
|
static evaluateNode(node, values) {
|
|
@@ -180,6 +180,8 @@ function serializeField(field) {
|
|
|
180
180
|
if (field.grid) result.grid = field.grid;
|
|
181
181
|
if (field.ariaLabel) result.ariaLabel = field.ariaLabel;
|
|
182
182
|
if (field.ariaDescribedBy) result.ariaDescribedBy = field.ariaDescribedBy;
|
|
183
|
+
if (field.tooltip) result.tooltip = field.tooltip;
|
|
184
|
+
if (field.tooltipAriaLabel) result.tooltipAriaLabel = field.tooltipAriaLabel;
|
|
183
185
|
if ('options' in field && field.options) result.options = serializeOptions(field.options);
|
|
184
186
|
if ('rows' in field && field.rows) result.rows = field.rows;
|
|
185
187
|
if ('min' in field && void 0 !== field.min) result.min = field.min;
|
|
@@ -191,7 +193,15 @@ function serializeField(field) {
|
|
|
191
193
|
if ('maxSize' in field && field.maxSize) result.maxSize = field.maxSize;
|
|
192
194
|
if ('showPreview' in field && field.showPreview) result.showPreview = field.showPreview;
|
|
193
195
|
if ('use12Hour' in field && field.use12Hour) result.use12Hour = field.use12Hour;
|
|
196
|
+
if ('minRows' in field && void 0 !== field.minRows) result.minRows = field.minRows;
|
|
197
|
+
if ('maxLength' in field && void 0 !== field.maxLength) result.maxLength = field.maxLength;
|
|
198
|
+
if ('maxItems' in field && void 0 !== field.maxItems) result.maxItems = field.maxItems;
|
|
199
|
+
if ('emptyMessage' in field && field.emptyMessage) result.emptyMessage = field.emptyMessage;
|
|
200
|
+
if ('searchPlaceholder' in field && field.searchPlaceholder) result.searchPlaceholder = field.searchPlaceholder;
|
|
201
|
+
if ('addItemLabel' in field && field.addItemLabel) result.addItemLabel = field.addItemLabel;
|
|
202
|
+
if ('removeItemAriaLabel' in field && field.removeItemAriaLabel) result.removeItemAriaLabel = field.removeItemAriaLabel;
|
|
194
203
|
if ('component' in field && field.component) result.component = field.component;
|
|
204
|
+
if ('valueType' in field && field.valueType) result.valueType = field.valueType;
|
|
195
205
|
if ('componentProps' in field && field.componentProps) result.componentProps = field.componentProps;
|
|
196
206
|
return result;
|
|
197
207
|
}
|
|
@@ -151,6 +151,8 @@ function serializeField(field) {
|
|
|
151
151
|
if (field.grid) result.grid = field.grid;
|
|
152
152
|
if (field.ariaLabel) result.ariaLabel = field.ariaLabel;
|
|
153
153
|
if (field.ariaDescribedBy) result.ariaDescribedBy = field.ariaDescribedBy;
|
|
154
|
+
if (field.tooltip) result.tooltip = field.tooltip;
|
|
155
|
+
if (field.tooltipAriaLabel) result.tooltipAriaLabel = field.tooltipAriaLabel;
|
|
154
156
|
if ('options' in field && field.options) result.options = serializeOptions(field.options);
|
|
155
157
|
if ('rows' in field && field.rows) result.rows = field.rows;
|
|
156
158
|
if ('min' in field && void 0 !== field.min) result.min = field.min;
|
|
@@ -162,7 +164,15 @@ function serializeField(field) {
|
|
|
162
164
|
if ('maxSize' in field && field.maxSize) result.maxSize = field.maxSize;
|
|
163
165
|
if ('showPreview' in field && field.showPreview) result.showPreview = field.showPreview;
|
|
164
166
|
if ('use12Hour' in field && field.use12Hour) result.use12Hour = field.use12Hour;
|
|
167
|
+
if ('minRows' in field && void 0 !== field.minRows) result.minRows = field.minRows;
|
|
168
|
+
if ('maxLength' in field && void 0 !== field.maxLength) result.maxLength = field.maxLength;
|
|
169
|
+
if ('maxItems' in field && void 0 !== field.maxItems) result.maxItems = field.maxItems;
|
|
170
|
+
if ('emptyMessage' in field && field.emptyMessage) result.emptyMessage = field.emptyMessage;
|
|
171
|
+
if ('searchPlaceholder' in field && field.searchPlaceholder) result.searchPlaceholder = field.searchPlaceholder;
|
|
172
|
+
if ('addItemLabel' in field && field.addItemLabel) result.addItemLabel = field.addItemLabel;
|
|
173
|
+
if ('removeItemAriaLabel' in field && field.removeItemAriaLabel) result.removeItemAriaLabel = field.removeItemAriaLabel;
|
|
165
174
|
if ('component' in field && field.component) result.component = field.component;
|
|
175
|
+
if ('valueType' in field && field.valueType) result.valueType = field.valueType;
|
|
166
176
|
if ('componentProps' in field && field.componentProps) result.componentProps = field.componentProps;
|
|
167
177
|
return result;
|
|
168
178
|
}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __webpack_require__ = {};
|
|
3
|
+
(()=>{
|
|
4
|
+
__webpack_require__.d = (exports1, definition)=>{
|
|
5
|
+
for(var key in definition)if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: definition[key]
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
})();
|
|
11
|
+
(()=>{
|
|
12
|
+
__webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);
|
|
13
|
+
})();
|
|
14
|
+
(()=>{
|
|
15
|
+
__webpack_require__.r = (exports1)=>{
|
|
16
|
+
if ("u" > typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
|
|
17
|
+
value: 'Module'
|
|
18
|
+
});
|
|
19
|
+
Object.defineProperty(exports1, '__esModule', {
|
|
20
|
+
value: true
|
|
21
|
+
});
|
|
22
|
+
};
|
|
23
|
+
})();
|
|
24
|
+
var __webpack_exports__ = {};
|
|
25
|
+
__webpack_require__.r(__webpack_exports__);
|
|
26
|
+
__webpack_require__.d(__webpack_exports__, {
|
|
27
|
+
formatTemplate: ()=>formatTemplate,
|
|
28
|
+
StringListField: ()=>StringListField
|
|
29
|
+
});
|
|
30
|
+
const jsx_runtime_namespaceObject = require("react/jsx-runtime");
|
|
31
|
+
const external_lucide_react_namespaceObject = require("lucide-react");
|
|
32
|
+
const external_react_namespaceObject = require("react");
|
|
33
|
+
const button_cjs_namespaceObject = require("../ui/button.cjs");
|
|
34
|
+
const form_field_cjs_namespaceObject = require("../ui/form-field.cjs");
|
|
35
|
+
const textarea_cjs_namespaceObject = require("../ui/textarea.cjs");
|
|
36
|
+
function formatTemplate(template, values) {
|
|
37
|
+
return template.replace(/\{\{(\w+)\}\}/g, (match, token)=>token in values ? String(values[token]) : match);
|
|
38
|
+
}
|
|
39
|
+
function StringListField({ field, value, onChange, onBlur, error, disabled = false, required = false, inputRef }) {
|
|
40
|
+
const items = value ?? [];
|
|
41
|
+
const maxItems = field.maxItems ?? 1 / 0;
|
|
42
|
+
const canAdd = !disabled && items.length < maxItems;
|
|
43
|
+
const addItemLabel = field.addItemLabel ?? 'Add';
|
|
44
|
+
const removeItemAriaLabel = field.removeItemAriaLabel ?? 'Remove {{label}} {{position}}';
|
|
45
|
+
const [rowIds, setRowIds] = (0, external_react_namespaceObject.useState)(()=>items.map(()=>crypto.randomUUID()));
|
|
46
|
+
const [prevLength, setPrevLength] = (0, external_react_namespaceObject.useState)(items.length);
|
|
47
|
+
if (prevLength !== items.length) {
|
|
48
|
+
setPrevLength(items.length);
|
|
49
|
+
setRowIds((prev)=>prev.length < items.length ? [
|
|
50
|
+
...prev,
|
|
51
|
+
...Array.from({
|
|
52
|
+
length: items.length - prev.length
|
|
53
|
+
}, ()=>crypto.randomUUID())
|
|
54
|
+
] : prev.slice(0, items.length));
|
|
55
|
+
}
|
|
56
|
+
const addItem = (0, external_react_namespaceObject.useCallback)(()=>{
|
|
57
|
+
setRowIds((prev)=>[
|
|
58
|
+
...prev,
|
|
59
|
+
crypto.randomUUID()
|
|
60
|
+
]);
|
|
61
|
+
onChange([
|
|
62
|
+
...items,
|
|
63
|
+
''
|
|
64
|
+
]);
|
|
65
|
+
}, [
|
|
66
|
+
items,
|
|
67
|
+
onChange
|
|
68
|
+
]);
|
|
69
|
+
const removeItem = (0, external_react_namespaceObject.useCallback)((index)=>{
|
|
70
|
+
setRowIds((prev)=>prev.filter((_, i)=>i !== index));
|
|
71
|
+
onChange(items.filter((_, i)=>i !== index));
|
|
72
|
+
}, [
|
|
73
|
+
items,
|
|
74
|
+
onChange
|
|
75
|
+
]);
|
|
76
|
+
const updateItem = (0, external_react_namespaceObject.useCallback)((index, next)=>{
|
|
77
|
+
onChange(items.map((item, i)=>i === index ? next : item));
|
|
78
|
+
}, [
|
|
79
|
+
items,
|
|
80
|
+
onChange
|
|
81
|
+
]);
|
|
82
|
+
return /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsxs)(form_field_cjs_namespaceObject.FormField, {
|
|
83
|
+
"data-slot": "string-list-field",
|
|
84
|
+
children: [
|
|
85
|
+
/*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(form_field_cjs_namespaceObject.FormFieldLabel, {
|
|
86
|
+
required: required,
|
|
87
|
+
tooltip: field.tooltip,
|
|
88
|
+
tooltipAriaLabel: field.tooltipAriaLabel,
|
|
89
|
+
children: field.label
|
|
90
|
+
}),
|
|
91
|
+
/*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)("div", {
|
|
92
|
+
className: "grid gap-1.5",
|
|
93
|
+
children: items.map((item, index)=>/*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsxs)("div", {
|
|
94
|
+
className: "flex items-start gap-2",
|
|
95
|
+
children: [
|
|
96
|
+
/*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(textarea_cjs_namespaceObject.Textarea, {
|
|
97
|
+
ref: 0 === index ? inputRef : void 0,
|
|
98
|
+
value: item,
|
|
99
|
+
onChange: (e)=>updateItem(index, e.target.value),
|
|
100
|
+
onBlur: onBlur,
|
|
101
|
+
minRows: field.minRows ?? 2,
|
|
102
|
+
maxLength: field.maxLength,
|
|
103
|
+
disabled: disabled,
|
|
104
|
+
"aria-label": `${field.label} ${index + 1}`,
|
|
105
|
+
"aria-invalid": error ? true : void 0,
|
|
106
|
+
className: "flex-1"
|
|
107
|
+
}),
|
|
108
|
+
/*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(button_cjs_namespaceObject.Button, {
|
|
109
|
+
type: "button",
|
|
110
|
+
variant: "ghost",
|
|
111
|
+
size: "sm",
|
|
112
|
+
icon: true,
|
|
113
|
+
disabled: disabled,
|
|
114
|
+
onClick: ()=>removeItem(index),
|
|
115
|
+
"aria-label": formatTemplate(removeItemAriaLabel, {
|
|
116
|
+
label: field.label,
|
|
117
|
+
position: index + 1
|
|
118
|
+
}),
|
|
119
|
+
className: "shrink-0 text-muted-foreground",
|
|
120
|
+
children: /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(external_lucide_react_namespaceObject.Trash2, {})
|
|
121
|
+
})
|
|
122
|
+
]
|
|
123
|
+
}, rowIds[index] ?? index))
|
|
124
|
+
}),
|
|
125
|
+
canAdd && /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)("div", {
|
|
126
|
+
children: /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsxs)(button_cjs_namespaceObject.Button, {
|
|
127
|
+
type: "button",
|
|
128
|
+
variant: "text",
|
|
129
|
+
size: "2xs",
|
|
130
|
+
onClick: addItem,
|
|
131
|
+
children: [
|
|
132
|
+
/*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(external_lucide_react_namespaceObject.Plus, {}),
|
|
133
|
+
addItemLabel
|
|
134
|
+
]
|
|
135
|
+
})
|
|
136
|
+
}),
|
|
137
|
+
/*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(form_field_cjs_namespaceObject.FormFieldDescription, {
|
|
138
|
+
children: field.description
|
|
139
|
+
}),
|
|
140
|
+
/*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(form_field_cjs_namespaceObject.FormFieldError, {
|
|
141
|
+
children: error
|
|
142
|
+
})
|
|
143
|
+
]
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
exports.StringListField = __webpack_exports__.StringListField;
|
|
147
|
+
exports.formatTemplate = __webpack_exports__.formatTemplate;
|
|
148
|
+
for(var __rspack_i in __webpack_exports__)if (-1 === [
|
|
149
|
+
"StringListField",
|
|
150
|
+
"formatTemplate"
|
|
151
|
+
].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
|
|
152
|
+
Object.defineProperty(exports, '__esModule', {
|
|
153
|
+
value: true
|
|
154
|
+
});
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type * as React from 'react';
|
|
2
|
+
import type { StringListFieldMetadata } from './form-schema';
|
|
3
|
+
/** Interpolate `{{token}}` placeholders; unknown tokens are left untouched. */
|
|
4
|
+
export declare function formatTemplate(template: string, values: Record<string, string | number>): string;
|
|
5
|
+
export interface StringListFieldProps {
|
|
6
|
+
field: StringListFieldMetadata;
|
|
7
|
+
value: string[] | undefined;
|
|
8
|
+
onChange: (value: string[]) => void;
|
|
9
|
+
/** Forwarded to every row so blur-mode validation and touched state work. */
|
|
10
|
+
onBlur?: () => void;
|
|
11
|
+
error?: string;
|
|
12
|
+
disabled?: boolean;
|
|
13
|
+
required?: boolean;
|
|
14
|
+
/**
|
|
15
|
+
* The Controller ref, attached to the first row. react-hook-form's `shouldFocusError`
|
|
16
|
+
* focuses the ref of the first invalid field on a failed submit; without this the list is
|
|
17
|
+
* the one built-in control it cannot reach, so the user is left with an error and no
|
|
18
|
+
* indication of where it is.
|
|
19
|
+
*/
|
|
20
|
+
inputRef?: React.Ref<HTMLTextAreaElement>;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Repeated multiline rows with Add / Remove — the `string-list` field type.
|
|
24
|
+
*
|
|
25
|
+
* Rendering it standalone with `field.tooltip` set requires an ancestor `TooltipProvider`:
|
|
26
|
+
* the info trigger is a Radix tooltip, which throws without one. Inside `MetadataForm` this
|
|
27
|
+
* is handled for you — it mounts a provider for schemas that use tooltip metadata.
|
|
28
|
+
*/
|
|
29
|
+
export declare function StringListField({ field, value, onChange, onBlur, error, disabled, required, inputRef, }: StringListFieldProps): import("react/jsx-runtime").JSX.Element;
|