colibri-ui 0.8.92 → 0.8.93

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.
@@ -39,6 +39,7 @@ const DatePicker = _a => {
39
39
  var _b;
40
40
  var {
41
41
  className,
42
+ disabled = false,
42
43
  endPlaceholder,
43
44
  hasError,
44
45
  hint,
@@ -55,7 +56,7 @@ const DatePicker = _a => {
55
56
  onChangeDate,
56
57
  onChangeRange
57
58
  } = _a,
58
- calendarProps = tslib.__rest(_a, ["className", "endPlaceholder", "hasError", "hint", "label", "placeholder", "required", "selectedDate", "selectedRange", "selectionMode", "size", "defaultVisibleMonth", "monthsToShow", "startPlaceholder", "onChangeDate", "onChangeRange"]);
59
+ calendarProps = tslib.__rest(_a, ["className", "disabled", "endPlaceholder", "hasError", "hint", "label", "placeholder", "required", "selectedDate", "selectedRange", "selectionMode", "size", "defaultVisibleMonth", "monthsToShow", "startPlaceholder", "onChangeDate", "onChangeRange"]);
59
60
  const [date, setDate] = React.useState(selectedDate);
60
61
  const [range, setRange] = React.useState(selectedRange);
61
62
  const [isOpen, setIsOpen] = React.useState(false);
@@ -64,6 +65,7 @@ const DatePicker = _a => {
64
65
  const calendarSize = calendarSizeByDatepickerSize[size];
65
66
  const visibleMonth = (_b = calendarValue !== null && calendarValue !== void 0 ? calendarValue : calendarRangeValue[0]) !== null && _b !== void 0 ? _b : new Date();
66
67
  const isRangeMode = selectionMode === "range";
68
+ const isCalendarOpen = isOpen && !disabled;
67
69
  React.useEffect(() => {
68
70
  setDate(selectedDate);
69
71
  }, [selectedDate]);
@@ -73,12 +75,14 @@ const DatePicker = _a => {
73
75
  setRange([selectedRangeStart, selectedRangeEnd]);
74
76
  }, [isRangeMode, selectedRangeStart, selectedRangeEnd]);
75
77
  const handleDateChange = nextDate => {
78
+ if (disabled) return;
76
79
  const nextValue = index.toISODate(nextDate);
77
80
  setDate(nextValue);
78
81
  setIsOpen(false);
79
82
  onChangeDate === null || onChangeDate === void 0 ? void 0 : onChangeDate(nextValue);
80
83
  };
81
84
  const handleRangeChange = nextRange => {
85
+ if (disabled) return;
82
86
  const nextValue = [nextRange[0] ? index.toISODate(nextRange[0]) : "", nextRange[1] ? index.toISODate(nextRange[1]) : ""];
83
87
  setRange(nextValue);
84
88
  if (nextValue[0] && nextValue[1]) setIsOpen(false);
@@ -110,14 +114,15 @@ const DatePicker = _a => {
110
114
  className: styles__default.default["range-input"]
111
115
  }, /*#__PURE__*/React__default.default.createElement(index$1.InputRoot, {
112
116
  className: styles__default.default["range-control-start"],
113
- disabled: false,
117
+ disabled: disabled,
114
118
  hasError: hasError,
115
119
  size: size
116
120
  }, /*#__PURE__*/React__default.default.createElement(index$2.BaseInput, {
117
- "aria-expanded": isOpen,
121
+ "aria-expanded": isCalendarOpen,
118
122
  "aria-haspopup": "true",
119
123
  "aria-invalid": hasError,
120
124
  autoComplete: "off",
125
+ disabled: disabled,
121
126
  maxLength: 10,
122
127
  placeholder: startPlaceholder !== null && startPlaceholder !== void 0 ? startPlaceholder : placeholder,
123
128
  readOnly: true,
@@ -125,15 +130,16 @@ const DatePicker = _a => {
125
130
  value: index.toDMYDate(range[0])
126
131
  })), /*#__PURE__*/React__default.default.createElement(index$1.InputRoot, {
127
132
  className: styles__default.default["range-control-end"],
128
- disabled: false,
133
+ disabled: disabled,
129
134
  endIcon: /*#__PURE__*/React__default.default.createElement(CalendarIcon, null),
130
135
  hasError: hasError,
131
136
  size: size
132
137
  }, /*#__PURE__*/React__default.default.createElement(index$2.BaseInput, {
133
- "aria-expanded": isOpen,
138
+ "aria-expanded": isCalendarOpen,
134
139
  "aria-haspopup": "true",
135
140
  "aria-invalid": hasError,
136
141
  autoComplete: "off",
142
+ disabled: disabled,
137
143
  maxLength: 10,
138
144
  placeholder: endPlaceholder !== null && endPlaceholder !== void 0 ? endPlaceholder : placeholder,
139
145
  readOnly: true,
@@ -146,7 +152,8 @@ const DatePicker = _a => {
146
152
  hint: hint,
147
153
  hasError: hasError
148
154
  }, /*#__PURE__*/React__default.default.createElement(index$4.Dropdown, {
149
- visible: isOpen,
155
+ disabled: disabled,
156
+ visible: isCalendarOpen,
150
157
  onVisibleChange: setIsOpen,
151
158
  placement: "bottom",
152
159
  preventAutoClose: true,
@@ -155,13 +162,16 @@ const DatePicker = _a => {
155
162
  className: styles__default.default["calendar-popup"]
156
163
  }, renderCalendar())
157
164
  }, /*#__PURE__*/React__default.default.createElement("div", {
158
- className: styles__default.default.trigger
165
+ "aria-disabled": disabled || undefined,
166
+ className: styles__default.default.trigger,
167
+ tabIndex: disabled ? -1 : 0
159
168
  }, isRangeMode ? renderRangeInput() : (/*#__PURE__*/React__default.default.createElement(index$5.Input, {
160
169
  className: styles__default.default.input,
161
- "aria-expanded": isOpen,
170
+ "aria-expanded": isCalendarOpen,
162
171
  "aria-haspopup": "true",
163
172
  "aria-invalid": hasError,
164
173
  autoComplete: "off",
174
+ disabled: disabled,
165
175
  endIcon: /*#__PURE__*/React__default.default.createElement(CalendarIcon, null),
166
176
  hasError: hasError,
167
177
  maxLength: 10,
@@ -1,6 +1,7 @@
1
1
  import type { DatepickerSize, DatepickerCalendarProps, Props as DatepickerProps } from "../../index.props";
2
2
  export type DatePickerProps = DatepickerCalendarProps & {
3
3
  className?: string;
4
+ disabled?: boolean;
4
5
  endPlaceholder?: string;
5
6
  hasError?: boolean;
6
7
  hint?: DatepickerProps["hint"];
@@ -1,3 +1,3 @@
1
1
  import React from "react";
2
2
  import type { Props } from "./index.props";
3
- export declare const Datepicker: ({ className, endPlaceholder, hasError, hint, label, placeholder, required, selectedDate, selectedRange, selectionMode, size, startPlaceholder, onChangeDate, onChangeRange, ...calendarProps }: Props) => React.JSX.Element;
3
+ export declare const Datepicker: ({ className, disabled, endPlaceholder, hasError, hint, label, placeholder, required, selectedDate, selectedRange, selectionMode, size, startPlaceholder, onChangeDate, onChangeRange, ...calendarProps }: Props) => React.JSX.Element;
@@ -15,6 +15,7 @@ var styles__default = /*#__PURE__*/_interopDefault(styles);
15
15
  const Datepicker = _a => {
16
16
  var {
17
17
  className,
18
+ disabled,
18
19
  endPlaceholder,
19
20
  hasError,
20
21
  hint,
@@ -29,10 +30,11 @@ const Datepicker = _a => {
29
30
  onChangeDate,
30
31
  onChangeRange
31
32
  } = _a,
32
- calendarProps = tslib.__rest(_a, ["className", "endPlaceholder", "hasError", "hint", "label", "placeholder", "required", "selectedDate", "selectedRange", "selectionMode", "size", "startPlaceholder", "onChangeDate", "onChangeRange"]);
33
+ calendarProps = tslib.__rest(_a, ["className", "disabled", "endPlaceholder", "hasError", "hint", "label", "placeholder", "required", "selectedDate", "selectedRange", "selectionMode", "size", "startPlaceholder", "onChangeDate", "onChangeRange"]);
33
34
  return /*#__PURE__*/React__default.default.createElement("div", {
34
35
  className: clsx__default.default(styles__default.default.root, className)
35
36
  }, /*#__PURE__*/React__default.default.createElement(index.DatePicker, Object.assign({}, calendarProps, {
37
+ disabled: disabled,
36
38
  endPlaceholder: endPlaceholder,
37
39
  hasError: hasError,
38
40
  hint: hint,
@@ -6,6 +6,7 @@ export type DatepickerRangeValue = [string, string];
6
6
  export type DatepickerCalendarProps = Omit<CalendarCommonProps, "className" | "size">;
7
7
  export type Props = DatepickerCalendarProps & {
8
8
  className?: string;
9
+ disabled?: boolean;
9
10
  endPlaceholder?: string;
10
11
  hasError?: boolean;
11
12
  hint?: ReactNode;
@@ -39,9 +39,14 @@ const MultiSelect = ({
39
39
  name,
40
40
  value = [],
41
41
  type,
42
- onChange
42
+ onChange,
43
+ "aria-label": ariaLabel
43
44
  }) => {
44
45
  const [isOpen, setIsOpen] = React.useState(false);
46
+ const id = React.useId();
47
+ const labelId = label ? `${id}-label` : undefined;
48
+ const valueId = `${id}-value`;
49
+ const hintId = hint ? `${id}-hint` : undefined;
45
50
  const internalSelectedKeys = React.useMemo(() => value.map(index.toKey), [value]);
46
51
  const preparedGroups = React.useMemo(() => groups.map(group => Object.assign(Object.assign({}, group), {
47
52
  options: group.options.map(option => Object.assign(Object.assign({}, option), {
@@ -80,7 +85,9 @@ const MultiSelect = ({
80
85
  }, className),
81
86
  required: required,
82
87
  label: label,
88
+ labelId: labelId,
83
89
  hint: hint,
90
+ hintId: hintId,
84
91
  hasError: hasError
85
92
  }, /*#__PURE__*/React__default.default.createElement(index$2.Dropdown, {
86
93
  placement: "bottom-start",
@@ -96,7 +103,11 @@ const MultiSelect = ({
96
103
  }),
97
104
  samewidth: true
98
105
  }, /*#__PURE__*/React__default.default.createElement("div", {
99
- tabIndex: 0,
106
+ "aria-describedby": hintId,
107
+ "aria-disabled": disabled || undefined,
108
+ "aria-label": labelId ? undefined : ariaLabel,
109
+ "aria-labelledby": labelId ? `${labelId} ${valueId}` : undefined,
110
+ tabIndex: disabled ? -1 : 0,
100
111
  role: "button",
101
112
  style: {
102
113
  width: fullWidth ? "100%" : "fit-content"
@@ -118,6 +129,7 @@ const MultiSelect = ({
118
129
  }),
119
130
  disabled: Boolean(disabled)
120
131
  }, /*#__PURE__*/React__default.default.createElement("div", {
132
+ id: valueId,
121
133
  className: clsx__default.default(styles__default.default["base-input"], styles__default.default[type === "chip" ? "base-input-flex" : "base-input-text"])
122
134
  }, preparedLabel.length ? type === "chip" ?
123
135
  // eslint-disable-next-line @typescript-eslint/no-shadow
@@ -20,7 +20,9 @@ export type SelectedItem = {
20
20
  group: string;
21
21
  option: string;
22
22
  };
23
- export interface MultiSelectProps extends Omit<FormFieldProps, "children"> {
23
+ export interface MultiSelectProps extends Omit<FormFieldProps, "children" | "labelId"> {
24
+ /** Accessible name of the trigger when no visible `label` is passed. */
25
+ "aria-label"?: string;
24
26
  groups: GroupProps[];
25
27
  className?: string;
26
28
  zIndex?: number;
package/README.md CHANGED
@@ -196,6 +196,57 @@ const css = `@media ${media.down("sm")} { … }`;
196
196
 
197
197
  Returns `false` on the server and during hydration. Use it to decide whether to mount a heavy component; to show/hide markup use CSS media queries, otherwise the wrong variant renders until hydration.
198
198
 
199
+ ## Development Commands
200
+
201
+ Run these commands from the repository root after installing dependencies with `yarn install`.
202
+
203
+ ### Checks and Fixes
204
+
205
+ | Command | Purpose |
206
+ | ---------------------- | ---------------------------------------------------------------------------------------------------------------------- |
207
+ | `yarn lint` | Run both ESLint and Stylelint. |
208
+ | `yarn lint:ts` | Check JavaScript and TypeScript with ESLint. |
209
+ | `yarn lint:ts:fix` | Apply automatic ESLint fixes. |
210
+ | `yarn lint:css` | Check SCSS with Stylelint. |
211
+ | `yarn lint:css:fix` | Apply automatic Stylelint fixes. |
212
+ | `yarn lint:deps` | Check component dependency boundaries. |
213
+ | `yarn test` | Run Jest tests and collect coverage in `.coverage/`. |
214
+ | `yarn test:coverage` | Explicitly enable coverage; currently equivalent to `yarn test` because coverage is enabled in the Jest configuration. |
215
+ | `yarn audit:dead-code` | Check for unused files, exports and dependencies with Knip. |
216
+
217
+ `./verify.sh` runs lint, dependency boundary checks, tests and the dead code audit in sequence, stopping at the first failure.
218
+
219
+ ### Storybook
220
+
221
+ | Command | Purpose |
222
+ | ---------------------- | ------------------------------------------------------- |
223
+ | `yarn storybook` | Start the Storybook development server on port 6006. |
224
+ | `yarn build-storybook` | Build the static Storybook site in `storybook-static/`. |
225
+
226
+ ### Package Build
227
+
228
+ | Command | Purpose |
229
+ | -------------------------- | --------------------------------------------------------------------------------------------------------------------- |
230
+ | `yarn build` | Clean `dist/`, build CommonJS and ESM output with Rollup, run all build stages below and check the resulting exports. |
231
+ | `yarn clean` | Delete `dist/`. |
232
+ | `yarn build:sass` | Compile SCSS to CSS and apply Autoprefixer for both package formats. |
233
+ | `yarn build:updateImports` | Replace SCSS import paths with CSS paths in the built JavaScript. |
234
+ | `yarn build:variables` | Generate CSS variables files for Buenos Aires and Jaipur. |
235
+ | `yarn build:postbuild` | Copy package metadata and README, and generate component package manifests. |
236
+ | `yarn build:check` | Check that built CommonJS and ESM entry points provide the runtime exports declared in their types. |
237
+
238
+ Use `yarn build` for a complete build. Individual build stages operate on existing output and are mainly useful when diagnosing the build pipeline.
239
+
240
+ ### Audits
241
+
242
+ | Command | Purpose |
243
+ | -------------------- | ---------------------------------------------------------------------------------------------------------------- |
244
+ | `yarn run audit` | Check production and development dependencies for known vulnerabilities using Yarn's audit command. |
245
+ | `yarn audit:snyk` | Check dependencies with Snyk; requires Snyk authentication. |
246
+ | `yarn audit:package` | Check the built package with Publint and Are the Types Wrong using the `node16` profile. Run after `yarn build`. |
247
+
248
+ Dependency security audits require network access. To check for available dependency updates, run `yarn outdated` directly.
249
+
199
250
  ## License
200
251
 
201
252
  MIT
package/Select/index.d.ts CHANGED
@@ -1,3 +1,3 @@
1
1
  import type { JSX } from "react";
2
2
  import type { SelectProps } from "./index.props";
3
- export declare const Select: <T extends string>({ options, value, name, zIndex, fontSize, label, hint, hasError, required, placeholder, disabled, size, fullWidth, customInputRoot, className, onChange, }: SelectProps<T>) => JSX.Element;
3
+ export declare const Select: <T extends string>({ options, value, name, zIndex, fontSize, label, hint, hasError, required, placeholder, disabled, size, fullWidth, customInputRoot, className, onChange, "aria-label": ariaLabel, }: SelectProps<T>) => JSX.Element;
package/Select/index.js CHANGED
@@ -31,9 +31,14 @@ const Select = ({
31
31
  fullWidth = false,
32
32
  customInputRoot,
33
33
  className,
34
- onChange
34
+ onChange,
35
+ "aria-label": ariaLabel
35
36
  }) => {
36
37
  const [isOpen, setIsOpen] = React.useState(false);
38
+ const id = React.useId();
39
+ const labelId = label ? `${id}-label` : undefined;
40
+ const valueId = `${id}-value`;
41
+ const hintId = hint ? `${id}-hint` : undefined;
37
42
  const preparedOptions = React.useMemo(() => options.map(({
38
43
  value: lvalue,
39
44
  label: llabel,
@@ -56,7 +61,9 @@ const Select = ({
56
61
  }, className),
57
62
  required: required,
58
63
  label: label,
64
+ labelId: labelId,
59
65
  hint: hint,
66
+ hintId: hintId,
60
67
  hasError: hasError
61
68
  }, /*#__PURE__*/React__default.default.createElement(index$1.Dropdown, {
62
69
  placement: "bottom-start",
@@ -72,7 +79,11 @@ const Select = ({
72
79
  }),
73
80
  samewidth: true
74
81
  }, customInputRoot ? customInputRoot : (/*#__PURE__*/React__default.default.createElement("div", {
75
- tabIndex: 0,
82
+ "aria-describedby": hintId,
83
+ "aria-disabled": disabled || undefined,
84
+ "aria-label": labelId ? undefined : ariaLabel,
85
+ "aria-labelledby": labelId ? `${labelId} ${valueId}` : undefined,
86
+ tabIndex: disabled ? -1 : 0,
76
87
  role: "button",
77
88
  style: {
78
89
  width: fullWidth ? "100%" : "fit-content"
@@ -92,6 +103,7 @@ const Select = ({
92
103
  }),
93
104
  disabled: Boolean(disabled)
94
105
  }, /*#__PURE__*/React__default.default.createElement("div", {
106
+ id: valueId,
95
107
  className: styles__default.default["base-input"],
96
108
  "data-testid": "base-input"
97
109
  }, preparedLabel !== null && preparedLabel !== void 0 ? preparedLabel : (/*#__PURE__*/React__default.default.createElement("span", {
@@ -10,7 +10,9 @@ export interface IOption<T extends string> {
10
10
  label: ReactNode;
11
11
  value: T;
12
12
  }
13
- export interface SelectProps<T extends string> extends Omit<FormFieldProps, "children"> {
13
+ export interface SelectProps<T extends string> extends Omit<FormFieldProps, "children" | "labelId"> {
14
+ /** Accessible name of the trigger when no visible `label` is passed. */
15
+ "aria-label"?: string;
14
16
  className?: string;
15
17
  customInputRoot?: ReactNode;
16
18
  disabled?: boolean;
@@ -28,7 +28,8 @@ const TimeSelect = ({
28
28
  size,
29
29
  zIndex,
30
30
  hasError,
31
- hint
31
+ hint,
32
+ "aria-label": ariaLabel
32
33
  }) => {
33
34
  const baseOptions = React.useMemo(() => helpers.generateSuggest(interval).map(item => ({
34
35
  value: item.time,
@@ -43,6 +44,7 @@ const TimeSelect = ({
43
44
  });
44
45
  }), [baseOptions, currentDate, selectedDate, allowedTimeRange, interval]);
45
46
  return /*#__PURE__*/React__default.default.createElement(index$1.Select, {
47
+ "aria-label": ariaLabel,
46
48
  className: className,
47
49
  customInputRoot: customInputRoot,
48
50
  fontSize: fontSize,
@@ -1,3 +1,3 @@
1
1
  import React from "react";
2
2
  import type { FormFieldProps } from "./index.props";
3
- export declare const FormField: ({ label, hint, children, hasError, hintId, htmlFor, required, className, ref, }: FormFieldProps) => React.JSX.Element;
3
+ export declare const FormField: ({ label, hint, children, hasError, hintId, htmlFor, labelId, required, className, ref, }: FormFieldProps) => React.JSX.Element;
@@ -18,6 +18,7 @@ const FormField = ({
18
18
  hasError,
19
19
  hintId,
20
20
  htmlFor,
21
+ labelId,
21
22
  required,
22
23
  className,
23
24
  ref
@@ -29,7 +30,8 @@ const FormField = ({
29
30
  [styles__default.default.label_required]: Boolean(required)
30
31
  }),
31
32
  tag: "label",
32
- htmlFor: htmlFor
33
+ htmlFor: htmlFor,
34
+ id: labelId
33
35
  }, label)), children, hint && (/*#__PURE__*/React__default.default.createElement(index.Typography, {
34
36
  id: hintId,
35
37
  className: clsx__default.default({
@@ -9,6 +9,8 @@ export type FormFieldProps = PropsWithChildren<{
9
9
  /** Id of the control the label belongs to. */
10
10
  htmlFor?: string;
11
11
  label?: ReactNode;
12
+ /** Id of the label, referenced by the control's `aria-labelledby`. */
13
+ labelId?: string;
12
14
  ref?: React.Ref<HTMLDivElement>;
13
15
  required?: boolean;
14
16
  }>;
@@ -31,6 +31,7 @@ const DatePicker = _a => {
31
31
  var _b;
32
32
  var {
33
33
  className,
34
+ disabled = false,
34
35
  endPlaceholder,
35
36
  hasError,
36
37
  hint,
@@ -47,7 +48,7 @@ const DatePicker = _a => {
47
48
  onChangeDate,
48
49
  onChangeRange
49
50
  } = _a,
50
- calendarProps = __rest(_a, ["className", "endPlaceholder", "hasError", "hint", "label", "placeholder", "required", "selectedDate", "selectedRange", "selectionMode", "size", "defaultVisibleMonth", "monthsToShow", "startPlaceholder", "onChangeDate", "onChangeRange"]);
51
+ calendarProps = __rest(_a, ["className", "disabled", "endPlaceholder", "hasError", "hint", "label", "placeholder", "required", "selectedDate", "selectedRange", "selectionMode", "size", "defaultVisibleMonth", "monthsToShow", "startPlaceholder", "onChangeDate", "onChangeRange"]);
51
52
  const [date, setDate] = useState(selectedDate);
52
53
  const [range, setRange] = useState(selectedRange);
53
54
  const [isOpen, setIsOpen] = useState(false);
@@ -56,6 +57,7 @@ const DatePicker = _a => {
56
57
  const calendarSize = calendarSizeByDatepickerSize[size];
57
58
  const visibleMonth = (_b = calendarValue !== null && calendarValue !== void 0 ? calendarValue : calendarRangeValue[0]) !== null && _b !== void 0 ? _b : new Date();
58
59
  const isRangeMode = selectionMode === "range";
60
+ const isCalendarOpen = isOpen && !disabled;
59
61
  useEffect(() => {
60
62
  setDate(selectedDate);
61
63
  }, [selectedDate]);
@@ -65,12 +67,14 @@ const DatePicker = _a => {
65
67
  setRange([selectedRangeStart, selectedRangeEnd]);
66
68
  }, [isRangeMode, selectedRangeStart, selectedRangeEnd]);
67
69
  const handleDateChange = nextDate => {
70
+ if (disabled) return;
68
71
  const nextValue = toISODate(nextDate);
69
72
  setDate(nextValue);
70
73
  setIsOpen(false);
71
74
  onChangeDate === null || onChangeDate === void 0 ? void 0 : onChangeDate(nextValue);
72
75
  };
73
76
  const handleRangeChange = nextRange => {
77
+ if (disabled) return;
74
78
  const nextValue = [nextRange[0] ? toISODate(nextRange[0]) : "", nextRange[1] ? toISODate(nextRange[1]) : ""];
75
79
  setRange(nextValue);
76
80
  if (nextValue[0] && nextValue[1]) setIsOpen(false);
@@ -102,14 +106,15 @@ const DatePicker = _a => {
102
106
  className: styles["range-input"]
103
107
  }, /*#__PURE__*/React.createElement(InputRoot, {
104
108
  className: styles["range-control-start"],
105
- disabled: false,
109
+ disabled: disabled,
106
110
  hasError: hasError,
107
111
  size: size
108
112
  }, /*#__PURE__*/React.createElement(BaseInput, {
109
- "aria-expanded": isOpen,
113
+ "aria-expanded": isCalendarOpen,
110
114
  "aria-haspopup": "true",
111
115
  "aria-invalid": hasError,
112
116
  autoComplete: "off",
117
+ disabled: disabled,
113
118
  maxLength: 10,
114
119
  placeholder: startPlaceholder !== null && startPlaceholder !== void 0 ? startPlaceholder : placeholder,
115
120
  readOnly: true,
@@ -117,15 +122,16 @@ const DatePicker = _a => {
117
122
  value: toDMYDate(range[0])
118
123
  })), /*#__PURE__*/React.createElement(InputRoot, {
119
124
  className: styles["range-control-end"],
120
- disabled: false,
125
+ disabled: disabled,
121
126
  endIcon: /*#__PURE__*/React.createElement(CalendarIcon, null),
122
127
  hasError: hasError,
123
128
  size: size
124
129
  }, /*#__PURE__*/React.createElement(BaseInput, {
125
- "aria-expanded": isOpen,
130
+ "aria-expanded": isCalendarOpen,
126
131
  "aria-haspopup": "true",
127
132
  "aria-invalid": hasError,
128
133
  autoComplete: "off",
134
+ disabled: disabled,
129
135
  maxLength: 10,
130
136
  placeholder: endPlaceholder !== null && endPlaceholder !== void 0 ? endPlaceholder : placeholder,
131
137
  readOnly: true,
@@ -138,7 +144,8 @@ const DatePicker = _a => {
138
144
  hint: hint,
139
145
  hasError: hasError
140
146
  }, /*#__PURE__*/React.createElement(Dropdown, {
141
- visible: isOpen,
147
+ disabled: disabled,
148
+ visible: isCalendarOpen,
142
149
  onVisibleChange: setIsOpen,
143
150
  placement: "bottom",
144
151
  preventAutoClose: true,
@@ -147,13 +154,16 @@ const DatePicker = _a => {
147
154
  className: styles["calendar-popup"]
148
155
  }, renderCalendar())
149
156
  }, /*#__PURE__*/React.createElement("div", {
150
- className: styles.trigger
157
+ "aria-disabled": disabled || undefined,
158
+ className: styles.trigger,
159
+ tabIndex: disabled ? -1 : 0
151
160
  }, isRangeMode ? renderRangeInput() : (/*#__PURE__*/React.createElement(Input, {
152
161
  className: styles.input,
153
- "aria-expanded": isOpen,
162
+ "aria-expanded": isCalendarOpen,
154
163
  "aria-haspopup": "true",
155
164
  "aria-invalid": hasError,
156
165
  autoComplete: "off",
166
+ disabled: disabled,
157
167
  endIcon: /*#__PURE__*/React.createElement(CalendarIcon, null),
158
168
  hasError: hasError,
159
169
  maxLength: 10,
@@ -1,6 +1,7 @@
1
1
  import type { DatepickerSize, DatepickerCalendarProps, Props as DatepickerProps } from "../../index.props";
2
2
  export type DatePickerProps = DatepickerCalendarProps & {
3
3
  className?: string;
4
+ disabled?: boolean;
4
5
  endPlaceholder?: string;
5
6
  hasError?: boolean;
6
7
  hint?: DatepickerProps["hint"];
@@ -1,3 +1,3 @@
1
1
  import React from "react";
2
2
  import type { Props } from "./index.props";
3
- export declare const Datepicker: ({ className, endPlaceholder, hasError, hint, label, placeholder, required, selectedDate, selectedRange, selectionMode, size, startPlaceholder, onChangeDate, onChangeRange, ...calendarProps }: Props) => React.JSX.Element;
3
+ export declare const Datepicker: ({ className, disabled, endPlaceholder, hasError, hint, label, placeholder, required, selectedDate, selectedRange, selectionMode, size, startPlaceholder, onChangeDate, onChangeRange, ...calendarProps }: Props) => React.JSX.Element;
@@ -7,6 +7,7 @@ import { DatePicker } from './components/DatePicker/index.js';
7
7
  const Datepicker = _a => {
8
8
  var {
9
9
  className,
10
+ disabled,
10
11
  endPlaceholder,
11
12
  hasError,
12
13
  hint,
@@ -21,10 +22,11 @@ const Datepicker = _a => {
21
22
  onChangeDate,
22
23
  onChangeRange
23
24
  } = _a,
24
- calendarProps = __rest(_a, ["className", "endPlaceholder", "hasError", "hint", "label", "placeholder", "required", "selectedDate", "selectedRange", "selectionMode", "size", "startPlaceholder", "onChangeDate", "onChangeRange"]);
25
+ calendarProps = __rest(_a, ["className", "disabled", "endPlaceholder", "hasError", "hint", "label", "placeholder", "required", "selectedDate", "selectedRange", "selectionMode", "size", "startPlaceholder", "onChangeDate", "onChangeRange"]);
25
26
  return /*#__PURE__*/React.createElement("div", {
26
27
  className: clsx(styles.root, className)
27
28
  }, /*#__PURE__*/React.createElement(DatePicker, Object.assign({}, calendarProps, {
29
+ disabled: disabled,
28
30
  endPlaceholder: endPlaceholder,
29
31
  hasError: hasError,
30
32
  hint: hint,
@@ -6,6 +6,7 @@ export type DatepickerRangeValue = [string, string];
6
6
  export type DatepickerCalendarProps = Omit<CalendarCommonProps, "className" | "size">;
7
7
  export type Props = DatepickerCalendarProps & {
8
8
  className?: string;
9
+ disabled?: boolean;
9
10
  endPlaceholder?: string;
10
11
  hasError?: boolean;
11
12
  hint?: ReactNode;
@@ -1,4 +1,4 @@
1
- import React, { useState, useMemo, useCallback } from 'react';
1
+ import React, { useState, useId, useMemo, useCallback } from 'react';
2
2
  import clsx from 'clsx';
3
3
  import { Dropdown } from '../Dropdown/index.js';
4
4
  import { InputRoot } from '../base/InputRoot/index.js';
@@ -31,9 +31,14 @@ const MultiSelect = ({
31
31
  name,
32
32
  value = [],
33
33
  type,
34
- onChange
34
+ onChange,
35
+ "aria-label": ariaLabel
35
36
  }) => {
36
37
  const [isOpen, setIsOpen] = useState(false);
38
+ const id = useId();
39
+ const labelId = label ? `${id}-label` : undefined;
40
+ const valueId = `${id}-value`;
41
+ const hintId = hint ? `${id}-hint` : undefined;
37
42
  const internalSelectedKeys = useMemo(() => value.map(toKey), [value]);
38
43
  const preparedGroups = useMemo(() => groups.map(group => Object.assign(Object.assign({}, group), {
39
44
  options: group.options.map(option => Object.assign(Object.assign({}, option), {
@@ -72,7 +77,9 @@ const MultiSelect = ({
72
77
  }, className),
73
78
  required: required,
74
79
  label: label,
80
+ labelId: labelId,
75
81
  hint: hint,
82
+ hintId: hintId,
76
83
  hasError: hasError
77
84
  }, /*#__PURE__*/React.createElement(Dropdown, {
78
85
  placement: "bottom-start",
@@ -88,7 +95,11 @@ const MultiSelect = ({
88
95
  }),
89
96
  samewidth: true
90
97
  }, /*#__PURE__*/React.createElement("div", {
91
- tabIndex: 0,
98
+ "aria-describedby": hintId,
99
+ "aria-disabled": disabled || undefined,
100
+ "aria-label": labelId ? undefined : ariaLabel,
101
+ "aria-labelledby": labelId ? `${labelId} ${valueId}` : undefined,
102
+ tabIndex: disabled ? -1 : 0,
92
103
  role: "button",
93
104
  style: {
94
105
  width: fullWidth ? "100%" : "fit-content"
@@ -110,6 +121,7 @@ const MultiSelect = ({
110
121
  }),
111
122
  disabled: Boolean(disabled)
112
123
  }, /*#__PURE__*/React.createElement("div", {
124
+ id: valueId,
113
125
  className: clsx(styles["base-input"], styles[type === "chip" ? "base-input-flex" : "base-input-text"])
114
126
  }, preparedLabel.length ? type === "chip" ?
115
127
  // eslint-disable-next-line @typescript-eslint/no-shadow
@@ -20,7 +20,9 @@ export type SelectedItem = {
20
20
  group: string;
21
21
  option: string;
22
22
  };
23
- export interface MultiSelectProps extends Omit<FormFieldProps, "children"> {
23
+ export interface MultiSelectProps extends Omit<FormFieldProps, "children" | "labelId"> {
24
+ /** Accessible name of the trigger when no visible `label` is passed. */
25
+ "aria-label"?: string;
24
26
  groups: GroupProps[];
25
27
  className?: string;
26
28
  zIndex?: number;
@@ -1,3 +1,3 @@
1
1
  import type { JSX } from "react";
2
2
  import type { SelectProps } from "./index.props";
3
- export declare const Select: <T extends string>({ options, value, name, zIndex, fontSize, label, hint, hasError, required, placeholder, disabled, size, fullWidth, customInputRoot, className, onChange, }: SelectProps<T>) => JSX.Element;
3
+ export declare const Select: <T extends string>({ options, value, name, zIndex, fontSize, label, hint, hasError, required, placeholder, disabled, size, fullWidth, customInputRoot, className, onChange, "aria-label": ariaLabel, }: SelectProps<T>) => JSX.Element;
@@ -1,4 +1,4 @@
1
- import React, { useState, useMemo } from 'react';
1
+ import React, { useState, useId, useMemo } from 'react';
2
2
  import clsx from 'clsx';
3
3
  import { Chevron } from '../Icons/Chevron.js';
4
4
  import { InputRoot } from '../base/InputRoot/index.js';
@@ -23,9 +23,14 @@ const Select = ({
23
23
  fullWidth = false,
24
24
  customInputRoot,
25
25
  className,
26
- onChange
26
+ onChange,
27
+ "aria-label": ariaLabel
27
28
  }) => {
28
29
  const [isOpen, setIsOpen] = useState(false);
30
+ const id = useId();
31
+ const labelId = label ? `${id}-label` : undefined;
32
+ const valueId = `${id}-value`;
33
+ const hintId = hint ? `${id}-hint` : undefined;
29
34
  const preparedOptions = useMemo(() => options.map(({
30
35
  value: lvalue,
31
36
  label: llabel,
@@ -48,7 +53,9 @@ const Select = ({
48
53
  }, className),
49
54
  required: required,
50
55
  label: label,
56
+ labelId: labelId,
51
57
  hint: hint,
58
+ hintId: hintId,
52
59
  hasError: hasError
53
60
  }, /*#__PURE__*/React.createElement(Dropdown, {
54
61
  placement: "bottom-start",
@@ -64,7 +71,11 @@ const Select = ({
64
71
  }),
65
72
  samewidth: true
66
73
  }, customInputRoot ? customInputRoot : (/*#__PURE__*/React.createElement("div", {
67
- tabIndex: 0,
74
+ "aria-describedby": hintId,
75
+ "aria-disabled": disabled || undefined,
76
+ "aria-label": labelId ? undefined : ariaLabel,
77
+ "aria-labelledby": labelId ? `${labelId} ${valueId}` : undefined,
78
+ tabIndex: disabled ? -1 : 0,
68
79
  role: "button",
69
80
  style: {
70
81
  width: fullWidth ? "100%" : "fit-content"
@@ -84,6 +95,7 @@ const Select = ({
84
95
  }),
85
96
  disabled: Boolean(disabled)
86
97
  }, /*#__PURE__*/React.createElement("div", {
98
+ id: valueId,
87
99
  className: styles["base-input"],
88
100
  "data-testid": "base-input"
89
101
  }, preparedLabel !== null && preparedLabel !== void 0 ? preparedLabel : (/*#__PURE__*/React.createElement("span", {
@@ -10,7 +10,9 @@ export interface IOption<T extends string> {
10
10
  label: ReactNode;
11
11
  value: T;
12
12
  }
13
- export interface SelectProps<T extends string> extends Omit<FormFieldProps, "children"> {
13
+ export interface SelectProps<T extends string> extends Omit<FormFieldProps, "children" | "labelId"> {
14
+ /** Accessible name of the trigger when no visible `label` is passed. */
15
+ "aria-label"?: string;
14
16
  className?: string;
15
17
  customInputRoot?: ReactNode;
16
18
  disabled?: boolean;
@@ -22,7 +22,8 @@ const TimeSelect = ({
22
22
  size,
23
23
  zIndex,
24
24
  hasError,
25
- hint
25
+ hint,
26
+ "aria-label": ariaLabel
26
27
  }) => {
27
28
  const baseOptions = useMemo(() => generateSuggest(interval).map(item => ({
28
29
  value: item.time,
@@ -37,6 +38,7 @@ const TimeSelect = ({
37
38
  });
38
39
  }), [baseOptions, currentDate, selectedDate, allowedTimeRange, interval]);
39
40
  return /*#__PURE__*/React.createElement(Select, {
41
+ "aria-label": ariaLabel,
40
42
  className: className,
41
43
  customInputRoot: customInputRoot,
42
44
  fontSize: fontSize,
@@ -1,3 +1,3 @@
1
1
  import React from "react";
2
2
  import type { FormFieldProps } from "./index.props";
3
- export declare const FormField: ({ label, hint, children, hasError, hintId, htmlFor, required, className, ref, }: FormFieldProps) => React.JSX.Element;
3
+ export declare const FormField: ({ label, hint, children, hasError, hintId, htmlFor, labelId, required, className, ref, }: FormFieldProps) => React.JSX.Element;
@@ -10,6 +10,7 @@ const FormField = ({
10
10
  hasError,
11
11
  hintId,
12
12
  htmlFor,
13
+ labelId,
13
14
  required,
14
15
  className,
15
16
  ref
@@ -21,7 +22,8 @@ const FormField = ({
21
22
  [styles.label_required]: Boolean(required)
22
23
  }),
23
24
  tag: "label",
24
- htmlFor: htmlFor
25
+ htmlFor: htmlFor,
26
+ id: labelId
25
27
  }, label)), children, hint && (/*#__PURE__*/React.createElement(Typography, {
26
28
  id: hintId,
27
29
  className: clsx({
@@ -9,6 +9,8 @@ export type FormFieldProps = PropsWithChildren<{
9
9
  /** Id of the control the label belongs to. */
10
10
  htmlFor?: string;
11
11
  label?: ReactNode;
12
+ /** Id of the label, referenced by the control's `aria-labelledby`. */
13
+ labelId?: string;
12
14
  ref?: React.Ref<HTMLDivElement>;
13
15
  required?: boolean;
14
16
  }>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "colibri-ui",
3
- "version": "0.8.92",
3
+ "version": "0.8.93",
4
4
  "description": "React UI components library",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",