@patternfly/react-core 6.0.0-alpha.100 → 6.0.0-alpha.102
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/CHANGELOG.md +12 -0
- package/components/package.json +1 -1
- package/deprecated/package.json +1 -1
- package/dist/dynamic/components/AboutModal/package.json +1 -1
- package/dist/dynamic/components/Accordion/package.json +1 -1
- package/dist/dynamic/components/ActionList/package.json +1 -1
- package/dist/dynamic/components/Alert/package.json +1 -1
- package/dist/dynamic/components/Avatar/package.json +1 -1
- package/dist/dynamic/components/BackToTop/package.json +1 -1
- package/dist/dynamic/components/Backdrop/package.json +1 -1
- package/dist/dynamic/components/BackgroundImage/package.json +1 -1
- package/dist/dynamic/components/Badge/package.json +1 -1
- package/dist/dynamic/components/Banner/package.json +1 -1
- package/dist/dynamic/components/Brand/package.json +1 -1
- package/dist/dynamic/components/Breadcrumb/package.json +1 -1
- package/dist/dynamic/components/Button/package.json +1 -1
- package/dist/dynamic/components/CalendarMonth/package.json +1 -1
- package/dist/dynamic/components/Card/package.json +1 -1
- package/dist/dynamic/components/Checkbox/package.json +1 -1
- package/dist/dynamic/components/ClipboardCopy/package.json +1 -1
- package/dist/dynamic/components/CodeBlock/package.json +1 -1
- package/dist/dynamic/components/Content/package.json +1 -1
- package/dist/dynamic/components/DataList/package.json +1 -1
- package/dist/dynamic/components/DatePicker/package.json +1 -1
- package/dist/dynamic/components/DescriptionList/package.json +1 -1
- package/dist/dynamic/components/Divider/package.json +1 -1
- package/dist/dynamic/components/Drawer/package.json +1 -1
- package/dist/dynamic/components/Dropdown/package.json +1 -1
- package/dist/dynamic/components/DualListSelector/package.json +1 -1
- package/dist/dynamic/components/EmptyState/package.json +1 -1
- package/dist/dynamic/components/ExpandableSection/package.json +1 -1
- package/dist/dynamic/components/FileUpload/package.json +1 -1
- package/dist/dynamic/components/Form/package.json +1 -1
- package/dist/dynamic/components/FormSelect/package.json +1 -1
- package/dist/dynamic/components/HelperText/package.json +1 -1
- package/dist/dynamic/components/Hint/package.json +1 -1
- package/dist/dynamic/components/Icon/package.json +1 -1
- package/dist/dynamic/components/InputGroup/package.json +1 -1
- package/dist/dynamic/components/JumpLinks/package.json +1 -1
- package/dist/dynamic/components/Label/package.json +1 -1
- package/dist/dynamic/components/List/package.json +1 -1
- package/dist/dynamic/components/LoginPage/package.json +1 -1
- package/dist/dynamic/components/Masthead/package.json +1 -1
- package/dist/dynamic/components/Menu/package.json +1 -1
- package/dist/dynamic/components/MenuToggle/package.json +1 -1
- package/dist/dynamic/components/Modal/package.json +1 -1
- package/dist/dynamic/components/MultipleFileUpload/package.json +1 -1
- package/dist/dynamic/components/Nav/package.json +1 -1
- package/dist/dynamic/components/NotificationBadge/package.json +1 -1
- package/dist/dynamic/components/NotificationDrawer/package.json +1 -1
- package/dist/dynamic/components/NumberInput/package.json +1 -1
- package/dist/dynamic/components/OverflowMenu/package.json +1 -1
- package/dist/dynamic/components/Page/package.json +1 -1
- package/dist/dynamic/components/Pagination/package.json +1 -1
- package/dist/dynamic/components/Panel/package.json +1 -1
- package/dist/dynamic/components/Popover/package.json +1 -1
- package/dist/dynamic/components/Progress/package.json +1 -1
- package/dist/dynamic/components/ProgressStepper/package.json +1 -1
- package/dist/dynamic/components/Radio/package.json +1 -1
- package/dist/dynamic/components/SearchInput/package.json +1 -1
- package/dist/dynamic/components/Select/package.json +1 -1
- package/dist/dynamic/components/Sidebar/package.json +1 -1
- package/dist/dynamic/components/SimpleList/package.json +1 -1
- package/dist/dynamic/components/Skeleton/package.json +1 -1
- package/dist/dynamic/components/SkipToContent/package.json +1 -1
- package/dist/dynamic/components/Slider/package.json +1 -1
- package/dist/dynamic/components/Spinner/package.json +1 -1
- package/dist/dynamic/components/Switch/package.json +1 -1
- package/dist/dynamic/components/Tabs/package.json +1 -1
- package/dist/dynamic/components/TextArea/package.json +1 -1
- package/dist/dynamic/components/TextInput/package.json +1 -1
- package/dist/dynamic/components/TextInputGroup/package.json +1 -1
- package/dist/dynamic/components/Tile/package.json +1 -1
- package/dist/dynamic/components/TimePicker/package.json +1 -1
- package/dist/dynamic/components/Timestamp/package.json +1 -1
- package/dist/dynamic/components/Title/package.json +1 -1
- package/dist/dynamic/components/ToggleGroup/package.json +1 -1
- package/dist/dynamic/components/Toolbar/package.json +1 -1
- package/dist/dynamic/components/Tooltip/package.json +1 -1
- package/dist/dynamic/components/TreeView/package.json +1 -1
- package/dist/dynamic/components/Truncate/package.json +1 -1
- package/dist/dynamic/components/Wizard/hooks/package.json +1 -1
- package/dist/dynamic/components/Wizard/package.json +1 -1
- package/dist/dynamic/deprecated/components/Chip/package.json +1 -1
- package/dist/dynamic/deprecated/components/DragDrop/package.json +1 -1
- package/dist/dynamic/deprecated/components/DualListSelector/package.json +1 -1
- package/dist/dynamic/deprecated/components/Modal/package.json +1 -1
- package/dist/dynamic/deprecated/components/Wizard/package.json +1 -1
- package/dist/dynamic/deprecated/components/package.json +1 -1
- package/dist/dynamic/helpers/FocusTrap/FocusTrap/package.json +1 -1
- package/dist/dynamic/helpers/GenerateId/GenerateId/package.json +1 -1
- package/dist/dynamic/helpers/KeyboardHandler/package.json +1 -1
- package/dist/dynamic/helpers/OUIA/ouia/package.json +1 -1
- package/dist/dynamic/helpers/Popper/Popper/package.json +1 -1
- package/dist/dynamic/helpers/constants/package.json +1 -1
- package/dist/dynamic/helpers/datetimeUtils/package.json +1 -1
- package/dist/dynamic/helpers/fileUtils/package.json +1 -1
- package/dist/dynamic/helpers/htmlConstants/package.json +1 -1
- package/dist/dynamic/helpers/package.json +1 -1
- package/dist/dynamic/helpers/resizeObserver/package.json +1 -1
- package/dist/dynamic/helpers/typeUtils/package.json +1 -1
- package/dist/dynamic/helpers/useInterval/package.json +1 -1
- package/dist/dynamic/helpers/useIsomorphicLayout/package.json +1 -1
- package/dist/dynamic/helpers/useUnmountEffect/package.json +1 -1
- package/dist/dynamic/helpers/util/package.json +1 -1
- package/dist/dynamic/layouts/Bullseye/package.json +1 -1
- package/dist/dynamic/layouts/Flex/package.json +1 -1
- package/dist/dynamic/layouts/Gallery/package.json +1 -1
- package/dist/dynamic/layouts/Grid/package.json +1 -1
- package/dist/dynamic/layouts/Level/package.json +1 -1
- package/dist/dynamic/layouts/Split/package.json +1 -1
- package/dist/dynamic/layouts/Stack/package.json +1 -1
- package/dist/dynamic/styles/package.json +1 -1
- package/dist/esm/components/Card/CardHeader.d.ts +16 -10
- package/dist/esm/components/Card/CardHeader.d.ts.map +1 -1
- package/dist/esm/components/Card/CardHeader.js +25 -29
- package/dist/esm/components/Card/CardHeader.js.map +1 -1
- package/dist/esm/components/NotificationDrawer/NotificationDrawerListItemHeader.d.ts +2 -0
- package/dist/esm/components/NotificationDrawer/NotificationDrawerListItemHeader.d.ts.map +1 -1
- package/dist/esm/components/NotificationDrawer/NotificationDrawerListItemHeader.js +2 -2
- package/dist/esm/components/NotificationDrawer/NotificationDrawerListItemHeader.js.map +1 -1
- package/dist/js/components/Card/CardHeader.d.ts +16 -10
- package/dist/js/components/Card/CardHeader.d.ts.map +1 -1
- package/dist/js/components/Card/CardHeader.js +25 -29
- package/dist/js/components/Card/CardHeader.js.map +1 -1
- package/dist/js/components/NotificationDrawer/NotificationDrawerListItemHeader.d.ts +2 -0
- package/dist/js/components/NotificationDrawer/NotificationDrawerListItemHeader.d.ts.map +1 -1
- package/dist/js/components/NotificationDrawer/NotificationDrawerListItemHeader.js +2 -2
- package/dist/js/components/NotificationDrawer/NotificationDrawerListItemHeader.js.map +1 -1
- package/dist/umd/assets/{output-BFvJVM-B.css → output-DDZmdp2b.css} +1405 -1390
- package/dist/umd/react-core.min.js +2 -2
- package/helpers/package.json +1 -1
- package/layouts/package.json +1 -1
- package/next/package.json +1 -1
- package/package.json +6 -6
- package/src/components/Card/CardHeader.tsx +115 -93
- package/src/components/Card/__tests__/CardHeader.test.tsx +330 -1
- package/src/components/Card/examples/CardClickable.tsx +11 -21
- package/src/components/Card/examples/CardClickableSelectable.tsx +6 -3
- package/src/components/Card/examples/CardSelectable.tsx +6 -3
- package/src/components/Card/examples/CardSingleSelectable.tsx +6 -3
- package/src/components/NotificationDrawer/NotificationDrawerListItemHeader.tsx +8 -1
- package/src/components/NotificationDrawer/__tests__/NotificationDrawerListItemHeader.test.tsx +24 -0
- package/src/components/NotificationDrawer/examples/NotificationDrawerBasic.tsx +14 -21
- package/src/components/NotificationDrawer/examples/NotificationDrawerGroups.tsx +18 -27
- package/dist/styles/assets/pficon/pf-v5-pficon.woff2 +0 -0
package/helpers/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"name":"@patternfly/react-core-helpers","main":"../dist/js/helpers/index.js","module":"../dist/esm/helpers/index.js","typings":"../dist/esm/helpers/index.d.ts","version":"6.0.0-alpha.
|
|
1
|
+
{"name":"@patternfly/react-core-helpers","main":"../dist/js/helpers/index.js","module":"../dist/esm/helpers/index.js","typings":"../dist/esm/helpers/index.d.ts","version":"6.0.0-alpha.101","private":true}
|
package/layouts/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"name":"@patternfly/react-core-layouts","main":"../dist/js/layouts/index.js","module":"../dist/esm/layouts/index.js","typings":"../dist/esm/layouts/index.d.ts","version":"6.0.0-alpha.
|
|
1
|
+
{"name":"@patternfly/react-core-layouts","main":"../dist/js/layouts/index.js","module":"../dist/esm/layouts/index.js","typings":"../dist/esm/layouts/index.d.ts","version":"6.0.0-alpha.101","private":true}
|
package/next/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"name":"@patternfly/react-core-next","main":"../dist/js/next/index.js","module":"../dist/esm/next/index.js","typings":"../dist/esm/next/index.d.ts","version":"6.0.0-alpha.
|
|
1
|
+
{"name":"@patternfly/react-core-next","main":"../dist/js/next/index.js","module":"../dist/esm/next/index.js","typings":"../dist/esm/next/index.d.ts","version":"6.0.0-alpha.101","private":true}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@patternfly/react-core",
|
|
3
|
-
"version": "6.0.0-alpha.
|
|
3
|
+
"version": "6.0.0-alpha.102",
|
|
4
4
|
"description": "This library provides a set of common React components for use with the PatternFly reference implementation.",
|
|
5
5
|
"main": "dist/js/index.js",
|
|
6
6
|
"module": "dist/esm/index.js",
|
|
@@ -47,15 +47,15 @@
|
|
|
47
47
|
"clean:exports": "node scripts/cleanDistExports.js"
|
|
48
48
|
},
|
|
49
49
|
"dependencies": {
|
|
50
|
-
"@patternfly/react-icons": "^6.0.0-alpha.
|
|
51
|
-
"@patternfly/react-styles": "^6.0.0-alpha.
|
|
52
|
-
"@patternfly/react-tokens": "^6.0.0-alpha.
|
|
50
|
+
"@patternfly/react-icons": "^6.0.0-alpha.36",
|
|
51
|
+
"@patternfly/react-styles": "^6.0.0-alpha.35",
|
|
52
|
+
"@patternfly/react-tokens": "^6.0.0-alpha.35",
|
|
53
53
|
"focus-trap": "7.5.4",
|
|
54
54
|
"react-dropzone": "^14.2.3",
|
|
55
55
|
"tslib": "^2.6.2"
|
|
56
56
|
},
|
|
57
57
|
"devDependencies": {
|
|
58
|
-
"@patternfly/patternfly": "6.0.0-alpha.
|
|
58
|
+
"@patternfly/patternfly": "6.0.0-alpha.210",
|
|
59
59
|
"case-anything": "^2.1.13",
|
|
60
60
|
"css": "^3.0.0",
|
|
61
61
|
"fs-extra": "^11.2.0"
|
|
@@ -64,5 +64,5 @@
|
|
|
64
64
|
"react": "^17 || ^18",
|
|
65
65
|
"react-dom": "^17 || ^18"
|
|
66
66
|
},
|
|
67
|
-
"gitHead": "
|
|
67
|
+
"gitHead": "065953356048e1ee3036f266aaf16e479e94bc5e"
|
|
68
68
|
}
|
|
@@ -26,23 +26,29 @@ export interface CardHeaderSelectableActionsObject {
|
|
|
26
26
|
hasNoOffset?: boolean;
|
|
27
27
|
/** Additional classes added to the selectable actions wrapper */
|
|
28
28
|
className?: string;
|
|
29
|
-
/** ID passed to the selectable or clickable
|
|
30
|
-
|
|
31
|
-
|
|
29
|
+
/** Custom ID passed to the selectable card's input or a clickable-only card's button/anchor.
|
|
30
|
+
* If omitted, a random unique ID will be assigned to a selectable card's input. */
|
|
31
|
+
selectableActionId?: string;
|
|
32
|
+
/** Adds an accessible name to the input of a selectable card or clickable button/anchor of a clickable-only card.
|
|
33
|
+
* This or selectableActionAriaLabelledby is required for clickable-only cards.
|
|
34
|
+
*/
|
|
32
35
|
selectableActionAriaLabel?: string;
|
|
33
|
-
/**
|
|
34
|
-
*
|
|
36
|
+
/** A single or list of space-delimited ID's that provide an accessible name to the input of a selectable card
|
|
37
|
+
* or clickable button/anchor of a clickable-only card. This or selectableActionAriaLabelledby is required
|
|
38
|
+
* for clickable-only cards.
|
|
35
39
|
*/
|
|
36
40
|
selectableActionAriaLabelledby?: string;
|
|
37
41
|
/** Callback for when a selectable card input changes */
|
|
38
42
|
onChange?: (event: React.FormEvent<HTMLInputElement>, checked: boolean) => void;
|
|
39
|
-
/** Action to call when clickable card is clicked */
|
|
40
|
-
onClickAction?: (event: React.
|
|
41
|
-
/** Link to navigate to when clickable card is clicked */
|
|
43
|
+
/** Action to call when a clickable-only card is clicked. This cannot be combined with the to prop. */
|
|
44
|
+
onClickAction?: (event: React.MouseEvent) => void;
|
|
45
|
+
/** Link to navigate to when a clickable-only card is clicked. This cannot be combined with the onClickAction prop. */
|
|
42
46
|
to?: string;
|
|
43
|
-
/**
|
|
47
|
+
/** Additional props spread to a selectable card input or clickable-only card's button/anchor. */
|
|
48
|
+
selectableActionProps?: any;
|
|
49
|
+
/** Flag to indicate whether a clickable-only card's link should open in a new tab/window. */
|
|
44
50
|
isExternalLink?: boolean;
|
|
45
|
-
/** Name for the input element of a
|
|
51
|
+
/** Name for the input element of a selectable card. */
|
|
46
52
|
name?: string;
|
|
47
53
|
/** @deprecated Flag indicating whether the selectable card input is checked. We recommend using
|
|
48
54
|
* the isSelected prop on the card component instead.
|
|
@@ -79,101 +85,117 @@ export const CardHeader: React.FunctionComponent<CardHeaderProps> = ({
|
|
|
79
85
|
toggleButtonProps,
|
|
80
86
|
isToggleRightAligned,
|
|
81
87
|
...props
|
|
82
|
-
}: CardHeaderProps) =>
|
|
83
|
-
|
|
84
|
-
{({ cardId, isClickable, isSelectable, isSelected, isClicked, isDisabled: isCardDisabled }) => {
|
|
85
|
-
const cardHeaderToggle = (
|
|
86
|
-
<div className={css(styles.cardHeaderToggle)}>
|
|
87
|
-
<Button
|
|
88
|
-
variant="plain"
|
|
89
|
-
type="button"
|
|
90
|
-
onClick={(evt) => {
|
|
91
|
-
onExpand(evt, cardId);
|
|
92
|
-
}}
|
|
93
|
-
{...toggleButtonProps}
|
|
94
|
-
icon={
|
|
95
|
-
<span className={css(styles.cardHeaderToggleIcon)}>
|
|
96
|
-
<AngleRightIcon aria-hidden="true" />
|
|
97
|
-
</span>
|
|
98
|
-
}
|
|
99
|
-
/>
|
|
100
|
-
</div>
|
|
101
|
-
);
|
|
88
|
+
}: CardHeaderProps) => {
|
|
89
|
+
const uniqueId = React.useId();
|
|
102
90
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
91
|
+
return (
|
|
92
|
+
<CardContext.Consumer>
|
|
93
|
+
{({ cardId, isClickable, isSelectable, isSelected, isDisabled: isCardDisabled }) => {
|
|
94
|
+
const cardHeaderToggle = (
|
|
95
|
+
<div className={css(styles.cardHeaderToggle)}>
|
|
96
|
+
<Button
|
|
97
|
+
variant="plain"
|
|
98
|
+
type="button"
|
|
99
|
+
onClick={(evt) => {
|
|
100
|
+
onExpand(evt, cardId);
|
|
101
|
+
}}
|
|
102
|
+
{...toggleButtonProps}
|
|
103
|
+
icon={
|
|
104
|
+
<span className={css(styles.cardHeaderToggleIcon)}>
|
|
105
|
+
<AngleRightIcon aria-hidden="true" />
|
|
106
|
+
</span>
|
|
107
|
+
}
|
|
108
|
+
/>
|
|
109
|
+
</div>
|
|
110
110
|
);
|
|
111
|
-
}
|
|
112
111
|
|
|
113
|
-
|
|
114
|
-
if (
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
112
|
+
const isClickableOrSelectableOnly = (isClickable && !isSelectable) || (isSelectable && !isClickable);
|
|
113
|
+
if (actions?.actions && isClickableOrSelectableOnly) {
|
|
114
|
+
// eslint-disable-next-line no-console
|
|
115
|
+
console.error(
|
|
116
|
+
`Card: ${
|
|
117
|
+
isClickable ? 'Clickable' : 'Selectable'
|
|
118
|
+
} only cards should not contain any other actions. If you wish to include additional actions, use a clickable and selectable card.`
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const isClickableOnlyCard = isClickable && !isSelectable;
|
|
123
|
+
if (
|
|
124
|
+
(isClickableOnlyCard || isSelectable) &&
|
|
125
|
+
!selectableActions?.selectableActionAriaLabel &&
|
|
126
|
+
!selectableActions?.selectableActionAriaLabelledby
|
|
127
|
+
) {
|
|
128
|
+
// eslint-disable-next-line no-console
|
|
129
|
+
console.error(
|
|
130
|
+
`Card: ${isClickableOnlyCard ? 'Clickable-only cards' : 'Cards with a selectable input'} must have either the selectableActions.selectableActionAriaLabel or selectableActions.selectableActionAriaLabelledby prop passed in order to provide an accessible name to the clickable element.`
|
|
131
|
+
);
|
|
118
132
|
}
|
|
119
|
-
};
|
|
120
133
|
|
|
121
|
-
|
|
122
|
-
const
|
|
134
|
+
const SelectableCardInput = selectableActions?.variant === 'single' ? Radio : Checkbox;
|
|
135
|
+
const getSelectableProps = () => ({
|
|
123
136
|
className: 'pf-m-standalone',
|
|
124
|
-
inputClassName: isClickable && !isSelectable && 'pf-v6-screen-reader',
|
|
125
137
|
label: <></>,
|
|
126
138
|
'aria-label': selectableActions.selectableActionAriaLabel,
|
|
127
139
|
'aria-labelledby': selectableActions.selectableActionAriaLabelledby,
|
|
128
|
-
id: selectableActions.selectableActionId
|
|
140
|
+
id: selectableActions.selectableActionId ?? `card-selectable-${uniqueId}`,
|
|
129
141
|
name: selectableActions.name,
|
|
130
|
-
isDisabled: isCardDisabled
|
|
131
|
-
|
|
132
|
-
|
|
142
|
+
isDisabled: isCardDisabled,
|
|
143
|
+
onChange: selectableActions.onChange,
|
|
144
|
+
isChecked: selectableActions.isChecked ?? isSelected,
|
|
145
|
+
...selectableActions.selectableActionProps
|
|
146
|
+
});
|
|
133
147
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
148
|
+
const isClickableLinkCard = selectableActions?.to !== undefined;
|
|
149
|
+
const ClickableCardComponent = isClickableLinkCard ? 'a' : 'button';
|
|
150
|
+
const getClickableProps = () => {
|
|
151
|
+
const isDisabledLinkCard = isCardDisabled && isClickableLinkCard;
|
|
152
|
+
const baseProps = {
|
|
153
|
+
className: css('pf-v6-c-card__clickable-action', isDisabledLinkCard && styles.modifiers.disabled),
|
|
154
|
+
id: selectableActions.selectableActionId,
|
|
155
|
+
'aria-label': selectableActions.selectableActionAriaLabel,
|
|
156
|
+
'aria-labelledby': selectableActions.selectableActionAriaLabelledby,
|
|
157
|
+
...selectableActions.selectableActionProps
|
|
139
158
|
};
|
|
140
|
-
}
|
|
141
|
-
if (isSelectable) {
|
|
142
|
-
return { ...baseProps, onChange: selectableActions.onChange, isChecked: isSelectableInputChecked };
|
|
143
|
-
}
|
|
144
159
|
|
|
145
|
-
|
|
146
|
-
|
|
160
|
+
if (isClickableLinkCard) {
|
|
161
|
+
return {
|
|
162
|
+
...baseProps,
|
|
163
|
+
href: selectableActions.to,
|
|
164
|
+
...(isCardDisabled && { tabIndex: -1, 'aria-disabled': true }),
|
|
165
|
+
...(selectableActions.isExternalLink && { target: '_blank' })
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
return { ...baseProps, type: 'button', disabled: isCardDisabled, onClick: selectableActions.onClickAction };
|
|
170
|
+
};
|
|
147
171
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
<
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
</CardContext.Consumer>
|
|
178
|
-
);
|
|
172
|
+
return (
|
|
173
|
+
<div
|
|
174
|
+
className={css(styles.cardHeader, isToggleRightAligned && styles.modifiers.toggleRight, className)}
|
|
175
|
+
id={id}
|
|
176
|
+
{...props}
|
|
177
|
+
>
|
|
178
|
+
{onExpand && !isToggleRightAligned && cardHeaderToggle}
|
|
179
|
+
{(actions || (selectableActions && (isClickable || isSelectable))) && (
|
|
180
|
+
<CardActions
|
|
181
|
+
className={actions?.className}
|
|
182
|
+
hasNoOffset={actions?.hasNoOffset || selectableActions?.hasNoOffset}
|
|
183
|
+
>
|
|
184
|
+
{actions?.actions}
|
|
185
|
+
{selectableActions && (isClickable || isSelectable) && (
|
|
186
|
+
<CardSelectableActions className={selectableActions?.className}>
|
|
187
|
+
{isSelectable && <SelectableCardInput {...getSelectableProps()} />}
|
|
188
|
+
{isClickableOnlyCard && <ClickableCardComponent {...getClickableProps()} />}
|
|
189
|
+
</CardSelectableActions>
|
|
190
|
+
)}
|
|
191
|
+
</CardActions>
|
|
192
|
+
)}
|
|
193
|
+
{children && <CardHeaderMain>{children}</CardHeaderMain>}
|
|
194
|
+
{onExpand && isToggleRightAligned && cardHeaderToggle}
|
|
195
|
+
</div>
|
|
196
|
+
);
|
|
197
|
+
}}
|
|
198
|
+
</CardContext.Consumer>
|
|
199
|
+
);
|
|
200
|
+
};
|
|
179
201
|
CardHeader.displayName = 'CardHeader';
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { render } from '@testing-library/react';
|
|
2
|
+
import { render, screen } from '@testing-library/react';
|
|
3
|
+
import userEvent from '@testing-library/user-event';
|
|
3
4
|
import { CardHeader } from '../CardHeader';
|
|
5
|
+
import { CardContext } from '../Card';
|
|
4
6
|
|
|
5
7
|
describe('CardHeader', () => {
|
|
6
8
|
test('onExpand adds the toggle button', () => {
|
|
@@ -13,3 +15,330 @@ describe('CardHeader', () => {
|
|
|
13
15
|
expect(asFragment()).toMatchSnapshot();
|
|
14
16
|
});
|
|
15
17
|
});
|
|
18
|
+
|
|
19
|
+
// TODO: check if hasNoOffset for actions/selectableActions and className for selectableActions render
|
|
20
|
+
describe('Card with actions and selectableActions', () => {
|
|
21
|
+
test('Does not render selectable or clickable actions by default', () => {
|
|
22
|
+
render(<CardHeader>Test</CardHeader>);
|
|
23
|
+
|
|
24
|
+
expect(screen.queryByRole('checkbox')).not.toBeInTheDocument();
|
|
25
|
+
expect(screen.queryByRole('button')).not.toBeInTheDocument();
|
|
26
|
+
expect(screen.queryByRole('link')).not.toBeInTheDocument();
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
test('Renders checkbox input when Card has isSelectable and selectableActions.variant = "multiple"', () => {
|
|
30
|
+
render(
|
|
31
|
+
<CardContext.Provider value={{ isSelectable: true }}>
|
|
32
|
+
<CardHeader selectableActions={{ variant: 'multiple' }}>Test</CardHeader>
|
|
33
|
+
</CardContext.Provider>
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
expect(screen.getByRole('checkbox')).toBeInTheDocument();
|
|
37
|
+
});
|
|
38
|
+
test('Renders checkbox input by default when Card has isSelectable and selectableActions is passed with any props', () => {
|
|
39
|
+
render(
|
|
40
|
+
<CardContext.Provider value={{ isSelectable: true }}>
|
|
41
|
+
<CardHeader selectableActions={{ className: 'test' }}>Test</CardHeader>
|
|
42
|
+
</CardContext.Provider>
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
expect(screen.getByRole('checkbox')).toBeInTheDocument();
|
|
46
|
+
});
|
|
47
|
+
test('Renders radio input when Card has isSelectable and selectableActions.variant = "single"', () => {
|
|
48
|
+
render(
|
|
49
|
+
<CardContext.Provider value={{ isSelectable: true }}>
|
|
50
|
+
<CardHeader selectableActions={{ variant: 'single' }}>Test</CardHeader>
|
|
51
|
+
</CardContext.Provider>
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
expect(screen.getByRole('radio')).toBeInTheDocument();
|
|
55
|
+
});
|
|
56
|
+
test('Renders default ID for selectable card input when selectableActions.selectableActionId is not passed', () => {
|
|
57
|
+
render(
|
|
58
|
+
<CardContext.Provider value={{ isSelectable: true }}>
|
|
59
|
+
<CardHeader selectableActions={{ variant: 'multiple' }}>Test</CardHeader>
|
|
60
|
+
</CardContext.Provider>
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
expect(screen.getByRole('checkbox').getAttribute('id')).toMatch(/^card-selectable/);
|
|
64
|
+
});
|
|
65
|
+
test('Renders custom ID for selectable card input when selectableActions.selectableActionId is passed', () => {
|
|
66
|
+
render(
|
|
67
|
+
<CardContext.Provider value={{ isSelectable: true }}>
|
|
68
|
+
<CardHeader selectableActions={{ variant: 'multiple', selectableActionId: 'custom-id' }}>Test</CardHeader>
|
|
69
|
+
</CardContext.Provider>
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
expect(screen.getByRole('checkbox')).toHaveAttribute('id', 'custom-id');
|
|
73
|
+
});
|
|
74
|
+
test('Renders name on a selectable card input', () => {
|
|
75
|
+
render(
|
|
76
|
+
<CardContext.Provider value={{ isSelectable: true }}>
|
|
77
|
+
<CardHeader selectableActions={{ variant: 'single', name: 'test' }}>Test</CardHeader>
|
|
78
|
+
</CardContext.Provider>
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
expect(screen.getByRole('radio')).toHaveAttribute('name', 'test');
|
|
82
|
+
});
|
|
83
|
+
test('Renders a selectable card input as not checked by default', () => {
|
|
84
|
+
render(
|
|
85
|
+
<CardContext.Provider value={{ isSelectable: true }}>
|
|
86
|
+
<CardHeader selectableActions={{ variant: 'multiple' }}>Test</CardHeader>
|
|
87
|
+
</CardContext.Provider>
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
expect(screen.getByRole('checkbox')).not.toBeChecked();
|
|
91
|
+
});
|
|
92
|
+
test('Renders a selectable card input as checked when Card has isSelected = true', () => {
|
|
93
|
+
render(
|
|
94
|
+
<CardContext.Provider value={{ isSelectable: true, isSelected: true }}>
|
|
95
|
+
<CardHeader selectableActions={{ variant: 'multiple' }}>Test</CardHeader>
|
|
96
|
+
</CardContext.Provider>
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
expect(screen.getByRole('checkbox')).toBeChecked();
|
|
100
|
+
});
|
|
101
|
+
test('Renders a selectable card input as checked when deprecated selectableActions.isChecked is true', () => {
|
|
102
|
+
render(
|
|
103
|
+
<CardContext.Provider value={{ isSelectable: true }}>
|
|
104
|
+
<CardHeader selectableActions={{ variant: 'multiple', isChecked: true }}>Test</CardHeader>
|
|
105
|
+
</CardContext.Provider>
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
expect(screen.getByRole('checkbox')).toBeChecked();
|
|
109
|
+
});
|
|
110
|
+
test('Renders additional props on selectable card input when selectableActions.selectableActionProps is passed', () => {
|
|
111
|
+
render(
|
|
112
|
+
<CardContext.Provider value={{ isSelectable: true }}>
|
|
113
|
+
<CardHeader selectableActions={{ variant: 'multiple', selectableActionProps: { style: { color: 'red' } } }}>
|
|
114
|
+
Test
|
|
115
|
+
</CardHeader>
|
|
116
|
+
</CardContext.Provider>
|
|
117
|
+
);
|
|
118
|
+
|
|
119
|
+
expect(screen.getByRole('checkbox')).toHaveAttribute('style');
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
test('Does not call onChange for selectable card when card is not clicked', async () => {
|
|
123
|
+
const user = userEvent.setup();
|
|
124
|
+
const onChangeMock = jest.fn();
|
|
125
|
+
|
|
126
|
+
render(
|
|
127
|
+
<>
|
|
128
|
+
<button>Test click</button>
|
|
129
|
+
<CardContext.Provider value={{ isSelectable: true }}>
|
|
130
|
+
<CardHeader selectableActions={{ variant: 'multiple', onChange: onChangeMock }}>Test</CardHeader>
|
|
131
|
+
</CardContext.Provider>
|
|
132
|
+
</>
|
|
133
|
+
);
|
|
134
|
+
|
|
135
|
+
await user.click(screen.getByRole('button', { name: 'Test click' }));
|
|
136
|
+
expect(onChangeMock).not.toHaveBeenCalled();
|
|
137
|
+
});
|
|
138
|
+
test('Calls onChange for selectable card when card is clicked', async () => {
|
|
139
|
+
const user = userEvent.setup();
|
|
140
|
+
const onChangeMock = jest.fn();
|
|
141
|
+
|
|
142
|
+
render(
|
|
143
|
+
<CardContext.Provider value={{ isSelectable: true }}>
|
|
144
|
+
<CardHeader selectableActions={{ variant: 'multiple', onChange: onChangeMock }}>Test</CardHeader>
|
|
145
|
+
</CardContext.Provider>
|
|
146
|
+
);
|
|
147
|
+
|
|
148
|
+
const labelElement = document.querySelector('label');
|
|
149
|
+
await user.click(labelElement as HTMLElement);
|
|
150
|
+
expect(onChangeMock).toHaveBeenCalled();
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
test('Renders button element when Card has isClickable and selectableActions.onClickAction is passed"', () => {
|
|
154
|
+
render(
|
|
155
|
+
<CardContext.Provider value={{ isClickable: true }}>
|
|
156
|
+
<CardHeader selectableActions={{ onClickAction: () => {} }}>Test</CardHeader>
|
|
157
|
+
</CardContext.Provider>
|
|
158
|
+
);
|
|
159
|
+
|
|
160
|
+
expect(screen.getByRole('button')).toBeInTheDocument();
|
|
161
|
+
});
|
|
162
|
+
test('Renders anchor element when Card has isClickable and selectableActions.to is passed"', () => {
|
|
163
|
+
render(
|
|
164
|
+
<CardContext.Provider value={{ isClickable: true }}>
|
|
165
|
+
<CardHeader selectableActions={{ to: '#' }}>Test</CardHeader>
|
|
166
|
+
</CardContext.Provider>
|
|
167
|
+
);
|
|
168
|
+
|
|
169
|
+
expect(screen.getByRole('link')).toBeInTheDocument();
|
|
170
|
+
});
|
|
171
|
+
test('Renders href when Card has isClickable and selectableActions.to is passed"', () => {
|
|
172
|
+
render(
|
|
173
|
+
<CardContext.Provider value={{ isClickable: true }}>
|
|
174
|
+
<CardHeader selectableActions={{ to: '#some-id' }}>Test</CardHeader>
|
|
175
|
+
</CardContext.Provider>
|
|
176
|
+
);
|
|
177
|
+
|
|
178
|
+
expect(screen.getByRole('link')).toHaveAttribute('href', '#some-id');
|
|
179
|
+
});
|
|
180
|
+
test('Does not render ID on clickable element when selectableActions.selectableActionId is not passed"', () => {
|
|
181
|
+
render(
|
|
182
|
+
<CardContext.Provider value={{ isClickable: true }}>
|
|
183
|
+
<CardHeader selectableActions={{ to: '#' }}>Test</CardHeader>
|
|
184
|
+
</CardContext.Provider>
|
|
185
|
+
);
|
|
186
|
+
|
|
187
|
+
expect(screen.getByRole('link')).not.toHaveAttribute('id');
|
|
188
|
+
});
|
|
189
|
+
test('Renders ID on clickable element when selectableActions.selectableActionId is passed"', () => {
|
|
190
|
+
render(
|
|
191
|
+
<CardContext.Provider value={{ isClickable: true }}>
|
|
192
|
+
<CardHeader selectableActions={{ to: '#', selectableActionId: 'custom-id' }}>Test</CardHeader>
|
|
193
|
+
</CardContext.Provider>
|
|
194
|
+
);
|
|
195
|
+
|
|
196
|
+
expect(screen.getByRole('link')).toHaveAttribute('id', 'custom-id');
|
|
197
|
+
});
|
|
198
|
+
test('Renders additional props on clickable element when selectableActions.selectableActionProps is passed', () => {
|
|
199
|
+
render(
|
|
200
|
+
<CardContext.Provider value={{ isClickable: true }}>
|
|
201
|
+
<CardHeader selectableActions={{ to: '#', selectableActionProps: { style: { color: 'red' } } }}>
|
|
202
|
+
Test
|
|
203
|
+
</CardHeader>
|
|
204
|
+
</CardContext.Provider>
|
|
205
|
+
);
|
|
206
|
+
|
|
207
|
+
expect(screen.getByRole('link')).toHaveAttribute('style');
|
|
208
|
+
});
|
|
209
|
+
test('Does not render target="_blank" on clickable card anchor element by default"', () => {
|
|
210
|
+
render(
|
|
211
|
+
<CardContext.Provider value={{ isClickable: true }}>
|
|
212
|
+
<CardHeader selectableActions={{ to: '#' }}>Test</CardHeader>
|
|
213
|
+
</CardContext.Provider>
|
|
214
|
+
);
|
|
215
|
+
|
|
216
|
+
expect(screen.getByRole('link')).not.toHaveAttribute('target');
|
|
217
|
+
});
|
|
218
|
+
test('Renders target="_blank" on clickable card anchor element when selectableActions.isExternalLink is true"', () => {
|
|
219
|
+
render(
|
|
220
|
+
<CardContext.Provider value={{ isClickable: true }}>
|
|
221
|
+
<CardHeader selectableActions={{ to: '#', isExternalLink: true }}>Test</CardHeader>
|
|
222
|
+
</CardContext.Provider>
|
|
223
|
+
);
|
|
224
|
+
|
|
225
|
+
expect(screen.getByRole('link')).toHaveAttribute('target', '_blank');
|
|
226
|
+
});
|
|
227
|
+
test('Calls onClickAction for clickable card when card is clicked', async () => {
|
|
228
|
+
const user = userEvent.setup();
|
|
229
|
+
const onClickMock = jest.fn();
|
|
230
|
+
|
|
231
|
+
render(
|
|
232
|
+
<CardContext.Provider value={{ isClickable: true }}>
|
|
233
|
+
<CardHeader selectableActions={{ onClickAction: onClickMock }}>Test</CardHeader>
|
|
234
|
+
</CardContext.Provider>
|
|
235
|
+
);
|
|
236
|
+
|
|
237
|
+
await user.click(screen.getByRole('button'));
|
|
238
|
+
expect(onClickMock).toHaveBeenCalled();
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
test('Throws error when Card is either clickable or selectable only and has actions prop passed"', () => {
|
|
242
|
+
const errorMock = jest.fn() as any;
|
|
243
|
+
global.console = { error: errorMock } as any;
|
|
244
|
+
render(
|
|
245
|
+
<CardContext.Provider value={{ isClickable: true }}>
|
|
246
|
+
<CardHeader
|
|
247
|
+
actions={{ actions: <button>Toggle</button> }}
|
|
248
|
+
selectableActions={{ to: '#', selectableActionAriaLabel: 'Link' }}
|
|
249
|
+
>
|
|
250
|
+
Test
|
|
251
|
+
</CardHeader>
|
|
252
|
+
</CardContext.Provider>
|
|
253
|
+
);
|
|
254
|
+
|
|
255
|
+
expect(errorMock).toHaveBeenCalled();
|
|
256
|
+
});
|
|
257
|
+
test('Does not throw error when Card is both clickable and selectable and has actions prop passed"', () => {
|
|
258
|
+
const errorMock = jest.fn() as any;
|
|
259
|
+
global.console = { error: errorMock } as any;
|
|
260
|
+
render(
|
|
261
|
+
<CardContext.Provider value={{ isClickable: true, isSelectable: true }}>
|
|
262
|
+
<CardHeader
|
|
263
|
+
actions={{ actions: <button>Toggle</button> }}
|
|
264
|
+
selectableActions={{ to: '#', selectableActionAriaLabel: 'Link' }}
|
|
265
|
+
>
|
|
266
|
+
Test
|
|
267
|
+
</CardHeader>
|
|
268
|
+
</CardContext.Provider>
|
|
269
|
+
);
|
|
270
|
+
|
|
271
|
+
expect(errorMock).not.toHaveBeenCalled();
|
|
272
|
+
});
|
|
273
|
+
test('Throws error when Card has isClickable and selectableActions.selectableActionAriaLabel or selectableActions.selectableActionAriaLabelledby is not passed"', () => {
|
|
274
|
+
const errorMock = jest.fn() as any;
|
|
275
|
+
global.console = { error: errorMock } as any;
|
|
276
|
+
render(
|
|
277
|
+
<CardContext.Provider value={{ isClickable: true }}>
|
|
278
|
+
<CardHeader selectableActions={{ to: '#' }}>Test</CardHeader>
|
|
279
|
+
</CardContext.Provider>
|
|
280
|
+
);
|
|
281
|
+
|
|
282
|
+
expect(errorMock).toHaveBeenCalled();
|
|
283
|
+
});
|
|
284
|
+
test('Throws error when Card has isSelectable and selectableActions.selectableActionAriaLabel or selectableActions.selectableActionAriaLabelledby is not passed"', () => {
|
|
285
|
+
const errorMock = jest.fn() as any;
|
|
286
|
+
global.console = { error: errorMock } as any;
|
|
287
|
+
render(
|
|
288
|
+
<CardContext.Provider value={{ isSelectable: true }}>
|
|
289
|
+
<CardHeader selectableActions={{ variant: 'multiple' }}>Test</CardHeader>
|
|
290
|
+
</CardContext.Provider>
|
|
291
|
+
);
|
|
292
|
+
|
|
293
|
+
expect(errorMock).toHaveBeenCalled();
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
test('Renders accessible name on selectable card input when selectableActions.selectableActionAriaLabel is passed', () => {
|
|
297
|
+
const accessibleName = 'Accessible name';
|
|
298
|
+
render(
|
|
299
|
+
<CardContext.Provider value={{ isSelectable: true }}>
|
|
300
|
+
<CardHeader selectableActions={{ variant: 'multiple', selectableActionAriaLabel: accessibleName }}>
|
|
301
|
+
Test
|
|
302
|
+
</CardHeader>
|
|
303
|
+
</CardContext.Provider>
|
|
304
|
+
);
|
|
305
|
+
|
|
306
|
+
expect(screen.getByRole('checkbox')).toHaveAccessibleName(accessibleName);
|
|
307
|
+
});
|
|
308
|
+
test('Renders accessible name on selectable card input when selectableActions.selectableActionAriaLabelledby is passed', () => {
|
|
309
|
+
const labelingId = 'labelling-id';
|
|
310
|
+
const accessibleName = 'Accessible name';
|
|
311
|
+
render(
|
|
312
|
+
<CardContext.Provider value={{ isSelectable: true }}>
|
|
313
|
+
<CardHeader selectableActions={{ variant: 'multiple', selectableActionAriaLabelledby: labelingId }}>
|
|
314
|
+
<div id={labelingId}>{accessibleName}</div>
|
|
315
|
+
</CardHeader>
|
|
316
|
+
</CardContext.Provider>
|
|
317
|
+
);
|
|
318
|
+
|
|
319
|
+
expect(screen.getByRole('checkbox')).toHaveAccessibleName(accessibleName);
|
|
320
|
+
});
|
|
321
|
+
test('Renders accessible name on clickable card clickable element when selectableActions.selectableActionAriaLabel is passed', () => {
|
|
322
|
+
const accessibleName = 'Accessible name';
|
|
323
|
+
render(
|
|
324
|
+
<CardContext.Provider value={{ isClickable: true }}>
|
|
325
|
+
<CardHeader selectableActions={{ to: '#', selectableActionAriaLabel: accessibleName }}>Test</CardHeader>
|
|
326
|
+
</CardContext.Provider>
|
|
327
|
+
);
|
|
328
|
+
|
|
329
|
+
expect(screen.getByRole('link')).toHaveAccessibleName(accessibleName);
|
|
330
|
+
});
|
|
331
|
+
test('Renders accessible name on clickable card clickable element when selectableActions.selectableActionAriaLabelledby is passed', () => {
|
|
332
|
+
const labelingId = 'labelling-id';
|
|
333
|
+
const accessibleName = 'Accessible name';
|
|
334
|
+
render(
|
|
335
|
+
<CardContext.Provider value={{ isClickable: true }}>
|
|
336
|
+
<CardHeader selectableActions={{ to: '#', selectableActionAriaLabelledby: labelingId }}>
|
|
337
|
+
<div id={labelingId}>{accessibleName}</div>
|
|
338
|
+
</CardHeader>
|
|
339
|
+
</CardContext.Provider>
|
|
340
|
+
);
|
|
341
|
+
|
|
342
|
+
expect(screen.getByRole('link')).toHaveAccessibleName(accessibleName);
|
|
343
|
+
});
|
|
344
|
+
});
|