@carbon/react 1.103.0-rc.0 → 1.103.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.
@@ -11,8 +11,10 @@ import { type SupportedLocale } from './DatePickerLocales';
11
11
  export type DatePickerTypes = 'simple' | 'single' | 'range';
12
12
  export interface DatePickerProps {
13
13
  /**
14
- * Flatpickr prop passthrough enables direct date input, and when set to false,
15
- * we must clear dates manually by resetting the value prop to to a falsy value (such as `""`, `null`, or `undefined`) or an array of all falsy values, making it a controlled input.
14
+ * Flatpickr prop passthrough enables direct date input, and when set to
15
+ * false, we must clear dates manually by resetting the value prop to an empty
16
+ * value (such as `""`, `null`, or `undefined`) or an array of all empty
17
+ * values, making it a controlled input.
16
18
  */
17
19
  allowInput?: boolean;
18
20
  /**
@@ -26,6 +26,7 @@ import { FormContext } from '../FluidForm/FormContext.js';
26
26
  import { WarningFilled, WarningAltFilled } from '@carbon/icons-react';
27
27
  import { datePartsOrder } from '@carbon/utilities';
28
28
  import { SUPPORTED_LOCALES } from './DatePickerLocales.js';
29
+ import { isEmptyDateValue } from './utils.js';
29
30
 
30
31
  // Weekdays shorthand for English locale
31
32
  // Ensure localization exists before trying to access it
@@ -591,9 +592,9 @@ const DatePicker = /*#__PURE__*/forwardRef((props, ref) => {
591
592
  useEffect(() => {
592
593
  // when value prop is manually reset, this clears the flatpickr calendar instance and text input
593
594
  // run if both:
594
- // 1. value prop is set to a falsy value (`""`, `undefined`, `null`, etc) OR an array of all falsy values
595
+ // 1. value prop is set to an empty value (`""`, `undefined`, `null`, etc) OR an array of all empty values
595
596
  // 2. flatpickr instance contains values in its `selectedDates` property so it hasn't already been cleared
596
- if ((!value || Array.isArray(value) && value.every(date => !date)) && calendarRef.current?.selectedDates.length) {
597
+ if ((isEmptyDateValue(value) || Array.isArray(value) && value.every(isEmptyDateValue)) && calendarRef.current?.selectedDates.length) {
597
598
  calendarRef.current?.clear();
598
599
  if (startInputField.current) {
599
600
  startInputField.current.value = '';
@@ -607,7 +608,7 @@ const DatePicker = /*#__PURE__*/forwardRef((props, ref) => {
607
608
  if (calendarRef.current?.set) {
608
609
  if (value !== undefined) {
609
610
  // To make up for calendarRef.current.setDate not making provision for an empty string or array
610
- if (value === '' || value === null || Array.isArray(value) && (value.length === 0 || value.every(element => !element))) {
611
+ if (value === '' || value === null || Array.isArray(value) && (value.length === 0 || value.every(isEmptyDateValue))) {
611
612
  // only clear if there are selected dates to avoid unnecessary operations
612
613
  if (calendarRef.current.selectedDates.length > 0) {
613
614
  calendarRef.current.clear();
@@ -618,7 +619,7 @@ const DatePicker = /*#__PURE__*/forwardRef((props, ref) => {
618
619
  }
619
620
  updateClassNames(calendarRef.current, prefix);
620
621
  //for simple date picker w/o calendar; initial mount may not have value
621
- } else if (!calendarRef.current && value) {
622
+ } else if (!calendarRef.current && typeof value !== 'undefined' && value !== null) {
622
623
  startInputField.current.value = value;
623
624
  }
624
625
  }, [value, prefix, startInputField]);
@@ -652,8 +653,10 @@ const DatePicker = /*#__PURE__*/forwardRef((props, ref) => {
652
653
  });
653
654
  DatePicker.propTypes = {
654
655
  /**
655
- * Flatpickr prop passthrough enables direct date input, and when set to false,
656
- * we must clear dates manually by resetting the value prop to a falsy value (such as `""`, `null`, or `undefined`) or an array of all falsy values, making it a controlled input.
656
+ * Flatpickr prop passthrough enables direct date input, and when set to
657
+ * false, we must clear dates manually by resetting the value prop to an empty
658
+ * value (such as `""`, `null`, or `undefined`) or an array of all empty
659
+ * values, making it a controlled input.
657
660
  */
658
661
  allowInput: PropTypes.bool,
659
662
  /**
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Copyright IBM Corp. 2019, 2025
2
+ * Copyright IBM Corp. 2019, 2026
3
3
  *
4
4
  * This source code is licensed under the Apache-2.0 license found in the
5
5
  * LICENSE file in the root directory of this source tree.
@@ -6,6 +6,7 @@
6
6
  */
7
7
 
8
8
  import baseRangePlugin from 'flatpickr/dist/plugins/rangePlugin';
9
+ import { isEmptyDateValue } from '../utils.js';
9
10
 
10
11
  /**
11
12
  * @param config Plugin configuration.
@@ -38,7 +39,7 @@ const rangePlugin = (config = {}) => {
38
39
  const inputToElement = typeof inputTo === 'string' ? document.querySelector(inputTo) : inputTo;
39
40
  [inputFrom, inputToElement].forEach((input, i) => {
40
41
  if (input && input instanceof HTMLInputElement) {
41
- input.value = !dates[i] ? '' : formatDate(new Date(dates[i]), fp.config.dateFormat);
42
+ input.value = isEmptyDateValue(dates[i]) ? '' : formatDate(new Date(dates[i]), fp.config.dateFormat);
42
43
  }
43
44
  });
44
45
  }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Copyright IBM Corp. 2026
3
+ *
4
+ * This source code is licensed under the Apache-2.0 license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+ export declare const isEmptyDateValue: (date: unknown) => date is "" | null | undefined;
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Copyright IBM Corp. 2016, 2023
3
+ *
4
+ * This source code is licensed under the Apache-2.0 license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+
8
+ const isEmptyDateValue = date => date === '' || date === null || typeof date === 'undefined';
9
+
10
+ export { isEmptyDateValue };
@@ -288,6 +288,9 @@ function TabList({
288
288
  // VISIBLE IF:
289
289
  // SCROLLABLE
290
290
  // AND SCROLL_LEFT > 0
291
+ //
292
+ // TODO: Hoist `buttonWidth` to a module level constant like
293
+ // `verticalTabHeight`.
291
294
  const buttonWidth = 44;
292
295
  // Next Button
293
296
  // VISIBLE IF:
@@ -382,14 +385,13 @@ function TabList({
382
385
  // eslint-disable-next-line react-hooks/exhaustive-deps -- https://github.com/carbon-design-system/carbon/issues/20452
383
386
  }, []);
384
387
  useEffect(() => {
385
- //adding 1 in calculation for firefox support
388
+ // adding 1 in calculation for firefox support
386
389
  setIsNextButtonVisible(ref.current ? scrollLeft + buttonWidth + ref.current.clientWidth + 1 < ref.current.scrollWidth : false);
387
- if (dismissable) {
388
- if (ref.current) {
389
- setIsScrollable(ref.current.scrollWidth > ref.current.clientWidth);
390
- }
390
+ if (dismissable && ref.current) {
391
+ // adding 1 in calculation for firefox support
392
+ setIsScrollable(ref.current.scrollWidth > ref.current.clientWidth + 1);
391
393
  }
392
- }, [scrollLeft, children, dismissable, isScrollable]);
394
+ }, [children, dismissable, scrollLeft]);
393
395
  useEffect(() => {
394
396
  if (tabs.current[selectedIndex]?.disabled) {
395
397
  const activeTabs = tabs.current.filter(tab => {
@@ -59,11 +59,11 @@ export interface ClickableTileProps extends HTMLAttributes<HTMLAnchorElement> {
59
59
  /**
60
60
  * Specify the function to run when the ClickableTile is clicked
61
61
  */
62
- onClick?(event: MouseEvent): void;
62
+ onClick?(event: MouseEvent<HTMLAnchorElement> | KeyboardEvent<HTMLAnchorElement>): void;
63
63
  /**
64
64
  * Specify the function to run when the ClickableTile is interacted with via a keyboard
65
65
  */
66
- onKeyDown?(event: KeyboardEvent): void;
66
+ onKeyDown?(event: KeyboardEvent<HTMLAnchorElement>): void;
67
67
  /**
68
68
  * The rel property for the link.
69
69
  */
@@ -106,6 +106,9 @@ const ClickableTile = /*#__PURE__*/React.forwardRef(({
106
106
  [`${prefix}--tile--decorator`]: decorator,
107
107
  [`${prefix}--tile--decorator-rounded`]: decorator && hasRoundedCorners
108
108
  }, className);
109
+
110
+ // TODO: Can this be removed? Or is cds--tile--is-clicked supposed to use this instead of `clicked`?
111
+ // This state is never used
109
112
  const [isSelected, setIsSelected] = useState(clicked);
110
113
  function handleOnClick(evt) {
111
114
  evt?.persist?.();
@@ -114,8 +117,10 @@ const ClickableTile = /*#__PURE__*/React.forwardRef(({
114
117
  }
115
118
  function handleOnKeyDown(evt) {
116
119
  evt?.persist?.();
117
- if (matches(evt, [Enter, Space])) {
120
+ if (!href && matches(evt, [Enter, Space])) {
121
+ evt.preventDefault();
118
122
  setIsSelected(!isSelected);
123
+ onClick(evt);
119
124
  }
120
125
  onKeyDown(evt);
121
126
  }
@@ -11,8 +11,10 @@ import { type SupportedLocale } from './DatePickerLocales';
11
11
  export type DatePickerTypes = 'simple' | 'single' | 'range';
12
12
  export interface DatePickerProps {
13
13
  /**
14
- * Flatpickr prop passthrough enables direct date input, and when set to false,
15
- * we must clear dates manually by resetting the value prop to to a falsy value (such as `""`, `null`, or `undefined`) or an array of all falsy values, making it a controlled input.
14
+ * Flatpickr prop passthrough enables direct date input, and when set to
15
+ * false, we must clear dates manually by resetting the value prop to an empty
16
+ * value (such as `""`, `null`, or `undefined`) or an array of all empty
17
+ * values, making it a controlled input.
16
18
  */
17
19
  allowInput?: boolean;
18
20
  /**
@@ -30,6 +30,7 @@ var FormContext = require('../FluidForm/FormContext.js');
30
30
  var iconsReact = require('@carbon/icons-react');
31
31
  var utilities = require('@carbon/utilities');
32
32
  var DatePickerLocales = require('./DatePickerLocales.js');
33
+ var utils$1 = require('./utils.js');
33
34
 
34
35
  // Weekdays shorthand for English locale
35
36
  // Ensure localization exists before trying to access it
@@ -595,9 +596,9 @@ const DatePicker = /*#__PURE__*/React.forwardRef((props, ref) => {
595
596
  React.useEffect(() => {
596
597
  // when value prop is manually reset, this clears the flatpickr calendar instance and text input
597
598
  // run if both:
598
- // 1. value prop is set to a falsy value (`""`, `undefined`, `null`, etc) OR an array of all falsy values
599
+ // 1. value prop is set to an empty value (`""`, `undefined`, `null`, etc) OR an array of all empty values
599
600
  // 2. flatpickr instance contains values in its `selectedDates` property so it hasn't already been cleared
600
- if ((!value || Array.isArray(value) && value.every(date => !date)) && calendarRef.current?.selectedDates.length) {
601
+ if ((utils$1.isEmptyDateValue(value) || Array.isArray(value) && value.every(utils$1.isEmptyDateValue)) && calendarRef.current?.selectedDates.length) {
601
602
  calendarRef.current?.clear();
602
603
  if (startInputField.current) {
603
604
  startInputField.current.value = '';
@@ -611,7 +612,7 @@ const DatePicker = /*#__PURE__*/React.forwardRef((props, ref) => {
611
612
  if (calendarRef.current?.set) {
612
613
  if (value !== undefined) {
613
614
  // To make up for calendarRef.current.setDate not making provision for an empty string or array
614
- if (value === '' || value === null || Array.isArray(value) && (value.length === 0 || value.every(element => !element))) {
615
+ if (value === '' || value === null || Array.isArray(value) && (value.length === 0 || value.every(utils$1.isEmptyDateValue))) {
615
616
  // only clear if there are selected dates to avoid unnecessary operations
616
617
  if (calendarRef.current.selectedDates.length > 0) {
617
618
  calendarRef.current.clear();
@@ -622,7 +623,7 @@ const DatePicker = /*#__PURE__*/React.forwardRef((props, ref) => {
622
623
  }
623
624
  updateClassNames(calendarRef.current, prefix);
624
625
  //for simple date picker w/o calendar; initial mount may not have value
625
- } else if (!calendarRef.current && value) {
626
+ } else if (!calendarRef.current && typeof value !== 'undefined' && value !== null) {
626
627
  startInputField.current.value = value;
627
628
  }
628
629
  }, [value, prefix, startInputField]);
@@ -656,8 +657,10 @@ const DatePicker = /*#__PURE__*/React.forwardRef((props, ref) => {
656
657
  });
657
658
  DatePicker.propTypes = {
658
659
  /**
659
- * Flatpickr prop passthrough enables direct date input, and when set to false,
660
- * we must clear dates manually by resetting the value prop to a falsy value (such as `""`, `null`, or `undefined`) or an array of all falsy values, making it a controlled input.
660
+ * Flatpickr prop passthrough enables direct date input, and when set to
661
+ * false, we must clear dates manually by resetting the value prop to an empty
662
+ * value (such as `""`, `null`, or `undefined`) or an array of all empty
663
+ * values, making it a controlled input.
661
664
  */
662
665
  allowInput: PropTypes.bool,
663
666
  /**
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Copyright IBM Corp. 2019, 2025
2
+ * Copyright IBM Corp. 2019, 2026
3
3
  *
4
4
  * This source code is licensed under the Apache-2.0 license found in the
5
5
  * LICENSE file in the root directory of this source tree.
@@ -8,6 +8,7 @@
8
8
  'use strict';
9
9
 
10
10
  var baseRangePlugin = require('flatpickr/dist/plugins/rangePlugin');
11
+ var utils = require('../utils.js');
11
12
 
12
13
  /**
13
14
  * @param config Plugin configuration.
@@ -40,7 +41,7 @@ const rangePlugin = (config = {}) => {
40
41
  const inputToElement = typeof inputTo === 'string' ? document.querySelector(inputTo) : inputTo;
41
42
  [inputFrom, inputToElement].forEach((input, i) => {
42
43
  if (input && input instanceof HTMLInputElement) {
43
- input.value = !dates[i] ? '' : formatDate(new Date(dates[i]), fp.config.dateFormat);
44
+ input.value = utils.isEmptyDateValue(dates[i]) ? '' : formatDate(new Date(dates[i]), fp.config.dateFormat);
44
45
  }
45
46
  });
46
47
  }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Copyright IBM Corp. 2026
3
+ *
4
+ * This source code is licensed under the Apache-2.0 license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+ export declare const isEmptyDateValue: (date: unknown) => date is "" | null | undefined;
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Copyright IBM Corp. 2016, 2023
3
+ *
4
+ * This source code is licensed under the Apache-2.0 license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+
8
+ 'use strict';
9
+
10
+ const isEmptyDateValue = date => date === '' || date === null || typeof date === 'undefined';
11
+
12
+ exports.isEmptyDateValue = isEmptyDateValue;
@@ -290,6 +290,9 @@ function TabList({
290
290
  // VISIBLE IF:
291
291
  // SCROLLABLE
292
292
  // AND SCROLL_LEFT > 0
293
+ //
294
+ // TODO: Hoist `buttonWidth` to a module level constant like
295
+ // `verticalTabHeight`.
293
296
  const buttonWidth = 44;
294
297
  // Next Button
295
298
  // VISIBLE IF:
@@ -384,14 +387,13 @@ function TabList({
384
387
  // eslint-disable-next-line react-hooks/exhaustive-deps -- https://github.com/carbon-design-system/carbon/issues/20452
385
388
  }, []);
386
389
  React.useEffect(() => {
387
- //adding 1 in calculation for firefox support
390
+ // adding 1 in calculation for firefox support
388
391
  setIsNextButtonVisible(ref.current ? scrollLeft + buttonWidth + ref.current.clientWidth + 1 < ref.current.scrollWidth : false);
389
- if (dismissable) {
390
- if (ref.current) {
391
- setIsScrollable(ref.current.scrollWidth > ref.current.clientWidth);
392
- }
392
+ if (dismissable && ref.current) {
393
+ // adding 1 in calculation for firefox support
394
+ setIsScrollable(ref.current.scrollWidth > ref.current.clientWidth + 1);
393
395
  }
394
- }, [scrollLeft, children, dismissable, isScrollable]);
396
+ }, [children, dismissable, scrollLeft]);
395
397
  React.useEffect(() => {
396
398
  if (tabs.current[selectedIndex]?.disabled) {
397
399
  const activeTabs = tabs.current.filter(tab => {
@@ -59,11 +59,11 @@ export interface ClickableTileProps extends HTMLAttributes<HTMLAnchorElement> {
59
59
  /**
60
60
  * Specify the function to run when the ClickableTile is clicked
61
61
  */
62
- onClick?(event: MouseEvent): void;
62
+ onClick?(event: MouseEvent<HTMLAnchorElement> | KeyboardEvent<HTMLAnchorElement>): void;
63
63
  /**
64
64
  * Specify the function to run when the ClickableTile is interacted with via a keyboard
65
65
  */
66
- onKeyDown?(event: KeyboardEvent): void;
66
+ onKeyDown?(event: KeyboardEvent<HTMLAnchorElement>): void;
67
67
  /**
68
68
  * The rel property for the link.
69
69
  */
@@ -108,6 +108,9 @@ const ClickableTile = /*#__PURE__*/React.forwardRef(({
108
108
  [`${prefix}--tile--decorator`]: decorator,
109
109
  [`${prefix}--tile--decorator-rounded`]: decorator && hasRoundedCorners
110
110
  }, className);
111
+
112
+ // TODO: Can this be removed? Or is cds--tile--is-clicked supposed to use this instead of `clicked`?
113
+ // This state is never used
111
114
  const [isSelected, setIsSelected] = React.useState(clicked);
112
115
  function handleOnClick(evt) {
113
116
  evt?.persist?.();
@@ -116,8 +119,10 @@ const ClickableTile = /*#__PURE__*/React.forwardRef(({
116
119
  }
117
120
  function handleOnKeyDown(evt) {
118
121
  evt?.persist?.();
119
- if (match.matches(evt, [keys.Enter, keys.Space])) {
122
+ if (!href && match.matches(evt, [keys.Enter, keys.Space])) {
123
+ evt.preventDefault();
120
124
  setIsSelected(!isSelected);
125
+ onClick(evt);
121
126
  }
122
127
  onKeyDown(evt);
123
128
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@carbon/react",
3
3
  "description": "React components for the Carbon Design System",
4
- "version": "1.103.0-rc.0",
4
+ "version": "1.103.0",
5
5
  "license": "Apache-2.0",
6
6
  "main": "lib/index.js",
7
7
  "types": "lib/index.d.ts",
@@ -52,11 +52,11 @@
52
52
  },
53
53
  "dependencies": {
54
54
  "@babel/runtime": "^7.27.3",
55
- "@carbon/feature-flags": "^1.1.0-rc.0",
55
+ "@carbon/feature-flags": "^1.1.0",
56
56
  "@carbon/icons-react": "^11.76.0",
57
57
  "@carbon/layout": "^11.49.0",
58
- "@carbon/styles": "^1.102.0-rc.0",
59
- "@carbon/utilities": "^0.17.0-rc.0",
58
+ "@carbon/styles": "^1.102.0",
59
+ "@carbon/utilities": "^0.17.0",
60
60
  "@floating-ui/react": "^0.27.4",
61
61
  "@ibm/telemetry-js": "^1.5.0",
62
62
  "classnames": "2.5.1",
@@ -131,5 +131,5 @@
131
131
  "**/*.scss",
132
132
  "**/*.css"
133
133
  ],
134
- "gitHead": "f3e7c2811340637ead19b4a1a550a20820602cc4"
134
+ "gitHead": "443fbe43ff4bd1df327997b8b0b0ebeee634d002"
135
135
  }