@uipath/apollo-wind 2.36.2 → 2.37.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.
@@ -32,7 +32,7 @@ const external_lucide_react_namespaceObject = require("lucide-react");
32
32
  const external_react_namespaceObject = require("react");
33
33
  const external_button_cjs_namespaceObject = require("./button.cjs");
34
34
  const index_cjs_namespaceObject = require("../../lib/index.cjs");
35
- const file_upload_FileUpload = /*#__PURE__*/ external_react_namespaceObject.forwardRef(function({ id, ariaLabel, onFilesChange, accept, multiple = false, disabled = false, maxSize, className, showPreview = false, errors, onBlur }, ref) {
35
+ const file_upload_FileUpload = /*#__PURE__*/ external_react_namespaceObject.forwardRef(function({ id, ariaLabel, onFilesChange, accept, multiple = false, disabled = false, maxSize, className, showPreview = false, errors, onBlur, 'aria-invalid': ariaInvalid, 'aria-describedby': ariaDescribedBy, 'aria-errormessage': ariaErrorMessage }, ref) {
36
36
  const [files, setFiles] = external_react_namespaceObject.useState([]);
37
37
  const [isDragging, setIsDragging] = external_react_namespaceObject.useState(false);
38
38
  const [fileErrors, setFileErrors] = external_react_namespaceObject.useState(new Map());
@@ -177,12 +177,18 @@ const file_upload_FileUpload = /*#__PURE__*/ external_react_namespaceObject.forw
177
177
  multiple: multiple,
178
178
  disabled: disabled,
179
179
  onChange: handleInputChange,
180
- "aria-label": id ? void 0 : ariaLabel ?? 'File upload'
180
+ "aria-label": id ? void 0 : ariaLabel ?? 'File upload',
181
+ "aria-invalid": ariaInvalid,
182
+ "aria-describedby": ariaDescribedBy,
183
+ "aria-errormessage": ariaErrorMessage
181
184
  }),
182
185
  /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsxs)("div", {
183
186
  role: "button",
184
187
  "aria-label": ariaLabel ?? 'File upload area',
185
188
  "aria-disabled": disabled,
189
+ "aria-invalid": ariaInvalid,
190
+ "aria-describedby": ariaDescribedBy,
191
+ "aria-errormessage": ariaErrorMessage,
186
192
  tabIndex: disabled ? -1 : 0,
187
193
  className: (0, index_cjs_namespaceObject.cn)('relative flex flex-col items-center justify-center w-full h-32 px-4 py-6 border-2 border-dashed rounded-lg cursor-pointer transition-colors', 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background', 'future:rounded-xl', isDragging ? 'border-primary bg-primary/5' : 'border-input bg-background hover:bg-accent/50 future:border-border future:bg-surface-raised future:hover:bg-surface-overlay', disabled && 'opacity-50 cursor-not-allowed hover:bg-background future:hover:bg-surface-raised'),
188
194
  onDragEnter: handleDragEnter,
@@ -26,5 +26,8 @@ export interface FileUploadProps {
26
26
  /** External errors keyed by filename. Use this to set errors from outside (e.g., upload failures). */
27
27
  errors?: Record<string, string>;
28
28
  onBlur?: React.FocusEventHandler<HTMLFieldSetElement>;
29
+ 'aria-invalid'?: React.AriaAttributes['aria-invalid'];
30
+ 'aria-describedby'?: string;
31
+ 'aria-errormessage'?: string;
29
32
  }
30
33
  export declare const FileUpload: React.ForwardRefExoticComponent<FileUploadProps & React.RefAttributes<HTMLFieldSetElement>>;
@@ -4,7 +4,7 @@ import { Upload, X } from "lucide-react";
4
4
  import { forwardRef, useRef, useState } from "react";
5
5
  import { Button } from "./button.js";
6
6
  import { cn } from "../../lib/index.js";
7
- const file_upload_FileUpload = /*#__PURE__*/ forwardRef(function({ id, ariaLabel, onFilesChange, accept, multiple = false, disabled = false, maxSize, className, showPreview = false, errors, onBlur }, ref) {
7
+ const file_upload_FileUpload = /*#__PURE__*/ forwardRef(function({ id, ariaLabel, onFilesChange, accept, multiple = false, disabled = false, maxSize, className, showPreview = false, errors, onBlur, 'aria-invalid': ariaInvalid, 'aria-describedby': ariaDescribedBy, 'aria-errormessage': ariaErrorMessage }, ref) {
8
8
  const [files, setFiles] = useState([]);
9
9
  const [isDragging, setIsDragging] = useState(false);
10
10
  const [fileErrors, setFileErrors] = useState(new Map());
@@ -149,12 +149,18 @@ const file_upload_FileUpload = /*#__PURE__*/ forwardRef(function({ id, ariaLabel
149
149
  multiple: multiple,
150
150
  disabled: disabled,
151
151
  onChange: handleInputChange,
152
- "aria-label": id ? void 0 : ariaLabel ?? 'File upload'
152
+ "aria-label": id ? void 0 : ariaLabel ?? 'File upload',
153
+ "aria-invalid": ariaInvalid,
154
+ "aria-describedby": ariaDescribedBy,
155
+ "aria-errormessage": ariaErrorMessage
153
156
  }),
154
157
  /*#__PURE__*/ jsxs("div", {
155
158
  role: "button",
156
159
  "aria-label": ariaLabel ?? 'File upload area',
157
160
  "aria-disabled": disabled,
161
+ "aria-invalid": ariaInvalid,
162
+ "aria-describedby": ariaDescribedBy,
163
+ "aria-errormessage": ariaErrorMessage,
158
164
  tabIndex: disabled ? -1 : 0,
159
165
  className: cn('relative flex flex-col items-center justify-center w-full h-32 px-4 py-6 border-2 border-dashed rounded-lg cursor-pointer transition-colors', 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background', 'future:rounded-xl', isDragging ? 'border-primary bg-primary/5' : 'border-input bg-background hover:bg-accent/50 future:border-border future:bg-surface-raised future:hover:bg-surface-overlay', disabled && 'opacity-50 cursor-not-allowed hover:bg-background future:hover:bg-surface-raised'),
160
166
  onDragEnter: handleDragEnter,
@@ -60,7 +60,7 @@ var __webpack_modules__ = {
60
60
  "./datetime-picker" (module) {
61
61
  module.exports = require("./datetime-picker.cjs");
62
62
  },
63
- "./dialog" (module) {
63
+ "@/components/ui/dialog" (module) {
64
64
  module.exports = require("./dialog.cjs");
65
65
  },
66
66
  "./drawer" (module) {
@@ -81,7 +81,7 @@ var __webpack_modules__ = {
81
81
  "@/components/ui/hover-card" (module) {
82
82
  module.exports = require("./hover-card.cjs");
83
83
  },
84
- "./input-group" (module) {
84
+ "@/components/ui/input-group" (module) {
85
85
  module.exports = require("./input-group.cjs");
86
86
  },
87
87
  "@/components/ui/input" (module) {
@@ -162,13 +162,13 @@ var __webpack_modules__ = {
162
162
  "./tabs" (module) {
163
163
  module.exports = require("./tabs.cjs");
164
164
  },
165
- "./textarea" (module) {
165
+ "@/components/ui/textarea" (module) {
166
166
  module.exports = require("./textarea.cjs");
167
167
  },
168
168
  "./toggle-group" (module) {
169
169
  module.exports = require("./toggle-group.cjs");
170
170
  },
171
- "./toggle" (module) {
171
+ "@/components/ui/toggle" (module) {
172
172
  module.exports = require("./toggle.cjs");
173
173
  },
174
174
  "./tooltip" (module) {
@@ -367,7 +367,7 @@ var __webpack_exports__ = {};
367
367
  "default"
368
368
  ].indexOf(__rspack_import_key) < 0) __rspack_reexport[__rspack_import_key] = ()=>_datetime_picker__rspack_import_19[__rspack_import_key];
369
369
  __webpack_require__.d(__webpack_exports__, __rspack_reexport);
370
- var _dialog__rspack_import_20 = __webpack_require__("./dialog");
370
+ var _dialog__rspack_import_20 = __webpack_require__("@/components/ui/dialog");
371
371
  var __rspack_reexport = {};
372
372
  for(const __rspack_import_key in _dialog__rspack_import_20)if ([
373
373
  "TreeView",
@@ -423,7 +423,7 @@ var __webpack_exports__ = {};
423
423
  "default"
424
424
  ].indexOf(__rspack_import_key) < 0) __rspack_reexport[__rspack_import_key] = ()=>_input__rspack_import_27[__rspack_import_key];
425
425
  __webpack_require__.d(__webpack_exports__, __rspack_reexport);
426
- var _input_group__rspack_import_28 = __webpack_require__("./input-group");
426
+ var _input_group__rspack_import_28 = __webpack_require__("@/components/ui/input-group");
427
427
  var __rspack_reexport = {};
428
428
  for(const __rspack_import_key in _input_group__rspack_import_28)if ([
429
429
  "TreeView",
@@ -605,14 +605,14 @@ var __webpack_exports__ = {};
605
605
  "default"
606
606
  ].indexOf(__rspack_import_key) < 0) __rspack_reexport[__rspack_import_key] = ()=>_tabs__rspack_import_53[__rspack_import_key];
607
607
  __webpack_require__.d(__webpack_exports__, __rspack_reexport);
608
- var _textarea__rspack_import_54 = __webpack_require__("./textarea");
608
+ var _textarea__rspack_import_54 = __webpack_require__("@/components/ui/textarea");
609
609
  var __rspack_reexport = {};
610
610
  for(const __rspack_import_key in _textarea__rspack_import_54)if ([
611
611
  "TreeView",
612
612
  "default"
613
613
  ].indexOf(__rspack_import_key) < 0) __rspack_reexport[__rspack_import_key] = ()=>_textarea__rspack_import_54[__rspack_import_key];
614
614
  __webpack_require__.d(__webpack_exports__, __rspack_reexport);
615
- var _toggle__rspack_import_55 = __webpack_require__("./toggle");
615
+ var _toggle__rspack_import_55 = __webpack_require__("@/components/ui/toggle");
616
616
  var __rspack_reexport = {};
617
617
  for(const __rspack_import_key in _toggle__rspack_import_55)if ([
618
618
  "TreeView",
@@ -38,12 +38,33 @@ const external_button_cjs_namespaceObject = require("./button.cjs");
38
38
  const external_input_cjs_namespaceObject = require("./input.cjs");
39
39
  const external_textarea_cjs_namespaceObject = require("./textarea.cjs");
40
40
  const index_cjs_namespaceObject = require("../../lib/index.cjs");
41
- const InputGroup = /*#__PURE__*/ external_react_namespaceObject.forwardRef(({ className, variant = 'default', size = 'default', ...props }, ref)=>/*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)("div", {
42
- ref: ref,
43
- role: "group",
44
- className: (0, index_cjs_namespaceObject.cn)('group/input-group relative flex w-full items-center gap-2 transition-colors has-[>textarea]:h-auto has-[>textarea]:items-start', 'default' === size && 'h-9 rounded-md px-3 py-1 future:h-10 future:rounded-xl future:py-2', 'xs' === size && 'h-6 gap-1 rounded px-2', 'default' === variant && 'border border-input bg-transparent future:border-0 future:bg-surface-overlay', 'ghost' === variant && 'border-0 bg-surface-overlay', 'has-[[data-slot=input-group-control]:focus-visible]:ring-2 has-[[data-slot=input-group-control]:focus-visible]:ring-ring future:has-[[data-slot=input-group-control]:focus-visible]:ring-offset-2 future:has-[[data-slot=input-group-control]:focus-visible]:ring-offset-background', 'has-[[data-slot][aria-invalid=true]]:border-destructive has-[[data-slot][aria-invalid=true]]:ring-destructive/20', 'has-[[data-slot=input-group-control]:disabled]:cursor-not-allowed has-[[data-slot=input-group-control]:disabled]:opacity-50', className),
45
- ...props
46
- }));
41
+ const InputGroupValidationContext = /*#__PURE__*/ external_react_namespaceObject.createContext({});
42
+ const InputGroup = /*#__PURE__*/ external_react_namespaceObject.forwardRef(({ className, error, errorId, variant = 'default', size = 'default', ...props }, ref)=>{
43
+ const generatedId = external_react_namespaceObject.useId();
44
+ const validationId = errorId ?? `input-group-${generatedId.replace(/:/g, '')}-error`;
45
+ return /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsxs)(InputGroupValidationContext.Provider, {
46
+ value: {
47
+ error,
48
+ errorId: validationId
49
+ },
50
+ children: [
51
+ /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)("div", {
52
+ ref: ref,
53
+ role: "group",
54
+ className: (0, index_cjs_namespaceObject.cn)('group/input-group relative flex w-full items-center gap-2 transition-colors has-[>textarea]:h-auto has-[>textarea]:items-start', 'default' === size && 'h-9 rounded-md px-3 py-1 future:h-10 future:rounded-xl future:py-2', 'xs' === size && 'h-6 gap-1 rounded px-2', 'default' === variant && 'border border-input bg-transparent future:border-0 future:bg-surface-overlay', 'ghost' === variant && 'border-0 bg-surface-overlay', 'has-[[data-slot=input-group-control]:focus-visible]:ring-2 has-[[data-slot=input-group-control]:focus-visible]:ring-ring future:has-[[data-slot=input-group-control]:focus-visible]:ring-offset-2 future:has-[[data-slot=input-group-control]:focus-visible]:ring-offset-background', 'has-[[data-slot][aria-invalid=true]]:border-error has-[[data-slot][aria-invalid=true]]:ring-error/20 future:has-[[data-slot][aria-invalid=true]]:ring-1 future:has-[[data-slot][aria-invalid=true]]:ring-error/40', error && 'border-error ring-error/20 future:ring-1 future:ring-error/40', 'has-[[data-slot=input-group-control]:disabled]:cursor-not-allowed has-[[data-slot=input-group-control]:disabled]:opacity-50', className),
55
+ ...props
56
+ }),
57
+ error && /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)("p", {
58
+ id: validationId,
59
+ "data-slot": "input-group-error",
60
+ "aria-live": "polite",
61
+ "aria-atomic": "true",
62
+ className: "mt-1 text-xs leading-4 text-error",
63
+ children: error
64
+ })
65
+ ]
66
+ });
67
+ });
47
68
  InputGroup.displayName = 'InputGroup';
48
69
  const inputGroupAddonVariants = (0, external_class_variance_authority_namespaceObject.cva)('flex h-auto cursor-text items-center justify-center gap-1 text-sm text-muted-foreground select-none group-has-[[data-slot=input-group-control]:disabled]/input-group:opacity-50 [&>svg:not([class*="size-"])]:size-4', {
49
70
  variants: {
@@ -86,19 +107,42 @@ const InputGroupText = /*#__PURE__*/ external_react_namespaceObject.forwardRef((
86
107
  ...props
87
108
  }));
88
109
  InputGroupText.displayName = 'InputGroupText';
89
- const InputGroupInput = /*#__PURE__*/ external_react_namespaceObject.forwardRef(({ className, ...props }, ref)=>/*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(external_input_cjs_namespaceObject.Input, {
90
- ref: ref,
91
- "data-slot": "input-group-control",
92
- className: (0, index_cjs_namespaceObject.cn)('h-full flex-1 rounded-none border-0 bg-transparent p-0 shadow-none focus-visible:ring-0 focus-visible:ring-offset-0 future:h-full future:rounded-none future:border-0 future:bg-transparent future:p-0 future:focus-visible:ring-offset-0', className),
93
- ...props
94
- }));
110
+ const InputGroupInput = /*#__PURE__*/ external_react_namespaceObject.forwardRef(({ 'aria-describedby': ariaDescribedBy, 'aria-errormessage': ariaErrorMessage, 'aria-invalid': ariaInvalid, className, ...props }, ref)=>{
111
+ const validation = external_react_namespaceObject.useContext(InputGroupValidationContext);
112
+ const describedBy = [
113
+ ariaDescribedBy,
114
+ validation.error ? validation.errorId : void 0
115
+ ].filter(Boolean).join(' ');
116
+ return /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)("div", {
117
+ className: "min-w-0 flex-1",
118
+ children: /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(external_input_cjs_namespaceObject.Input, {
119
+ ref: ref,
120
+ "data-slot": "input-group-control",
121
+ "aria-describedby": describedBy || void 0,
122
+ "aria-errormessage": validation.error ? validation.errorId : ariaErrorMessage,
123
+ "aria-invalid": validation.error ? true : ariaInvalid,
124
+ className: (0, index_cjs_namespaceObject.cn)('h-full w-full rounded-none !border-0 !ring-0 bg-transparent p-0 shadow-none focus-visible:ring-0 focus-visible:ring-offset-0 future:h-full future:rounded-none future:border-0 future:bg-transparent future:p-0 future:focus-visible:ring-offset-0', className),
125
+ ...props
126
+ })
127
+ });
128
+ });
95
129
  InputGroupInput.displayName = 'InputGroupInput';
96
- const InputGroupTextarea = /*#__PURE__*/ external_react_namespaceObject.forwardRef(({ className, ...props }, ref)=>/*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(external_textarea_cjs_namespaceObject.Textarea, {
130
+ const InputGroupTextarea = /*#__PURE__*/ external_react_namespaceObject.forwardRef(({ 'aria-describedby': ariaDescribedBy, 'aria-errormessage': ariaErrorMessage, 'aria-invalid': ariaInvalid, className, ...props }, ref)=>{
131
+ const validation = external_react_namespaceObject.useContext(InputGroupValidationContext);
132
+ const describedBy = [
133
+ ariaDescribedBy,
134
+ validation.error ? validation.errorId : void 0
135
+ ].filter(Boolean).join(' ');
136
+ return /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(external_textarea_cjs_namespaceObject.Textarea, {
97
137
  ref: ref,
98
138
  "data-slot": "input-group-control",
99
- className: (0, index_cjs_namespaceObject.cn)('min-h-0 flex-1 resize-none rounded-none border-0 bg-transparent p-0 py-2 shadow-none focus-visible:ring-0 focus-visible:ring-offset-0 future:rounded-none future:border-0 future:bg-transparent future:focus-visible:ring-offset-0', className),
139
+ "aria-describedby": describedBy || void 0,
140
+ "aria-errormessage": validation.error ? validation.errorId : ariaErrorMessage,
141
+ "aria-invalid": validation.error ? true : ariaInvalid,
142
+ className: (0, index_cjs_namespaceObject.cn)('min-h-0 flex-1 resize-none rounded-none !border-0 !ring-0 bg-transparent p-0 py-2 shadow-none focus-visible:ring-0 focus-visible:ring-offset-0 future:rounded-none future:border-0 future:bg-transparent future:focus-visible:ring-offset-0', className),
100
143
  ...props
101
- }));
144
+ });
145
+ });
102
146
  InputGroupTextarea.displayName = 'InputGroupTextarea';
103
147
  exports.InputGroup = __webpack_exports__.InputGroup;
104
148
  exports.InputGroupAddon = __webpack_exports__.InputGroupAddon;
@@ -6,6 +6,10 @@ import { type TextareaProps } from './textarea';
6
6
  export interface InputGroupProps extends React.HTMLAttributes<HTMLDivElement> {
7
7
  variant?: 'default' | 'ghost';
8
8
  size?: 'default' | 'xs';
9
+ /** Field-specific validation feedback rendered below the grouped control. */
10
+ error?: React.ReactNode;
11
+ /** Optional id for the inline validation message. */
12
+ errorId?: string;
9
13
  }
10
14
  declare const InputGroup: React.ForwardRefExoticComponent<InputGroupProps & React.RefAttributes<HTMLDivElement>>;
11
15
  declare const inputGroupAddonVariants: (props?: ({
@@ -20,7 +24,7 @@ declare const InputGroupButton: React.ForwardRefExoticComponent<InputGroupButton
20
24
  export interface InputGroupTextProps extends React.HTMLAttributes<HTMLSpanElement> {
21
25
  }
22
26
  declare const InputGroupText: React.ForwardRefExoticComponent<InputGroupTextProps & React.RefAttributes<HTMLSpanElement>>;
23
- export interface InputGroupInputProps extends Omit<InputProps, 'variant' | 'size'> {
27
+ export interface InputGroupInputProps extends Omit<InputProps, 'variant' | 'size' | 'error' | 'errorId'> {
24
28
  }
25
29
  declare const InputGroupInput: React.ForwardRefExoticComponent<InputGroupInputProps & React.RefAttributes<HTMLInputElement>>;
26
30
  export interface InputGroupTextareaProps extends Omit<TextareaProps, 'variant'> {
@@ -1,16 +1,37 @@
1
- import { jsx } from "react/jsx-runtime";
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
2
  import { cva } from "class-variance-authority";
3
- import { forwardRef } from "react";
3
+ import { createContext, forwardRef, useContext, useId } from "react";
4
4
  import { Button } from "./button.js";
5
5
  import { Input } from "./input.js";
6
6
  import { Textarea } from "./textarea.js";
7
7
  import { cn } from "../../lib/index.js";
8
- const InputGroup = /*#__PURE__*/ forwardRef(({ className, variant = 'default', size = 'default', ...props }, ref)=>/*#__PURE__*/ jsx("div", {
9
- ref: ref,
10
- role: "group",
11
- className: cn('group/input-group relative flex w-full items-center gap-2 transition-colors has-[>textarea]:h-auto has-[>textarea]:items-start', 'default' === size && 'h-9 rounded-md px-3 py-1 future:h-10 future:rounded-xl future:py-2', 'xs' === size && 'h-6 gap-1 rounded px-2', 'default' === variant && 'border border-input bg-transparent future:border-0 future:bg-surface-overlay', 'ghost' === variant && 'border-0 bg-surface-overlay', 'has-[[data-slot=input-group-control]:focus-visible]:ring-2 has-[[data-slot=input-group-control]:focus-visible]:ring-ring future:has-[[data-slot=input-group-control]:focus-visible]:ring-offset-2 future:has-[[data-slot=input-group-control]:focus-visible]:ring-offset-background', 'has-[[data-slot][aria-invalid=true]]:border-destructive has-[[data-slot][aria-invalid=true]]:ring-destructive/20', 'has-[[data-slot=input-group-control]:disabled]:cursor-not-allowed has-[[data-slot=input-group-control]:disabled]:opacity-50', className),
12
- ...props
13
- }));
8
+ const InputGroupValidationContext = /*#__PURE__*/ createContext({});
9
+ const InputGroup = /*#__PURE__*/ forwardRef(({ className, error, errorId, variant = 'default', size = 'default', ...props }, ref)=>{
10
+ const generatedId = useId();
11
+ const validationId = errorId ?? `input-group-${generatedId.replace(/:/g, '')}-error`;
12
+ return /*#__PURE__*/ jsxs(InputGroupValidationContext.Provider, {
13
+ value: {
14
+ error,
15
+ errorId: validationId
16
+ },
17
+ children: [
18
+ /*#__PURE__*/ jsx("div", {
19
+ ref: ref,
20
+ role: "group",
21
+ className: cn('group/input-group relative flex w-full items-center gap-2 transition-colors has-[>textarea]:h-auto has-[>textarea]:items-start', 'default' === size && 'h-9 rounded-md px-3 py-1 future:h-10 future:rounded-xl future:py-2', 'xs' === size && 'h-6 gap-1 rounded px-2', 'default' === variant && 'border border-input bg-transparent future:border-0 future:bg-surface-overlay', 'ghost' === variant && 'border-0 bg-surface-overlay', 'has-[[data-slot=input-group-control]:focus-visible]:ring-2 has-[[data-slot=input-group-control]:focus-visible]:ring-ring future:has-[[data-slot=input-group-control]:focus-visible]:ring-offset-2 future:has-[[data-slot=input-group-control]:focus-visible]:ring-offset-background', 'has-[[data-slot][aria-invalid=true]]:border-error has-[[data-slot][aria-invalid=true]]:ring-error/20 future:has-[[data-slot][aria-invalid=true]]:ring-1 future:has-[[data-slot][aria-invalid=true]]:ring-error/40', error && 'border-error ring-error/20 future:ring-1 future:ring-error/40', 'has-[[data-slot=input-group-control]:disabled]:cursor-not-allowed has-[[data-slot=input-group-control]:disabled]:opacity-50', className),
22
+ ...props
23
+ }),
24
+ error && /*#__PURE__*/ jsx("p", {
25
+ id: validationId,
26
+ "data-slot": "input-group-error",
27
+ "aria-live": "polite",
28
+ "aria-atomic": "true",
29
+ className: "mt-1 text-xs leading-4 text-error",
30
+ children: error
31
+ })
32
+ ]
33
+ });
34
+ });
14
35
  InputGroup.displayName = 'InputGroup';
15
36
  const inputGroupAddonVariants = cva('flex h-auto cursor-text items-center justify-center gap-1 text-sm text-muted-foreground select-none group-has-[[data-slot=input-group-control]:disabled]/input-group:opacity-50 [&>svg:not([class*="size-"])]:size-4', {
16
37
  variants: {
@@ -53,18 +74,41 @@ const InputGroupText = /*#__PURE__*/ forwardRef(({ className, ...props }, ref)=>
53
74
  ...props
54
75
  }));
55
76
  InputGroupText.displayName = 'InputGroupText';
56
- const InputGroupInput = /*#__PURE__*/ forwardRef(({ className, ...props }, ref)=>/*#__PURE__*/ jsx(Input, {
57
- ref: ref,
58
- "data-slot": "input-group-control",
59
- className: cn('h-full flex-1 rounded-none border-0 bg-transparent p-0 shadow-none focus-visible:ring-0 focus-visible:ring-offset-0 future:h-full future:rounded-none future:border-0 future:bg-transparent future:p-0 future:focus-visible:ring-offset-0', className),
60
- ...props
61
- }));
77
+ const InputGroupInput = /*#__PURE__*/ forwardRef(({ 'aria-describedby': ariaDescribedBy, 'aria-errormessage': ariaErrorMessage, 'aria-invalid': ariaInvalid, className, ...props }, ref)=>{
78
+ const validation = useContext(InputGroupValidationContext);
79
+ const describedBy = [
80
+ ariaDescribedBy,
81
+ validation.error ? validation.errorId : void 0
82
+ ].filter(Boolean).join(' ');
83
+ return /*#__PURE__*/ jsx("div", {
84
+ className: "min-w-0 flex-1",
85
+ children: /*#__PURE__*/ jsx(Input, {
86
+ ref: ref,
87
+ "data-slot": "input-group-control",
88
+ "aria-describedby": describedBy || void 0,
89
+ "aria-errormessage": validation.error ? validation.errorId : ariaErrorMessage,
90
+ "aria-invalid": validation.error ? true : ariaInvalid,
91
+ className: cn('h-full w-full rounded-none !border-0 !ring-0 bg-transparent p-0 shadow-none focus-visible:ring-0 focus-visible:ring-offset-0 future:h-full future:rounded-none future:border-0 future:bg-transparent future:p-0 future:focus-visible:ring-offset-0', className),
92
+ ...props
93
+ })
94
+ });
95
+ });
62
96
  InputGroupInput.displayName = 'InputGroupInput';
63
- const InputGroupTextarea = /*#__PURE__*/ forwardRef(({ className, ...props }, ref)=>/*#__PURE__*/ jsx(Textarea, {
97
+ const InputGroupTextarea = /*#__PURE__*/ forwardRef(({ 'aria-describedby': ariaDescribedBy, 'aria-errormessage': ariaErrorMessage, 'aria-invalid': ariaInvalid, className, ...props }, ref)=>{
98
+ const validation = useContext(InputGroupValidationContext);
99
+ const describedBy = [
100
+ ariaDescribedBy,
101
+ validation.error ? validation.errorId : void 0
102
+ ].filter(Boolean).join(' ');
103
+ return /*#__PURE__*/ jsx(Textarea, {
64
104
  ref: ref,
65
105
  "data-slot": "input-group-control",
66
- className: cn('min-h-0 flex-1 resize-none rounded-none border-0 bg-transparent p-0 py-2 shadow-none focus-visible:ring-0 focus-visible:ring-offset-0 future:rounded-none future:border-0 future:bg-transparent future:focus-visible:ring-offset-0', className),
106
+ "aria-describedby": describedBy || void 0,
107
+ "aria-errormessage": validation.error ? validation.errorId : ariaErrorMessage,
108
+ "aria-invalid": validation.error ? true : ariaInvalid,
109
+ className: cn('min-h-0 flex-1 resize-none rounded-none !border-0 !ring-0 bg-transparent p-0 py-2 shadow-none focus-visible:ring-0 focus-visible:ring-offset-0 future:rounded-none future:border-0 future:bg-transparent future:focus-visible:ring-offset-0', className),
67
110
  ...props
68
- }));
111
+ });
112
+ });
69
113
  InputGroupTextarea.displayName = 'InputGroupTextarea';
70
114
  export { InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput, InputGroupText, InputGroupTextarea };
@@ -29,13 +29,37 @@ __webpack_require__.d(__webpack_exports__, {
29
29
  const jsx_runtime_namespaceObject = require("react/jsx-runtime");
30
30
  const external_react_namespaceObject = require("react");
31
31
  const utils_cjs_namespaceObject = require("../../lib/utils.cjs");
32
- const Input = /*#__PURE__*/ external_react_namespaceObject.forwardRef(({ className, type, variant = 'default', size = 'default', ...props }, ref)=>/*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)("input", {
33
- type: type,
34
- "data-slot": "input",
35
- className: (0, utils_cjs_namespaceObject.cn)('flex w-full transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50', 'default' === size && 'h-9 rounded-md px-3 py-1 text-base placeholder:text-muted-foreground md:text-sm', 'xs' === size && 'h-6 rounded px-2 text-xs placeholder:text-muted-foreground', 'default' === variant && 'border border-input bg-transparent', 'ghost' === variant && 'border-0 bg-surface-overlay', 'default' === variant && 'default' === size && 'future:h-10 future:rounded-xl future:border-0 future:bg-surface-overlay future:py-2 future:text-sm future:placeholder:text-foreground-muted future:placeholder:font-normal future:focus-visible:ring-offset-2 future:focus-visible:ring-offset-background', className),
36
- ref: ref,
37
- ...props
38
- }));
32
+ const Input = /*#__PURE__*/ external_react_namespaceObject.forwardRef(({ 'aria-describedby': ariaDescribedBy, 'aria-errormessage': ariaErrorMessage, 'aria-invalid': ariaInvalid, className, error, errorId, id, type, variant = 'default', size = 'default', ...props }, ref)=>{
33
+ const generatedId = external_react_namespaceObject.useId();
34
+ const validationId = errorId ?? `${id ?? `input-${generatedId.replace(/:/g, '')}`}-error`;
35
+ const describedBy = [
36
+ ariaDescribedBy,
37
+ error ? validationId : void 0
38
+ ].filter(Boolean).join(' ');
39
+ return /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsxs)(jsx_runtime_namespaceObject.Fragment, {
40
+ children: [
41
+ /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)("input", {
42
+ type: type,
43
+ "data-slot": "input",
44
+ id: id,
45
+ ...props,
46
+ "aria-describedby": describedBy || void 0,
47
+ "aria-errormessage": error ? validationId : ariaErrorMessage,
48
+ "aria-invalid": error ? true : ariaInvalid,
49
+ className: (0, utils_cjs_namespaceObject.cn)('flex w-full transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-error aria-invalid:focus-visible:ring-error', 'default' === size && 'h-9 rounded-md px-3 py-1 text-base placeholder:text-muted-foreground md:text-sm', 'xs' === size && 'h-6 rounded px-2 text-xs placeholder:text-muted-foreground', 'default' === variant && 'border border-input bg-transparent', 'ghost' === variant && 'border-0 bg-surface-overlay', 'default' === variant && 'default' === size && 'future:h-10 future:rounded-xl future:border-0 future:bg-surface-overlay future:py-2 future:text-sm future:placeholder:text-foreground-muted future:placeholder:font-normal future:focus-visible:ring-offset-2 future:focus-visible:ring-offset-background future:aria-invalid:ring-1 future:aria-invalid:ring-error/40', className),
50
+ ref: ref
51
+ }),
52
+ error && /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)("p", {
53
+ id: validationId,
54
+ "data-slot": "input-error",
55
+ "aria-live": "polite",
56
+ "aria-atomic": "true",
57
+ className: "mt-1 text-xs leading-4 text-error",
58
+ children: error
59
+ })
60
+ ]
61
+ });
62
+ });
39
63
  Input.displayName = 'Input';
40
64
  exports.Input = __webpack_exports__.Input;
41
65
  for(var __rspack_i in __webpack_exports__)if (-1 === [
@@ -2,6 +2,13 @@ import * as React from 'react';
2
2
  export interface InputProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'size'> {
3
3
  variant?: 'default' | 'ghost';
4
4
  size?: 'default' | 'xs';
5
+ /**
6
+ * Field-specific feedback rendered immediately below the input.
7
+ * Keep the message focused on what went wrong and how to resolve it.
8
+ */
9
+ error?: React.ReactNode;
10
+ /** Optional id for the inline validation message. */
11
+ errorId?: string;
5
12
  }
6
13
  declare const Input: React.ForwardRefExoticComponent<InputProps & React.RefAttributes<HTMLInputElement>>;
7
14
  export { Input };
@@ -1,12 +1,36 @@
1
- import { jsx } from "react/jsx-runtime";
2
- import { forwardRef } from "react";
1
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
2
+ import { forwardRef, useId } from "react";
3
3
  import { cn } from "../../lib/utils.js";
4
- const Input = /*#__PURE__*/ forwardRef(({ className, type, variant = 'default', size = 'default', ...props }, ref)=>/*#__PURE__*/ jsx("input", {
5
- type: type,
6
- "data-slot": "input",
7
- className: cn('flex w-full transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50', 'default' === size && 'h-9 rounded-md px-3 py-1 text-base placeholder:text-muted-foreground md:text-sm', 'xs' === size && 'h-6 rounded px-2 text-xs placeholder:text-muted-foreground', 'default' === variant && 'border border-input bg-transparent', 'ghost' === variant && 'border-0 bg-surface-overlay', 'default' === variant && 'default' === size && 'future:h-10 future:rounded-xl future:border-0 future:bg-surface-overlay future:py-2 future:text-sm future:placeholder:text-foreground-muted future:placeholder:font-normal future:focus-visible:ring-offset-2 future:focus-visible:ring-offset-background', className),
8
- ref: ref,
9
- ...props
10
- }));
4
+ const Input = /*#__PURE__*/ forwardRef(({ 'aria-describedby': ariaDescribedBy, 'aria-errormessage': ariaErrorMessage, 'aria-invalid': ariaInvalid, className, error, errorId, id, type, variant = 'default', size = 'default', ...props }, ref)=>{
5
+ const generatedId = useId();
6
+ const validationId = errorId ?? `${id ?? `input-${generatedId.replace(/:/g, '')}`}-error`;
7
+ const describedBy = [
8
+ ariaDescribedBy,
9
+ error ? validationId : void 0
10
+ ].filter(Boolean).join(' ');
11
+ return /*#__PURE__*/ jsxs(Fragment, {
12
+ children: [
13
+ /*#__PURE__*/ jsx("input", {
14
+ type: type,
15
+ "data-slot": "input",
16
+ id: id,
17
+ ...props,
18
+ "aria-describedby": describedBy || void 0,
19
+ "aria-errormessage": error ? validationId : ariaErrorMessage,
20
+ "aria-invalid": error ? true : ariaInvalid,
21
+ className: cn('flex w-full transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-error aria-invalid:focus-visible:ring-error', 'default' === size && 'h-9 rounded-md px-3 py-1 text-base placeholder:text-muted-foreground md:text-sm', 'xs' === size && 'h-6 rounded px-2 text-xs placeholder:text-muted-foreground', 'default' === variant && 'border border-input bg-transparent', 'ghost' === variant && 'border-0 bg-surface-overlay', 'default' === variant && 'default' === size && 'future:h-10 future:rounded-xl future:border-0 future:bg-surface-overlay future:py-2 future:text-sm future:placeholder:text-foreground-muted future:placeholder:font-normal future:focus-visible:ring-offset-2 future:focus-visible:ring-offset-background future:aria-invalid:ring-1 future:aria-invalid:ring-error/40', className),
22
+ ref: ref
23
+ }),
24
+ error && /*#__PURE__*/ jsx("p", {
25
+ id: validationId,
26
+ "data-slot": "input-error",
27
+ "aria-live": "polite",
28
+ "aria-atomic": "true",
29
+ className: "mt-1 text-xs leading-4 text-error",
30
+ children: error
31
+ })
32
+ ]
33
+ });
34
+ });
11
35
  Input.displayName = 'Input';
12
36
  export { Input };
@@ -44,11 +44,12 @@ const lock_toggle_button_cjs_namespaceObject = require("./components/lock-toggle
44
44
  const mode_menu_item_cjs_namespaceObject = require("./components/mode-menu-item.cjs");
45
45
  const external_types_cjs_namespaceObject = require("./types.cjs");
46
46
  const external_utils_cjs_namespaceObject = require("./utils.cjs");
47
- function LockableValueField({ value = '', onValueChange, onValueBlur, locked = true, onLockedChange, mode = 'fixed', onModeChange, renderExpressionEditor, fieldType = 'string', onFieldTypeChange, required, onRequiredChange, label, fileUploadAriaLabel, headerActions, compact, controlsVisibility = 'visible', showFieldActions = true, options = external_utils_cjs_namespaceObject.DEFAULT_SELECT_OPTIONS, onGenerateWithAi, variables = [], id, className }) {
48
- const generatedId = (0, external_react_namespaceObject.useId)();
47
+ function LockableValueField({ value = '', onValueChange, onValueBlur, locked = true, onLockedChange, mode = 'fixed', onModeChange, renderExpressionEditor, fieldType = 'string', onFieldTypeChange, required, onRequiredChange, label, error, errorId, fileUploadAriaLabel, headerActions, compact, controlsVisibility = 'visible', showFieldActions = true, options = external_utils_cjs_namespaceObject.DEFAULT_SELECT_OPTIONS, onGenerateWithAi, variables = [], id, className }) {
48
+ const generatedId = (0, external_react_namespaceObject.useId)().replace(/:/g, '');
49
49
  const [datePopoverOpen, setDatePopoverOpen] = (0, external_react_namespaceObject.useState)(false);
50
50
  const [selectOpen, setSelectOpen] = (0, external_react_namespaceObject.useState)(false);
51
51
  const fieldId = id ?? generatedId;
52
+ const validationId = errorId ?? `${fieldId}-error`;
52
53
  const typeMeta = external_types_cjs_namespaceObject.FIELD_TYPE_META[fieldType];
53
54
  const effectiveMode = typeMeta.supportsExpression ? mode : 'fixed';
54
55
  const editableOnValueChange = locked ? void 0 : onValueChange;
@@ -77,6 +78,8 @@ function LockableValueField({ value = '', onValueChange, onValueBlur, locked = t
77
78
  headerActions: headerActions
78
79
  }),
79
80
  typeMeta.supportsExpression ? /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsxs)(external_input_group_cjs_namespaceObject.InputGroup, {
81
+ error: error,
82
+ errorId: validationId,
80
83
  children: [
81
84
  /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(external_input_group_cjs_namespaceObject.InputGroupAddon, {
82
85
  align: "inline-start",
@@ -92,7 +95,11 @@ function LockableValueField({ value = '', onValueChange, onValueBlur, locked = t
92
95
  onBlur: onValueBlur,
93
96
  readOnly: !editableOnValueChange,
94
97
  placeholder: fieldLabel,
95
- fieldType
98
+ fieldType,
99
+ 'aria-invalid': error ? true : void 0,
100
+ 'aria-describedby': error ? validationId : void 0,
101
+ 'aria-errormessage': error ? validationId : void 0,
102
+ 'data-slot': 'input-group-control'
96
103
  }) : /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(external_input_group_cjs_namespaceObject.InputGroupInput, {
97
104
  id: fieldId,
98
105
  readOnly: !editableOnValueChange,
@@ -111,6 +118,9 @@ function LockableValueField({ value = '', onValueChange, onValueBlur, locked = t
111
118
  className: "flex h-full flex-1 items-center px-3",
112
119
  children: /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(external_switch_cjs_namespaceObject.Switch, {
113
120
  id: fieldId,
121
+ "aria-invalid": error ? true : void 0,
122
+ "aria-describedby": error ? validationId : void 0,
123
+ "aria-errormessage": error ? validationId : void 0,
114
124
  checked: 'true' === value,
115
125
  onCheckedChange: (checked)=>onValueChange?.(String(checked)),
116
126
  onBlur: onValueBlur,
@@ -129,6 +139,9 @@ function LockableValueField({ value = '', onValueChange, onValueBlur, locked = t
129
139
  type: "button",
130
140
  id: fieldId,
131
141
  "data-slot": "input-group-control",
142
+ "aria-invalid": error ? true : void 0,
143
+ "aria-describedby": error ? validationId : void 0,
144
+ "aria-errormessage": error ? validationId : void 0,
132
145
  disabled: !onValueChange,
133
146
  className: "flex h-full flex-1 items-center text-left text-sm text-foreground outline-none disabled:cursor-not-allowed disabled:opacity-50",
134
147
  children: value ? (0, external_utils_cjs_namespaceObject.formatDateValue)(value) : /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)("span", {
@@ -204,6 +217,9 @@ function LockableValueField({ value = '', onValueChange, onValueBlur, locked = t
204
217
  }),
205
218
  locked ? /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(external_input_cjs_namespaceObject.Input, {
206
219
  id: fieldId,
220
+ "aria-invalid": error ? true : void 0,
221
+ "aria-describedby": error ? validationId : void 0,
222
+ "aria-errormessage": error ? validationId : void 0,
207
223
  readOnly: true,
208
224
  value: lockedDisplayValue,
209
225
  placeholder: fieldLabel,
@@ -222,6 +238,9 @@ function LockableValueField({ value = '', onValueChange, onValueBlur, locked = t
222
238
  /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(external_select_cjs_namespaceObject.SelectTrigger, {
223
239
  id: fieldId,
224
240
  className: "flex-1",
241
+ "aria-invalid": error ? true : void 0,
242
+ "aria-describedby": error ? validationId : void 0,
243
+ "aria-errormessage": error ? validationId : void 0,
225
244
  children: /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(external_select_cjs_namespaceObject.SelectValue, {
226
245
  placeholder: "Select an option"
227
246
  })
@@ -241,16 +260,30 @@ function LockableValueField({ value = '', onValueChange, onValueBlur, locked = t
241
260
  onChange: (selected)=>onValueChange?.(JSON.stringify(selected)),
242
261
  placeholder: "Select options...",
243
262
  disabled: !onValueChange,
244
- onBlur: onValueBlur
263
+ onBlur: onValueBlur,
264
+ "aria-invalid": error ? true : void 0,
265
+ "aria-describedby": error ? validationId : void 0,
266
+ "aria-errormessage": error ? validationId : void 0
245
267
  }) : 'file' === fieldType && /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(external_file_upload_cjs_namespaceObject.FileUpload, {
246
268
  id: fieldId,
247
269
  ariaLabel: fileUploadAriaLabel ?? ('string' == typeof label ? label : fieldLabel),
248
270
  className: "flex-1",
249
271
  onFilesChange: (files)=>onValueChange?.(files.map((f)=>f.name).join(', ')),
250
272
  disabled: !onValueChange,
251
- onBlur: onValueBlur
273
+ onBlur: onValueBlur,
274
+ "aria-invalid": error ? true : void 0,
275
+ "aria-describedby": error ? validationId : void 0,
276
+ "aria-errormessage": error ? validationId : void 0
252
277
  })
253
278
  ]
279
+ }),
280
+ error && !typeMeta.supportsExpression && /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)("p", {
281
+ id: validationId,
282
+ "data-slot": "lockable-value-field-error",
283
+ "aria-live": "polite",
284
+ "aria-atomic": "true",
285
+ className: "mt-1 text-xs leading-4 text-error",
286
+ children: error
254
287
  })
255
288
  ]
256
289
  });
@@ -11,4 +11,4 @@ import type { LockableValueFieldProps } from './types';
11
11
  * Insert-variable menu is empty (and disabled) unless `variables` is
12
12
  * provided; file uploads aren't persisted anywhere.
13
13
  */
14
- export declare function LockableValueField({ value, onValueChange, onValueBlur, locked, onLockedChange, mode, onModeChange, renderExpressionEditor, fieldType, onFieldTypeChange, required, onRequiredChange, label, fileUploadAriaLabel, headerActions, compact, controlsVisibility, showFieldActions, options, onGenerateWithAi, variables, id, className, }: LockableValueFieldProps): import("react/jsx-runtime").JSX.Element;
14
+ export declare function LockableValueField({ value, onValueChange, onValueBlur, locked, onLockedChange, mode, onModeChange, renderExpressionEditor, fieldType, onFieldTypeChange, required, onRequiredChange, label, error, errorId, fileUploadAriaLabel, headerActions, compact, controlsVisibility, showFieldActions, options, onGenerateWithAi, variables, id, className, }: LockableValueFieldProps): import("react/jsx-runtime").JSX.Element;
@@ -16,11 +16,12 @@ import { LockToggleButton } from "./components/lock-toggle-button.js";
16
16
  import { ModeMenuItem } from "./components/mode-menu-item.js";
17
17
  import { FIELD_TYPE_META } from "./types.js";
18
18
  import { DEFAULT_SELECT_OPTIONS, formatDateValue, getLockedDisplayValue, parseDateValue, parseListValue, toDateOnlyString } from "./utils.js";
19
- function LockableValueField({ value = '', onValueChange, onValueBlur, locked = true, onLockedChange, mode = 'fixed', onModeChange, renderExpressionEditor, fieldType = 'string', onFieldTypeChange, required, onRequiredChange, label, fileUploadAriaLabel, headerActions, compact, controlsVisibility = 'visible', showFieldActions = true, options = DEFAULT_SELECT_OPTIONS, onGenerateWithAi, variables = [], id, className }) {
20
- const generatedId = useId();
19
+ function LockableValueField({ value = '', onValueChange, onValueBlur, locked = true, onLockedChange, mode = 'fixed', onModeChange, renderExpressionEditor, fieldType = 'string', onFieldTypeChange, required, onRequiredChange, label, error, errorId, fileUploadAriaLabel, headerActions, compact, controlsVisibility = 'visible', showFieldActions = true, options = DEFAULT_SELECT_OPTIONS, onGenerateWithAi, variables = [], id, className }) {
20
+ const generatedId = useId().replace(/:/g, '');
21
21
  const [datePopoverOpen, setDatePopoverOpen] = useState(false);
22
22
  const [selectOpen, setSelectOpen] = useState(false);
23
23
  const fieldId = id ?? generatedId;
24
+ const validationId = errorId ?? `${fieldId}-error`;
24
25
  const typeMeta = FIELD_TYPE_META[fieldType];
25
26
  const effectiveMode = typeMeta.supportsExpression ? mode : 'fixed';
26
27
  const editableOnValueChange = locked ? void 0 : onValueChange;
@@ -49,6 +50,8 @@ function LockableValueField({ value = '', onValueChange, onValueBlur, locked = t
49
50
  headerActions: headerActions
50
51
  }),
51
52
  typeMeta.supportsExpression ? /*#__PURE__*/ jsxs(InputGroup, {
53
+ error: error,
54
+ errorId: validationId,
52
55
  children: [
53
56
  /*#__PURE__*/ jsx(InputGroupAddon, {
54
57
  align: "inline-start",
@@ -64,7 +67,11 @@ function LockableValueField({ value = '', onValueChange, onValueBlur, locked = t
64
67
  onBlur: onValueBlur,
65
68
  readOnly: !editableOnValueChange,
66
69
  placeholder: fieldLabel,
67
- fieldType
70
+ fieldType,
71
+ 'aria-invalid': error ? true : void 0,
72
+ 'aria-describedby': error ? validationId : void 0,
73
+ 'aria-errormessage': error ? validationId : void 0,
74
+ 'data-slot': 'input-group-control'
68
75
  }) : /*#__PURE__*/ jsx(InputGroupInput, {
69
76
  id: fieldId,
70
77
  readOnly: !editableOnValueChange,
@@ -83,6 +90,9 @@ function LockableValueField({ value = '', onValueChange, onValueBlur, locked = t
83
90
  className: "flex h-full flex-1 items-center px-3",
84
91
  children: /*#__PURE__*/ jsx(Switch, {
85
92
  id: fieldId,
93
+ "aria-invalid": error ? true : void 0,
94
+ "aria-describedby": error ? validationId : void 0,
95
+ "aria-errormessage": error ? validationId : void 0,
86
96
  checked: 'true' === value,
87
97
  onCheckedChange: (checked)=>onValueChange?.(String(checked)),
88
98
  onBlur: onValueBlur,
@@ -101,6 +111,9 @@ function LockableValueField({ value = '', onValueChange, onValueBlur, locked = t
101
111
  type: "button",
102
112
  id: fieldId,
103
113
  "data-slot": "input-group-control",
114
+ "aria-invalid": error ? true : void 0,
115
+ "aria-describedby": error ? validationId : void 0,
116
+ "aria-errormessage": error ? validationId : void 0,
104
117
  disabled: !onValueChange,
105
118
  className: "flex h-full flex-1 items-center text-left text-sm text-foreground outline-none disabled:cursor-not-allowed disabled:opacity-50",
106
119
  children: value ? formatDateValue(value) : /*#__PURE__*/ jsx("span", {
@@ -176,6 +189,9 @@ function LockableValueField({ value = '', onValueChange, onValueBlur, locked = t
176
189
  }),
177
190
  locked ? /*#__PURE__*/ jsx(Input, {
178
191
  id: fieldId,
192
+ "aria-invalid": error ? true : void 0,
193
+ "aria-describedby": error ? validationId : void 0,
194
+ "aria-errormessage": error ? validationId : void 0,
179
195
  readOnly: true,
180
196
  value: lockedDisplayValue,
181
197
  placeholder: fieldLabel,
@@ -194,6 +210,9 @@ function LockableValueField({ value = '', onValueChange, onValueBlur, locked = t
194
210
  /*#__PURE__*/ jsx(SelectTrigger, {
195
211
  id: fieldId,
196
212
  className: "flex-1",
213
+ "aria-invalid": error ? true : void 0,
214
+ "aria-describedby": error ? validationId : void 0,
215
+ "aria-errormessage": error ? validationId : void 0,
197
216
  children: /*#__PURE__*/ jsx(SelectValue, {
198
217
  placeholder: "Select an option"
199
218
  })
@@ -213,16 +232,30 @@ function LockableValueField({ value = '', onValueChange, onValueBlur, locked = t
213
232
  onChange: (selected)=>onValueChange?.(JSON.stringify(selected)),
214
233
  placeholder: "Select options...",
215
234
  disabled: !onValueChange,
216
- onBlur: onValueBlur
235
+ onBlur: onValueBlur,
236
+ "aria-invalid": error ? true : void 0,
237
+ "aria-describedby": error ? validationId : void 0,
238
+ "aria-errormessage": error ? validationId : void 0
217
239
  }) : 'file' === fieldType && /*#__PURE__*/ jsx(FileUpload, {
218
240
  id: fieldId,
219
241
  ariaLabel: fileUploadAriaLabel ?? ('string' == typeof label ? label : fieldLabel),
220
242
  className: "flex-1",
221
243
  onFilesChange: (files)=>onValueChange?.(files.map((f)=>f.name).join(', ')),
222
244
  disabled: !onValueChange,
223
- onBlur: onValueBlur
245
+ onBlur: onValueBlur,
246
+ "aria-invalid": error ? true : void 0,
247
+ "aria-describedby": error ? validationId : void 0,
248
+ "aria-errormessage": error ? validationId : void 0
224
249
  })
225
250
  ]
251
+ }),
252
+ error && !typeMeta.supportsExpression && /*#__PURE__*/ jsx("p", {
253
+ id: validationId,
254
+ "data-slot": "lockable-value-field-error",
255
+ "aria-live": "polite",
256
+ "aria-atomic": "true",
257
+ className: "mt-1 text-xs leading-4 text-error",
258
+ children: error
226
259
  })
227
260
  ]
228
261
  });
@@ -1,5 +1,5 @@
1
1
  import { type LucideIcon } from 'lucide-react';
2
- import type { ReactNode } from 'react';
2
+ import type { AriaAttributes, ReactNode } from 'react';
3
3
  export type LockableValueFieldMode = 'fixed' | 'expression';
4
4
  export type LockableFieldType = 'string' | 'integer' | 'date' | 'boolean' | 'single-select' | 'multi-select' | 'file';
5
5
  interface FieldTypeMeta {
@@ -42,6 +42,10 @@ export interface LockableValueFieldProps {
42
42
  readOnly: boolean;
43
43
  placeholder: string;
44
44
  fieldType: LockableFieldType;
45
+ 'aria-invalid'?: AriaAttributes['aria-invalid'];
46
+ 'aria-describedby'?: string;
47
+ 'aria-errormessage'?: string;
48
+ 'data-slot'?: string;
45
49
  }) => ReactNode;
46
50
  /** The field's data type. Defaults to 'string'. Determines which control renders the value. */
47
51
  fieldType?: LockableFieldType;
@@ -53,6 +57,10 @@ export interface LockableValueFieldProps {
53
57
  onRequiredChange?: (required: boolean) => void;
54
58
  /** Overrides the default mode-based label (e.g. a field name instead of "String value"). */
55
59
  label?: ReactNode;
60
+ /** Field-specific validation feedback rendered immediately below the active control. */
61
+ error?: ReactNode;
62
+ /** Optional id for the inline validation message. */
63
+ errorId?: string;
56
64
  /** Accessible name for the file-upload dropzone. Defaults to a string `label`, then the computed field label. */
57
65
  fileUploadAriaLabel?: string;
58
66
  /** Extra content rendered after the built-in AI assist / Insert variable buttons (e.g. a delete button). */
@@ -35,7 +35,7 @@ const external_checkbox_cjs_namespaceObject = require("./checkbox.cjs");
35
35
  const external_command_cjs_namespaceObject = require("./command.cjs");
36
36
  const external_popover_cjs_namespaceObject = require("./popover.cjs");
37
37
  const index_cjs_namespaceObject = require("../../lib/index.cjs");
38
- const MultiSelect = /*#__PURE__*/ external_react_namespaceObject.forwardRef(({ id, options, selected, onChange, placeholder = 'Select items...', emptyMessage = 'No items found.', className, maxSelected, disabled = false, searchPlaceholder = 'Search...', clearAllText, onBlur }, ref)=>{
38
+ const MultiSelect = /*#__PURE__*/ external_react_namespaceObject.forwardRef(({ id, options, selected, onChange, placeholder = 'Select items...', emptyMessage = 'No items found.', className, maxSelected, disabled = false, searchPlaceholder = 'Search...', clearAllText, onBlur, 'aria-invalid': ariaInvalid, 'aria-describedby': ariaDescribedBy, 'aria-errormessage': ariaErrorMessage }, ref)=>{
39
39
  const [open, setOpen] = external_react_namespaceObject.useState(false);
40
40
  const handleUnselect = (value)=>{
41
41
  onChange(selected.filter((s)=>s !== value));
@@ -71,6 +71,9 @@ const MultiSelect = /*#__PURE__*/ external_react_namespaceObject.forwardRef(({ i
71
71
  variant: "outline",
72
72
  role: "combobox",
73
73
  "aria-expanded": open,
74
+ "aria-invalid": ariaInvalid,
75
+ "aria-describedby": ariaDescribedBy,
76
+ "aria-errormessage": ariaErrorMessage,
74
77
  "aria-label": id ? void 0 : selected.length > 0 ? `${selected.length} ${1 === selected.length ? 'item' : 'items'} selected` : placeholder,
75
78
  className: (0, index_cjs_namespaceObject.cn)('w-full justify-between future:rounded-xl future:border-0 future:bg-surface-overlay future:hover:bg-surface-hover future:font-normal future:text-muted-foreground', selected.length > 0 ? 'h-auto min-h-10' : 'h-10'),
76
79
  disabled: disabled,
@@ -17,6 +17,9 @@ export interface MultiSelectProps {
17
17
  clearAllText?: string | ((count: number) => string);
18
18
  /** Called when the multi-select popover closes after being opened. */
19
19
  onBlur?: () => void;
20
+ 'aria-invalid'?: React.AriaAttributes['aria-invalid'];
21
+ 'aria-describedby'?: string;
22
+ 'aria-errormessage'?: string;
20
23
  }
21
24
  declare const MultiSelect: React.ForwardRefExoticComponent<MultiSelectProps & React.RefAttributes<HTMLDivElement>>;
22
25
  export { MultiSelect };
@@ -7,7 +7,7 @@ import { Checkbox } from "./checkbox.js";
7
7
  import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList } from "./command.js";
8
8
  import { Popover, PopoverContent, PopoverTrigger } from "./popover.js";
9
9
  import { cn } from "../../lib/index.js";
10
- const MultiSelect = /*#__PURE__*/ forwardRef(({ id, options, selected, onChange, placeholder = 'Select items...', emptyMessage = 'No items found.', className, maxSelected, disabled = false, searchPlaceholder = 'Search...', clearAllText, onBlur }, ref)=>{
10
+ const MultiSelect = /*#__PURE__*/ forwardRef(({ id, options, selected, onChange, placeholder = 'Select items...', emptyMessage = 'No items found.', className, maxSelected, disabled = false, searchPlaceholder = 'Search...', clearAllText, onBlur, 'aria-invalid': ariaInvalid, 'aria-describedby': ariaDescribedBy, 'aria-errormessage': ariaErrorMessage }, ref)=>{
11
11
  const [open, setOpen] = useState(false);
12
12
  const handleUnselect = (value)=>{
13
13
  onChange(selected.filter((s)=>s !== value));
@@ -43,6 +43,9 @@ const MultiSelect = /*#__PURE__*/ forwardRef(({ id, options, selected, onChange,
43
43
  variant: "outline",
44
44
  role: "combobox",
45
45
  "aria-expanded": open,
46
+ "aria-invalid": ariaInvalid,
47
+ "aria-describedby": ariaDescribedBy,
48
+ "aria-errormessage": ariaErrorMessage,
46
49
  "aria-label": id ? void 0 : selected.length > 0 ? `${selected.length} ${1 === selected.length ? 'item' : 'items'} selected` : placeholder,
47
50
  className: cn('w-full justify-between future:rounded-xl future:border-0 future:bg-surface-overlay future:hover:bg-surface-hover future:font-normal future:text-muted-foreground', selected.length > 0 ? 'h-auto min-h-10' : 'h-10'),
48
51
  disabled: disabled,
package/dist/styles.css CHANGED
@@ -2171,6 +2171,10 @@
2171
2171
  .rounded-bl-2xl {
2172
2172
  border-bottom-left-radius: var(--radius-2xl);
2173
2173
  }
2174
+ .\!border-0 {
2175
+ border-style: var(--tw-border-style) !important;
2176
+ border-width: 0px !important;
2177
+ }
2174
2178
  .border {
2175
2179
  border-style: var(--tw-border-style);
2176
2180
  border-width: 1px;
@@ -2291,6 +2295,9 @@
2291
2295
  border-color: color-mix(in oklab, var(--destructive) 30%, transparent);
2292
2296
  }
2293
2297
  }
2298
+ .border-error {
2299
+ border-color: var(--error);
2300
+ }
2294
2301
  .border-error\/20 {
2295
2302
  border-color: var(--error);
2296
2303
  @supports (color: color-mix(in lab, red, red)) {
@@ -4352,6 +4359,10 @@
4352
4359
  --tw-shadow: 0 1px 2px 0 var(--tw-shadow-color, rgb(0 0 0 / 0.05));
4353
4360
  box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
4354
4361
  }
4362
+ .\!ring-0 {
4363
+ --tw-ring-shadow: var(--tw-ring-inset,) 0 0 0 calc(0px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor) !important;
4364
+ box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow) !important;
4365
+ }
4355
4366
  .ring {
4356
4367
  --tw-ring-shadow: var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor);
4357
4368
  box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
@@ -4383,6 +4394,12 @@
4383
4394
  .ring-emerald-500 {
4384
4395
  --tw-ring-color: var(--color-emerald-500);
4385
4396
  }
4397
+ .ring-error\/20 {
4398
+ --tw-ring-color: var(--error);
4399
+ @supports (color: color-mix(in lab, red, red)) {
4400
+ --tw-ring-color: color-mix(in oklab, var(--error) 20%, transparent);
4401
+ }
4402
+ }
4386
4403
  .ring-primary {
4387
4404
  --tw-ring-color: var(--primary);
4388
4405
  }
@@ -5611,16 +5628,16 @@
5611
5628
  --tw-ring-color: var(--ring);
5612
5629
  }
5613
5630
  }
5614
- .has-\[\[data-slot\]\[aria-invalid\=true\]\]\:border-destructive {
5631
+ .has-\[\[data-slot\]\[aria-invalid\=true\]\]\:border-error {
5615
5632
  &:has(*:is([data-slot][aria-invalid=true])) {
5616
- border-color: var(--destructive);
5633
+ border-color: var(--error);
5617
5634
  }
5618
5635
  }
5619
- .has-\[\[data-slot\]\[aria-invalid\=true\]\]\:ring-destructive\/20 {
5636
+ .has-\[\[data-slot\]\[aria-invalid\=true\]\]\:ring-error\/20 {
5620
5637
  &:has(*:is([data-slot][aria-invalid=true])) {
5621
- --tw-ring-color: var(--destructive);
5638
+ --tw-ring-color: var(--error);
5622
5639
  @supports (color: color-mix(in lab, red, red)) {
5623
- --tw-ring-color: color-mix(in oklab, var(--destructive) 20%, transparent);
5640
+ --tw-ring-color: color-mix(in oklab, var(--error) 20%, transparent);
5624
5641
  }
5625
5642
  }
5626
5643
  }
@@ -5639,6 +5656,18 @@
5639
5656
  opacity: 50%;
5640
5657
  }
5641
5658
  }
5659
+ .aria-invalid\:border-error {
5660
+ &[aria-invalid="true"] {
5661
+ border-color: var(--error);
5662
+ }
5663
+ }
5664
+ .aria-invalid\:focus-visible\:ring-error {
5665
+ &[aria-invalid="true"] {
5666
+ &:focus-visible {
5667
+ --tw-ring-color: var(--error);
5668
+ }
5669
+ }
5670
+ }
5642
5671
  .aria-selected\:text-muted-foreground {
5643
5672
  &[aria-selected="true"] {
5644
5673
  color: var(--muted-foreground);
@@ -6475,6 +6504,20 @@
6475
6504
  box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
6476
6505
  }
6477
6506
  }
6507
+ .future\:ring-1 {
6508
+ :is(.future-dark, .future-light) & {
6509
+ --tw-ring-shadow: var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor);
6510
+ box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
6511
+ }
6512
+ }
6513
+ .future\:ring-error\/40 {
6514
+ :is(.future-dark, .future-light) & {
6515
+ --tw-ring-color: var(--error);
6516
+ @supports (color: color-mix(in lab, red, red)) {
6517
+ --tw-ring-color: color-mix(in oklab, var(--error) 40%, transparent);
6518
+ }
6519
+ }
6520
+ }
6478
6521
  .future\:placeholder\:font-normal {
6479
6522
  :is(.future-dark, .future-light) & {
6480
6523
  &::placeholder {
@@ -6581,6 +6624,42 @@
6581
6624
  }
6582
6625
  }
6583
6626
  }
6627
+ .future\:has-\[\[data-slot\]\[aria-invalid\=true\]\]\:ring-1 {
6628
+ :is(.future-dark, .future-light) & {
6629
+ &:has(*:is([data-slot][aria-invalid=true])) {
6630
+ --tw-ring-shadow: var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor);
6631
+ box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
6632
+ }
6633
+ }
6634
+ }
6635
+ .future\:has-\[\[data-slot\]\[aria-invalid\=true\]\]\:ring-error\/40 {
6636
+ :is(.future-dark, .future-light) & {
6637
+ &:has(*:is([data-slot][aria-invalid=true])) {
6638
+ --tw-ring-color: var(--error);
6639
+ @supports (color: color-mix(in lab, red, red)) {
6640
+ --tw-ring-color: color-mix(in oklab, var(--error) 40%, transparent);
6641
+ }
6642
+ }
6643
+ }
6644
+ }
6645
+ .future\:aria-invalid\:ring-1 {
6646
+ :is(.future-dark, .future-light) & {
6647
+ &[aria-invalid="true"] {
6648
+ --tw-ring-shadow: var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor);
6649
+ box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
6650
+ }
6651
+ }
6652
+ }
6653
+ .future\:aria-invalid\:ring-error\/40 {
6654
+ :is(.future-dark, .future-light) & {
6655
+ &[aria-invalid="true"] {
6656
+ --tw-ring-color: var(--error);
6657
+ @supports (color: color-mix(in lab, red, red)) {
6658
+ --tw-ring-color: color-mix(in oklab, var(--error) 40%, transparent);
6659
+ }
6660
+ }
6661
+ }
6662
+ }
6584
6663
  .future\:data-\[state\=checked\]\:border-foreground-accent {
6585
6664
  :is(.future-dark, .future-light) & {
6586
6665
  &[data-state="checked"] {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uipath/apollo-wind",
3
- "version": "2.36.2",
3
+ "version": "2.37.0",
4
4
  "description": "UiPath wind design system - A Tailwind CSS based React component library",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",