@uipath/apollo-wind 2.50.0 → 2.52.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/dist/components/forms/field-renderer.cjs +80 -6
  2. package/dist/components/forms/field-renderer.js +80 -6
  3. package/dist/components/forms/form-designer.cjs +10 -10
  4. package/dist/components/forms/form-designer.js +10 -10
  5. package/dist/components/forms/form-schema.d.ts +38 -2
  6. package/dist/components/forms/index.cjs +15 -5
  7. package/dist/components/forms/index.d.ts +7 -6
  8. package/dist/components/forms/index.js +6 -5
  9. package/dist/components/forms/metadata-form.cjs +97 -37
  10. package/dist/components/forms/metadata-form.d.ts +11 -3
  11. package/dist/components/forms/metadata-form.js +94 -37
  12. package/dist/components/forms/rules-engine.cjs +14 -3
  13. package/dist/components/forms/rules-engine.d.ts +16 -0
  14. package/dist/components/forms/rules-engine.js +14 -3
  15. package/dist/components/forms/schema-serializer.cjs +10 -0
  16. package/dist/components/forms/schema-serializer.js +10 -0
  17. package/dist/components/forms/string-list-field.cjs +154 -0
  18. package/dist/components/forms/string-list-field.d.ts +29 -0
  19. package/dist/components/forms/string-list-field.js +117 -0
  20. package/dist/components/forms/validation-converter.cjs +68 -23
  21. package/dist/components/forms/validation-converter.d.ts +23 -2
  22. package/dist/components/forms/validation-converter.js +64 -22
  23. package/dist/components/ui/datetime-picker.cjs +3 -1
  24. package/dist/components/ui/datetime-picker.d.ts +4 -0
  25. package/dist/components/ui/datetime-picker.js +3 -1
  26. package/dist/components/ui/form-field.cjs +17 -2
  27. package/dist/components/ui/form-field.d.ts +7 -0
  28. package/dist/components/ui/form-field.js +17 -2
  29. package/dist/components/ui/index.cjs +124 -114
  30. package/dist/components/ui/index.d.ts +3 -2
  31. package/dist/components/ui/index.js +2 -1
  32. package/dist/components/ui/info-tooltip.cjs +61 -0
  33. package/dist/components/ui/info-tooltip.d.ts +10 -0
  34. package/dist/components/ui/info-tooltip.js +27 -0
  35. package/dist/components/ui/prompt-editor/components/EditorToolbar.cjs +18 -2
  36. package/dist/components/ui/prompt-editor/components/EditorToolbar.d.ts +3 -1
  37. package/dist/components/ui/prompt-editor/components/EditorToolbar.js +19 -3
  38. package/dist/components/ui/prompt-editor/components/MarkdownPreview.cjs +4 -2
  39. package/dist/components/ui/prompt-editor/components/MarkdownPreview.js +4 -2
  40. package/dist/components/ui/prompt-editor/plugins/ToolbarActionsPlugin.cjs +14 -4
  41. package/dist/components/ui/prompt-editor/plugins/ToolbarActionsPlugin.js +14 -4
  42. package/dist/components/ui/prompt-editor/prompt-editor-config.cjs +2 -0
  43. package/dist/components/ui/prompt-editor/prompt-editor-config.d.ts +2 -0
  44. package/dist/components/ui/prompt-editor/prompt-editor-config.js +2 -0
  45. package/dist/components/ui/prompt-editor/prompt-editor.cjs +10 -1
  46. package/dist/components/ui/prompt-editor/prompt-editor.js +10 -1
  47. package/dist/components/ui/prompt-editor/types.d.ts +7 -1
  48. package/dist/components/ui/prompt-editor/utils/rich-serialization.cjs +48 -1
  49. package/dist/components/ui/prompt-editor/utils/rich-serialization.d.ts +0 -14
  50. package/dist/components/ui/prompt-editor/utils/rich-serialization.js +50 -3
  51. package/dist/components/ui/select.cjs +1 -1
  52. package/dist/components/ui/select.js +1 -1
  53. package/dist/components/ui/textarea.cjs +1 -1
  54. package/dist/components/ui/textarea.js +1 -1
  55. package/dist/index.cjs +14 -0
  56. package/dist/index.d.ts +7 -2
  57. package/dist/index.js +4 -2
  58. package/dist/styles.css +13 -0
  59. package/package.json +2 -2
@@ -0,0 +1,117 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { Plus, Trash2 } from "lucide-react";
3
+ import { useCallback, useState } from "react";
4
+ import { Button } from "../ui/button.js";
5
+ import { FormField, FormFieldDescription, FormFieldError, FormFieldLabel } from "../ui/form-field.js";
6
+ import { Textarea } from "../ui/textarea.js";
7
+ function formatTemplate(template, values) {
8
+ return template.replace(/\{\{(\w+)\}\}/g, (match, token)=>token in values ? String(values[token]) : match);
9
+ }
10
+ function StringListField({ field, value, onChange, onBlur, error, disabled = false, required = false, inputRef }) {
11
+ const items = value ?? [];
12
+ const maxItems = field.maxItems ?? 1 / 0;
13
+ const canAdd = !disabled && items.length < maxItems;
14
+ const addItemLabel = field.addItemLabel ?? 'Add';
15
+ const removeItemAriaLabel = field.removeItemAriaLabel ?? 'Remove {{label}} {{position}}';
16
+ const [rowIds, setRowIds] = useState(()=>items.map(()=>crypto.randomUUID()));
17
+ const [prevLength, setPrevLength] = useState(items.length);
18
+ if (prevLength !== items.length) {
19
+ setPrevLength(items.length);
20
+ setRowIds((prev)=>prev.length < items.length ? [
21
+ ...prev,
22
+ ...Array.from({
23
+ length: items.length - prev.length
24
+ }, ()=>crypto.randomUUID())
25
+ ] : prev.slice(0, items.length));
26
+ }
27
+ const addItem = useCallback(()=>{
28
+ setRowIds((prev)=>[
29
+ ...prev,
30
+ crypto.randomUUID()
31
+ ]);
32
+ onChange([
33
+ ...items,
34
+ ''
35
+ ]);
36
+ }, [
37
+ items,
38
+ onChange
39
+ ]);
40
+ const removeItem = useCallback((index)=>{
41
+ setRowIds((prev)=>prev.filter((_, i)=>i !== index));
42
+ onChange(items.filter((_, i)=>i !== index));
43
+ }, [
44
+ items,
45
+ onChange
46
+ ]);
47
+ const updateItem = useCallback((index, next)=>{
48
+ onChange(items.map((item, i)=>i === index ? next : item));
49
+ }, [
50
+ items,
51
+ onChange
52
+ ]);
53
+ return /*#__PURE__*/ jsxs(FormField, {
54
+ "data-slot": "string-list-field",
55
+ children: [
56
+ /*#__PURE__*/ jsx(FormFieldLabel, {
57
+ required: required,
58
+ tooltip: field.tooltip,
59
+ tooltipAriaLabel: field.tooltipAriaLabel,
60
+ children: field.label
61
+ }),
62
+ /*#__PURE__*/ jsx("div", {
63
+ className: "grid gap-1.5",
64
+ children: items.map((item, index)=>/*#__PURE__*/ jsxs("div", {
65
+ className: "flex items-start gap-2",
66
+ children: [
67
+ /*#__PURE__*/ jsx(Textarea, {
68
+ ref: 0 === index ? inputRef : void 0,
69
+ value: item,
70
+ onChange: (e)=>updateItem(index, e.target.value),
71
+ onBlur: onBlur,
72
+ minRows: field.minRows ?? 2,
73
+ maxLength: field.maxLength,
74
+ disabled: disabled,
75
+ "aria-label": `${field.label} ${index + 1}`,
76
+ "aria-invalid": error ? true : void 0,
77
+ className: "flex-1"
78
+ }),
79
+ /*#__PURE__*/ jsx(Button, {
80
+ type: "button",
81
+ variant: "ghost",
82
+ size: "sm",
83
+ icon: true,
84
+ disabled: disabled,
85
+ onClick: ()=>removeItem(index),
86
+ "aria-label": formatTemplate(removeItemAriaLabel, {
87
+ label: field.label,
88
+ position: index + 1
89
+ }),
90
+ className: "shrink-0 text-muted-foreground",
91
+ children: /*#__PURE__*/ jsx(Trash2, {})
92
+ })
93
+ ]
94
+ }, rowIds[index] ?? index))
95
+ }),
96
+ canAdd && /*#__PURE__*/ jsx("div", {
97
+ children: /*#__PURE__*/ jsxs(Button, {
98
+ type: "button",
99
+ variant: "text",
100
+ size: "2xs",
101
+ onClick: addItem,
102
+ children: [
103
+ /*#__PURE__*/ jsx(Plus, {}),
104
+ addItemLabel
105
+ ]
106
+ })
107
+ }),
108
+ /*#__PURE__*/ jsx(FormFieldDescription, {
109
+ children: field.description
110
+ }),
111
+ /*#__PURE__*/ jsx(FormFieldError, {
112
+ children: error
113
+ })
114
+ ]
115
+ });
116
+ }
117
+ export { StringListField, formatTemplate };
@@ -24,24 +24,45 @@ var __webpack_require__ = {};
24
24
  var __webpack_exports__ = {};
25
25
  __webpack_require__.r(__webpack_exports__);
26
26
  __webpack_require__.d(__webpack_exports__, {
27
+ mergeValidationConfigs: ()=>mergeValidationConfigs,
27
28
  buildZodSchemaFromFields: ()=>buildZodSchemaFromFields,
28
- validationConfigToZod: ()=>validationConfigToZod,
29
- mergeValidationConfigs: ()=>mergeValidationConfigs
29
+ isEmptyFieldValue: ()=>isEmptyFieldValue,
30
+ validationConfigToZod: ()=>validationConfigToZod
30
31
  });
31
32
  const external_zod_namespaceObject = require("zod");
32
- function validationConfigToZod(config, fieldType) {
33
- let schema = getBaseSchemaForType(fieldType);
33
+ const external_rules_engine_cjs_namespaceObject = require("./rules-engine.cjs");
34
+ function validationConfigToZod(config, fieldType, customValueType) {
35
+ let schema = getBaseSchemaForType(fieldType, customValueType);
34
36
  if (!config) return schema.optional();
35
- schema = applyStringConstraints(schema, config, fieldType);
36
- schema = applyNumberConstraints(schema, config, fieldType);
37
- schema = applyArrayConstraints(schema, config, fieldType);
37
+ schema = applyStringConstraints(schema, config, fieldType, customValueType);
38
+ schema = applyNumberConstraints(schema, config, fieldType, customValueType);
39
+ schema = applyArrayConstraints(schema, config, fieldType, customValueType);
38
40
  if (config.required) {
39
- if (isStringType(fieldType) && !config.minLength) schema = schema.min(1, config.messages?.required || 'This field is required');
40
- return schema;
41
+ const requiredMessage = config.messages?.required || 'This field is required';
42
+ if (isStringType(fieldType, customValueType)) schema = schema.refine((value)=>!isEmptyFieldValue(value), {
43
+ message: requiredMessage
44
+ });
45
+ if (isArrayType(fieldType, customValueType) && (null == config.minItems || config.minItems < 1)) schema = schema.min(1, requiredMessage);
46
+ return applyCustomExpression(schema, config);
41
47
  }
42
- return schema.optional();
48
+ return applyCustomExpression(schema, config).optional();
49
+ }
50
+ function applyCustomExpression(schema, config) {
51
+ if (!config.custom) return schema;
52
+ const expression = config.custom;
53
+ const message = config.messages?.custom || 'This value is not valid';
54
+ return schema.superRefine((value, ctx)=>{
55
+ const result = external_rules_engine_cjs_namespaceObject.RulesEngine.tryEvaluateExpression(expression, {
56
+ value
57
+ });
58
+ if (!result.ok) return;
59
+ if (!result.value) ctx.addIssue({
60
+ code: 'custom',
61
+ message
62
+ });
63
+ });
43
64
  }
44
- function getBaseSchemaForType(fieldType) {
65
+ function getBaseSchemaForType(fieldType, customValueType) {
45
66
  switch(fieldType){
46
67
  case 'text':
47
68
  case 'textarea':
@@ -58,6 +79,7 @@ function getBaseSchemaForType(fieldType) {
58
79
  case 'radio':
59
80
  return external_zod_namespaceObject.z.string();
60
81
  case 'multiselect':
82
+ case 'string-list':
61
83
  return external_zod_namespaceObject.z.array(external_zod_namespaceObject.z.string());
62
84
  case 'date':
63
85
  return external_zod_namespaceObject.z.coerce.date();
@@ -66,12 +88,30 @@ function getBaseSchemaForType(fieldType) {
66
88
  case 'file':
67
89
  return external_zod_namespaceObject.z.any();
68
90
  case 'custom':
69
- return external_zod_namespaceObject.z.any();
91
+ switch(customValueType){
92
+ case 'string':
93
+ return external_zod_namespaceObject.z.string();
94
+ case 'number':
95
+ return external_zod_namespaceObject.z.number();
96
+ case 'boolean':
97
+ return external_zod_namespaceObject.z.boolean();
98
+ case 'string-array':
99
+ return external_zod_namespaceObject.z.array(external_zod_namespaceObject.z.string());
100
+ default:
101
+ return external_zod_namespaceObject.z.any();
102
+ }
70
103
  default:
71
104
  return external_zod_namespaceObject.z.string();
72
105
  }
73
106
  }
74
- function isStringType(fieldType) {
107
+ function isEmptyFieldValue(value) {
108
+ if (null == value) return true;
109
+ if ('string' == typeof value) return '' === value.trim();
110
+ if (Array.isArray(value)) return 0 === value.length;
111
+ return false;
112
+ }
113
+ function isStringType(fieldType, customValueType) {
114
+ if ('custom' === fieldType) return 'string' === customValueType;
75
115
  return [
76
116
  'text',
77
117
  'textarea',
@@ -80,19 +120,22 @@ function isStringType(fieldType) {
80
120
  'radio'
81
121
  ].includes(fieldType);
82
122
  }
83
- function isNumberType(fieldType) {
123
+ function isNumberType(fieldType, customValueType) {
124
+ if ('custom' === fieldType) return 'number' === customValueType;
84
125
  return [
85
126
  'number',
86
127
  'slider'
87
128
  ].includes(fieldType);
88
129
  }
89
- function isArrayType(fieldType) {
130
+ function isArrayType(fieldType, customValueType) {
131
+ if ('custom' === fieldType) return 'string-array' === customValueType;
90
132
  return [
91
- 'multiselect'
133
+ 'multiselect',
134
+ 'string-list'
92
135
  ].includes(fieldType);
93
136
  }
94
- function applyStringConstraints(schema, config, fieldType) {
95
- if (!isStringType(fieldType)) return schema;
137
+ function applyStringConstraints(schema, config, fieldType, customValueType) {
138
+ if (!isStringType(fieldType, customValueType)) return schema;
96
139
  let stringSchema = schema;
97
140
  if (null != config.minLength) stringSchema = stringSchema.min(config.minLength, config.messages?.minLength || `Must be at least ${config.minLength} characters`);
98
141
  if (null != config.maxLength) stringSchema = stringSchema.max(config.maxLength, config.messages?.maxLength || `Must be at most ${config.maxLength} characters`);
@@ -106,8 +149,8 @@ function applyStringConstraints(schema, config, fieldType) {
106
149
  if (config.url) stringSchema = stringSchema.url(config.messages?.url || 'Invalid URL');
107
150
  return stringSchema;
108
151
  }
109
- function applyNumberConstraints(schema, config, fieldType) {
110
- if (!isNumberType(fieldType)) return schema;
152
+ function applyNumberConstraints(schema, config, fieldType, customValueType) {
153
+ if (!isNumberType(fieldType, customValueType)) return schema;
111
154
  let numberSchema = schema;
112
155
  if (config.integer) numberSchema = numberSchema.int(config.messages?.integer || 'Must be a whole number');
113
156
  if (null != config.min) numberSchema = numberSchema.min(config.min, config.messages?.min || `Must be at least ${config.min}`);
@@ -116,8 +159,8 @@ function applyNumberConstraints(schema, config, fieldType) {
116
159
  if (config.negative) numberSchema = numberSchema.negative(config.messages?.negative || 'Must be a negative number');
117
160
  return numberSchema;
118
161
  }
119
- function applyArrayConstraints(schema, config, fieldType) {
120
- if (!isArrayType(fieldType)) return schema;
162
+ function applyArrayConstraints(schema, config, fieldType, customValueType) {
163
+ if (!isArrayType(fieldType, customValueType)) return schema;
121
164
  let arraySchema = schema;
122
165
  if (null != config.minItems) arraySchema = arraySchema.min(config.minItems, config.messages?.minItems || `Select at least ${config.minItems} item(s)`);
123
166
  if (null != config.maxItems) arraySchema = arraySchema.max(config.maxItems, config.messages?.maxItems || `Select at most ${config.maxItems} item(s)`);
@@ -125,7 +168,7 @@ function applyArrayConstraints(schema, config, fieldType) {
125
168
  }
126
169
  function buildZodSchemaFromFields(fields) {
127
170
  const shape = {};
128
- for (const field of fields)shape[field.name] = validationConfigToZod(field.validation, field.type);
171
+ for (const field of fields)shape[field.name] = validationConfigToZod(field.validation, field.type, field.valueType);
129
172
  return external_zod_namespaceObject.z.object(shape);
130
173
  }
131
174
  function mergeValidationConfigs(base, override) {
@@ -142,10 +185,12 @@ function mergeValidationConfigs(base, override) {
142
185
  };
143
186
  }
144
187
  exports.buildZodSchemaFromFields = __webpack_exports__.buildZodSchemaFromFields;
188
+ exports.isEmptyFieldValue = __webpack_exports__.isEmptyFieldValue;
145
189
  exports.mergeValidationConfigs = __webpack_exports__.mergeValidationConfigs;
146
190
  exports.validationConfigToZod = __webpack_exports__.validationConfigToZod;
147
191
  for(var __rspack_i in __webpack_exports__)if (-1 === [
148
192
  "buildZodSchemaFromFields",
193
+ "isEmptyFieldValue",
149
194
  "mergeValidationConfigs",
150
195
  "validationConfigToZod"
151
196
  ].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
@@ -1,5 +1,6 @@
1
1
  import { z } from 'zod';
2
- import type { ValidationConfig, FieldType } from './form-schema';
2
+ import type { CustomValueType, FieldType, ValidationConfig } from './form-schema';
3
+ export type { CustomValueType };
3
4
  /**
4
5
  * Validation Converter
5
6
  *
@@ -20,7 +21,21 @@ import type { ValidationConfig, FieldType } from './form-schema';
20
21
  * );
21
22
  * // Returns: z.string().min(2).email()
22
23
  */
23
- export declare function validationConfigToZod(config: ValidationConfig | undefined, fieldType: FieldType): z.ZodTypeAny;
24
+ export declare function validationConfigToZod(config: ValidationConfig | undefined, fieldType: FieldType,
25
+ /**
26
+ * Declared shape of a `type: 'custom'` field's value. Custom fields otherwise validate as
27
+ * `z.any()`, where `required` and the array constraints are no-ops.
28
+ */
29
+ customValueType?: CustomValueType): z.ZodTypeAny;
30
+ /**
31
+ * Check if field type uses string schema
32
+ */
33
+ /**
34
+ * The one definition of "empty" for a required field. Exported so the resolver and the
35
+ * conditional-required `superRefine` in metadata-form agree — they used to disagree, with
36
+ * the narrower resolver path missing whitespace-only strings.
37
+ */
38
+ export declare function isEmptyFieldValue(value: unknown): boolean;
24
39
  /**
25
40
  * Build a complete Zod object schema from field validations
26
41
  *
@@ -31,6 +46,12 @@ export declare function buildZodSchemaFromFields(fields: Array<{
31
46
  name: string;
32
47
  type: FieldType;
33
48
  validation?: ValidationConfig;
49
+ /**
50
+ * Declared shape of a `type: 'custom'` field. Accepted here as well as by
51
+ * `validationConfigToZod`, otherwise a schema built through this helper validates every
52
+ * typed custom field as `z.any()` and its `required` / `minItems` quietly do nothing.
53
+ */
54
+ valueType?: CustomValueType;
34
55
  }>): z.ZodObject<Record<string, z.ZodTypeAny>>;
35
56
  /**
36
57
  * Merge multiple ValidationConfigs (for rule-based validation changes)
@@ -1,17 +1,37 @@
1
1
  import { z } from "zod";
2
- function validationConfigToZod(config, fieldType) {
3
- let schema = getBaseSchemaForType(fieldType);
2
+ import { RulesEngine } from "./rules-engine.js";
3
+ function validationConfigToZod(config, fieldType, customValueType) {
4
+ let schema = getBaseSchemaForType(fieldType, customValueType);
4
5
  if (!config) return schema.optional();
5
- schema = applyStringConstraints(schema, config, fieldType);
6
- schema = applyNumberConstraints(schema, config, fieldType);
7
- schema = applyArrayConstraints(schema, config, fieldType);
6
+ schema = applyStringConstraints(schema, config, fieldType, customValueType);
7
+ schema = applyNumberConstraints(schema, config, fieldType, customValueType);
8
+ schema = applyArrayConstraints(schema, config, fieldType, customValueType);
8
9
  if (config.required) {
9
- if (isStringType(fieldType) && !config.minLength) schema = schema.min(1, config.messages?.required || 'This field is required');
10
- return schema;
10
+ const requiredMessage = config.messages?.required || 'This field is required';
11
+ if (isStringType(fieldType, customValueType)) schema = schema.refine((value)=>!isEmptyFieldValue(value), {
12
+ message: requiredMessage
13
+ });
14
+ if (isArrayType(fieldType, customValueType) && (null == config.minItems || config.minItems < 1)) schema = schema.min(1, requiredMessage);
15
+ return applyCustomExpression(schema, config);
11
16
  }
12
- return schema.optional();
17
+ return applyCustomExpression(schema, config).optional();
13
18
  }
14
- function getBaseSchemaForType(fieldType) {
19
+ function applyCustomExpression(schema, config) {
20
+ if (!config.custom) return schema;
21
+ const expression = config.custom;
22
+ const message = config.messages?.custom || 'This value is not valid';
23
+ return schema.superRefine((value, ctx)=>{
24
+ const result = RulesEngine.tryEvaluateExpression(expression, {
25
+ value
26
+ });
27
+ if (!result.ok) return;
28
+ if (!result.value) ctx.addIssue({
29
+ code: 'custom',
30
+ message
31
+ });
32
+ });
33
+ }
34
+ function getBaseSchemaForType(fieldType, customValueType) {
15
35
  switch(fieldType){
16
36
  case 'text':
17
37
  case 'textarea':
@@ -28,6 +48,7 @@ function getBaseSchemaForType(fieldType) {
28
48
  case 'radio':
29
49
  return z.string();
30
50
  case 'multiselect':
51
+ case 'string-list':
31
52
  return z.array(z.string());
32
53
  case 'date':
33
54
  return z.coerce.date();
@@ -36,12 +57,30 @@ function getBaseSchemaForType(fieldType) {
36
57
  case 'file':
37
58
  return z.any();
38
59
  case 'custom':
39
- return z.any();
60
+ switch(customValueType){
61
+ case 'string':
62
+ return z.string();
63
+ case 'number':
64
+ return z.number();
65
+ case 'boolean':
66
+ return z.boolean();
67
+ case 'string-array':
68
+ return z.array(z.string());
69
+ default:
70
+ return z.any();
71
+ }
40
72
  default:
41
73
  return z.string();
42
74
  }
43
75
  }
44
- function isStringType(fieldType) {
76
+ function isEmptyFieldValue(value) {
77
+ if (null == value) return true;
78
+ if ('string' == typeof value) return '' === value.trim();
79
+ if (Array.isArray(value)) return 0 === value.length;
80
+ return false;
81
+ }
82
+ function isStringType(fieldType, customValueType) {
83
+ if ('custom' === fieldType) return 'string' === customValueType;
45
84
  return [
46
85
  'text',
47
86
  'textarea',
@@ -50,19 +89,22 @@ function isStringType(fieldType) {
50
89
  'radio'
51
90
  ].includes(fieldType);
52
91
  }
53
- function isNumberType(fieldType) {
92
+ function isNumberType(fieldType, customValueType) {
93
+ if ('custom' === fieldType) return 'number' === customValueType;
54
94
  return [
55
95
  'number',
56
96
  'slider'
57
97
  ].includes(fieldType);
58
98
  }
59
- function isArrayType(fieldType) {
99
+ function isArrayType(fieldType, customValueType) {
100
+ if ('custom' === fieldType) return 'string-array' === customValueType;
60
101
  return [
61
- 'multiselect'
102
+ 'multiselect',
103
+ 'string-list'
62
104
  ].includes(fieldType);
63
105
  }
64
- function applyStringConstraints(schema, config, fieldType) {
65
- if (!isStringType(fieldType)) return schema;
106
+ function applyStringConstraints(schema, config, fieldType, customValueType) {
107
+ if (!isStringType(fieldType, customValueType)) return schema;
66
108
  let stringSchema = schema;
67
109
  if (null != config.minLength) stringSchema = stringSchema.min(config.minLength, config.messages?.minLength || `Must be at least ${config.minLength} characters`);
68
110
  if (null != config.maxLength) stringSchema = stringSchema.max(config.maxLength, config.messages?.maxLength || `Must be at most ${config.maxLength} characters`);
@@ -76,8 +118,8 @@ function applyStringConstraints(schema, config, fieldType) {
76
118
  if (config.url) stringSchema = stringSchema.url(config.messages?.url || 'Invalid URL');
77
119
  return stringSchema;
78
120
  }
79
- function applyNumberConstraints(schema, config, fieldType) {
80
- if (!isNumberType(fieldType)) return schema;
121
+ function applyNumberConstraints(schema, config, fieldType, customValueType) {
122
+ if (!isNumberType(fieldType, customValueType)) return schema;
81
123
  let numberSchema = schema;
82
124
  if (config.integer) numberSchema = numberSchema.int(config.messages?.integer || 'Must be a whole number');
83
125
  if (null != config.min) numberSchema = numberSchema.min(config.min, config.messages?.min || `Must be at least ${config.min}`);
@@ -86,8 +128,8 @@ function applyNumberConstraints(schema, config, fieldType) {
86
128
  if (config.negative) numberSchema = numberSchema.negative(config.messages?.negative || 'Must be a negative number');
87
129
  return numberSchema;
88
130
  }
89
- function applyArrayConstraints(schema, config, fieldType) {
90
- if (!isArrayType(fieldType)) return schema;
131
+ function applyArrayConstraints(schema, config, fieldType, customValueType) {
132
+ if (!isArrayType(fieldType, customValueType)) return schema;
91
133
  let arraySchema = schema;
92
134
  if (null != config.minItems) arraySchema = arraySchema.min(config.minItems, config.messages?.minItems || `Select at least ${config.minItems} item(s)`);
93
135
  if (null != config.maxItems) arraySchema = arraySchema.max(config.maxItems, config.messages?.maxItems || `Select at most ${config.maxItems} item(s)`);
@@ -95,7 +137,7 @@ function applyArrayConstraints(schema, config, fieldType) {
95
137
  }
96
138
  function buildZodSchemaFromFields(fields) {
97
139
  const shape = {};
98
- for (const field of fields)shape[field.name] = validationConfigToZod(field.validation, field.type);
140
+ for (const field of fields)shape[field.name] = validationConfigToZod(field.validation, field.type, field.valueType);
99
141
  return z.object(shape);
100
142
  }
101
143
  function mergeValidationConfigs(base, override) {
@@ -111,4 +153,4 @@ function mergeValidationConfigs(base, override) {
111
153
  }
112
154
  };
113
155
  }
114
- export { buildZodSchemaFromFields, mergeValidationConfigs, validationConfigToZod };
156
+ export { buildZodSchemaFromFields, isEmptyFieldValue, mergeValidationConfigs, validationConfigToZod };
@@ -36,7 +36,7 @@ const external_input_cjs_namespaceObject = require("./input.cjs");
36
36
  const external_label_cjs_namespaceObject = require("./label.cjs");
37
37
  const external_popover_cjs_namespaceObject = require("./popover.cjs");
38
38
  const index_cjs_namespaceObject = require("../../lib/index.cjs");
39
- const datetime_picker_DateTimePicker = /*#__PURE__*/ external_react_namespaceObject.forwardRef(function({ value, onValueChange, disabled, placeholder = 'Pick a date and time', className, use12Hour = false }, ref) {
39
+ const datetime_picker_DateTimePicker = /*#__PURE__*/ external_react_namespaceObject.forwardRef(function({ value, onValueChange, disabled, placeholder = 'Pick a date and time', className, use12Hour = false, 'aria-labelledby': ariaLabelledBy, 'aria-invalid': ariaInvalid }, ref) {
40
40
  const [open, setOpen] = external_react_namespaceObject.useState(false);
41
41
  const [selectedDate, setSelectedDate] = external_react_namespaceObject.useState(value);
42
42
  const [timeValue, setTimeValue] = external_react_namespaceObject.useState(value ? (0, external_date_fns_namespaceObject.format)(value, use12Hour ? 'hh:mm a' : 'HH:mm') : '');
@@ -76,6 +76,8 @@ const datetime_picker_DateTimePicker = /*#__PURE__*/ external_react_namespaceObj
76
76
  asChild: true,
77
77
  children: /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsxs)(external_button_cjs_namespaceObject.Button, {
78
78
  ref: ref,
79
+ "aria-labelledby": ariaLabelledBy,
80
+ "aria-invalid": ariaInvalid,
79
81
  variant: "outline",
80
82
  className: (0, index_cjs_namespaceObject.cn)('w-full justify-start text-left font-normal [&>svg]:text-foreground-muted hover:[&>svg]:text-accent-foreground', 'future:h-10 future:rounded-xl future:border-0 future:bg-surface-overlay future:px-4 future:gap-4 future:text-foreground future:hover:bg-surface-hover future:focus-visible:ring-offset-2 future:focus-visible:ring-offset-background', className),
81
83
  disabled: disabled,
@@ -6,5 +6,9 @@ export interface DateTimePickerProps {
6
6
  placeholder?: string;
7
7
  className?: string;
8
8
  use12Hour?: boolean;
9
+ /** Id of the element naming this control, forwarded to the trigger button. */
10
+ 'aria-labelledby'?: string;
11
+ /** Marks the trigger invalid, so the error is exposed on the control itself. */
12
+ 'aria-invalid'?: boolean;
9
13
  }
10
14
  export declare const DateTimePicker: React.ForwardRefExoticComponent<DateTimePickerProps & React.RefAttributes<HTMLButtonElement>>;
@@ -8,7 +8,7 @@ import { Input } from "./input.js";
8
8
  import { Label } from "./label.js";
9
9
  import { Popover, PopoverContent, PopoverTrigger } from "./popover.js";
10
10
  import { cn } from "../../lib/index.js";
11
- const datetime_picker_DateTimePicker = /*#__PURE__*/ forwardRef(function({ value, onValueChange, disabled, placeholder = 'Pick a date and time', className, use12Hour = false }, ref) {
11
+ const datetime_picker_DateTimePicker = /*#__PURE__*/ forwardRef(function({ value, onValueChange, disabled, placeholder = 'Pick a date and time', className, use12Hour = false, 'aria-labelledby': ariaLabelledBy, 'aria-invalid': ariaInvalid }, ref) {
12
12
  const [open, setOpen] = useState(false);
13
13
  const [selectedDate, setSelectedDate] = useState(value);
14
14
  const [timeValue, setTimeValue] = useState(value ? format(value, use12Hour ? 'hh:mm a' : 'HH:mm') : '');
@@ -48,6 +48,8 @@ const datetime_picker_DateTimePicker = /*#__PURE__*/ forwardRef(function({ value
48
48
  asChild: true,
49
49
  children: /*#__PURE__*/ jsxs(Button, {
50
50
  ref: ref,
51
+ "aria-labelledby": ariaLabelledBy,
52
+ "aria-invalid": ariaInvalid,
51
53
  variant: "outline",
52
54
  className: cn('w-full justify-start text-left font-normal [&>svg]:text-foreground-muted hover:[&>svg]:text-accent-foreground', 'future:h-10 future:rounded-xl future:border-0 future:bg-surface-overlay future:px-4 future:gap-4 future:text-foreground future:hover:bg-surface-hover future:focus-visible:ring-offset-2 future:focus-visible:ring-offset-background', className),
53
55
  disabled: disabled,
@@ -31,6 +31,7 @@ __webpack_require__.d(__webpack_exports__, {
31
31
  });
32
32
  const jsx_runtime_namespaceObject = require("react/jsx-runtime");
33
33
  const external_react_namespaceObject = require("react");
34
+ const external_info_tooltip_cjs_namespaceObject = require("./info-tooltip.cjs");
34
35
  const external_label_cjs_namespaceObject = require("./label.cjs");
35
36
  const index_cjs_namespaceObject = require("../../lib/index.cjs");
36
37
  const FormField = /*#__PURE__*/ external_react_namespaceObject.forwardRef(({ children, className, ...props }, ref)=>/*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)("div", {
@@ -41,15 +42,29 @@ const FormField = /*#__PURE__*/ external_react_namespaceObject.forwardRef(({ chi
41
42
  children: children
42
43
  }));
43
44
  FormField.displayName = 'FormField';
44
- const FormFieldLabel = /*#__PURE__*/ external_react_namespaceObject.forwardRef(({ children, required = false, ...props }, ref)=>/*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsxs)(external_label_cjs_namespaceObject.Label, {
45
+ const FormFieldLabel = /*#__PURE__*/ external_react_namespaceObject.forwardRef(({ children, required = false, tooltip, tooltipAriaLabel, className, ...props }, ref)=>{
46
+ const label = /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsxs)(external_label_cjs_namespaceObject.Label, {
45
47
  ref: ref,
46
48
  "data-slot": "form-field-label",
49
+ className: className,
47
50
  ...props,
48
51
  children: [
49
52
  children,
50
53
  required && /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(external_label_cjs_namespaceObject.RequiredIndicator, {})
51
54
  ]
52
- }));
55
+ });
56
+ if (null == tooltip || false === tooltip) return label;
57
+ return /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsxs)("span", {
58
+ className: "inline-flex items-center",
59
+ children: [
60
+ label,
61
+ /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(external_info_tooltip_cjs_namespaceObject.InfoTooltip, {
62
+ content: tooltip,
63
+ "aria-label": tooltipAriaLabel ?? 'More information'
64
+ })
65
+ ]
66
+ });
67
+ });
53
68
  FormFieldLabel.displayName = 'FormFieldLabel';
54
69
  const FormFieldDescription = /*#__PURE__*/ external_react_namespaceObject.forwardRef(({ children, className, ...props }, ref)=>{
55
70
  if (!children) return null;
@@ -19,6 +19,13 @@ declare const FormField: React.ForwardRefExoticComponent<Omit<React.DetailedHTML
19
19
  export interface FormFieldLabelProps extends React.ComponentPropsWithoutRef<typeof Label> {
20
20
  /** Appends the required indicator after the label text. */
21
21
  required?: boolean;
22
+ /**
23
+ * Appends an info-tooltip trigger after the label text and the required indicator.
24
+ * Requires an ancestor `TooltipProvider` (Radix throws without one).
25
+ */
26
+ tooltip?: React.ReactNode;
27
+ /** Accessible name of the tooltip trigger. Defaults to 'More information'. */
28
+ tooltipAriaLabel?: string;
22
29
  }
23
30
  /** Names the field. Pair with a control via `htmlFor`. */
24
31
  declare const FormFieldLabel: React.ForwardRefExoticComponent<FormFieldLabelProps & React.RefAttributes<HTMLLabelElement>>;
@@ -1,5 +1,6 @@
1
1
  import { jsx, jsxs } from "react/jsx-runtime";
2
2
  import { forwardRef } from "react";
3
+ import { InfoTooltip } from "./info-tooltip.js";
3
4
  import { Label, RequiredIndicator } from "./label.js";
4
5
  import { cn } from "../../lib/index.js";
5
6
  const FormField = /*#__PURE__*/ forwardRef(({ children, className, ...props }, ref)=>/*#__PURE__*/ jsx("div", {
@@ -10,15 +11,29 @@ const FormField = /*#__PURE__*/ forwardRef(({ children, className, ...props }, r
10
11
  children: children
11
12
  }));
12
13
  FormField.displayName = 'FormField';
13
- const FormFieldLabel = /*#__PURE__*/ forwardRef(({ children, required = false, ...props }, ref)=>/*#__PURE__*/ jsxs(Label, {
14
+ const FormFieldLabel = /*#__PURE__*/ forwardRef(({ children, required = false, tooltip, tooltipAriaLabel, className, ...props }, ref)=>{
15
+ const label = /*#__PURE__*/ jsxs(Label, {
14
16
  ref: ref,
15
17
  "data-slot": "form-field-label",
18
+ className: className,
16
19
  ...props,
17
20
  children: [
18
21
  children,
19
22
  required && /*#__PURE__*/ jsx(RequiredIndicator, {})
20
23
  ]
21
- }));
24
+ });
25
+ if (null == tooltip || false === tooltip) return label;
26
+ return /*#__PURE__*/ jsxs("span", {
27
+ className: "inline-flex items-center",
28
+ children: [
29
+ label,
30
+ /*#__PURE__*/ jsx(InfoTooltip, {
31
+ content: tooltip,
32
+ "aria-label": tooltipAriaLabel ?? 'More information'
33
+ })
34
+ ]
35
+ });
36
+ });
22
37
  FormFieldLabel.displayName = 'FormFieldLabel';
23
38
  const FormFieldDescription = /*#__PURE__*/ forwardRef(({ children, className, ...props }, ref)=>{
24
39
  if (!children) return null;