@carbon/react 1.70.0 → 1.71.0-rc.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (96) hide show
  1. package/.playwright/INTERNAL_AVT_REPORT_DO_NOT_USE.json +895 -895
  2. package/es/components/AILabel/index.js +15 -15
  3. package/es/components/CodeSnippet/CodeSnippet.d.ts +5 -2
  4. package/es/components/CodeSnippet/CodeSnippet.js +40 -1
  5. package/es/components/ComboBox/ComboBox.js +19 -22
  6. package/es/components/ComboButton/index.js +40 -1
  7. package/es/components/ContentSwitcher/ContentSwitcher.d.ts +2 -2
  8. package/es/components/ContentSwitcher/ContentSwitcher.js +1 -1
  9. package/es/components/Copy/Copy.d.ts +5 -2
  10. package/es/components/Copy/Copy.js +40 -1
  11. package/es/components/CopyButton/CopyButton.d.ts +5 -2
  12. package/es/components/CopyButton/CopyButton.js +40 -1
  13. package/es/components/DataTable/TableSelectRow.js +14 -6
  14. package/es/components/DataTable/TableToolbarSearch.js +1 -1
  15. package/es/components/DataTable/stories/examples/TableToolbarFilter.d.ts +1 -1
  16. package/es/components/DatePicker/plugins/fixEventsPlugin.js +2 -2
  17. package/es/components/DatePickerInput/DatePickerInput.d.ts +6 -1
  18. package/es/components/DatePickerInput/DatePickerInput.js +16 -10
  19. package/es/components/Dropdown/Dropdown.d.ts +5 -0
  20. package/es/components/Dropdown/Dropdown.js +132 -92
  21. package/es/components/FeatureFlags/index.js +1 -2
  22. package/es/components/IconButton/index.d.ts +4 -1
  23. package/es/components/IconButton/index.js +40 -1
  24. package/es/components/InlineCheckbox/InlineCheckbox.d.ts +50 -0
  25. package/es/components/InlineCheckbox/InlineCheckbox.js +3 -6
  26. package/es/components/InlineCheckbox/index.d.ts +9 -0
  27. package/es/components/LayoutDirection/LayoutDirection.d.ts +44 -0
  28. package/es/components/LayoutDirection/LayoutDirectionContext.d.ts +10 -0
  29. package/es/components/LayoutDirection/useLayoutDirection.d.ts +12 -0
  30. package/es/components/Menu/MenuItem.js +0 -3
  31. package/es/components/MultiSelect/FilterableMultiSelect.d.ts +1 -1
  32. package/es/components/MultiSelect/FilterableMultiSelect.js +1 -2
  33. package/es/components/MultiSelect/MultiSelect.js +1 -1
  34. package/es/components/Notification/Notification.d.ts +9 -2
  35. package/es/components/Notification/Notification.js +16 -2
  36. package/es/components/NumberInput/NumberInput.d.ts +5 -0
  37. package/es/components/NumberInput/NumberInput.js +17 -9
  38. package/es/components/OverflowMenu/next/index.js +40 -1
  39. package/es/components/Pagination/Pagination.js +1 -1
  40. package/es/components/PaginationNav/PaginationNav.d.ts +1 -1
  41. package/es/components/PaginationNav/PaginationNav.js +10 -5
  42. package/es/components/Tabs/Tabs.js +46 -29
  43. package/es/components/TextArea/TextArea.d.ts +5 -0
  44. package/es/components/TextArea/TextArea.js +15 -7
  45. package/es/components/TextInput/TextInput.d.ts +5 -0
  46. package/es/components/TextInput/TextInput.js +15 -7
  47. package/es/components/UIShell/SideNavMenuItem.d.ts +5 -1
  48. package/es/components/UIShell/SideNavMenuItem.js +7 -2
  49. package/lib/components/AILabel/index.js +15 -15
  50. package/lib/components/CodeSnippet/CodeSnippet.d.ts +5 -2
  51. package/lib/components/CodeSnippet/CodeSnippet.js +40 -1
  52. package/lib/components/ComboBox/ComboBox.js +19 -22
  53. package/lib/components/ComboButton/index.js +40 -1
  54. package/lib/components/ContentSwitcher/ContentSwitcher.d.ts +2 -2
  55. package/lib/components/ContentSwitcher/ContentSwitcher.js +1 -1
  56. package/lib/components/Copy/Copy.d.ts +5 -2
  57. package/lib/components/Copy/Copy.js +40 -1
  58. package/lib/components/CopyButton/CopyButton.d.ts +5 -2
  59. package/lib/components/CopyButton/CopyButton.js +40 -1
  60. package/lib/components/DataTable/TableSelectRow.js +14 -6
  61. package/lib/components/DataTable/TableToolbarSearch.js +1 -1
  62. package/lib/components/DataTable/stories/examples/TableToolbarFilter.d.ts +1 -1
  63. package/lib/components/DatePicker/plugins/fixEventsPlugin.js +2 -2
  64. package/lib/components/DatePickerInput/DatePickerInput.d.ts +6 -1
  65. package/lib/components/DatePickerInput/DatePickerInput.js +16 -10
  66. package/lib/components/Dropdown/Dropdown.d.ts +5 -0
  67. package/lib/components/Dropdown/Dropdown.js +131 -91
  68. package/lib/components/FeatureFlags/index.js +1 -2
  69. package/lib/components/IconButton/index.d.ts +4 -1
  70. package/lib/components/IconButton/index.js +40 -1
  71. package/lib/components/InlineCheckbox/InlineCheckbox.d.ts +50 -0
  72. package/lib/components/InlineCheckbox/InlineCheckbox.js +3 -6
  73. package/lib/components/InlineCheckbox/index.d.ts +9 -0
  74. package/lib/components/LayoutDirection/LayoutDirection.d.ts +44 -0
  75. package/lib/components/LayoutDirection/LayoutDirectionContext.d.ts +10 -0
  76. package/lib/components/LayoutDirection/useLayoutDirection.d.ts +12 -0
  77. package/lib/components/Menu/MenuItem.js +0 -3
  78. package/lib/components/MultiSelect/FilterableMultiSelect.d.ts +1 -1
  79. package/lib/components/MultiSelect/FilterableMultiSelect.js +1 -2
  80. package/lib/components/MultiSelect/MultiSelect.js +1 -1
  81. package/lib/components/Notification/Notification.d.ts +9 -2
  82. package/lib/components/Notification/Notification.js +16 -2
  83. package/lib/components/NumberInput/NumberInput.d.ts +5 -0
  84. package/lib/components/NumberInput/NumberInput.js +17 -9
  85. package/lib/components/OverflowMenu/next/index.js +40 -1
  86. package/lib/components/Pagination/Pagination.js +1 -1
  87. package/lib/components/PaginationNav/PaginationNav.d.ts +1 -1
  88. package/lib/components/PaginationNav/PaginationNav.js +10 -5
  89. package/lib/components/Tabs/Tabs.js +46 -29
  90. package/lib/components/TextArea/TextArea.d.ts +5 -0
  91. package/lib/components/TextArea/TextArea.js +15 -7
  92. package/lib/components/TextInput/TextInput.d.ts +5 -0
  93. package/lib/components/TextInput/TextInput.js +15 -7
  94. package/lib/components/UIShell/SideNavMenuItem.d.ts +5 -1
  95. package/lib/components/UIShell/SideNavMenuItem.js +7 -2
  96. package/package.json +4 -4
@@ -264,7 +264,7 @@ const FilterableMultiSelect = /*#__PURE__*/React__default.forwardRef(function Fi
264
264
  inputValue,
265
265
  stateReducer,
266
266
  isItemDisabled(item, _index) {
267
- return item.disabled;
267
+ return item?.disabled;
268
268
  }
269
269
  });
270
270
  function stateReducer(state, actionAndChanges) {
@@ -381,7 +381,6 @@ const FilterableMultiSelect = /*#__PURE__*/React__default.forwardRef(function Fi
381
381
  activeIndex: highlightedIndex,
382
382
  initialSelectedItems,
383
383
  selectedItems: controlledSelectedItems,
384
- itemToString,
385
384
  onStateChange(changes) {
386
385
  switch (changes.type) {
387
386
  case SelectedItemKeyDownBackspace:
@@ -196,7 +196,7 @@ const MultiSelect = /*#__PURE__*/React__default.forwardRef((_ref, ref) => {
196
196
  selectedItem: controlledSelectedItems,
197
197
  items: filteredItems,
198
198
  isItemDisabled(item, _index) {
199
- return item.disabled;
199
+ return item?.disabled;
200
200
  },
201
201
  ...downshiftProps
202
202
  };
@@ -516,6 +516,13 @@ export declare namespace ActionableNotification {
516
516
  * Callout
517
517
  * ==================
518
518
  */
519
+ /**
520
+ * Deprecated callout kind values.
521
+ * @deprecated Use NewKindProps instead.
522
+ */
523
+ export type DeprecatedKindProps = 'error' | 'info' | 'info-square' | 'success' | 'warning' | 'warning-alt';
524
+ export type NewKindProps = 'warning' | 'info';
525
+ export type KindProps = DeprecatedKindProps | NewKindProps;
519
526
  export interface CalloutProps extends HTMLAttributes<HTMLDivElement> {
520
527
  /**
521
528
  * Pass in the action button label that will be rendered within the ActionableNotification.
@@ -532,7 +539,7 @@ export interface CalloutProps extends HTMLAttributes<HTMLDivElement> {
532
539
  /**
533
540
  * Specify what state the notification represents
534
541
  */
535
- kind?: 'error' | 'info' | 'info-square' | 'success' | 'warning' | 'warning-alt';
542
+ kind?: KindProps;
536
543
  /**
537
544
  * Specify whether you are using the low contrast variant of the Callout.
538
545
  */
@@ -576,7 +583,7 @@ export declare namespace Callout {
576
583
  /**
577
584
  * Specify what state the notification represents
578
585
  */
579
- kind: PropTypes.Requireable<string>;
586
+ kind: (props: any, propName: any, componentName: any, ...rest: any[]) => any;
580
587
  /**
581
588
  * Specify whether you are using the low contrast variant of the Callout.
582
589
  */
@@ -22,6 +22,7 @@ import { noopFn } from '../../internal/noopFn.js';
22
22
  import wrapFocus, { wrapFocusWithoutSentinels } from '../../internal/wrapFocus.js';
23
23
  import { useFeatureFlag } from '../FeatureFlags/index.js';
24
24
  import { warning } from '../../internal/warning.js';
25
+ import deprecateValuesWithin from '../../prop-types/deprecateValuesWithin.js';
25
26
  import { Text } from '../Text/Text.js';
26
27
  import { match, matches } from '../../internal/keyboard/match.js';
27
28
  import { Tab, Escape } from '../../internal/keyboard/keys.js';
@@ -693,6 +694,19 @@ ActionableNotification.propTypes = {
693
694
  * ==================
694
695
  */
695
696
 
697
+ /**
698
+ * Deprecated callout kind values.
699
+ * @deprecated Use NewKindProps instead.
700
+ */
701
+
702
+ const propMappingFunction = deprecatedValue => {
703
+ const mapping = {
704
+ error: 'warning',
705
+ // only redirect error -> warning
706
+ success: 'info' // only redirect success -> info
707
+ };
708
+ return mapping[deprecatedValue];
709
+ };
696
710
  function Callout(_ref8) {
697
711
  let {
698
712
  actionButtonLabel,
@@ -703,7 +717,7 @@ function Callout(_ref8) {
703
717
  subtitle,
704
718
  statusIconDescription,
705
719
  className,
706
- kind = 'error',
720
+ kind = 'info',
707
721
  lowContrast,
708
722
  ...rest
709
723
  } = _ref8;
@@ -759,7 +773,7 @@ Callout.propTypes = {
759
773
  /**
760
774
  * Specify what state the notification represents
761
775
  */
762
- kind: PropTypes.oneOf(['error', 'info', 'info-square', 'success', 'warning', 'warning-alt']),
776
+ kind: deprecateValuesWithin(PropTypes.oneOf(['error', 'info', 'info-square', 'success', 'warning', 'warning-alt']), ['warning', 'info'], propMappingFunction),
763
777
  /**
764
778
  * Specify whether you are using the low contrast variant of the Callout.
765
779
  */
@@ -24,6 +24,10 @@ export interface NumberInputProps extends Omit<React.InputHTMLAttributes<HTMLInp
24
24
  * Specify an optional className to be applied to the wrapper node
25
25
  */
26
26
  className?: string;
27
+ /**
28
+ * **Experimental**: Provide a `decorator` component to be rendered inside the `TextInput` component
29
+ */
30
+ decorator?: ReactNode;
27
31
  /**
28
32
  * Optional starting value for uncontrolled state
29
33
  */
@@ -113,6 +117,7 @@ export interface NumberInputProps extends Omit<React.InputHTMLAttributes<HTMLInp
113
117
  */
114
118
  size?: 'sm' | 'md' | 'lg';
115
119
  /**
120
+ * @deprecated please use `decorator` instead.
116
121
  * **Experimental**: Provide a `Slug` component to be rendered inside the `TextInput` component
117
122
  */
118
123
  slug?: ReactNode;
@@ -37,6 +37,7 @@ const NumberInput = /*#__PURE__*/React__default.forwardRef(function NumberInput(
37
37
  const {
38
38
  allowEmpty = false,
39
39
  className: customClassName,
40
+ decorator,
40
41
  disabled = false,
41
42
  disableWheel: disableWheelProp = false,
42
43
  defaultValue = 0,
@@ -112,7 +113,8 @@ const NumberInput = /*#__PURE__*/React__default.forwardRef(function NumberInput(
112
113
  const [incrementNumLabel, decrementNumLabel] = [t('increment.number'), t('decrement.number')];
113
114
  const wrapperClasses = cx(`${prefix}--number__input-wrapper`, {
114
115
  [`${prefix}--number__input-wrapper--warning`]: normalizedProps.warn,
115
- [`${prefix}--number__input-wrapper--slug`]: slug
116
+ [`${prefix}--number__input-wrapper--slug`]: slug,
117
+ [`${prefix}--number__input-wrapper--decorator`]: decorator
116
118
  });
117
119
  const iconClasses = cx({
118
120
  [`${prefix}--number__invalid`]: normalizedProps.invalid || normalizedProps.warn,
@@ -186,18 +188,18 @@ const NumberInput = /*#__PURE__*/React__default.forwardRef(function NumberInput(
186
188
  }
187
189
  }
188
190
 
189
- // Slug is always size `mini`
190
- let normalizedSlug;
191
- if (slug && slug['type']?.displayName === 'AILabel') {
192
- normalizedSlug = /*#__PURE__*/React__default.cloneElement(slug, {
191
+ // AILabel always size `mini`
192
+ let normalizedDecorator = /*#__PURE__*/React__default.isValidElement(slug ?? decorator) ? slug ?? decorator : null;
193
+ if (normalizedDecorator && normalizedDecorator['type']?.displayName === 'AILabel') {
194
+ normalizedDecorator = /*#__PURE__*/React__default.cloneElement(normalizedDecorator, {
193
195
  size: 'mini'
194
196
  });
195
197
  }
196
198
 
197
199
  // Need to update the internal value when the revert button is clicked
198
200
  let isRevertActive;
199
- if (slug && slug['type']?.displayName === 'AILabel') {
200
- isRevertActive = normalizedSlug.props.revertActive;
201
+ if (normalizedDecorator && normalizedDecorator['type']?.displayName === 'AILabel') {
202
+ isRevertActive = normalizedDecorator.props.revertActive;
201
203
  }
202
204
  useEffect(() => {
203
205
  if (!isRevertActive && slug && defaultValue) {
@@ -252,7 +254,9 @@ const NumberInput = /*#__PURE__*/React__default.forwardRef(function NumberInput(
252
254
  step: step,
253
255
  type: "number",
254
256
  value: value
255
- })), normalizedSlug, Icon ? /*#__PURE__*/React__default.createElement(Icon, {
257
+ })), slug ? normalizedDecorator : decorator ? /*#__PURE__*/React__default.createElement("div", {
258
+ className: `${prefix}--number__input-inner-wrapper--decorator`
259
+ }, normalizedDecorator) : '', Icon ? /*#__PURE__*/React__default.createElement(Icon, {
256
260
  className: iconClasses
257
261
  }) : null, !hideSteppers && /*#__PURE__*/React__default.createElement("div", {
258
262
  className: `${prefix}--number__controls`
@@ -297,6 +301,10 @@ NumberInput.propTypes = {
297
301
  * Specify an optional className to be applied to the wrapper node
298
302
  */
299
303
  className: PropTypes.string,
304
+ /**
305
+ * **Experimental**: Provide a `decorator` component to be rendered inside the `NumberInput` component
306
+ */
307
+ decorator: PropTypes.node,
300
308
  /**
301
309
  * Optional starting value for uncontrolled state
302
310
  */
@@ -379,7 +387,7 @@ NumberInput.propTypes = {
379
387
  /**
380
388
  * **Experimental**: Provide a `Slug` component to be rendered inside the `NumberInput` component
381
389
  */
382
- slug: PropTypes.node,
390
+ slug: deprecate(PropTypes.node, 'The `slug` prop for `NumberInput` is no longer needed and has ' + 'been deprecated in v11 in favor of the new `decorator` prop. It will be moved in the next major release.'),
383
391
  /**
384
392
  * Specify how much the values should increase/decrease upon clicking on up/down button
385
393
  */
@@ -19,8 +19,22 @@ import mergeRefs from '../../../tools/mergeRefs.js';
19
19
  import { useId } from '../../../internal/useId.js';
20
20
  import { usePrefix } from '../../../internal/usePrefix.js';
21
21
  import { useAttachedMenu } from '../../../internal/useAttachedMenu.js';
22
+ import deprecateValuesWithin from '../../../prop-types/deprecateValuesWithin.js';
22
23
 
23
24
  const defaultSize = 'md';
25
+ const propMappingFunction = deprecatedValue => {
26
+ const mapping = {
27
+ 'top-left': 'top-start',
28
+ 'top-right': 'top-end',
29
+ 'bottom-left': 'bottom-start',
30
+ 'bottom-right': 'bottom-end',
31
+ 'left-bottom': 'left-end',
32
+ 'left-top': 'left-start',
33
+ 'right-bottom': 'right-end',
34
+ 'right-top': 'right-start'
35
+ };
36
+ return mapping[deprecatedValue];
37
+ };
24
38
  const OverflowMenu = /*#__PURE__*/React__default.forwardRef(function OverflowMenu(_ref, forwardRef) {
25
39
  let {
26
40
  autoAlign = false,
@@ -162,7 +176,32 @@ OverflowMenu.propTypes = {
162
176
  /**
163
177
  * Specify how the trigger tooltip should be aligned.
164
178
  */
165
- tooltipAlignment: PropTypes.oneOf(['top', 'top-left', 'top-right', 'bottom', 'bottom-left', 'bottom-right', 'left', 'right']),
179
+ tooltipAlignment: deprecateValuesWithin(PropTypes.oneOf(['top', 'top-left',
180
+ // deprecated use top-start instead
181
+ 'top-right',
182
+ // deprecated use top-end instead
183
+
184
+ 'bottom', 'bottom-left',
185
+ // deprecated use bottom-start instead
186
+ 'bottom-right',
187
+ // deprecated use bottom-end instead
188
+
189
+ 'left', 'left-bottom',
190
+ // deprecated use left-end instead
191
+ 'left-top',
192
+ // deprecated use left-start instead
193
+
194
+ 'right', 'right-bottom',
195
+ // deprecated use right-end instead
196
+ 'right-top',
197
+ // deprecated use right-start instead
198
+
199
+ // new values to match floating-ui
200
+ 'top-start', 'top-end', 'bottom-start', 'bottom-end', 'left-end', 'left-start', 'right-end', 'right-start']),
201
+ //allowed prop values
202
+ ['top', 'top-start', 'top-end', 'bottom', 'bottom-start', 'bottom-end', 'left', 'left-start', 'left-end', 'right', 'right-start', 'right-end'],
203
+ //optional mapper function
204
+ propMappingFunction),
166
205
  /**
167
206
  * Specify a DOM node where the Menu should be rendered in. Defaults to document.body.
168
207
  */
@@ -245,7 +245,7 @@ const Pagination = /*#__PURE__*/React__default.forwardRef(function Pagination(_r
245
245
  onClick: decrementPage,
246
246
  ref: backBtnRef
247
247
  }, _CaretLeft || (_CaretLeft = /*#__PURE__*/React__default.createElement(CaretLeft, null))), /*#__PURE__*/React__default.createElement(IconButton, {
248
- align: "top-right",
248
+ align: "top-end",
249
249
  disabled: forwardButtonDisabled || isLastPage,
250
250
  kind: "ghost",
251
251
  className: forwardButtonClasses,
@@ -28,7 +28,7 @@ interface PaginationNavProps extends Omit<React.HTMLAttributes<HTMLElement>, 'on
28
28
  */
29
29
  disableOverflow?: boolean;
30
30
  /**
31
- * The number of items to be shown.
31
+ * The number of items to be shown (minimum of 4 unless props.items < 4).
32
32
  */
33
33
  itemsShown?: number;
34
34
  /**
@@ -12,6 +12,8 @@ import cx from 'classnames';
12
12
  import { CaretRight, CaretLeft, OverflowMenuHorizontal } from '@carbon/icons-react';
13
13
  import { IconButton } from '../IconButton/index.js';
14
14
  import { usePrefix } from '../../internal/usePrefix.js';
15
+ import { breakpoints } from '@carbon/layout';
16
+ import { useMatchMedia } from '../../internal/useMatchMedia.js';
15
17
 
16
18
  var _CaretRight, _CaretLeft, _option;
17
19
  const translationIds = {
@@ -179,8 +181,10 @@ const PaginationNav = /*#__PURE__*/React__default.forwardRef(function Pagination
179
181
  translateWithId: t = translateWithId,
180
182
  ...rest
181
183
  } = _ref4;
184
+ const smMediaQuery = `(max-width: ${breakpoints.sm.width})`;
185
+ const isSm = useMatchMedia(smMediaQuery);
182
186
  const [currentPage, setCurrentPage] = useState(page);
183
- const [itemsDisplayedOnPage, setItemsDisplayedOnPage] = useState(itemsShown >= 4 ? itemsShown : 4);
187
+ const [itemsDisplayedOnPage, setItemsDisplayedOnPage] = useState(itemsShown >= 4 && !isSm ? itemsShown : 4);
184
188
  const [cuts, setCuts] = useState(calculateCuts(currentPage, totalItems, itemsDisplayedOnPage));
185
189
  const prevPage = usePrevious(currentPage);
186
190
  const prefix = usePrefix();
@@ -225,9 +229,10 @@ const PaginationNav = /*#__PURE__*/React__default.forwardRef(function Pagination
225
229
 
226
230
  // re-calculate cuts if props.totalItems or props.itemsShown change
227
231
  useEffect(() => {
228
- setItemsDisplayedOnPage(itemsShown >= 4 ? itemsShown : 4);
229
- setCuts(calculateCuts(currentPage, totalItems, itemsShown));
230
- }, [totalItems, itemsShown]); // eslint-disable-line react-hooks/exhaustive-deps
232
+ const itemsToBeShown = itemsShown >= 4 && !isSm ? itemsShown : 4;
233
+ setItemsDisplayedOnPage(Math.max(itemsToBeShown, 4));
234
+ setCuts(calculateCuts(currentPage, totalItems, Math.max(itemsToBeShown, 4)));
235
+ }, [totalItems, itemsShown, isSm]); // eslint-disable-line react-hooks/exhaustive-deps
231
236
 
232
237
  // update cuts if necessary whenever currentPage changes
233
238
  useEffect(() => {
@@ -386,7 +391,7 @@ PaginationNav.propTypes = {
386
391
  // eslint-disable-line react/prop-types
387
392
 
388
393
  /**
389
- * The number of items to be shown.
394
+ * The number of items to be shown (minimum of 4 unless props.items < 4).
390
395
  */
391
396
  itemsShown: PropTypes.number,
392
397
  /**
@@ -346,6 +346,41 @@ function TabList(_ref4) {
346
346
  setActiveIndex(selectedIndex);
347
347
  }
348
348
  }
349
+
350
+ /**
351
+ * Scroll the tab into view if it is not already visible
352
+ * @param tab - The tab to scroll into view
353
+ * @returns {void}
354
+ */
355
+ function scrollTabIntoView(tab) {
356
+ if (!isScrollable || !ref.current) {
357
+ return;
358
+ }
359
+ if (tab) {
360
+ // The width of the "scroll buttons"
361
+ const {
362
+ width: tabWidth
363
+ } = tab.getBoundingClientRect();
364
+
365
+ // The start and end position of the selected tab
366
+ const start = tab.offsetLeft;
367
+ const end = tab.offsetLeft + tabWidth;
368
+
369
+ // The start and end of the visible area for the tabs
370
+ const visibleStart = ref.current.scrollLeft + buttonWidth;
371
+ const visibleEnd = ref.current.scrollLeft + ref.current.clientWidth - buttonWidth;
372
+
373
+ // The beginning of the tab is clipped and not visible
374
+ if (start < visibleStart) {
375
+ setScrollLeft(start - buttonWidth);
376
+ }
377
+
378
+ // The end of the tab is clipped and not visible
379
+ if (end > visibleEnd) {
380
+ setScrollLeft(end + buttonWidth - ref.current.clientWidth);
381
+ }
382
+ }
383
+ }
349
384
  useEffectOnce(() => {
350
385
  const tab = tabs.current[selectedIndex];
351
386
  if (scrollIntoView && tab) {
@@ -377,12 +412,12 @@ function TabList(_ref4) {
377
412
  });
378
413
  useIsomorphicEffect(() => {
379
414
  if (ref.current) {
380
- //adding 1 in calculation for firefox support
415
+ // adding 1 in calculation for firefox support
381
416
  setIsScrollable(ref.current.scrollWidth > ref.current.clientWidth + 1);
382
417
  }
383
418
  function handler() {
384
419
  if (ref.current) {
385
- //adding 1 in calculation for firefox support
420
+ // adding 1 in calculation for firefox support
386
421
  setIsScrollable(ref.current.scrollWidth > ref.current.clientWidth + 1);
387
422
  }
388
423
  }
@@ -400,36 +435,18 @@ function TabList(_ref4) {
400
435
  ref.current.scrollLeft = scrollLeft;
401
436
  }
402
437
  }, [scrollLeft]);
438
+
439
+ // scroll manual tabs when active index changes (focus outline movement)
403
440
  useIsomorphicEffect(() => {
404
- if (!isScrollable || !ref.current) {
405
- return;
406
- }
407
441
  const tab = activation === 'manual' ? tabs.current[activeIndex] : tabs.current[selectedIndex];
408
- if (tab) {
409
- // The width of the "scroll buttons"
410
-
411
- // The start and end position of the selected tab
412
- const {
413
- width: tabWidth
414
- } = tab.getBoundingClientRect();
415
- const start = tab.offsetLeft;
416
- const end = tab.offsetLeft + tabWidth;
417
-
418
- // The start and end of the visible area for the tabs
419
- const visibleStart = ref.current.scrollLeft + buttonWidth;
420
- const visibleEnd = ref.current.scrollLeft + ref.current.clientWidth - buttonWidth;
421
-
422
- // The beginning of the tab is clipped and not visible
423
- if (start < visibleStart) {
424
- setScrollLeft(start - buttonWidth);
425
- }
442
+ scrollTabIntoView(tab);
443
+ }, [activation, activeIndex]);
426
444
 
427
- // The end of the tab is clipped and not visible
428
- if (end > visibleEnd) {
429
- setScrollLeft(end + buttonWidth - ref.current.clientWidth);
430
- }
431
- }
432
- }, [activation, activeIndex, selectedIndex, isScrollable, children]);
445
+ // scroll tabs when selected index changes
446
+ useIsomorphicEffect(() => {
447
+ const tab = tabs.current[selectedIndex];
448
+ scrollTabIntoView(tab);
449
+ }, [selectedIndex, isScrollable, children]);
433
450
  usePressable(previousButton, {
434
451
  onPress(_ref6) {
435
452
  let {
@@ -15,6 +15,10 @@ export interface TextAreaProps extends React.InputHTMLAttributes<HTMLTextAreaEle
15
15
  * Specify the `cols` attribute for the underlying `<textarea>` node
16
16
  */
17
17
  cols?: number;
18
+ /**
19
+ * **Experimental**: Provide a `decorator` component to be rendered inside the `TextArea` component
20
+ */
21
+ decorator?: ReactNode;
18
22
  /**
19
23
  * Optionally provide the default value of the `<textarea>`
20
24
  */
@@ -90,6 +94,7 @@ export interface TextAreaProps extends React.InputHTMLAttributes<HTMLTextAreaEle
90
94
  */
91
95
  rows?: number;
92
96
  /**
97
+ * @deprecated please use `decorator` instead.
93
98
  * **Experimental**: Provide a `Slug` component to be rendered inside the `TextArea` component
94
99
  */
95
100
  slug?: ReactNode;
@@ -25,6 +25,7 @@ import { Text } from '../Text/Text.js';
25
25
  const TextArea = /*#__PURE__*/React__default.forwardRef((props, forwardRef) => {
26
26
  const {
27
27
  className,
28
+ decorator,
28
29
  disabled = false,
29
30
  id,
30
31
  labelText,
@@ -154,7 +155,8 @@ const TextArea = /*#__PURE__*/React__default.forwardRef((props, forwardRef) => {
154
155
  [`${prefix}--text-area__wrapper--cols`]: other.cols,
155
156
  [`${prefix}--text-area__wrapper--readonly`]: other.readOnly,
156
157
  [`${prefix}--text-area__wrapper--warn`]: warn,
157
- [`${prefix}--text-area__wrapper--slug`]: slug
158
+ [`${prefix}--text-area__wrapper--slug`]: slug,
159
+ [`${prefix}--text-area__wrapper--decorator`]: decorator
158
160
  });
159
161
  const labelClasses = cx(`${prefix}--label`, {
160
162
  [`${prefix}--visually-hidden`]: hideLabel && !isFluid,
@@ -253,10 +255,10 @@ const TextArea = /*#__PURE__*/React__default.forwardRef((props, forwardRef) => {
253
255
  ref: ref
254
256
  }));
255
257
 
256
- // Slug is always size `mini`
257
- let normalizedSlug;
258
- if (slug && slug['type']?.displayName === 'AILabel') {
259
- normalizedSlug = /*#__PURE__*/React__default.cloneElement(slug, {
258
+ // AILabel is always size `mini`
259
+ let normalizedDecorator = /*#__PURE__*/React__default.isValidElement(slug ?? decorator) ? slug ?? decorator : null;
260
+ if (normalizedDecorator && normalizedDecorator['type']?.displayName === 'AILabel') {
261
+ normalizedDecorator = /*#__PURE__*/React__default.cloneElement(normalizedDecorator, {
260
262
  size: 'mini'
261
263
  });
262
264
  }
@@ -271,7 +273,9 @@ const TextArea = /*#__PURE__*/React__default.forwardRef((props, forwardRef) => {
271
273
  className: `${prefix}--text-area__invalid-icon`
272
274
  }), warn && !invalid && !isFluid && /*#__PURE__*/React__default.createElement(WarningAltFilled, {
273
275
  className: `${prefix}--text-area__invalid-icon ${prefix}--text-area__invalid-icon--warning`
274
- }), input, normalizedSlug, /*#__PURE__*/React__default.createElement("span", {
276
+ }), input, slug ? normalizedDecorator : decorator ? /*#__PURE__*/React__default.createElement("div", {
277
+ className: `${prefix}--text-area__inner-wrapper--decorator`
278
+ }, normalizedDecorator) : '', /*#__PURE__*/React__default.createElement("span", {
275
279
  className: `${prefix}--text-area__counter-alert`,
276
280
  role: "alert",
277
281
  "aria-live": "assertive",
@@ -296,6 +300,10 @@ TextArea.propTypes = {
296
300
  * Specify the method used for calculating the counter number
297
301
  */
298
302
  counterMode: PropTypes.oneOf(['character', 'word']),
303
+ /**
304
+ * **Experimental**: Provide a `decorator` component to be rendered inside the `TextArea` component
305
+ */
306
+ decorator: PropTypes.node,
299
307
  /**
300
308
  * Optionally provide the default value of the `<textarea>`
301
309
  */
@@ -372,7 +380,7 @@ TextArea.propTypes = {
372
380
  /**
373
381
  * **Experimental**: Provide a `Slug` component to be rendered inside the `TextArea` component
374
382
  */
375
- slug: PropTypes.node,
383
+ slug: deprecate(PropTypes.node, 'The `slug` prop for `TextArea` has ' + 'been deprecated in favor of the new `decorator` prop. It will be removed in the next major release.'),
376
384
  /**
377
385
  * Provide the current value of the `<textarea>`
378
386
  */
@@ -11,6 +11,10 @@ export interface TextInputProps extends Omit<React.InputHTMLAttributes<HTMLInput
11
11
  * Specify an optional className to be applied to the `<input>` node
12
12
  */
13
13
  className?: string;
14
+ /**
15
+ * **Experimental**: Provide a `decorator` component to be rendered inside the `TextInput` component
16
+ */
17
+ decorator?: ReactNode;
14
18
  /**
15
19
  * Optionally provide the default value of the `<input>`
16
20
  */
@@ -86,6 +90,7 @@ export interface TextInputProps extends Omit<React.InputHTMLAttributes<HTMLInput
86
90
  */
87
91
  size?: 'sm' | 'md' | 'lg' | 'xl';
88
92
  /**
93
+ * @deprecated please use `decorator` instead.
89
94
  * **Experimental**: Provide a `Slug` component to be rendered inside the `TextInput` component
90
95
  */
91
96
  slug?: ReactNode;
@@ -23,6 +23,7 @@ import { Text } from '../Text/Text.js';
23
23
  const TextInput = /*#__PURE__*/React__default.forwardRef(function TextInput(_ref, ref) {
24
24
  let {
25
25
  className,
26
+ decorator,
26
27
  disabled = false,
27
28
  helperText,
28
29
  hideLabel,
@@ -115,7 +116,8 @@ const TextInput = /*#__PURE__*/React__default.forwardRef(function TextInput(_ref
115
116
  });
116
117
  const fieldWrapperClasses = cx(`${prefix}--text-input__field-wrapper`, {
117
118
  [`${prefix}--text-input__field-wrapper--warning`]: normalizedProps.warn,
118
- [`${prefix}--text-input__field-wrapper--slug`]: slug
119
+ [`${prefix}--text-input__field-wrapper--slug`]: slug,
120
+ [`${prefix}--text-input__field-wrapper--decorator`]: decorator
119
121
  });
120
122
  const iconClasses = cx({
121
123
  [`${prefix}--text-input__invalid-icon`]: normalizedProps.invalid || normalizedProps.warn,
@@ -179,10 +181,10 @@ const TextInput = /*#__PURE__*/React__default.forwardRef(function TextInput(_ref
179
181
  }, [ariaAnnouncement, prevAnnouncement]);
180
182
  const Icon = normalizedProps.icon;
181
183
 
182
- // Slug is always size `mini`
183
- let normalizedSlug;
184
- if (slug && slug['type']?.displayName === 'AILabel') {
185
- normalizedSlug = /*#__PURE__*/React__default.cloneElement(slug, {
184
+ // AILabel is always size `mini`
185
+ let normalizedDecorator = /*#__PURE__*/React__default.isValidElement(slug ?? decorator) ? slug ?? decorator : null;
186
+ if (normalizedDecorator && normalizedDecorator['type']?.displayName === 'AILabel') {
187
+ normalizedDecorator = /*#__PURE__*/React__default.cloneElement(normalizedDecorator, {
186
188
  size: 'mini'
187
189
  });
188
190
  }
@@ -197,7 +199,9 @@ const TextInput = /*#__PURE__*/React__default.forwardRef(function TextInput(_ref
197
199
  "data-invalid": normalizedProps.invalid || null
198
200
  }, Icon && /*#__PURE__*/React__default.createElement(Icon, {
199
201
  className: iconClasses
200
- }), input, normalizedSlug, /*#__PURE__*/React__default.createElement("span", {
202
+ }), input, slug ? normalizedDecorator : decorator ? /*#__PURE__*/React__default.createElement("div", {
203
+ className: `${prefix}--text-input__field-inner-wrapper--decorator`
204
+ }, normalizedDecorator) : '', /*#__PURE__*/React__default.createElement("span", {
201
205
  className: `${prefix}--text-input__counter-alert`,
202
206
  role: "alert",
203
207
  "aria-live": "assertive",
@@ -215,6 +219,10 @@ TextInput.propTypes = {
215
219
  * Specify an optional className to be applied to the `<input>` node
216
220
  */
217
221
  className: PropTypes.string,
222
+ /**
223
+ * **Experimental**: Provide a `decorator` component to be rendered inside the `TextInput` component
224
+ */
225
+ decorator: PropTypes.node,
218
226
  /**
219
227
  * Optionally provide the default value of the `<input>`
220
228
  */
@@ -290,7 +298,7 @@ TextInput.propTypes = {
290
298
  /**
291
299
  * **Experimental**: Provide a `Slug` component to be rendered inside the `TextInput` component
292
300
  */
293
- slug: PropTypes.node,
301
+ slug: deprecate(PropTypes.node, 'The `slug` prop for `TextInput` has ' + 'been deprecated in favor of the new `decorator` prop. It will be removed in the next major release.'),
294
302
  /**
295
303
  * Specify the type of the `<input>`
296
304
  */
@@ -4,7 +4,7 @@
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
  */
7
- import React, { ComponentProps } from 'react';
7
+ import React, { ElementType, ComponentProps } from 'react';
8
8
  import Link from './Link';
9
9
  interface SideNavMenuItemProps extends ComponentProps<typeof Link> {
10
10
  /**
@@ -25,6 +25,10 @@ interface SideNavMenuItemProps extends ComponentProps<typeof Link> {
25
25
  * Optionally provide an href for the underlying li`
26
26
  */
27
27
  href?: string;
28
+ /**
29
+ * Optional component to render instead of default Link
30
+ */
31
+ as?: ElementType;
28
32
  }
29
33
  declare const SideNavMenuItem: React.ForwardRefExoticComponent<Omit<SideNavMenuItemProps, "ref"> & React.RefAttributes<HTMLElement>>;
30
34
  export default SideNavMenuItem;
@@ -18,6 +18,7 @@ const SideNavMenuItem = /*#__PURE__*/React__default.forwardRef(function SideNavM
18
18
  const {
19
19
  children,
20
20
  className: customClassName,
21
+ as: Component = Link,
21
22
  isActive,
22
23
  ...rest
23
24
  } = props;
@@ -28,7 +29,7 @@ const SideNavMenuItem = /*#__PURE__*/React__default.forwardRef(function SideNavM
28
29
  });
29
30
  return /*#__PURE__*/React__default.createElement("li", {
30
31
  className: className
31
- }, /*#__PURE__*/React__default.createElement(Link, _extends({}, rest, {
32
+ }, /*#__PURE__*/React__default.createElement(Component, _extends({}, rest, {
32
33
  className: linkClassName,
33
34
  ref: ref
34
35
  }), /*#__PURE__*/React__default.createElement(SideNavLinkText, null, children)));
@@ -52,7 +53,11 @@ SideNavMenuItem.propTypes = {
52
53
  * has an href that is the same as the current page. Can also pass in
53
54
  * `aria-current="page"`, as well.
54
55
  */
55
- isActive: PropTypes.bool
56
+ isActive: PropTypes.bool,
57
+ /**
58
+ * Optional component to render instead of default Link
59
+ */
60
+ as: PropTypes.elementType
56
61
  };
57
62
 
58
63
  export { SideNavMenuItem as default };