@carbon/react 1.54.0-rc.0 → 1.54.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 +822 -822
- package/es/components/Button/Button.d.ts +1 -1
- package/es/components/Button/Button.js +13 -89
- package/es/components/Button/ButtonBase.d.ts +10 -0
- package/es/components/Button/ButtonBase.js +110 -0
- package/es/components/CodeSnippet/CodeSnippet.js +1 -0
- package/es/components/IconButton/index.js +2 -3
- package/es/components/Menu/Menu.js +2 -0
- package/es/components/ModalWrapper/ModalWrapper.d.ts +1 -1
- package/es/components/Slider/Slider.Skeleton.js +6 -2
- package/es/components/StructuredList/StructuredList.d.ts +8 -0
- package/es/components/StructuredList/StructuredList.js +28 -10
- package/es/feature-flags.js +2 -1
- package/es/internal/environment.js +5 -1
- package/es/internal/keyboard/navigation.js +6 -2
- package/es/internal/useOutsideClick.js +31 -0
- package/lib/components/Button/Button.d.ts +1 -1
- package/lib/components/Button/Button.js +13 -90
- package/lib/components/Button/ButtonBase.d.ts +10 -0
- package/lib/components/Button/ButtonBase.js +119 -0
- package/lib/components/CodeSnippet/CodeSnippet.js +1 -0
- package/lib/components/IconButton/index.js +2 -3
- package/lib/components/Menu/Menu.js +2 -0
- package/lib/components/ModalWrapper/ModalWrapper.d.ts +1 -1
- package/lib/components/Slider/Slider.Skeleton.js +5 -1
- package/lib/components/StructuredList/StructuredList.d.ts +8 -0
- package/lib/components/StructuredList/StructuredList.js +27 -9
- package/lib/feature-flags.js +2 -1
- package/lib/internal/environment.js +5 -1
- package/lib/internal/keyboard/navigation.js +6 -2
- package/lib/internal/useOutsideClick.js +35 -0
- package/package.json +6 -6
|
@@ -14,7 +14,7 @@ export declare const ButtonTooltipAlignments: readonly ["start", "center", "end"
|
|
|
14
14
|
export type ButtonTooltipAlignment = (typeof ButtonTooltipAlignments)[number];
|
|
15
15
|
export declare const ButtonTooltipPositions: string[];
|
|
16
16
|
export type ButtonTooltipPosition = (typeof ButtonTooltipPositions)[number];
|
|
17
|
-
interface ButtonBaseProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
|
|
17
|
+
export interface ButtonBaseProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
|
|
18
18
|
/**
|
|
19
19
|
* Specify the message read by screen readers for the danger button variant
|
|
20
20
|
*/
|
|
@@ -8,11 +8,9 @@
|
|
|
8
8
|
import { extends as _extends } from '../../_virtual/_rollupPluginBabelHelpers.js';
|
|
9
9
|
import PropTypes from 'prop-types';
|
|
10
10
|
import React__default, { useRef } from 'react';
|
|
11
|
-
import cx from 'classnames';
|
|
12
11
|
import { IconButton } from '../IconButton/index.js';
|
|
13
12
|
import { composeEventHandlers } from '../../tools/events.js';
|
|
14
|
-
import
|
|
15
|
-
import { useId } from '../../internal/useId.js';
|
|
13
|
+
import ButtonBase from './ButtonBase.js';
|
|
16
14
|
|
|
17
15
|
const ButtonKinds = ['primary', 'secondary', 'danger', 'ghost', 'danger--primary', 'danger--ghost', 'danger--tertiary', 'tertiary'];
|
|
18
16
|
const ButtonSizes = ['sm', 'md', 'lg', 'xl', '2xl'];
|
|
@@ -24,18 +22,13 @@ function isIconOnlyButton(hasIconOnly, _kind) {
|
|
|
24
22
|
}
|
|
25
23
|
return false;
|
|
26
24
|
}
|
|
27
|
-
const Button = /*#__PURE__*/React__default.forwardRef(function Button(
|
|
28
|
-
|
|
25
|
+
const Button = /*#__PURE__*/React__default.forwardRef(function Button(props, ref) {
|
|
26
|
+
const tooltipRef = useRef(null);
|
|
27
|
+
const {
|
|
29
28
|
as,
|
|
30
29
|
children,
|
|
31
|
-
className,
|
|
32
|
-
dangerDescription = 'danger',
|
|
33
|
-
disabled = false,
|
|
34
30
|
hasIconOnly = false,
|
|
35
|
-
href,
|
|
36
31
|
iconDescription,
|
|
37
|
-
isExpressive = false,
|
|
38
|
-
isSelected,
|
|
39
32
|
kind = 'primary',
|
|
40
33
|
onBlur,
|
|
41
34
|
onClick,
|
|
@@ -44,92 +37,21 @@ const Button = /*#__PURE__*/React__default.forwardRef(function Button(_ref, ref)
|
|
|
44
37
|
onMouseLeave,
|
|
45
38
|
renderIcon: ButtonImageElement,
|
|
46
39
|
size,
|
|
47
|
-
tabIndex,
|
|
48
40
|
tooltipAlignment = 'center',
|
|
49
41
|
tooltipPosition = 'top',
|
|
50
|
-
type = 'button',
|
|
51
42
|
...rest
|
|
52
|
-
} =
|
|
53
|
-
const tooltipRef = useRef(null);
|
|
54
|
-
const prefix = usePrefix();
|
|
43
|
+
} = props;
|
|
55
44
|
const handleClick = evt => {
|
|
56
45
|
// Prevent clicks on the tooltip from triggering the button click event
|
|
57
46
|
if (evt.target === tooltipRef.current) {
|
|
58
47
|
evt.preventDefault();
|
|
59
48
|
}
|
|
60
49
|
};
|
|
61
|
-
const buttonClasses = cx(className, {
|
|
62
|
-
[`${prefix}--btn`]: true,
|
|
63
|
-
[`${prefix}--btn--sm`]: size === 'sm' && !isExpressive,
|
|
64
|
-
// TODO: V12 - Remove this class
|
|
65
|
-
[`${prefix}--btn--md`]: size === 'md' && !isExpressive,
|
|
66
|
-
// TODO: V12 - Remove this class
|
|
67
|
-
[`${prefix}--btn--xl`]: size === 'xl',
|
|
68
|
-
// TODO: V12 - Remove this class
|
|
69
|
-
[`${prefix}--btn--2xl`]: size === '2xl',
|
|
70
|
-
// TODO: V12 - Remove this class
|
|
71
|
-
[`${prefix}--layout--size-${size}`]: size,
|
|
72
|
-
[`${prefix}--btn--${kind}`]: kind,
|
|
73
|
-
[`${prefix}--btn--disabled`]: disabled,
|
|
74
|
-
[`${prefix}--btn--expressive`]: isExpressive,
|
|
75
|
-
[`${prefix}--btn--icon-only`]: hasIconOnly,
|
|
76
|
-
[`${prefix}--btn--selected`]: hasIconOnly && isSelected && kind === 'ghost'
|
|
77
|
-
});
|
|
78
|
-
const commonProps = {
|
|
79
|
-
tabIndex,
|
|
80
|
-
className: buttonClasses,
|
|
81
|
-
ref
|
|
82
|
-
};
|
|
83
|
-
const buttonImage = !ButtonImageElement ? null : /*#__PURE__*/React__default.createElement(ButtonImageElement, {
|
|
84
|
-
"aria-label": iconDescription,
|
|
85
|
-
className: `${prefix}--btn__icon`,
|
|
86
|
-
"aria-hidden": "true"
|
|
87
|
-
});
|
|
88
50
|
const iconOnlyImage = !ButtonImageElement ? null : /*#__PURE__*/React__default.createElement(ButtonImageElement, null);
|
|
89
|
-
const dangerButtonVariants = ['danger', 'danger--tertiary', 'danger--ghost'];
|
|
90
|
-
let component = 'button';
|
|
91
|
-
const assistiveId = useId('danger-description');
|
|
92
|
-
const {
|
|
93
|
-
'aria-pressed': ariaPressed,
|
|
94
|
-
'aria-describedby': ariaDescribedBy
|
|
95
|
-
} = rest;
|
|
96
|
-
let otherProps = {
|
|
97
|
-
disabled,
|
|
98
|
-
type,
|
|
99
|
-
'aria-describedby': dangerButtonVariants.includes(kind) ? assistiveId : ariaDescribedBy || undefined,
|
|
100
|
-
'aria-pressed': ariaPressed ?? (hasIconOnly && kind === 'ghost' ? isSelected : undefined)
|
|
101
|
-
};
|
|
102
|
-
const anchorProps = {
|
|
103
|
-
href
|
|
104
|
-
};
|
|
105
|
-
let assistiveText = null;
|
|
106
|
-
if (dangerButtonVariants.includes(kind)) {
|
|
107
|
-
assistiveText = /*#__PURE__*/React__default.createElement("span", {
|
|
108
|
-
id: assistiveId,
|
|
109
|
-
className: `${prefix}--visually-hidden`
|
|
110
|
-
}, dangerDescription);
|
|
111
|
-
}
|
|
112
|
-
if (as) {
|
|
113
|
-
component = as;
|
|
114
|
-
otherProps = {
|
|
115
|
-
...otherProps,
|
|
116
|
-
...anchorProps
|
|
117
|
-
};
|
|
118
|
-
} else if (href && !disabled) {
|
|
119
|
-
component = 'a';
|
|
120
|
-
otherProps = anchorProps;
|
|
121
|
-
}
|
|
122
51
|
if (!isIconOnlyButton(hasIconOnly)) {
|
|
123
|
-
return /*#__PURE__*/React__default.createElement(
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
onFocus,
|
|
127
|
-
onBlur,
|
|
128
|
-
onClick,
|
|
129
|
-
...rest,
|
|
130
|
-
...commonProps,
|
|
131
|
-
...otherProps
|
|
132
|
-
}, assistiveText, children, buttonImage);
|
|
52
|
+
return /*#__PURE__*/React__default.createElement(ButtonBase, _extends({
|
|
53
|
+
ref: ref
|
|
54
|
+
}, props));
|
|
133
55
|
} else {
|
|
134
56
|
let align = undefined;
|
|
135
57
|
if (tooltipPosition === 'top' || tooltipPosition === 'bottom') {
|
|
@@ -146,7 +68,8 @@ const Button = /*#__PURE__*/React__default.forwardRef(function Button(_ref, ref)
|
|
|
146
68
|
if (tooltipPosition === 'right' || tooltipPosition === 'left') {
|
|
147
69
|
align = tooltipPosition;
|
|
148
70
|
}
|
|
149
|
-
return /*#__PURE__*/React__default.createElement(IconButton, _extends({
|
|
71
|
+
return /*#__PURE__*/React__default.createElement(IconButton, _extends({}, rest, {
|
|
72
|
+
ref: ref,
|
|
150
73
|
as: as,
|
|
151
74
|
align: align,
|
|
152
75
|
label: iconDescription,
|
|
@@ -156,8 +79,9 @@ const Button = /*#__PURE__*/React__default.forwardRef(function Button(_ref, ref)
|
|
|
156
79
|
onMouseLeave: onMouseLeave,
|
|
157
80
|
onFocus: onFocus,
|
|
158
81
|
onBlur: onBlur,
|
|
159
|
-
onClick: composeEventHandlers([onClick, handleClick])
|
|
160
|
-
|
|
82
|
+
onClick: composeEventHandlers([onClick, handleClick]),
|
|
83
|
+
renderIcon: iconOnlyImage ? null : ButtonImageElement // avoid doubling the icon.
|
|
84
|
+
}), iconOnlyImage ?? children);
|
|
161
85
|
}
|
|
162
86
|
});
|
|
163
87
|
Button.displayName = 'Button';
|
|
@@ -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
|
+
import React from 'react';
|
|
8
|
+
import { ButtonProps } from './Button';
|
|
9
|
+
declare const ButtonBase: React.ForwardRefExoticComponent<Omit<ButtonProps<React.ElementType<any>>, "ref"> & React.RefAttributes<unknown>>;
|
|
10
|
+
export default ButtonBase;
|
|
@@ -0,0 +1,110 @@
|
|
|
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
|
+
import React__default from 'react';
|
|
9
|
+
import cx from 'classnames';
|
|
10
|
+
import { usePrefix } from '../../internal/usePrefix.js';
|
|
11
|
+
import { useId } from '../../internal/useId.js';
|
|
12
|
+
|
|
13
|
+
const ButtonBase = /*#__PURE__*/React__default.forwardRef(function ButtonBase(_ref, ref) {
|
|
14
|
+
let {
|
|
15
|
+
as,
|
|
16
|
+
children,
|
|
17
|
+
className,
|
|
18
|
+
dangerDescription = 'danger',
|
|
19
|
+
disabled = false,
|
|
20
|
+
hasIconOnly = false,
|
|
21
|
+
href,
|
|
22
|
+
iconDescription,
|
|
23
|
+
isExpressive = false,
|
|
24
|
+
isSelected,
|
|
25
|
+
kind = 'primary',
|
|
26
|
+
onBlur,
|
|
27
|
+
onClick,
|
|
28
|
+
onFocus,
|
|
29
|
+
onMouseEnter,
|
|
30
|
+
onMouseLeave,
|
|
31
|
+
renderIcon: ButtonImageElement,
|
|
32
|
+
size,
|
|
33
|
+
tabIndex,
|
|
34
|
+
type = 'button',
|
|
35
|
+
...rest
|
|
36
|
+
} = _ref;
|
|
37
|
+
const prefix = usePrefix();
|
|
38
|
+
const buttonClasses = cx(className, {
|
|
39
|
+
[`${prefix}--btn`]: true,
|
|
40
|
+
[`${prefix}--btn--sm`]: size === 'sm' && !isExpressive,
|
|
41
|
+
// TODO: V12 - Remove this class
|
|
42
|
+
[`${prefix}--btn--md`]: size === 'md' && !isExpressive,
|
|
43
|
+
// TODO: V12 - Remove this class
|
|
44
|
+
[`${prefix}--btn--xl`]: size === 'xl',
|
|
45
|
+
// TODO: V12 - Remove this class
|
|
46
|
+
[`${prefix}--btn--2xl`]: size === '2xl',
|
|
47
|
+
// TODO: V12 - Remove this class
|
|
48
|
+
[`${prefix}--layout--size-${size}`]: size,
|
|
49
|
+
[`${prefix}--btn--${kind}`]: kind,
|
|
50
|
+
[`${prefix}--btn--disabled`]: disabled,
|
|
51
|
+
[`${prefix}--btn--expressive`]: isExpressive,
|
|
52
|
+
[`${prefix}--btn--icon-only`]: hasIconOnly && !className?.includes(`${prefix}--btn--icon-only`),
|
|
53
|
+
[`${prefix}--btn--selected`]: hasIconOnly && isSelected && kind === 'ghost'
|
|
54
|
+
});
|
|
55
|
+
const commonProps = {
|
|
56
|
+
tabIndex,
|
|
57
|
+
className: buttonClasses,
|
|
58
|
+
ref
|
|
59
|
+
};
|
|
60
|
+
const buttonImage = !ButtonImageElement ? null : /*#__PURE__*/React__default.createElement(ButtonImageElement, {
|
|
61
|
+
"aria-label": iconDescription,
|
|
62
|
+
className: `${prefix}--btn__icon`,
|
|
63
|
+
"aria-hidden": "true"
|
|
64
|
+
});
|
|
65
|
+
const dangerButtonVariants = ['danger', 'danger--tertiary', 'danger--ghost'];
|
|
66
|
+
let component = 'button';
|
|
67
|
+
const assistiveId = useId('danger-description');
|
|
68
|
+
const {
|
|
69
|
+
'aria-pressed': ariaPressed,
|
|
70
|
+
'aria-describedby': ariaDescribedBy
|
|
71
|
+
} = rest;
|
|
72
|
+
let otherProps = {
|
|
73
|
+
disabled,
|
|
74
|
+
type,
|
|
75
|
+
'aria-describedby': dangerButtonVariants.includes(kind) ? assistiveId : ariaDescribedBy || undefined,
|
|
76
|
+
'aria-pressed': ariaPressed ?? (hasIconOnly && kind === 'ghost' ? isSelected : undefined)
|
|
77
|
+
};
|
|
78
|
+
const anchorProps = {
|
|
79
|
+
href
|
|
80
|
+
};
|
|
81
|
+
let assistiveText = null;
|
|
82
|
+
if (dangerButtonVariants.includes(kind)) {
|
|
83
|
+
assistiveText = /*#__PURE__*/React__default.createElement("span", {
|
|
84
|
+
id: assistiveId,
|
|
85
|
+
className: `${prefix}--visually-hidden`
|
|
86
|
+
}, dangerDescription);
|
|
87
|
+
}
|
|
88
|
+
if (as) {
|
|
89
|
+
component = as;
|
|
90
|
+
otherProps = {
|
|
91
|
+
...otherProps,
|
|
92
|
+
...anchorProps
|
|
93
|
+
};
|
|
94
|
+
} else if (href && !disabled) {
|
|
95
|
+
component = 'a';
|
|
96
|
+
otherProps = anchorProps;
|
|
97
|
+
}
|
|
98
|
+
return /*#__PURE__*/React__default.createElement(component, {
|
|
99
|
+
onMouseEnter,
|
|
100
|
+
onMouseLeave,
|
|
101
|
+
onFocus,
|
|
102
|
+
onBlur,
|
|
103
|
+
onClick,
|
|
104
|
+
...rest,
|
|
105
|
+
...commonProps,
|
|
106
|
+
...otherProps
|
|
107
|
+
}, assistiveText, children, buttonImage);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
export { ButtonBase as default };
|
|
@@ -8,12 +8,11 @@
|
|
|
8
8
|
import { extends as _extends } from '../../_virtual/_rollupPluginBabelHelpers.js';
|
|
9
9
|
import PropTypes from 'prop-types';
|
|
10
10
|
import React__default from 'react';
|
|
11
|
-
import Button from '../Button/Button.js';
|
|
12
|
-
import '../Button/Button.Skeleton.js';
|
|
13
11
|
import cx from 'classnames';
|
|
14
12
|
import '../Tooltip/DefinitionTooltip.js';
|
|
15
13
|
import { Tooltip } from '../Tooltip/Tooltip.js';
|
|
16
14
|
import { usePrefix } from '../../internal/usePrefix.js';
|
|
15
|
+
import ButtonBase from '../Button/ButtonBase.js';
|
|
17
16
|
|
|
18
17
|
const IconButtonKinds = ['primary', 'secondary', 'ghost', 'tertiary'];
|
|
19
18
|
const IconButton = /*#__PURE__*/React__default.forwardRef(function IconButton(_ref, ref) {
|
|
@@ -45,7 +44,7 @@ const IconButton = /*#__PURE__*/React__default.forwardRef(function IconButton(_r
|
|
|
45
44
|
enterDelayMs: enterDelayMs,
|
|
46
45
|
label: label,
|
|
47
46
|
leaveDelayMs: leaveDelayMs
|
|
48
|
-
}, /*#__PURE__*/React__default.createElement(
|
|
47
|
+
}, /*#__PURE__*/React__default.createElement(ButtonBase, _extends({}, rest, {
|
|
49
48
|
disabled: disabled,
|
|
50
49
|
kind: kind,
|
|
51
50
|
ref: ref,
|
|
@@ -59,7 +59,7 @@ export default class ModalWrapper extends React.Component<ModalWrapperProps, Mod
|
|
|
59
59
|
shouldCloseAfterSubmit: PropTypes.Requireable<boolean>;
|
|
60
60
|
status: PropTypes.Requireable<string>;
|
|
61
61
|
triggerButtonIconDescription: PropTypes.Requireable<string>;
|
|
62
|
-
triggerButtonKind: PropTypes.Requireable<"primary" | "secondary" | "
|
|
62
|
+
triggerButtonKind: PropTypes.Requireable<"primary" | "secondary" | "danger" | "ghost" | "danger--primary" | "danger--ghost" | "danger--tertiary" | "tertiary">;
|
|
63
63
|
withHeader: PropTypes.Requireable<boolean>;
|
|
64
64
|
};
|
|
65
65
|
triggerButton: React.RefObject<HTMLButtonElement>;
|
|
@@ -7,9 +7,10 @@
|
|
|
7
7
|
|
|
8
8
|
import { extends as _extends } from '../../_virtual/_rollupPluginBabelHelpers.js';
|
|
9
9
|
import PropTypes from 'prop-types';
|
|
10
|
-
import React__default from 'react';
|
|
10
|
+
import React__default, { useState } from 'react';
|
|
11
11
|
import cx from 'classnames';
|
|
12
12
|
import { usePrefix } from '../../internal/usePrefix.js';
|
|
13
|
+
import useIsomorphicEffect from '../../internal/useIsomorphicEffect.js';
|
|
13
14
|
import { LowerHandle, UpperHandle } from './SliderHandles.js';
|
|
14
15
|
|
|
15
16
|
var _LowerHandle, _UpperHandle, _UpperHandle2, _LowerHandle2;
|
|
@@ -21,7 +22,10 @@ const SliderSkeleton = _ref => {
|
|
|
21
22
|
...rest
|
|
22
23
|
} = _ref;
|
|
23
24
|
const prefix = usePrefix();
|
|
24
|
-
const isRtl =
|
|
25
|
+
const [isRtl, setIsRtl] = useState(false);
|
|
26
|
+
useIsomorphicEffect(() => {
|
|
27
|
+
setIsRtl(document ? document.dir === 'rtl' : false);
|
|
28
|
+
}, []);
|
|
25
29
|
const containerClasses = cx(`${prefix}--slider-container`, `${prefix}--skeleton`, {
|
|
26
30
|
[`${prefix}--slider-container--two-handles`]: twoHandles,
|
|
27
31
|
[`${prefix}--slider-container--rtl`]: isRtl
|
|
@@ -144,6 +144,10 @@ export interface StructuredListRowProps extends DivAttrs {
|
|
|
144
144
|
* Provide a handler that is invoked on the key down event for the control
|
|
145
145
|
*/
|
|
146
146
|
onKeyDown?(event: KeyboardEvent): void;
|
|
147
|
+
/**
|
|
148
|
+
* Mark if this row should be selectable
|
|
149
|
+
*/
|
|
150
|
+
selection?: boolean;
|
|
147
151
|
}
|
|
148
152
|
export declare function StructuredListRow(props: StructuredListRowProps): import("react/jsx-runtime").JSX.Element;
|
|
149
153
|
export declare namespace StructuredListRow {
|
|
@@ -172,6 +176,10 @@ export declare namespace StructuredListRow {
|
|
|
172
176
|
* Provide a handler that is invoked on the key down event for the control,
|
|
173
177
|
*/
|
|
174
178
|
onKeyDown: PropTypes.Requireable<(...args: any[]) => any>;
|
|
179
|
+
/**
|
|
180
|
+
* Mark if this row should be selectable
|
|
181
|
+
*/
|
|
182
|
+
selection: PropTypes.Requireable<boolean>;
|
|
175
183
|
};
|
|
176
184
|
}
|
|
177
185
|
export interface StructuredListInputProps extends DivAttrs {
|
|
@@ -6,15 +6,18 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import { extends as _extends } from '../../_virtual/_rollupPluginBabelHelpers.js';
|
|
9
|
-
import React__default, { useState } from 'react';
|
|
9
|
+
import React__default, { useState, useRef } from 'react';
|
|
10
10
|
import PropTypes from 'prop-types';
|
|
11
11
|
import cx from 'classnames';
|
|
12
12
|
import { useId } from '../../internal/useId.js';
|
|
13
13
|
import deprecate from '../../prop-types/deprecate.js';
|
|
14
14
|
import { usePrefix } from '../../internal/usePrefix.js';
|
|
15
15
|
import '../Text/index.js';
|
|
16
|
+
import { RadioButtonChecked, RadioButton } from '@carbon/icons-react';
|
|
17
|
+
import { useOutsideClick } from '../../internal/useOutsideClick.js';
|
|
16
18
|
import { Text } from '../Text/Text.js';
|
|
17
19
|
|
|
20
|
+
var _StructuredListCell, _RadioButtonChecked, _RadioButton;
|
|
18
21
|
const GridSelectedRowStateContext = /*#__PURE__*/React__default.createContext(null);
|
|
19
22
|
const GridSelectedRowDispatchContext = /*#__PURE__*/React__default.createContext(null);
|
|
20
23
|
function StructuredListWrapper(props) {
|
|
@@ -137,6 +140,7 @@ function StructuredListRow(props) {
|
|
|
137
140
|
className,
|
|
138
141
|
head,
|
|
139
142
|
onClick,
|
|
143
|
+
selection,
|
|
140
144
|
...other
|
|
141
145
|
} = props;
|
|
142
146
|
const [hasFocusWithin, setHasFocusWithin] = useState(false);
|
|
@@ -149,25 +153,35 @@ function StructuredListRow(props) {
|
|
|
149
153
|
};
|
|
150
154
|
const classes = cx(`${prefix}--structured-list-row`, {
|
|
151
155
|
[`${prefix}--structured-list-row--header-row`]: head,
|
|
152
|
-
[`${prefix}--structured-list-row--focused-within`]: hasFocusWithin,
|
|
156
|
+
[`${prefix}--structured-list-row--focused-within`]: hasFocusWithin && !selection || hasFocusWithin && selection && (selectedRow === id || selectedRow === null),
|
|
157
|
+
// Ensure focus on the first item when navigating through Tab keys and no row is selected (selectedRow === null)
|
|
153
158
|
[`${prefix}--structured-list-row--selected`]: selectedRow === id
|
|
154
159
|
}, className);
|
|
160
|
+
const itemRef = useRef(null);
|
|
161
|
+
const handleClick = () => {
|
|
162
|
+
setHasFocusWithin(false);
|
|
163
|
+
};
|
|
164
|
+
useOutsideClick(itemRef, handleClick);
|
|
155
165
|
return head ? /*#__PURE__*/React__default.createElement("div", _extends({
|
|
156
166
|
role: "row"
|
|
157
167
|
}, other, {
|
|
158
|
-
className: classes
|
|
159
|
-
|
|
160
|
-
|
|
168
|
+
className: classes
|
|
169
|
+
}), selection && (_StructuredListCell || (_StructuredListCell = /*#__PURE__*/React__default.createElement(StructuredListCell, {
|
|
170
|
+
head: true
|
|
171
|
+
}))), children) :
|
|
161
172
|
/*#__PURE__*/
|
|
162
173
|
// eslint-disable-next-line jsx-a11y/interactive-supports-focus
|
|
163
|
-
React__default.createElement("div", _extends({
|
|
164
|
-
"aria-busy": "true"
|
|
165
|
-
}, other, {
|
|
174
|
+
React__default.createElement("div", _extends({}, other, {
|
|
166
175
|
role: "row",
|
|
167
176
|
className: classes,
|
|
177
|
+
ref: itemRef,
|
|
168
178
|
onClick: event => {
|
|
169
179
|
setSelectedRow?.(id);
|
|
170
180
|
onClick && onClick(event);
|
|
181
|
+
if (selection) {
|
|
182
|
+
// focus items only when selection is enabled
|
|
183
|
+
setHasFocusWithin(true);
|
|
184
|
+
}
|
|
171
185
|
},
|
|
172
186
|
onFocus: () => {
|
|
173
187
|
setHasFocusWithin(true);
|
|
@@ -178,7 +192,7 @@ function StructuredListRow(props) {
|
|
|
178
192
|
onKeyDown: onKeyDown
|
|
179
193
|
}), /*#__PURE__*/React__default.createElement(GridRowContext.Provider, {
|
|
180
194
|
value: value
|
|
181
|
-
}, children));
|
|
195
|
+
}, selection && /*#__PURE__*/React__default.createElement(StructuredListCell, null, selectedRow === id ? _RadioButtonChecked || (_RadioButtonChecked = /*#__PURE__*/React__default.createElement(RadioButtonChecked, null)) : _RadioButton || (_RadioButton = /*#__PURE__*/React__default.createElement(RadioButton, null))), children));
|
|
182
196
|
}
|
|
183
197
|
StructuredListRow.propTypes = {
|
|
184
198
|
/**
|
|
@@ -204,7 +218,11 @@ StructuredListRow.propTypes = {
|
|
|
204
218
|
/**
|
|
205
219
|
* Provide a handler that is invoked on the key down event for the control,
|
|
206
220
|
*/
|
|
207
|
-
onKeyDown: PropTypes.func
|
|
221
|
+
onKeyDown: PropTypes.func,
|
|
222
|
+
/**
|
|
223
|
+
* Mark if this row should be selectable
|
|
224
|
+
*/
|
|
225
|
+
selection: PropTypes.bool
|
|
208
226
|
};
|
|
209
227
|
function StructuredListInput(props) {
|
|
210
228
|
const defaultId = useId('structureListInput');
|
package/es/feature-flags.js
CHANGED
|
@@ -12,5 +12,6 @@ FeatureFlags.merge({
|
|
|
12
12
|
'enable-css-grid': true,
|
|
13
13
|
'enable-v11-release': true,
|
|
14
14
|
'enable-experimental-tile-contrast': false,
|
|
15
|
-
'enable-v12-tile-radio-icons': false
|
|
15
|
+
'enable-v12-tile-radio-icons': false,
|
|
16
|
+
'enable-v12-structured-list-visible-icons': false
|
|
16
17
|
});
|
|
@@ -10,6 +10,10 @@
|
|
|
10
10
|
*
|
|
11
11
|
* @see https://github.com/facebook/fbjs/blob/4d1751311d3f67af2dcce2e40df8512a23c7b9c6/packages/fbjs/src/core/ExecutionEnvironment.js#L12
|
|
12
12
|
*/
|
|
13
|
-
const canUseDOM = !!(typeof window !== 'undefined' &&
|
|
13
|
+
const canUseDOM = !!(typeof window !== 'undefined' &&
|
|
14
|
+
// eslint-disable-next-line ssr-friendly/no-dom-globals-in-module-scope
|
|
15
|
+
window.document &&
|
|
16
|
+
// eslint-disable-next-line ssr-friendly/no-dom-globals-in-module-scope
|
|
17
|
+
window.document.createElement);
|
|
14
18
|
|
|
15
19
|
export { canUseDOM };
|
|
@@ -39,7 +39,9 @@ const getNextIndex = (key, index, arrayLength) => {
|
|
|
39
39
|
*/
|
|
40
40
|
const DOCUMENT_POSITION_BROAD_PRECEDING =
|
|
41
41
|
// Checks `typeof Node` for `react-docgen`
|
|
42
|
-
typeof Node !== 'undefined' &&
|
|
42
|
+
typeof Node !== 'undefined' &&
|
|
43
|
+
// eslint-disable-next-line ssr-friendly/no-dom-globals-in-module-scope
|
|
44
|
+
Node.DOCUMENT_POSITION_PRECEDING | Node.DOCUMENT_POSITION_CONTAINS;
|
|
43
45
|
|
|
44
46
|
/**
|
|
45
47
|
* A flag `node.compareDocumentPosition(target)` returns,
|
|
@@ -47,7 +49,9 @@ typeof Node !== 'undefined' && Node.DOCUMENT_POSITION_PRECEDING | Node.DOCUMENT_
|
|
|
47
49
|
*/
|
|
48
50
|
const DOCUMENT_POSITION_BROAD_FOLLOWING =
|
|
49
51
|
// Checks `typeof Node` for `react-docgen`
|
|
50
|
-
typeof Node !== 'undefined' &&
|
|
52
|
+
typeof Node !== 'undefined' &&
|
|
53
|
+
// eslint-disable-next-line ssr-friendly/no-dom-globals-in-module-scope
|
|
54
|
+
Node.DOCUMENT_POSITION_FOLLOWING | Node.DOCUMENT_POSITION_CONTAINED_BY;
|
|
51
55
|
|
|
52
56
|
/**
|
|
53
57
|
* CSS selector that selects major nodes that are sequential-focusable.
|
|
@@ -0,0 +1,31 @@
|
|
|
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
|
+
import { useRef, useEffect } from 'react';
|
|
9
|
+
import { useEvent } from './useEvent.js';
|
|
10
|
+
import { canUseDOM } from './environment.js';
|
|
11
|
+
|
|
12
|
+
function useOutsideClick(ref, callback) {
|
|
13
|
+
const savedCallback = useRef(callback);
|
|
14
|
+
useEffect(() => {
|
|
15
|
+
savedCallback.current = callback;
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
// We conditionally guard the `useEvent` hook for SSR. `canUseDOM` can be
|
|
19
|
+
// treated as a constant as it will be false when executed in a Node.js
|
|
20
|
+
// environment and true when executed in the browser
|
|
21
|
+
if (canUseDOM) {
|
|
22
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
23
|
+
useEvent(window, 'click', event => {
|
|
24
|
+
if (ref.current && !ref.current.contains(event.target)) {
|
|
25
|
+
savedCallback.current(event);
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export { useOutsideClick };
|
|
@@ -14,7 +14,7 @@ export declare const ButtonTooltipAlignments: readonly ["start", "center", "end"
|
|
|
14
14
|
export type ButtonTooltipAlignment = (typeof ButtonTooltipAlignments)[number];
|
|
15
15
|
export declare const ButtonTooltipPositions: string[];
|
|
16
16
|
export type ButtonTooltipPosition = (typeof ButtonTooltipPositions)[number];
|
|
17
|
-
interface ButtonBaseProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
|
|
17
|
+
export interface ButtonBaseProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
|
|
18
18
|
/**
|
|
19
19
|
* Specify the message read by screen readers for the danger button variant
|
|
20
20
|
*/
|