@carbon/react 1.84.0-rc.0 → 1.84.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.
- package/.playwright/INTERNAL_AVT_REPORT_DO_NOT_USE.json +883 -883
- package/es/components/ComposedModal/ComposedModal.js +19 -2
- package/es/components/Modal/Modal.js +19 -2
- package/es/components/MultiSelect/FilterableMultiSelect.js +21 -0
- package/es/components/OverflowMenu/OverflowMenu.js +4 -5
- package/es/components/PageHeader/PageHeader.d.ts +10 -9
- package/es/components/PageHeader/PageHeader.js +92 -32
- package/es/components/PageHeader/index.d.ts +2 -2
- package/es/components/PageHeader/index.js +1 -1
- package/es/components/Search/Search.js +0 -1
- package/es/components/Slider/Slider.js +6 -0
- package/es/components/TextArea/TextArea.js +4 -4
- package/es/components/TileGroup/TileGroup.d.ts +4 -4
- package/es/components/TileGroup/TileGroup.js +45 -53
- package/es/components/TileGroup/index.d.ts +3 -3
- package/es/components/UIShell/HeaderMenuItem.js +2 -1
- package/es/index.js +1 -1
- package/es/internal/useOverflowItems.d.ts +29 -0
- package/es/internal/useOverflowItems.js +122 -0
- package/lib/components/ComposedModal/ComposedModal.js +19 -2
- package/lib/components/Modal/Modal.js +19 -2
- package/lib/components/MultiSelect/FilterableMultiSelect.js +21 -0
- package/lib/components/OverflowMenu/OverflowMenu.js +4 -5
- package/lib/components/PageHeader/PageHeader.d.ts +10 -9
- package/lib/components/PageHeader/PageHeader.js +90 -32
- package/lib/components/PageHeader/index.d.ts +2 -2
- package/lib/components/PageHeader/index.js +0 -2
- package/lib/components/Search/Search.js +0 -1
- package/lib/components/Slider/Slider.js +6 -0
- package/lib/components/TextArea/TextArea.js +4 -4
- package/lib/components/TileGroup/TileGroup.d.ts +4 -4
- package/lib/components/TileGroup/TileGroup.js +44 -52
- package/lib/components/TileGroup/index.d.ts +3 -3
- package/lib/components/UIShell/HeaderMenuItem.js +2 -1
- package/lib/index.js +1 -1
- package/lib/internal/useOverflowItems.d.ts +29 -0
- package/lib/internal/useOverflowItems.js +126 -0
- package/package.json +9 -9
- package/telemetry.yml +2 -0
|
@@ -176,7 +176,7 @@ const ComposedModal = /*#__PURE__*/React.forwardRef(function ComposedModal({
|
|
|
176
176
|
target: oldActiveNode,
|
|
177
177
|
relatedTarget: currentActiveNode
|
|
178
178
|
}) {
|
|
179
|
-
if (open && currentActiveNode && oldActiveNode && innerModal.current) {
|
|
179
|
+
if (!enableDialogElement && !focusTrapWithoutSentinels && open && currentActiveNode && oldActiveNode && innerModal.current) {
|
|
180
180
|
const {
|
|
181
181
|
current: bodyNode
|
|
182
182
|
} = innerModal;
|
|
@@ -195,6 +195,23 @@ const ComposedModal = /*#__PURE__*/React.forwardRef(function ComposedModal({
|
|
|
195
195
|
selectorsFloatingMenus: selectorsFloatingMenus?.filter(Boolean)
|
|
196
196
|
});
|
|
197
197
|
}
|
|
198
|
+
|
|
199
|
+
// Adjust scroll if needed so that element with focus is not obscured by gradient
|
|
200
|
+
const modalContent = document.querySelector(`.${prefix}--modal-content`);
|
|
201
|
+
if (!modalContent || !modalContent.classList.contains(`${prefix}--modal-scroll-content`) || !currentActiveNode || !modalContent.contains(currentActiveNode)) {
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
const lastContent = modalContent.children[modalContent.children.length - 1];
|
|
205
|
+
const gradientSpacing = modalContent.scrollHeight - lastContent.offsetTop - lastContent.clientHeight;
|
|
206
|
+
for (let elem of modalContent.children) {
|
|
207
|
+
if (elem.contains(currentActiveNode)) {
|
|
208
|
+
const spaceBelow = modalContent.clientHeight - elem.offsetTop + modalContent.scrollTop - elem.clientHeight;
|
|
209
|
+
if (spaceBelow < gradientSpacing) {
|
|
210
|
+
modalContent.scrollTop = modalContent.scrollTop + (gradientSpacing - spaceBelow);
|
|
211
|
+
}
|
|
212
|
+
break;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
198
215
|
}
|
|
199
216
|
function closeModal(evt) {
|
|
200
217
|
if (!onClose || onClose(evt) !== false) {
|
|
@@ -309,7 +326,7 @@ const ComposedModal = /*#__PURE__*/React.forwardRef(function ComposedModal({
|
|
|
309
326
|
role: "presentation",
|
|
310
327
|
ref: ref,
|
|
311
328
|
"aria-hidden": !open,
|
|
312
|
-
onBlur:
|
|
329
|
+
onBlur: handleBlur,
|
|
313
330
|
onClick: composeEventHandlers([rest?.onClick, handleOnClick]),
|
|
314
331
|
onMouseDown: composeEventHandlers([rest?.onMouseDown, handleOnMouseDown]),
|
|
315
332
|
onKeyDown: handleKeyDown,
|
|
@@ -129,7 +129,7 @@ const Modal = /*#__PURE__*/React.forwardRef(function Modal({
|
|
|
129
129
|
target: oldActiveNode,
|
|
130
130
|
relatedTarget: currentActiveNode
|
|
131
131
|
}) {
|
|
132
|
-
if (open && oldActiveNode instanceof HTMLElement && currentActiveNode instanceof HTMLElement) {
|
|
132
|
+
if (!enableDialogElement && open && oldActiveNode instanceof HTMLElement && currentActiveNode instanceof HTMLElement) {
|
|
133
133
|
const {
|
|
134
134
|
current: bodyNode
|
|
135
135
|
} = innerModal;
|
|
@@ -148,6 +148,23 @@ const Modal = /*#__PURE__*/React.forwardRef(function Modal({
|
|
|
148
148
|
selectorsFloatingMenus
|
|
149
149
|
});
|
|
150
150
|
}
|
|
151
|
+
|
|
152
|
+
// Adjust scroll if needed so that element with focus is not obscured by gradient
|
|
153
|
+
const modalContent = document.querySelector(`.${prefix}--modal-content`);
|
|
154
|
+
if (!modalContent || !modalContent.classList.contains(`${prefix}--modal-scroll-content`) || !currentActiveNode || !modalContent.contains(currentActiveNode)) {
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
const lastContent = modalContent.children[modalContent.children.length - 1];
|
|
158
|
+
const gradientSpacing = modalContent.scrollHeight - lastContent.offsetTop - lastContent.clientHeight;
|
|
159
|
+
for (let elem of modalContent.children) {
|
|
160
|
+
if (elem.contains(currentActiveNode)) {
|
|
161
|
+
const spaceBelow = modalContent.clientHeight - elem.offsetTop + modalContent.scrollTop - elem.clientHeight;
|
|
162
|
+
if (spaceBelow < gradientSpacing) {
|
|
163
|
+
modalContent.scrollTop = modalContent.scrollTop + (gradientSpacing - spaceBelow);
|
|
164
|
+
}
|
|
165
|
+
break;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
151
168
|
}
|
|
152
169
|
const onSecondaryButtonClick = onSecondarySubmit ? onSecondarySubmit : onRequestClose;
|
|
153
170
|
const modalClasses = cx(`${prefix}--modal`, {
|
|
@@ -404,7 +421,7 @@ const Modal = /*#__PURE__*/React.forwardRef(function Modal({
|
|
|
404
421
|
level: 0,
|
|
405
422
|
onKeyDown: handleKeyDown,
|
|
406
423
|
onClick: composeEventHandlers([rest?.onClick, handleOnClick]),
|
|
407
|
-
onBlur:
|
|
424
|
+
onBlur: handleBlur,
|
|
408
425
|
className: modalClasses,
|
|
409
426
|
role: "presentation",
|
|
410
427
|
ref: ref
|
|
@@ -248,6 +248,27 @@ const FilterableMultiSelect = /*#__PURE__*/forwardRef(function FilterableMultiSe
|
|
|
248
248
|
onMenuChange?.(isOpen);
|
|
249
249
|
}
|
|
250
250
|
}, [isOpen, onMenuChange, open]);
|
|
251
|
+
useEffect(() => {
|
|
252
|
+
const handleClickOutside = event => {
|
|
253
|
+
const target = event.target;
|
|
254
|
+
const wrapper = document.getElementById(id)?.closest(`.${prefix}--multi-select__wrapper`);
|
|
255
|
+
|
|
256
|
+
// If click is outside our component and menu is open or input is focused
|
|
257
|
+
if (wrapper && !wrapper.contains(target)) {
|
|
258
|
+
if (isOpen || inputFocused) {
|
|
259
|
+
setIsOpen(false);
|
|
260
|
+
setInputFocused(false);
|
|
261
|
+
setInputValue('');
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
};
|
|
265
|
+
if (inputFocused || isOpen) {
|
|
266
|
+
document.addEventListener('mousedown', handleClickOutside);
|
|
267
|
+
}
|
|
268
|
+
return () => {
|
|
269
|
+
document.removeEventListener('mousedown', handleClickOutside);
|
|
270
|
+
};
|
|
271
|
+
}, [isOpen, inputFocused]);
|
|
251
272
|
const {
|
|
252
273
|
getToggleButtonProps,
|
|
253
274
|
getLabelProps,
|
|
@@ -143,14 +143,14 @@ const OverflowMenu = /*#__PURE__*/forwardRef(({
|
|
|
143
143
|
setHasMountedTrigger(true);
|
|
144
144
|
}
|
|
145
145
|
}, []);
|
|
146
|
-
|
|
147
|
-
// Call `onClose` when menu closes.
|
|
148
146
|
useEffect(() => {
|
|
149
|
-
if (
|
|
147
|
+
if (open && !prevOpenState.current) {
|
|
148
|
+
onOpen();
|
|
149
|
+
} else if (!open && prevOpenState.current) {
|
|
150
150
|
onClose();
|
|
151
151
|
}
|
|
152
152
|
prevOpenState.current = open;
|
|
153
|
-
}, [open, onClose]);
|
|
153
|
+
}, [open, onClose, onOpen]);
|
|
154
154
|
useOutsideClick(wrapperRef, ({
|
|
155
155
|
target
|
|
156
156
|
}) => {
|
|
@@ -259,7 +259,6 @@ const OverflowMenu = /*#__PURE__*/forwardRef(({
|
|
|
259
259
|
}
|
|
260
260
|
}
|
|
261
261
|
}, !hasFocusin);
|
|
262
|
-
onOpen();
|
|
263
262
|
};
|
|
264
263
|
const getTarget = () => {
|
|
265
264
|
const triggerEl = triggerRef.current;
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import React, { type ComponentType, type FunctionComponent } from 'react';
|
|
8
8
|
import PropTypes from 'prop-types';
|
|
9
|
-
import {
|
|
9
|
+
import { TYPES } from '../Tag/Tag';
|
|
10
10
|
/**
|
|
11
11
|
* ----------
|
|
12
12
|
* PageHeader
|
|
@@ -199,16 +199,18 @@ declare const PageHeaderHeroImage: {
|
|
|
199
199
|
* PageHeaderTabBar
|
|
200
200
|
* ----------------
|
|
201
201
|
*/
|
|
202
|
+
interface TagItem {
|
|
203
|
+
type: keyof typeof TYPES;
|
|
204
|
+
text: string;
|
|
205
|
+
size?: 'sm' | 'md' | 'lg';
|
|
206
|
+
id: string;
|
|
207
|
+
}
|
|
202
208
|
interface PageHeaderTabBarProps {
|
|
203
209
|
children?: React.ReactNode;
|
|
204
210
|
className?: string;
|
|
211
|
+
tags?: TagItem[];
|
|
205
212
|
}
|
|
206
213
|
declare const PageHeaderTabBar: React.ForwardRefExoticComponent<PageHeaderTabBarProps & React.RefAttributes<HTMLDivElement>>;
|
|
207
|
-
interface PageHeaderTabsProps extends React.ComponentProps<typeof BaseTabs> {
|
|
208
|
-
children?: React.ReactNode;
|
|
209
|
-
className?: string;
|
|
210
|
-
}
|
|
211
|
-
declare const PageHeaderTabs: React.ForwardRefExoticComponent<PageHeaderTabsProps & React.RefAttributes<HTMLDivElement>>;
|
|
212
214
|
/**
|
|
213
215
|
* -------
|
|
214
216
|
* Exports
|
|
@@ -272,6 +274,5 @@ declare const HeroImage: {
|
|
|
272
274
|
};
|
|
273
275
|
};
|
|
274
276
|
declare const TabBar: React.ForwardRefExoticComponent<PageHeaderTabBarProps & React.RefAttributes<HTMLDivElement>>;
|
|
275
|
-
|
|
276
|
-
export {
|
|
277
|
-
export type { PageHeaderProps, PageHeaderBreadcrumbBarProps, PageHeaderContentProps, PageHeaderContentPageActionsProps, PageHeaderContentTextProps, PageHeaderHeroImageProps, PageHeaderTabBarProps, PageHeaderTabsProps, };
|
|
277
|
+
export { PageHeader, PageHeaderBreadcrumbBar, PageHeaderContent, PageHeaderContentPageActions, PageHeaderContentText, PageHeaderHeroImage, PageHeaderTabBar, Root, BreadcrumbBar, Content, ContentPageActions, ContentText, HeroImage, TabBar, };
|
|
278
|
+
export type { PageHeaderProps, PageHeaderBreadcrumbBarProps, PageHeaderContentProps, PageHeaderContentPageActionsProps, PageHeaderContentTextProps, PageHeaderHeroImageProps, PageHeaderTabBarProps, };
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import { extends as _extends } from '../../_virtual/_rollupPluginBabelHelpers.js';
|
|
9
|
-
import React, { useRef, useState, useLayoutEffect, useEffect } from 'react';
|
|
9
|
+
import React, { useRef, useState, useLayoutEffect, useEffect, useMemo, useCallback } from 'react';
|
|
10
10
|
import PropTypes from 'prop-types';
|
|
11
11
|
import cx from 'classnames';
|
|
12
12
|
import { usePrefix } from '../../internal/usePrefix.js';
|
|
@@ -20,7 +20,14 @@ import { DefinitionTooltip } from '../Tooltip/DefinitionTooltip.js';
|
|
|
20
20
|
import '../Tooltip/Tooltip.js';
|
|
21
21
|
import AspectRatio from '../AspectRatio/AspectRatio.js';
|
|
22
22
|
import { createOverflowHandler } from '@carbon/utilities';
|
|
23
|
-
import
|
|
23
|
+
import Tag from '../Tag/Tag.js';
|
|
24
|
+
import '../Tag/DismissibleTag.js';
|
|
25
|
+
import OperationalTag from '../Tag/OperationalTag.js';
|
|
26
|
+
import '../Tag/SelectableTag.js';
|
|
27
|
+
import '../Tag/Tag.Skeleton.js';
|
|
28
|
+
import useOverflowItems from '../../internal/useOverflowItems.js';
|
|
29
|
+
import { Popover, PopoverContent } from '../Popover/index.js';
|
|
30
|
+
import { useId } from '../../internal/useId.js';
|
|
24
31
|
import '../Grid/FlexGrid.js';
|
|
25
32
|
import { Grid as GridAsGridComponent } from '../Grid/Grid.js';
|
|
26
33
|
import '../Grid/Row.js';
|
|
@@ -355,46 +362,101 @@ PageHeaderHeroImage.propTypes = {
|
|
|
355
362
|
const PageHeaderTabBar = /*#__PURE__*/React.forwardRef(function PageHeaderTabBar({
|
|
356
363
|
className,
|
|
357
364
|
children,
|
|
365
|
+
tags = [],
|
|
358
366
|
...other
|
|
359
367
|
}, ref) {
|
|
360
368
|
const prefix = usePrefix();
|
|
361
369
|
const classNames = cx({
|
|
362
370
|
[`${prefix}--page-header__tab-bar`]: true
|
|
363
371
|
}, className);
|
|
372
|
+
// Early return if no tags are provided
|
|
373
|
+
if (!tags.length) {
|
|
374
|
+
return /*#__PURE__*/React.createElement("div", _extends({
|
|
375
|
+
className: classNames,
|
|
376
|
+
ref: ref
|
|
377
|
+
}, other), /*#__PURE__*/React.createElement(GridAsGridComponent, null, /*#__PURE__*/React.createElement(Column, {
|
|
378
|
+
lg: 16,
|
|
379
|
+
md: 8,
|
|
380
|
+
sm: 4
|
|
381
|
+
}, children)));
|
|
382
|
+
}
|
|
383
|
+
const [openPopover, setOpenPopover] = useState(false);
|
|
384
|
+
const tagSize = tags[0]?.size || 'md';
|
|
385
|
+
const instanceId = useId('PageHeaderTabBar');
|
|
386
|
+
const tagsWithIds = useMemo(() => {
|
|
387
|
+
return tags.map((tag, index) => ({
|
|
388
|
+
...tag,
|
|
389
|
+
id: tag.id || `tag-${index}-${instanceId}`
|
|
390
|
+
}));
|
|
391
|
+
}, [tags]);
|
|
392
|
+
const tagsContainerRef = useRef(null);
|
|
393
|
+
const offsetRef = useRef(null);
|
|
394
|
+
// To close popover when window resizes
|
|
395
|
+
useEffect(() => {
|
|
396
|
+
const handleResize = () => {
|
|
397
|
+
// Close the popover when window resizes to prevent unwanted opens
|
|
398
|
+
setOpenPopover(false);
|
|
399
|
+
};
|
|
400
|
+
window.addEventListener('resize', handleResize);
|
|
401
|
+
return () => {
|
|
402
|
+
window.removeEventListener('resize', handleResize);
|
|
403
|
+
};
|
|
404
|
+
}, []);
|
|
405
|
+
|
|
406
|
+
// overflow items hook
|
|
407
|
+
const {
|
|
408
|
+
visibleItems = [],
|
|
409
|
+
hiddenItems = [],
|
|
410
|
+
itemRefHandler = () => {}
|
|
411
|
+
} = useOverflowItems(tagsWithIds, tagsContainerRef, offsetRef) || {
|
|
412
|
+
visibleItems: [],
|
|
413
|
+
hiddenItems: [],
|
|
414
|
+
itemRefHandler: () => {}
|
|
415
|
+
};
|
|
416
|
+
const handleOverflowClick = useCallback(event => {
|
|
417
|
+
event.stopPropagation();
|
|
418
|
+
setOpenPopover(prev => !prev);
|
|
419
|
+
}, []);
|
|
420
|
+
|
|
421
|
+
// Function to render tags
|
|
422
|
+
const renderTags = () => /*#__PURE__*/React.createElement("div", {
|
|
423
|
+
className: `${prefix}--page-header__tags`,
|
|
424
|
+
ref: tagsContainerRef
|
|
425
|
+
}, visibleItems.map(tag => /*#__PURE__*/React.createElement(Tag, {
|
|
426
|
+
key: tag.id,
|
|
427
|
+
ref: node => itemRefHandler(tag.id, node),
|
|
428
|
+
type: tag.type,
|
|
429
|
+
size: tag.size,
|
|
430
|
+
className: `${prefix}--page-header__tag-item`
|
|
431
|
+
}, tag.text)), hiddenItems.length > 0 && /*#__PURE__*/React.createElement(Popover, {
|
|
432
|
+
open: openPopover,
|
|
433
|
+
onRequestClose: () => setOpenPopover(false)
|
|
434
|
+
}, /*#__PURE__*/React.createElement(OperationalTag, {
|
|
435
|
+
onClick: handleOverflowClick,
|
|
436
|
+
"aria-expanded": openPopover,
|
|
437
|
+
text: `+${hiddenItems.length}`,
|
|
438
|
+
size: tagSize
|
|
439
|
+
}), /*#__PURE__*/React.createElement(PopoverContent, {
|
|
440
|
+
className: "tag-popover-content"
|
|
441
|
+
}, /*#__PURE__*/React.createElement("div", {
|
|
442
|
+
className: `${prefix}--page-header__tags-popover-list`
|
|
443
|
+
}, hiddenItems.map(tag => /*#__PURE__*/React.createElement(Tag, {
|
|
444
|
+
key: tag.id,
|
|
445
|
+
type: tag.type,
|
|
446
|
+
size: tag.size
|
|
447
|
+
}, tag.text))))));
|
|
364
448
|
return /*#__PURE__*/React.createElement("div", _extends({
|
|
365
449
|
className: classNames,
|
|
366
450
|
ref: ref
|
|
367
|
-
}, other),
|
|
368
|
-
});
|
|
369
|
-
PageHeaderTabBar.displayName = 'PageHeaderTabBar';
|
|
370
|
-
const PageHeaderTabs = /*#__PURE__*/React.forwardRef(function PageHeaderTabs({
|
|
371
|
-
className,
|
|
372
|
-
children,
|
|
373
|
-
...other
|
|
374
|
-
}, ref) {
|
|
375
|
-
const prefix = usePrefix();
|
|
376
|
-
const childrenArray = React.Children.toArray(children);
|
|
377
|
-
let tabListElement = null;
|
|
378
|
-
const otherChildren = [];
|
|
379
|
-
|
|
380
|
-
// extract the TabList component so we can wrap a needed div around for
|
|
381
|
-
// layout purposes
|
|
382
|
-
childrenArray.forEach(child => {
|
|
383
|
-
if (child?.type?.displayName === 'TabList' || child?.type?.name === 'TabList') {
|
|
384
|
-
tabListElement = child;
|
|
385
|
-
} else {
|
|
386
|
-
otherChildren.push(child);
|
|
387
|
-
}
|
|
388
|
-
});
|
|
389
|
-
return /*#__PURE__*/React.createElement(Tabs$1, other, tabListElement && /*#__PURE__*/React.createElement("div", {
|
|
390
|
-
className: `${prefix}--page-header__tablist-wrapper`
|
|
391
|
-
}, /*#__PURE__*/React.createElement(GridAsGridComponent, null, /*#__PURE__*/React.createElement(Column, {
|
|
451
|
+
}, other), /*#__PURE__*/React.createElement(GridAsGridComponent, null, /*#__PURE__*/React.createElement(Column, {
|
|
392
452
|
lg: 16,
|
|
393
453
|
md: 8,
|
|
394
454
|
sm: 4
|
|
395
|
-
},
|
|
455
|
+
}, /*#__PURE__*/React.createElement("div", {
|
|
456
|
+
className: `${prefix}--page-header__tab-bar--tablist`
|
|
457
|
+
}, children, tags.length > 0 && renderTags()))));
|
|
396
458
|
});
|
|
397
|
-
|
|
459
|
+
PageHeaderTabBar.displayName = 'PageHeaderTabBar';
|
|
398
460
|
|
|
399
461
|
/**
|
|
400
462
|
* -------
|
|
@@ -415,7 +477,5 @@ const HeroImage = PageHeaderHeroImage;
|
|
|
415
477
|
HeroImage.displayName = 'PageHeaderHeroImage';
|
|
416
478
|
const TabBar = PageHeaderTabBar;
|
|
417
479
|
TabBar.displayName = 'PageHeaderTabBar';
|
|
418
|
-
const Tabs = PageHeaderTabs;
|
|
419
|
-
Tabs.displayName = 'PageHeader.Tabs';
|
|
420
480
|
|
|
421
|
-
export { BreadcrumbBar, Content, ContentPageActions, ContentText, HeroImage, PageHeader, PageHeaderBreadcrumbBar, PageHeaderContent, PageHeaderContentPageActions, PageHeaderContentText, PageHeaderHeroImage, PageHeaderTabBar,
|
|
481
|
+
export { BreadcrumbBar, Content, ContentPageActions, ContentText, HeroImage, PageHeader, PageHeaderBreadcrumbBar, PageHeaderContent, PageHeaderContentPageActions, PageHeaderContentText, PageHeaderHeroImage, PageHeaderTabBar, Root, TabBar };
|
|
@@ -4,5 +4,5 @@
|
|
|
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
|
-
export { PageHeader, PageHeaderBreadcrumbBar, PageHeaderContent, PageHeaderContentPageActions, PageHeaderContentText, PageHeaderTabBar, PageHeaderHeroImage,
|
|
8
|
-
export type { PageHeaderProps, PageHeaderBreadcrumbBarProps, PageHeaderContentProps, PageHeaderContentPageActionsProps, PageHeaderContentTextProps, PageHeaderTabBarProps, PageHeaderHeroImageProps,
|
|
7
|
+
export { PageHeader, PageHeaderBreadcrumbBar, PageHeaderContent, PageHeaderContentPageActions, PageHeaderContentText, PageHeaderTabBar, PageHeaderHeroImage, Root, BreadcrumbBar, Content, ContentPageActions, ContentText, TabBar, HeroImage, } from './PageHeader';
|
|
8
|
+
export type { PageHeaderProps, PageHeaderBreadcrumbBarProps, PageHeaderContentProps, PageHeaderContentPageActionsProps, PageHeaderContentTextProps, PageHeaderTabBarProps, PageHeaderHeroImageProps, } from './PageHeader';
|
|
@@ -5,4 +5,4 @@
|
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
export { BreadcrumbBar, Content, ContentPageActions, ContentText, HeroImage, PageHeader, PageHeaderBreadcrumbBar, PageHeaderContent, PageHeaderContentPageActions, PageHeaderContentText, PageHeaderHeroImage, PageHeaderTabBar,
|
|
8
|
+
export { BreadcrumbBar, Content, ContentPageActions, ContentText, HeroImage, PageHeader, PageHeaderBreadcrumbBar, PageHeaderContent, PageHeaderContentPageActions, PageHeaderContentText, PageHeaderHeroImage, PageHeaderTabBar, Root, TabBar } from './PageHeader.js';
|
|
@@ -134,7 +134,6 @@ const Search = /*#__PURE__*/React.forwardRef(function Search({
|
|
|
134
134
|
"aria-label": placeholder,
|
|
135
135
|
className: searchClasses
|
|
136
136
|
}, /*#__PURE__*/React.createElement("div", {
|
|
137
|
-
"aria-label": onExpand ? 'button' : undefined,
|
|
138
137
|
"aria-labelledby": onExpand ? searchId : undefined,
|
|
139
138
|
role: onExpand ? 'button' : undefined,
|
|
140
139
|
className: `${prefix}--search-magnifier`,
|
|
@@ -758,6 +758,9 @@ class Slider extends PureComponent {
|
|
|
758
758
|
valueUpper,
|
|
759
759
|
leftUpper
|
|
760
760
|
});
|
|
761
|
+
if (this.filledTrackRef.current) {
|
|
762
|
+
this.filledTrackRef.current.style.transform = this.state.isRtl ? `translate(${100 - this.state.leftUpper}%, -50%) scaleX(${(this.state.leftUpper - this.state.left) / 100})` : `translate(${this.state.left}%, -50%) scaleX(${(this.state.leftUpper - this.state.left) / 100})`;
|
|
763
|
+
}
|
|
761
764
|
} else {
|
|
762
765
|
const {
|
|
763
766
|
value,
|
|
@@ -771,6 +774,9 @@ class Slider extends PureComponent {
|
|
|
771
774
|
value,
|
|
772
775
|
left
|
|
773
776
|
});
|
|
777
|
+
if (this.filledTrackRef.current) {
|
|
778
|
+
this.filledTrackRef.current.style.transform = this.state.isRtl ? `translate(100%, -50%) scaleX(-${this.state.left / 100})` : `translate(0%, -50%) scaleX(${this.state.left / 100})`;
|
|
779
|
+
}
|
|
774
780
|
}
|
|
775
781
|
}
|
|
776
782
|
}
|
|
@@ -65,7 +65,7 @@ const TextArea = frFn((props, forwardRef) => {
|
|
|
65
65
|
if (counterMode === 'character') {
|
|
66
66
|
return strValue.length;
|
|
67
67
|
} else {
|
|
68
|
-
return strValue.match(/\
|
|
68
|
+
return strValue.match(/\p{L}+/gu)?.length || 0;
|
|
69
69
|
}
|
|
70
70
|
}
|
|
71
71
|
const [textCount, setTextCount] = useState(getInitialTextCount());
|
|
@@ -97,8 +97,8 @@ const TextArea = frFn((props, forwardRef) => {
|
|
|
97
97
|
onPaste: evt => {
|
|
98
98
|
if (!disabled) {
|
|
99
99
|
if (counterMode === 'word' && enableCounter && typeof maxCount !== 'undefined' && textareaRef.current !== null) {
|
|
100
|
-
const existingWords = textareaRef.current.value.match(/\
|
|
101
|
-
const pastedWords = evt.clipboardData.getData('Text').match(/\
|
|
100
|
+
const existingWords = textareaRef.current.value.match(/\p{L}+/gu) || [];
|
|
101
|
+
const pastedWords = evt.clipboardData.getData('Text').match(/\p{L}+/gu) || [];
|
|
102
102
|
const totalWords = existingWords.length + pastedWords.length;
|
|
103
103
|
if (totalWords > maxCount) {
|
|
104
104
|
evt.preventDefault();
|
|
@@ -127,7 +127,7 @@ const TextArea = frFn((props, forwardRef) => {
|
|
|
127
127
|
return;
|
|
128
128
|
}
|
|
129
129
|
if (enableCounter && typeof maxCount !== 'undefined' && textareaRef.current !== null) {
|
|
130
|
-
const matchedWords = evt.target?.value?.match(/\
|
|
130
|
+
const matchedWords = evt.target?.value?.match(/\p{L}+/gu);
|
|
131
131
|
if (matchedWords && matchedWords.length <= maxCount) {
|
|
132
132
|
textareaRef.current.removeAttribute('maxLength');
|
|
133
133
|
setTimeout(() => {
|
|
@@ -45,8 +45,9 @@ export interface TileGroupProps extends Omit<HTMLAttributes<HTMLFieldSetElement>
|
|
|
45
45
|
*/
|
|
46
46
|
required?: boolean;
|
|
47
47
|
}
|
|
48
|
-
declare const TileGroup: {
|
|
49
|
-
(
|
|
48
|
+
export declare const TileGroup: {
|
|
49
|
+
({ children, className, defaultSelected, disabled, legend, name, onChange, valueSelected, required, }: TileGroupProps): import("react/jsx-runtime").JSX.Element;
|
|
50
|
+
displayName: string;
|
|
50
51
|
propTypes: {
|
|
51
52
|
/**
|
|
52
53
|
* Provide a collection of <RadioTile> components to render in the group
|
|
@@ -86,6 +87,5 @@ declare const TileGroup: {
|
|
|
86
87
|
*/
|
|
87
88
|
valueSelected: PropTypes.Requireable<NonNullable<string | number | null | undefined>>;
|
|
88
89
|
};
|
|
89
|
-
displayName: string;
|
|
90
90
|
};
|
|
91
|
-
export
|
|
91
|
+
export {};
|
|
@@ -7,40 +7,42 @@
|
|
|
7
7
|
|
|
8
8
|
import { extends as _extends } from '../../_virtual/_rollupPluginBabelHelpers.js';
|
|
9
9
|
import PropTypes from 'prop-types';
|
|
10
|
-
import React, { useState } from 'react';
|
|
10
|
+
import React, { useState, useEffect, Children, isValidElement, cloneElement } from 'react';
|
|
11
11
|
import RadioTile from '../RadioTile/RadioTile.js';
|
|
12
12
|
import { usePrefix } from '../../internal/usePrefix.js';
|
|
13
13
|
import { noopFn } from '../../internal/noopFn.js';
|
|
14
14
|
|
|
15
|
-
const TileGroup =
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
} = props;
|
|
15
|
+
const TileGroup = ({
|
|
16
|
+
children,
|
|
17
|
+
className,
|
|
18
|
+
defaultSelected,
|
|
19
|
+
disabled,
|
|
20
|
+
legend,
|
|
21
|
+
name,
|
|
22
|
+
onChange = noopFn,
|
|
23
|
+
valueSelected,
|
|
24
|
+
required
|
|
25
|
+
}) => {
|
|
27
26
|
const prefix = usePrefix();
|
|
28
27
|
const [selected, setSelected] = useState(valueSelected ?? defaultSelected);
|
|
29
|
-
|
|
28
|
+
useEffect(() => {
|
|
29
|
+
if (typeof valueSelected !== 'undefined' && valueSelected !== selected) {
|
|
30
|
+
setSelected(valueSelected);
|
|
31
|
+
}
|
|
32
|
+
}, [valueSelected, selected]);
|
|
33
|
+
const handleChange = (value, name, evt) => {
|
|
34
|
+
if (value !== selected) {
|
|
35
|
+
setSelected(value);
|
|
36
|
+
onChange(value, name ?? '', evt);
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
const getRadioTilesWithWrappers = elements => {
|
|
40
|
+
const traverseAndModifyChildren = elements => {
|
|
41
|
+
return Children.map(elements, child => {
|
|
42
|
+
if (! /*#__PURE__*/isValidElement(child)) return child;
|
|
30
43
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
* only update if selected prop changes
|
|
34
|
-
*/
|
|
35
|
-
if (valueSelected !== prevValueSelected) {
|
|
36
|
-
setSelected(valueSelected);
|
|
37
|
-
setPrevValueSelected(valueSelected);
|
|
38
|
-
}
|
|
39
|
-
const getRadioTilesWithWrappers = children => {
|
|
40
|
-
const traverseAndModifyChildren = children => {
|
|
41
|
-
return React.Children.map(children, child => {
|
|
42
|
-
// If RadioTile found, return it with necessary props
|
|
43
|
-
if (child?.type === RadioTile) {
|
|
44
|
+
// If a `RadioTile` is found, return it with necessary props,
|
|
45
|
+
if (/*#__PURE__*/isValidElement(child) && child.type === RadioTile) {
|
|
44
46
|
const {
|
|
45
47
|
value,
|
|
46
48
|
...otherProps
|
|
@@ -53,38 +55,29 @@ const TileGroup = props => {
|
|
|
53
55
|
onChange: handleChange,
|
|
54
56
|
checked: value === selected
|
|
55
57
|
}));
|
|
56
|
-
} else if (child?.props?.children) {
|
|
57
|
-
// If the child is not RadioTile and has children, recheck the children
|
|
58
|
-
return /*#__PURE__*/React.cloneElement(child, {
|
|
59
|
-
...child.props,
|
|
60
|
-
children: traverseAndModifyChildren(child.props.children)
|
|
61
|
-
});
|
|
62
|
-
} else {
|
|
63
|
-
// If the child is neither a RadioTile nor has children, return it as is
|
|
64
|
-
return child;
|
|
65
58
|
}
|
|
59
|
+
|
|
60
|
+
// If the child is not RadioTile and has children, recheck the children
|
|
61
|
+
const children = child.props.children;
|
|
62
|
+
const hasChildren = Children.count(children) > 0;
|
|
63
|
+
if (hasChildren) {
|
|
64
|
+
return /*#__PURE__*/cloneElement(child, undefined, traverseAndModifyChildren(children));
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// If the child is neither a RadioTile nor has children, return it as is
|
|
68
|
+
return child;
|
|
66
69
|
});
|
|
67
70
|
};
|
|
68
|
-
return /*#__PURE__*/React.createElement(React.Fragment, null, traverseAndModifyChildren(
|
|
69
|
-
};
|
|
70
|
-
const handleChange = (newSelection, value, evt) => {
|
|
71
|
-
if (newSelection !== selected) {
|
|
72
|
-
setSelected(newSelection);
|
|
73
|
-
onChange(newSelection, name, evt);
|
|
74
|
-
}
|
|
75
|
-
};
|
|
76
|
-
const renderLegend = legend => {
|
|
77
|
-
if (legend) {
|
|
78
|
-
return /*#__PURE__*/React.createElement("legend", {
|
|
79
|
-
className: `${prefix}--label`
|
|
80
|
-
}, legend);
|
|
81
|
-
}
|
|
71
|
+
return /*#__PURE__*/React.createElement(React.Fragment, null, traverseAndModifyChildren(elements));
|
|
82
72
|
};
|
|
83
73
|
return /*#__PURE__*/React.createElement("fieldset", {
|
|
84
74
|
className: className ?? `${prefix}--tile-group`,
|
|
85
75
|
disabled: disabled
|
|
86
|
-
},
|
|
76
|
+
}, legend && /*#__PURE__*/React.createElement("legend", {
|
|
77
|
+
className: `${prefix}--label`
|
|
78
|
+
}, legend), /*#__PURE__*/React.createElement("div", null, getRadioTilesWithWrappers(children)));
|
|
87
79
|
};
|
|
80
|
+
TileGroup.displayName = 'TileGroup';
|
|
88
81
|
TileGroup.propTypes = {
|
|
89
82
|
/**
|
|
90
83
|
* Provide a collection of <RadioTile> components to render in the group
|
|
@@ -124,6 +117,5 @@ TileGroup.propTypes = {
|
|
|
124
117
|
*/
|
|
125
118
|
valueSelected: PropTypes.oneOfType([PropTypes.string, PropTypes.number])
|
|
126
119
|
};
|
|
127
|
-
TileGroup.displayName = 'TileGroup';
|
|
128
120
|
|
|
129
|
-
export { TileGroup
|
|
121
|
+
export { TileGroup };
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Copyright IBM Corp. 2016,
|
|
2
|
+
* Copyright IBM Corp. 2016, 2025
|
|
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
|
*/
|
|
7
|
-
import
|
|
7
|
+
import { TileGroup } from './TileGroup';
|
|
8
8
|
export default TileGroup;
|
|
9
|
-
export
|
|
9
|
+
export * from './TileGroup';
|
|
@@ -24,6 +24,7 @@ const HeaderMenuItem = /*#__PURE__*/forwardRef(function HeaderMenuItem({
|
|
|
24
24
|
...rest
|
|
25
25
|
}, ref) {
|
|
26
26
|
const prefix = usePrefix();
|
|
27
|
+
const resolvedTabIndex = tabIndex ?? 0;
|
|
27
28
|
if (isCurrentPage) {
|
|
28
29
|
isActive = isCurrentPage;
|
|
29
30
|
}
|
|
@@ -42,7 +43,7 @@ const HeaderMenuItem = /*#__PURE__*/forwardRef(function HeaderMenuItem({
|
|
|
42
43
|
"aria-current": hasCurrentClass ? true : ariaCurrent,
|
|
43
44
|
className: linkClassName,
|
|
44
45
|
ref: ref,
|
|
45
|
-
tabIndex:
|
|
46
|
+
tabIndex: resolvedTabIndex
|
|
46
47
|
}), /*#__PURE__*/React.createElement("span", {
|
|
47
48
|
className: `${prefix}--text-truncate--end`
|
|
48
49
|
}, children)));
|
package/es/index.js
CHANGED
|
@@ -148,7 +148,7 @@ export { default as TextAreaSkeleton } from './components/TextArea/TextArea.Skel
|
|
|
148
148
|
export { default as TextInput } from './components/TextInput/TextInput.js';
|
|
149
149
|
export { default as TextInputSkeleton } from './components/TextInput/TextInput.Skeleton.js';
|
|
150
150
|
export { ClickableTile, ExpandableTile, SelectableTile, Tile, TileAboveTheFoldContent, TileBelowTheFoldContent } from './components/Tile/Tile.js';
|
|
151
|
-
export {
|
|
151
|
+
export { TileGroup } from './components/TileGroup/TileGroup.js';
|
|
152
152
|
export { default as TimePicker } from './components/TimePicker/TimePicker.js';
|
|
153
153
|
export { default as TimePickerSelect } from './components/TimePickerSelect/TimePickerSelect.js';
|
|
154
154
|
export { Toggle } from './components/Toggle/Toggle.js';
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright IBM Corp. 2025, 2025
|
|
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
|
+
import { ReactNode, RefObject } from 'react';
|
|
8
|
+
type Item = {
|
|
9
|
+
id: string;
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* Manages overflow items in a container by automatically hiding items that don't fit.
|
|
13
|
+
* @param items - Array of items to manage for overflow, each must have an `id` property.
|
|
14
|
+
* @param containerRef - React ref to the container element that holds the items.
|
|
15
|
+
* @param offsetRef - Optional ref to an offset element (like a "more" button) whose width is reserved when calculating available space.
|
|
16
|
+
* @param maxItems - Optional maximum number of visible items. If undefined, only container space constrains visibility.
|
|
17
|
+
* @param onChange - Optional callback called when hidden items change. Receives array of currently hidden items.
|
|
18
|
+
* @returns Object with `visibleItems` (items to display), `hiddenItems` (items that don't fit), and `itemRefHandler` (function to attach refs to items for width measurement).
|
|
19
|
+
*/
|
|
20
|
+
declare const useOverflowItems: <T extends Item>(items: T[] | ReactNode, containerRef: RefObject<HTMLDivElement>, offsetRef?: RefObject<HTMLDivElement>, maxItems?: number, onChange?: (hiddenItems: T[]) => void) => {
|
|
21
|
+
visibleItems: T[];
|
|
22
|
+
hiddenItems: T[];
|
|
23
|
+
itemRefHandler: () => void;
|
|
24
|
+
} | {
|
|
25
|
+
visibleItems: T[];
|
|
26
|
+
itemRefHandler: (id: string, node: HTMLDivElement | null) => () => void;
|
|
27
|
+
hiddenItems: T[];
|
|
28
|
+
};
|
|
29
|
+
export default useOverflowItems;
|