@uipath/apollo-wind 2.52.3 → 2.53.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/dist/components/forms/field-renderer.cjs +42 -3
  2. package/dist/components/forms/field-renderer.js +42 -3
  3. package/dist/components/forms/string-list-field.cjs +3 -0
  4. package/dist/components/forms/string-list-field.js +3 -0
  5. package/dist/components/ui/button.cjs +1 -1
  6. package/dist/components/ui/button.js +1 -1
  7. package/dist/components/ui/checkbox.cjs +1 -1
  8. package/dist/components/ui/checkbox.js +1 -1
  9. package/dist/components/ui/combobox.cjs +70 -51
  10. package/dist/components/ui/combobox.d.ts +12 -0
  11. package/dist/components/ui/combobox.js +72 -53
  12. package/dist/components/ui/date-picker.cjs +102 -62
  13. package/dist/components/ui/date-picker.d.ts +28 -0
  14. package/dist/components/ui/date-picker.js +103 -63
  15. package/dist/components/ui/datetime-picker.cjs +90 -72
  16. package/dist/components/ui/datetime-picker.d.ts +12 -2
  17. package/dist/components/ui/datetime-picker.js +92 -74
  18. package/dist/components/ui/file-upload.cjs +21 -8
  19. package/dist/components/ui/file-upload.d.ts +7 -0
  20. package/dist/components/ui/file-upload.js +22 -9
  21. package/dist/components/ui/form-field.cjs +3 -3
  22. package/dist/components/ui/form-field.d.ts +11 -0
  23. package/dist/components/ui/form-field.js +3 -3
  24. package/dist/components/ui/index.cjs +16 -16
  25. package/dist/components/ui/input-group.cjs +0 -2
  26. package/dist/components/ui/input-group.d.ts +1 -1
  27. package/dist/components/ui/input-group.js +0 -2
  28. package/dist/components/ui/input.cjs +0 -2
  29. package/dist/components/ui/input.js +0 -2
  30. package/dist/components/ui/lockable-value-field/lockable-value-field.cjs +1 -1
  31. package/dist/components/ui/lockable-value-field/lockable-value-field.js +1 -1
  32. package/dist/components/ui/multi-select.cjs +125 -112
  33. package/dist/components/ui/multi-select.d.ts +7 -0
  34. package/dist/components/ui/multi-select.js +126 -113
  35. package/dist/components/ui/prompt-editor/prompt-editor.cjs +0 -2
  36. package/dist/components/ui/prompt-editor/prompt-editor.js +0 -2
  37. package/dist/components/ui/radio-group.cjs +2 -2
  38. package/dist/components/ui/radio-group.js +2 -2
  39. package/dist/components/ui/search.cjs +3 -1
  40. package/dist/components/ui/search.d.ts +4 -0
  41. package/dist/components/ui/search.js +3 -1
  42. package/dist/components/ui/select.cjs +33 -12
  43. package/dist/components/ui/select.d.ts +10 -1
  44. package/dist/components/ui/select.js +35 -14
  45. package/dist/components/ui/slider.cjs +7 -2
  46. package/dist/components/ui/slider.js +7 -2
  47. package/dist/components/ui/switch.cjs +1 -1
  48. package/dist/components/ui/switch.js +1 -1
  49. package/dist/components/ui/textarea.cjs +30 -11
  50. package/dist/components/ui/textarea.d.ts +7 -0
  51. package/dist/components/ui/textarea.js +32 -13
  52. package/dist/components/ui/tooltip.cjs +1 -1
  53. package/dist/components/ui/tooltip.js +1 -1
  54. package/dist/index.cjs +4 -1
  55. package/dist/index.d.ts +5 -1
  56. package/dist/index.js +2 -2
  57. package/dist/styles.css +112 -24
  58. package/package.json +1 -1
@@ -36,8 +36,15 @@ 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, 'aria-labelledby': ariaLabelledBy, 'aria-invalid': ariaInvalid }, ref) {
39
+ const external_form_field_cjs_namespaceObject = require("./form-field.cjs");
40
+ const datetime_picker_DateTimePicker = /*#__PURE__*/ external_react_namespaceObject.forwardRef(function({ value, onValueChange, disabled, placeholder = 'Pick a date and time', className, use12Hour = false, id, error, errorId, 'aria-labelledby': ariaLabelledBy, 'aria-invalid': ariaInvalid, 'aria-describedby': ariaDescribedBy, 'aria-errormessage': ariaErrorMessage }, ref) {
40
41
  const [open, setOpen] = external_react_namespaceObject.useState(false);
42
+ const generatedId = external_react_namespaceObject.useId();
43
+ const validationId = errorId ?? `${id ?? `datetime-picker-${generatedId.replace(/:/g, '')}`}-error`;
44
+ const describedBy = [
45
+ ariaDescribedBy,
46
+ error ? validationId : void 0
47
+ ].filter(Boolean).join(' ');
41
48
  const [selectedDate, setSelectedDate] = external_react_namespaceObject.useState(value);
42
49
  const [timeValue, setTimeValue] = external_react_namespaceObject.useState(value ? (0, external_date_fns_namespaceObject.format)(value, use12Hour ? 'hh:mm a' : 'HH:mm') : '');
43
50
  const handleDateSelect = (date)=>{
@@ -67,87 +74,98 @@ const datetime_picker_DateTimePicker = /*#__PURE__*/ external_react_namespaceObj
67
74
  const timePart = (0, external_date_fns_namespaceObject.format)(selectedDate, use12Hour ? 'hh:mm a' : 'HH:mm');
68
75
  return `${datePart} at ${timePart}`;
69
76
  };
70
- return /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsxs)(external_popover_cjs_namespaceObject.Popover, {
71
- "data-slot": "datetime-picker",
72
- open: open,
73
- onOpenChange: setOpen,
77
+ return /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsxs)(jsx_runtime_namespaceObject.Fragment, {
74
78
  children: [
75
- /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(external_popover_cjs_namespaceObject.PopoverTrigger, {
76
- asChild: true,
77
- children: /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsxs)(external_button_cjs_namespaceObject.Button, {
78
- ref: ref,
79
- "aria-labelledby": ariaLabelledBy,
80
- "aria-invalid": ariaInvalid,
81
- variant: "outline",
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),
83
- disabled: disabled,
84
- children: [
85
- /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(external_lucide_react_namespaceObject.CalendarIcon, {
86
- className: "mr-2 h-4 w-4"
87
- }),
88
- selectedDate ? formatDisplayValue() : /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)("span", {
89
- className: "text-foreground-muted",
90
- children: placeholder
91
- })
92
- ]
93
- })
94
- }),
95
- /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(external_popover_cjs_namespaceObject.PopoverContent, {
96
- className: "w-auto p-0",
97
- align: "start",
98
- children: /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsxs)("div", {
99
- className: "p-3 space-y-3",
100
- children: [
101
- /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(external_calendar_cjs_namespaceObject.Calendar, {
102
- mode: "single",
103
- selected: selectedDate,
104
- onSelect: handleDateSelect,
105
- initialFocus: true
106
- }),
107
- /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsxs)("div", {
108
- className: "border-t pt-3 space-y-2",
79
+ /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsxs)(external_popover_cjs_namespaceObject.Popover, {
80
+ "data-slot": "datetime-picker",
81
+ open: open,
82
+ onOpenChange: setOpen,
83
+ children: [
84
+ /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(external_popover_cjs_namespaceObject.PopoverTrigger, {
85
+ asChild: true,
86
+ children: /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsxs)(external_button_cjs_namespaceObject.Button, {
87
+ ref: ref,
88
+ id: id,
89
+ "aria-labelledby": ariaLabelledBy,
90
+ "aria-describedby": describedBy || void 0,
91
+ "aria-errormessage": error ? validationId : ariaErrorMessage,
92
+ "aria-invalid": error ? true : ariaInvalid,
93
+ variant: "outline",
94
+ 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),
95
+ disabled: disabled,
109
96
  children: [
110
- /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsxs)(external_label_cjs_namespaceObject.Label, {
111
- className: "text-sm font-medium flex items-center gap-2",
112
- children: [
113
- /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(external_lucide_react_namespaceObject.Clock, {
114
- className: "h-4 w-4"
115
- }),
116
- "Time"
117
- ]
97
+ /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(external_lucide_react_namespaceObject.CalendarIcon, {
98
+ className: "mr-2 h-4 w-4"
118
99
  }),
119
- /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(external_input_cjs_namespaceObject.Input, {
120
- type: "time",
121
- value: timeValue,
122
- onChange: handleTimeChange,
123
- className: "w-full"
100
+ selectedDate ? formatDisplayValue() : /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)("span", {
101
+ className: "text-foreground-muted",
102
+ children: placeholder
124
103
  })
125
104
  ]
126
- }),
127
- /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsxs)("div", {
128
- className: "flex gap-2",
105
+ })
106
+ }),
107
+ /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(external_popover_cjs_namespaceObject.PopoverContent, {
108
+ className: "w-auto p-0",
109
+ align: "start",
110
+ children: /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsxs)("div", {
111
+ className: "p-3 space-y-3",
129
112
  children: [
130
- /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(external_button_cjs_namespaceObject.Button, {
131
- variant: "outline",
132
- className: "w-full",
133
- onClick: ()=>{
134
- setSelectedDate(void 0);
135
- setTimeValue('');
136
- onValueChange?.(void 0);
137
- setOpen(false);
138
- },
139
- children: "Clear"
113
+ /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(external_calendar_cjs_namespaceObject.Calendar, {
114
+ mode: "single",
115
+ selected: selectedDate,
116
+ onSelect: handleDateSelect,
117
+ initialFocus: true
118
+ }),
119
+ /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsxs)("div", {
120
+ className: "border-t pt-3 space-y-2",
121
+ children: [
122
+ /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsxs)(external_label_cjs_namespaceObject.Label, {
123
+ className: "text-sm font-medium flex items-center gap-2",
124
+ children: [
125
+ /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(external_lucide_react_namespaceObject.Clock, {
126
+ className: "h-4 w-4"
127
+ }),
128
+ "Time"
129
+ ]
130
+ }),
131
+ /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(external_input_cjs_namespaceObject.Input, {
132
+ type: "time",
133
+ value: timeValue,
134
+ onChange: handleTimeChange,
135
+ className: "w-full"
136
+ })
137
+ ]
140
138
  }),
141
- /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(external_button_cjs_namespaceObject.Button, {
142
- className: "w-full",
143
- onClick: ()=>setOpen(false),
144
- disabled: !selectedDate,
145
- children: "Done"
139
+ /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsxs)("div", {
140
+ className: "flex gap-2",
141
+ children: [
142
+ /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(external_button_cjs_namespaceObject.Button, {
143
+ variant: "outline",
144
+ className: "w-full",
145
+ onClick: ()=>{
146
+ setSelectedDate(void 0);
147
+ setTimeValue('');
148
+ onValueChange?.(void 0);
149
+ setOpen(false);
150
+ },
151
+ children: "Clear"
152
+ }),
153
+ /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(external_button_cjs_namespaceObject.Button, {
154
+ className: "w-full",
155
+ onClick: ()=>setOpen(false),
156
+ disabled: !selectedDate,
157
+ children: "Done"
158
+ })
159
+ ]
146
160
  })
147
161
  ]
148
162
  })
149
- ]
150
- })
163
+ })
164
+ ]
165
+ }),
166
+ /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(external_form_field_cjs_namespaceObject.FormFieldError, {
167
+ id: validationId,
168
+ children: error
151
169
  })
152
170
  ]
153
171
  });
@@ -1,14 +1,24 @@
1
1
  import * as React from 'react';
2
2
  export interface DateTimePickerProps {
3
+ /** Applied to the trigger button, so a `<label htmlFor>` pointing at it associates correctly. */
4
+ id?: string;
3
5
  value?: Date;
4
6
  onValueChange?: (date: Date | undefined) => void;
5
7
  disabled?: boolean;
6
8
  placeholder?: string;
7
9
  className?: string;
8
10
  use12Hour?: boolean;
11
+ /**
12
+ * Field-specific feedback rendered immediately below the trigger.
13
+ * Keep the message focused on what went wrong and how to resolve it.
14
+ */
15
+ error?: React.ReactNode;
16
+ /** Optional id for the inline validation message. */
17
+ errorId?: string;
9
18
  /** Id of the element naming this control, forwarded to the trigger button. */
10
19
  'aria-labelledby'?: string;
11
- /** Marks the trigger invalid, so the error is exposed on the control itself. */
12
- 'aria-invalid'?: boolean;
20
+ 'aria-invalid'?: React.AriaAttributes['aria-invalid'];
21
+ 'aria-describedby'?: string;
22
+ 'aria-errormessage'?: string;
13
23
  }
14
24
  export declare const DateTimePicker: React.ForwardRefExoticComponent<DateTimePickerProps & React.RefAttributes<HTMLButtonElement>>;
@@ -1,15 +1,22 @@
1
- import { jsx, jsxs } from "react/jsx-runtime";
1
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
2
2
  import { format } from "date-fns";
3
3
  import { CalendarIcon, Clock } from "lucide-react";
4
- import { forwardRef, useState } from "react";
4
+ import { forwardRef, useId, useState } from "react";
5
5
  import { Button } from "./button.js";
6
6
  import { Calendar } from "./calendar.js";
7
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, 'aria-labelledby': ariaLabelledBy, 'aria-invalid': ariaInvalid }, ref) {
11
+ import { FormFieldError } from "./form-field.js";
12
+ const datetime_picker_DateTimePicker = /*#__PURE__*/ forwardRef(function({ value, onValueChange, disabled, placeholder = 'Pick a date and time', className, use12Hour = false, id, error, errorId, 'aria-labelledby': ariaLabelledBy, 'aria-invalid': ariaInvalid, 'aria-describedby': ariaDescribedBy, 'aria-errormessage': ariaErrorMessage }, ref) {
12
13
  const [open, setOpen] = useState(false);
14
+ const generatedId = useId();
15
+ const validationId = errorId ?? `${id ?? `datetime-picker-${generatedId.replace(/:/g, '')}`}-error`;
16
+ const describedBy = [
17
+ ariaDescribedBy,
18
+ error ? validationId : void 0
19
+ ].filter(Boolean).join(' ');
13
20
  const [selectedDate, setSelectedDate] = useState(value);
14
21
  const [timeValue, setTimeValue] = useState(value ? format(value, use12Hour ? 'hh:mm a' : 'HH:mm') : '');
15
22
  const handleDateSelect = (date)=>{
@@ -39,87 +46,98 @@ const datetime_picker_DateTimePicker = /*#__PURE__*/ forwardRef(function({ value
39
46
  const timePart = format(selectedDate, use12Hour ? 'hh:mm a' : 'HH:mm');
40
47
  return `${datePart} at ${timePart}`;
41
48
  };
42
- return /*#__PURE__*/ jsxs(Popover, {
43
- "data-slot": "datetime-picker",
44
- open: open,
45
- onOpenChange: setOpen,
49
+ return /*#__PURE__*/ jsxs(Fragment, {
46
50
  children: [
47
- /*#__PURE__*/ jsx(PopoverTrigger, {
48
- asChild: true,
49
- children: /*#__PURE__*/ jsxs(Button, {
50
- ref: ref,
51
- "aria-labelledby": ariaLabelledBy,
52
- "aria-invalid": ariaInvalid,
53
- variant: "outline",
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),
55
- disabled: disabled,
56
- children: [
57
- /*#__PURE__*/ jsx(CalendarIcon, {
58
- className: "mr-2 h-4 w-4"
59
- }),
60
- selectedDate ? formatDisplayValue() : /*#__PURE__*/ jsx("span", {
61
- className: "text-foreground-muted",
62
- children: placeholder
63
- })
64
- ]
65
- })
66
- }),
67
- /*#__PURE__*/ jsx(PopoverContent, {
68
- className: "w-auto p-0",
69
- align: "start",
70
- children: /*#__PURE__*/ jsxs("div", {
71
- className: "p-3 space-y-3",
72
- children: [
73
- /*#__PURE__*/ jsx(Calendar, {
74
- mode: "single",
75
- selected: selectedDate,
76
- onSelect: handleDateSelect,
77
- initialFocus: true
78
- }),
79
- /*#__PURE__*/ jsxs("div", {
80
- className: "border-t pt-3 space-y-2",
51
+ /*#__PURE__*/ jsxs(Popover, {
52
+ "data-slot": "datetime-picker",
53
+ open: open,
54
+ onOpenChange: setOpen,
55
+ children: [
56
+ /*#__PURE__*/ jsx(PopoverTrigger, {
57
+ asChild: true,
58
+ children: /*#__PURE__*/ jsxs(Button, {
59
+ ref: ref,
60
+ id: id,
61
+ "aria-labelledby": ariaLabelledBy,
62
+ "aria-describedby": describedBy || void 0,
63
+ "aria-errormessage": error ? validationId : ariaErrorMessage,
64
+ "aria-invalid": error ? true : ariaInvalid,
65
+ variant: "outline",
66
+ 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),
67
+ disabled: disabled,
81
68
  children: [
82
- /*#__PURE__*/ jsxs(Label, {
83
- className: "text-sm font-medium flex items-center gap-2",
84
- children: [
85
- /*#__PURE__*/ jsx(Clock, {
86
- className: "h-4 w-4"
87
- }),
88
- "Time"
89
- ]
69
+ /*#__PURE__*/ jsx(CalendarIcon, {
70
+ className: "mr-2 h-4 w-4"
90
71
  }),
91
- /*#__PURE__*/ jsx(Input, {
92
- type: "time",
93
- value: timeValue,
94
- onChange: handleTimeChange,
95
- className: "w-full"
72
+ selectedDate ? formatDisplayValue() : /*#__PURE__*/ jsx("span", {
73
+ className: "text-foreground-muted",
74
+ children: placeholder
96
75
  })
97
76
  ]
98
- }),
99
- /*#__PURE__*/ jsxs("div", {
100
- className: "flex gap-2",
77
+ })
78
+ }),
79
+ /*#__PURE__*/ jsx(PopoverContent, {
80
+ className: "w-auto p-0",
81
+ align: "start",
82
+ children: /*#__PURE__*/ jsxs("div", {
83
+ className: "p-3 space-y-3",
101
84
  children: [
102
- /*#__PURE__*/ jsx(Button, {
103
- variant: "outline",
104
- className: "w-full",
105
- onClick: ()=>{
106
- setSelectedDate(void 0);
107
- setTimeValue('');
108
- onValueChange?.(void 0);
109
- setOpen(false);
110
- },
111
- children: "Clear"
85
+ /*#__PURE__*/ jsx(Calendar, {
86
+ mode: "single",
87
+ selected: selectedDate,
88
+ onSelect: handleDateSelect,
89
+ initialFocus: true
90
+ }),
91
+ /*#__PURE__*/ jsxs("div", {
92
+ className: "border-t pt-3 space-y-2",
93
+ children: [
94
+ /*#__PURE__*/ jsxs(Label, {
95
+ className: "text-sm font-medium flex items-center gap-2",
96
+ children: [
97
+ /*#__PURE__*/ jsx(Clock, {
98
+ className: "h-4 w-4"
99
+ }),
100
+ "Time"
101
+ ]
102
+ }),
103
+ /*#__PURE__*/ jsx(Input, {
104
+ type: "time",
105
+ value: timeValue,
106
+ onChange: handleTimeChange,
107
+ className: "w-full"
108
+ })
109
+ ]
112
110
  }),
113
- /*#__PURE__*/ jsx(Button, {
114
- className: "w-full",
115
- onClick: ()=>setOpen(false),
116
- disabled: !selectedDate,
117
- children: "Done"
111
+ /*#__PURE__*/ jsxs("div", {
112
+ className: "flex gap-2",
113
+ children: [
114
+ /*#__PURE__*/ jsx(Button, {
115
+ variant: "outline",
116
+ className: "w-full",
117
+ onClick: ()=>{
118
+ setSelectedDate(void 0);
119
+ setTimeValue('');
120
+ onValueChange?.(void 0);
121
+ setOpen(false);
122
+ },
123
+ children: "Clear"
124
+ }),
125
+ /*#__PURE__*/ jsx(Button, {
126
+ className: "w-full",
127
+ onClick: ()=>setOpen(false),
128
+ disabled: !selectedDate,
129
+ children: "Done"
130
+ })
131
+ ]
118
132
  })
119
133
  ]
120
134
  })
121
- ]
122
- })
135
+ })
136
+ ]
137
+ }),
138
+ /*#__PURE__*/ jsx(FormFieldError, {
139
+ id: validationId,
140
+ children: error
123
141
  })
124
142
  ]
125
143
  });
@@ -32,7 +32,16 @@ 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, 'aria-invalid': ariaInvalid, 'aria-describedby': ariaDescribedBy, 'aria-errormessage': ariaErrorMessage }, ref) {
35
+ const external_form_field_cjs_namespaceObject = require("./form-field.cjs");
36
+ const file_upload_FileUpload = /*#__PURE__*/ external_react_namespaceObject.forwardRef(function({ id, ariaLabel, onFilesChange, accept, multiple = false, disabled = false, maxSize, className, showPreview = false, errors, onBlur, error, errorId, 'aria-invalid': ariaInvalid, 'aria-describedby': ariaDescribedBy, 'aria-errormessage': ariaErrorMessage }, ref) {
37
+ const generatedId = external_react_namespaceObject.useId();
38
+ const validationId = errorId ?? `${id ?? `file-upload-${generatedId.replace(/:/g, '')}`}-error`;
39
+ const describedBy = [
40
+ ariaDescribedBy,
41
+ error ? validationId : void 0
42
+ ].filter(Boolean).join(' ');
43
+ const resolvedAriaInvalid = error ? true : ariaInvalid;
44
+ const resolvedAriaErrorMessage = error ? validationId : ariaErrorMessage;
36
45
  const [files, setFiles] = external_react_namespaceObject.useState([]);
37
46
  const [isDragging, setIsDragging] = external_react_namespaceObject.useState(false);
38
47
  const [fileErrors, setFileErrors] = external_react_namespaceObject.useState(new Map());
@@ -178,19 +187,19 @@ const file_upload_FileUpload = /*#__PURE__*/ external_react_namespaceObject.forw
178
187
  disabled: disabled,
179
188
  onChange: handleInputChange,
180
189
  "aria-label": id ? void 0 : ariaLabel ?? 'File upload',
181
- "aria-invalid": ariaInvalid,
182
- "aria-describedby": ariaDescribedBy,
183
- "aria-errormessage": ariaErrorMessage
190
+ "aria-invalid": resolvedAriaInvalid,
191
+ "aria-describedby": describedBy || void 0,
192
+ "aria-errormessage": resolvedAriaErrorMessage
184
193
  }),
185
194
  /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsxs)("div", {
186
195
  role: "button",
187
196
  "aria-label": ariaLabel ?? 'File upload area',
188
197
  "aria-disabled": disabled,
189
- "aria-invalid": ariaInvalid,
190
- "aria-describedby": ariaDescribedBy,
191
- "aria-errormessage": ariaErrorMessage,
198
+ "aria-invalid": resolvedAriaInvalid,
199
+ "aria-describedby": describedBy || void 0,
200
+ "aria-errormessage": resolvedAriaErrorMessage,
192
201
  tabIndex: disabled ? -1 : 0,
193
- className: (0, index_cjs_namespaceObject.cn)('relative flex w-full flex-col items-center justify-center h-32 border-2 border-dashed rounded-lg px-4 py-6 cursor-pointer transition-colors', 'text-foreground-muted 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 future:border-border-subtle future:bg-surface-overlay future:hover:bg-surface-hover future:focus-visible:ring-offset-background', isDragging ? 'border-primary bg-primary/5' : 'border-input bg-background hover:bg-accent/50', disabled && 'opacity-50 cursor-not-allowed hover:bg-background future:hover:bg-surface-overlay'),
202
+ className: (0, index_cjs_namespaceObject.cn)('relative flex w-full flex-col items-center justify-center h-32 border-2 border-dashed rounded-lg px-4 py-6 cursor-pointer transition-colors', 'text-foreground-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background', 'aria-invalid:border-error aria-invalid:focus-visible:ring-error future:aria-invalid:border-error future:aria-invalid:ring-1 future:aria-invalid:ring-error/40', 'future:rounded-xl future:border-border-subtle future:bg-surface-overlay future:hover:bg-surface-hover future:focus-visible:ring-offset-background', isDragging ? 'border-primary bg-primary/5' : 'border-input bg-background hover:bg-accent/50', disabled && 'opacity-50 cursor-not-allowed hover:bg-background future:hover:bg-surface-overlay'),
194
203
  onDragEnter: handleDragEnter,
195
204
  onDragOver: handleDragOver,
196
205
  onDragLeave: handleDragLeave,
@@ -229,6 +238,10 @@ const file_upload_FileUpload = /*#__PURE__*/ external_react_namespaceObject.forw
229
238
  })
230
239
  ]
231
240
  }),
241
+ /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(external_form_field_cjs_namespaceObject.FormFieldError, {
242
+ id: validationId,
243
+ children: error
244
+ }),
232
245
  files.length > 0 && /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)("div", {
233
246
  className: "mt-4 space-y-2",
234
247
  children: files.map((file, index)=>{
@@ -26,6 +26,13 @@ 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
+ /**
30
+ * Field-level feedback rendered immediately below the dropzone, for example
31
+ * "Attach at least one file". Per-file problems belong in `errors` instead.
32
+ */
33
+ error?: React.ReactNode;
34
+ /** Optional id for the inline validation message. */
35
+ errorId?: string;
29
36
  'aria-invalid'?: React.AriaAttributes['aria-invalid'];
30
37
  'aria-describedby'?: string;
31
38
  'aria-errormessage'?: string;
@@ -1,10 +1,19 @@
1
1
  "use client";
2
2
  import { jsx, jsxs } from "react/jsx-runtime";
3
3
  import { Upload, X } from "lucide-react";
4
- import { forwardRef, useRef, useState } from "react";
4
+ import { forwardRef, useId, 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, 'aria-invalid': ariaInvalid, 'aria-describedby': ariaDescribedBy, 'aria-errormessage': ariaErrorMessage }, ref) {
7
+ import { FormFieldError } from "./form-field.js";
8
+ const file_upload_FileUpload = /*#__PURE__*/ forwardRef(function({ id, ariaLabel, onFilesChange, accept, multiple = false, disabled = false, maxSize, className, showPreview = false, errors, onBlur, error, errorId, 'aria-invalid': ariaInvalid, 'aria-describedby': ariaDescribedBy, 'aria-errormessage': ariaErrorMessage }, ref) {
9
+ const generatedId = useId();
10
+ const validationId = errorId ?? `${id ?? `file-upload-${generatedId.replace(/:/g, '')}`}-error`;
11
+ const describedBy = [
12
+ ariaDescribedBy,
13
+ error ? validationId : void 0
14
+ ].filter(Boolean).join(' ');
15
+ const resolvedAriaInvalid = error ? true : ariaInvalid;
16
+ const resolvedAriaErrorMessage = error ? validationId : ariaErrorMessage;
8
17
  const [files, setFiles] = useState([]);
9
18
  const [isDragging, setIsDragging] = useState(false);
10
19
  const [fileErrors, setFileErrors] = useState(new Map());
@@ -150,19 +159,19 @@ const file_upload_FileUpload = /*#__PURE__*/ forwardRef(function({ id, ariaLabel
150
159
  disabled: disabled,
151
160
  onChange: handleInputChange,
152
161
  "aria-label": id ? void 0 : ariaLabel ?? 'File upload',
153
- "aria-invalid": ariaInvalid,
154
- "aria-describedby": ariaDescribedBy,
155
- "aria-errormessage": ariaErrorMessage
162
+ "aria-invalid": resolvedAriaInvalid,
163
+ "aria-describedby": describedBy || void 0,
164
+ "aria-errormessage": resolvedAriaErrorMessage
156
165
  }),
157
166
  /*#__PURE__*/ jsxs("div", {
158
167
  role: "button",
159
168
  "aria-label": ariaLabel ?? 'File upload area',
160
169
  "aria-disabled": disabled,
161
- "aria-invalid": ariaInvalid,
162
- "aria-describedby": ariaDescribedBy,
163
- "aria-errormessage": ariaErrorMessage,
170
+ "aria-invalid": resolvedAriaInvalid,
171
+ "aria-describedby": describedBy || void 0,
172
+ "aria-errormessage": resolvedAriaErrorMessage,
164
173
  tabIndex: disabled ? -1 : 0,
165
- className: cn('relative flex w-full flex-col items-center justify-center h-32 border-2 border-dashed rounded-lg px-4 py-6 cursor-pointer transition-colors', 'text-foreground-muted 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 future:border-border-subtle future:bg-surface-overlay future:hover:bg-surface-hover future:focus-visible:ring-offset-background', isDragging ? 'border-primary bg-primary/5' : 'border-input bg-background hover:bg-accent/50', disabled && 'opacity-50 cursor-not-allowed hover:bg-background future:hover:bg-surface-overlay'),
174
+ className: cn('relative flex w-full flex-col items-center justify-center h-32 border-2 border-dashed rounded-lg px-4 py-6 cursor-pointer transition-colors', 'text-foreground-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background', 'aria-invalid:border-error aria-invalid:focus-visible:ring-error future:aria-invalid:border-error future:aria-invalid:ring-1 future:aria-invalid:ring-error/40', 'future:rounded-xl future:border-border-subtle future:bg-surface-overlay future:hover:bg-surface-hover future:focus-visible:ring-offset-background', isDragging ? 'border-primary bg-primary/5' : 'border-input bg-background hover:bg-accent/50', disabled && 'opacity-50 cursor-not-allowed hover:bg-background future:hover:bg-surface-overlay'),
166
175
  onDragEnter: handleDragEnter,
167
176
  onDragOver: handleDragOver,
168
177
  onDragLeave: handleDragLeave,
@@ -201,6 +210,10 @@ const file_upload_FileUpload = /*#__PURE__*/ forwardRef(function({ id, ariaLabel
201
210
  })
202
211
  ]
203
212
  }),
213
+ /*#__PURE__*/ jsx(FormFieldError, {
214
+ id: validationId,
215
+ children: error
216
+ }),
204
217
  files.length > 0 && /*#__PURE__*/ jsx("div", {
205
218
  className: "mt-4 space-y-2",
206
219
  children: files.map((file, index)=>{
@@ -37,7 +37,7 @@ const index_cjs_namespaceObject = require("../../lib/index.cjs");
37
37
  const FormField = /*#__PURE__*/ external_react_namespaceObject.forwardRef(({ children, className, ...props }, ref)=>/*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)("div", {
38
38
  ref: ref,
39
39
  "data-slot": "form-field",
40
- className: (0, index_cjs_namespaceObject.cn)('grid grid-cols-[minmax(0,1fr)] gap-1.5', className),
40
+ className: (0, index_cjs_namespaceObject.cn)('grid grid-cols-[minmax(0,1fr)] gap-1.5 [&>[data-slot=form-field-error]]:mt-0', className),
41
41
  ...props,
42
42
  children: children
43
43
  }));
@@ -81,11 +81,11 @@ const FormFieldError = /*#__PURE__*/ external_react_namespaceObject.forwardRef((
81
81
  if (!children) return null;
82
82
  return /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)("p", {
83
83
  ref: ref,
84
- "data-slot": "form-field-error",
85
84
  "aria-live": "polite",
86
85
  "aria-atomic": "true",
87
- className: (0, index_cjs_namespaceObject.cn)('text-xs leading-4 text-error', className),
86
+ className: (0, index_cjs_namespaceObject.cn)('text-xs leading-4 text-error mt-1.5', className),
88
87
  ...props,
88
+ "data-slot": "form-field-error",
89
89
  children: children
90
90
  });
91
91
  });
@@ -14,6 +14,17 @@ export type FormFieldProps = React.ComponentPropsWithoutRef<'div'>;
14
14
  * truncating. A `1fr` track still resolves to max-content when the host width
15
15
  * is indefinite, so shrink-to-fit hosts are unaffected. `className` is merged
16
16
  * last, so a consumer can still override with `grid-cols-2` or similar.
17
+ *
18
+ * A direct-child validation message's own top margin is cancelled here
19
+ * (`[&>[data-slot=form-field-error]]:mt-0`), since this stack's own `gap-1.5` already
20
+ * spaces it -- otherwise the two would add up. Scoped to this component rather than a
21
+ * bare `.gap-1.5` selector in global CSS: keeping it here means it compiles into
22
+ * Tailwind's layered output (so a consumer's own margin utility can still win, at
23
+ * (0,2,0) vs this rule's (0,1,0) within the same layer) and survives the field rhythm
24
+ * changing out from under an unrelated stylesheet. A hand-built `grid gap-1.5` stack
25
+ * that isn't `<FormField>` doesn't get this for free -- see `FieldExample` in
26
+ * apps/storybook's guidance-primitives.tsx for the pattern to reach for instead of
27
+ * reintroducing the cancellation ad hoc.
17
28
  */
18
29
  declare const FormField: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
19
30
  export interface FormFieldLabelProps extends React.ComponentPropsWithoutRef<typeof Label> {
@@ -6,7 +6,7 @@ import { cn } from "../../lib/index.js";
6
6
  const FormField = /*#__PURE__*/ forwardRef(({ children, className, ...props }, ref)=>/*#__PURE__*/ jsx("div", {
7
7
  ref: ref,
8
8
  "data-slot": "form-field",
9
- className: cn('grid grid-cols-[minmax(0,1fr)] gap-1.5', className),
9
+ className: cn('grid grid-cols-[minmax(0,1fr)] gap-1.5 [&>[data-slot=form-field-error]]:mt-0', className),
10
10
  ...props,
11
11
  children: children
12
12
  }));
@@ -50,11 +50,11 @@ const FormFieldError = /*#__PURE__*/ forwardRef(({ children, className, ...props
50
50
  if (!children) return null;
51
51
  return /*#__PURE__*/ jsx("p", {
52
52
  ref: ref,
53
- "data-slot": "form-field-error",
54
53
  "aria-live": "polite",
55
54
  "aria-atomic": "true",
56
- className: cn('text-xs leading-4 text-error', className),
55
+ className: cn('text-xs leading-4 text-error mt-1.5', className),
57
56
  ...props,
57
+ "data-slot": "form-field-error",
58
58
  children: children
59
59
  });
60
60
  });