@kaizen/components 1.38.4 → 1.38.6
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/dist/cjs/Menu/subcomponents/MenuItem/MenuItem.cjs +5 -1
- package/dist/cjs/Menu/subcomponents/MenuItem/MenuItem.cjs.map +1 -1
- package/dist/cjs/TimeField/TimeField.cjs +7 -7
- package/dist/cjs/TimeField/TimeField.cjs.map +1 -1
- package/dist/cjs/TimeField/TimeField.module.scss.cjs +1 -1
- package/dist/cjs/TitleBlockZen/TitleBlockZen.cjs +10 -5
- package/dist/cjs/TitleBlockZen/TitleBlockZen.cjs.map +1 -1
- package/dist/cjs/TitleBlockZen/constants.cjs +7 -0
- package/dist/cjs/TitleBlockZen/constants.cjs.map +1 -0
- package/dist/cjs/TitleBlockZen/subcomponents/MainActions.cjs +2 -0
- package/dist/cjs/TitleBlockZen/subcomponents/MainActions.cjs.map +1 -1
- package/dist/cjs/TitleBlockZen/subcomponents/MobileActions.cjs +31 -6
- package/dist/cjs/TitleBlockZen/subcomponents/MobileActions.cjs.map +1 -1
- package/dist/cjs/TitleBlockZen/subcomponents/SecondaryActions.cjs +3 -1
- package/dist/cjs/TitleBlockZen/subcomponents/SecondaryActions.cjs.map +1 -1
- package/dist/cjs/dts/Menu/subcomponents/MenuItem/MenuItem.d.ts +2 -1
- package/dist/cjs/dts/TitleBlockZen/TitleBlockZen.d.ts +1 -1
- package/dist/cjs/dts/TitleBlockZen/constants.d.ts +2 -0
- package/dist/cjs/dts/TitleBlockZen/index.d.ts +1 -0
- package/dist/cjs/dts/TitleBlockZen/subcomponents/MobileActions.d.ts +2 -1
- package/dist/cjs/dts/TitleBlockZen/types.d.ts +2 -0
- package/dist/cjs/index.cjs +3 -0
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/index.css +5 -5
- package/dist/esm/Menu/subcomponents/MenuItem/MenuItem.mjs +5 -1
- package/dist/esm/Menu/subcomponents/MenuItem/MenuItem.mjs.map +1 -1
- package/dist/esm/TimeField/TimeField.mjs +7 -7
- package/dist/esm/TimeField/TimeField.mjs.map +1 -1
- package/dist/esm/TimeField/TimeField.module.scss.mjs +1 -1
- package/dist/esm/TitleBlockZen/TitleBlockZen.mjs +10 -5
- package/dist/esm/TitleBlockZen/TitleBlockZen.mjs.map +1 -1
- package/dist/esm/TitleBlockZen/constants.mjs +4 -0
- package/dist/esm/TitleBlockZen/constants.mjs.map +1 -0
- package/dist/esm/TitleBlockZen/subcomponents/MainActions.mjs +2 -0
- package/dist/esm/TitleBlockZen/subcomponents/MainActions.mjs.map +1 -1
- package/dist/esm/TitleBlockZen/subcomponents/MobileActions.mjs +32 -7
- package/dist/esm/TitleBlockZen/subcomponents/MobileActions.mjs.map +1 -1
- package/dist/esm/TitleBlockZen/subcomponents/SecondaryActions.mjs +3 -1
- package/dist/esm/TitleBlockZen/subcomponents/SecondaryActions.mjs.map +1 -1
- package/dist/esm/dts/Menu/subcomponents/MenuItem/MenuItem.d.ts +2 -1
- package/dist/esm/dts/TitleBlockZen/TitleBlockZen.d.ts +1 -1
- package/dist/esm/dts/TitleBlockZen/constants.d.ts +2 -0
- package/dist/esm/dts/TitleBlockZen/index.d.ts +1 -0
- package/dist/esm/dts/TitleBlockZen/subcomponents/MobileActions.d.ts +2 -1
- package/dist/esm/dts/TitleBlockZen/types.d.ts +2 -0
- package/dist/esm/index.css +4 -4
- package/dist/esm/index.mjs +1 -0
- package/dist/esm/index.mjs.map +1 -1
- package/dist/index.d.ts +9 -3
- package/dist/styles.css +1 -1
- package/package.json +24 -24
- package/src/Menu/subcomponents/MenuItem/MenuItem.tsx +5 -0
- package/src/TimeField/TimeField.module.scss +2 -1
- package/src/TimeField/TimeField.tsx +9 -11
- package/src/TitleBlockZen/TitleBlockZen.spec.tsx +41 -0
- package/src/TitleBlockZen/TitleBlockZen.tsx +4 -0
- package/src/TitleBlockZen/constants.ts +3 -0
- package/src/TitleBlockZen/index.ts +1 -0
- package/src/TitleBlockZen/subcomponents/MainActions.tsx +2 -0
- package/src/TitleBlockZen/subcomponents/MobileActions.spec.tsx +87 -0
- package/src/TitleBlockZen/subcomponents/MobileActions.tsx +39 -3
- package/src/TitleBlockZen/subcomponents/SecondaryActions.tsx +2 -0
- package/src/TitleBlockZen/types.ts +2 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kaizen/components",
|
|
3
|
-
"version": "1.38.
|
|
3
|
+
"version": "1.38.6",
|
|
4
4
|
"description": "Kaizen component library",
|
|
5
5
|
"author": "Geoffrey Chong <geoff.chong@cultureamp.com>",
|
|
6
6
|
"homepage": "https://cultureamp.design",
|
|
@@ -44,26 +44,26 @@
|
|
|
44
44
|
"dependencies": {
|
|
45
45
|
"@floating-ui/react-dom": "^2.0.4",
|
|
46
46
|
"@headlessui/react": "<=1.5.0",
|
|
47
|
-
"@internationalized/date": "^3.5.
|
|
47
|
+
"@internationalized/date": "^3.5.1",
|
|
48
48
|
"@kaizen/hosted-assets": "^2.0.3",
|
|
49
49
|
"@popperjs/core": "^2.11.8",
|
|
50
50
|
"@reach/tabs": "^0.18.0",
|
|
51
|
-
"@react-aria/button": "^3.9.
|
|
52
|
-
"@react-aria/datepicker": "^3.9.
|
|
53
|
-
"@react-aria/focus": "^3.
|
|
54
|
-
"@react-aria/i18n": "^3.
|
|
55
|
-
"@react-aria/listbox": "^3.11.
|
|
56
|
-
"@react-aria/menu": "^3.
|
|
57
|
-
"@react-aria/overlays": "^3.
|
|
58
|
-
"@react-aria/select": "^3.14.
|
|
59
|
-
"@react-aria/utils": "^3.
|
|
60
|
-
"@react-stately/collections": "^3.10.
|
|
61
|
-
"@react-stately/datepicker": "^3.9.
|
|
62
|
-
"@react-stately/list": "^3.10.
|
|
63
|
-
"@react-stately/menu": "^3.
|
|
64
|
-
"@react-stately/select": "^3.6.
|
|
51
|
+
"@react-aria/button": "^3.9.1",
|
|
52
|
+
"@react-aria/datepicker": "^3.9.1",
|
|
53
|
+
"@react-aria/focus": "^3.16.0",
|
|
54
|
+
"@react-aria/i18n": "^3.10.0",
|
|
55
|
+
"@react-aria/listbox": "^3.11.3",
|
|
56
|
+
"@react-aria/menu": "^3.12.0",
|
|
57
|
+
"@react-aria/overlays": "^3.20.0",
|
|
58
|
+
"@react-aria/select": "^3.14.1",
|
|
59
|
+
"@react-aria/utils": "^3.23.0",
|
|
60
|
+
"@react-stately/collections": "^3.10.4",
|
|
61
|
+
"@react-stately/datepicker": "^3.9.1",
|
|
62
|
+
"@react-stately/list": "^3.10.2",
|
|
63
|
+
"@react-stately/menu": "^3.6.0",
|
|
64
|
+
"@react-stately/select": "^3.6.1",
|
|
65
65
|
"@react-types/shared": "^3.22.0",
|
|
66
|
-
"classnames": "^2.
|
|
66
|
+
"classnames": "^2.5.1",
|
|
67
67
|
"date-fns": "^2.30.0",
|
|
68
68
|
"lodash.debounce": "^4.0.8",
|
|
69
69
|
"nanobus": "^4.5.0",
|
|
@@ -96,10 +96,10 @@
|
|
|
96
96
|
},
|
|
97
97
|
"devDependencies": {
|
|
98
98
|
"@babel/plugin-transform-react-pure-annotations": "^7.23.3",
|
|
99
|
-
"@cultureamp/frontend-apis": "^9.
|
|
100
|
-
"@cultureamp/i18n-react-intl": "^2.1.
|
|
99
|
+
"@cultureamp/frontend-apis": "^9.1.3",
|
|
100
|
+
"@cultureamp/i18n-react-intl": "^2.1.8",
|
|
101
101
|
"@kaizen/design-tokens": "^10.3.17",
|
|
102
|
-
"@kaizen/tailwind": "^1.2.
|
|
102
|
+
"@kaizen/tailwind": "^1.2.2",
|
|
103
103
|
"@rollup/plugin-alias": "^5.1.0",
|
|
104
104
|
"@rollup/plugin-babel": "^6.0.4",
|
|
105
105
|
"@rollup/plugin-commonjs": "^25.0.7",
|
|
@@ -108,7 +108,7 @@
|
|
|
108
108
|
"@rollup/plugin-node-resolve": "^15.2.3",
|
|
109
109
|
"@rollup/plugin-typescript": "^11.1.5",
|
|
110
110
|
"@types/lodash.debounce": "^4.0.9",
|
|
111
|
-
"@types/react-dom": "^18.2.
|
|
111
|
+
"@types/react-dom": "^18.2.18",
|
|
112
112
|
"@types/react-textfit": "^1.1.4",
|
|
113
113
|
"@types/uuid": "^9.0.7",
|
|
114
114
|
"agadoo": "^3.0.0",
|
|
@@ -117,12 +117,12 @@
|
|
|
117
117
|
"concat-cli": "^4.0.0",
|
|
118
118
|
"query-string": "^8.1.0",
|
|
119
119
|
"react-intl": "^6.5.5",
|
|
120
|
-
"rollup": "^4.
|
|
120
|
+
"rollup": "^4.9.2",
|
|
121
121
|
"rollup-plugin-dts": "^6.1.0",
|
|
122
122
|
"rollup-plugin-ignore": "^1.0.10",
|
|
123
123
|
"rollup-plugin-node-externals": "^6.1.2",
|
|
124
124
|
"rollup-plugin-postcss": "^4.0.2",
|
|
125
|
-
"sass": "^1.69.
|
|
125
|
+
"sass": "^1.69.6",
|
|
126
126
|
"serialize-query-params": "^2.0.2",
|
|
127
127
|
"svgo": "^3.1.0",
|
|
128
128
|
"ts-jest": "^29.1.1",
|
|
@@ -130,7 +130,7 @@
|
|
|
130
130
|
"typescript-transform-paths": "^3.4.6"
|
|
131
131
|
},
|
|
132
132
|
"peerDependencies": {
|
|
133
|
-
"@cultureamp/i18n-react-intl": "^2.1.
|
|
133
|
+
"@cultureamp/i18n-react-intl": "^2.1.8",
|
|
134
134
|
"react": "^18.2.0",
|
|
135
135
|
"react-intl": "^6.5.5"
|
|
136
136
|
}
|
|
@@ -22,6 +22,7 @@ export type MenuItemProps = {
|
|
|
22
22
|
*/
|
|
23
23
|
isActive?: boolean
|
|
24
24
|
"data-testid"?: string
|
|
25
|
+
id?: string
|
|
25
26
|
}
|
|
26
27
|
|
|
27
28
|
export const MenuItem = ({
|
|
@@ -34,6 +35,7 @@ export const MenuItem = ({
|
|
|
34
35
|
target,
|
|
35
36
|
isActive,
|
|
36
37
|
"data-testid": dataTestId,
|
|
38
|
+
id,
|
|
37
39
|
}: MenuItemProps): JSX.Element => {
|
|
38
40
|
const wrappedLabel = <span className={styles.menuItem__Label}>{label}</span>
|
|
39
41
|
const iconNode = icon && <span className={styles.menuItem__Icon}>{icon}</span>
|
|
@@ -49,6 +51,7 @@ export const MenuItem = ({
|
|
|
49
51
|
return (
|
|
50
52
|
<li className={styles.menuListItem}>
|
|
51
53
|
<button
|
|
54
|
+
id={id}
|
|
52
55
|
type="button"
|
|
53
56
|
disabled={true}
|
|
54
57
|
className={className}
|
|
@@ -65,6 +68,7 @@ export const MenuItem = ({
|
|
|
65
68
|
return (
|
|
66
69
|
<li className={styles.menuListItem}>
|
|
67
70
|
<a
|
|
71
|
+
id={id}
|
|
68
72
|
href={href}
|
|
69
73
|
className={className}
|
|
70
74
|
target={target}
|
|
@@ -83,6 +87,7 @@ export const MenuItem = ({
|
|
|
83
87
|
return (
|
|
84
88
|
<li className={styles.menuListItem}>
|
|
85
89
|
<button
|
|
90
|
+
id={id}
|
|
86
91
|
type="button"
|
|
87
92
|
onClick={onClick}
|
|
88
93
|
className={className}
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
} from "@react-stately/datepicker"
|
|
9
9
|
import classnames from "classnames"
|
|
10
10
|
import { FieldMessage } from "~components/FieldMessage"
|
|
11
|
-
import {
|
|
11
|
+
import { Label } from "~components/Label"
|
|
12
12
|
import { OverrideClassName } from "~types/OverrideClassName"
|
|
13
13
|
import { TimeSegment } from "./subcomponents/TimeSegment"
|
|
14
14
|
import { StatusType, TimeValue, ValueType } from "./types"
|
|
@@ -79,7 +79,9 @@ const TimeFieldComponent = ({
|
|
|
79
79
|
locale,
|
|
80
80
|
validationState: status === "default" ? "valid" : "invalid",
|
|
81
81
|
})
|
|
82
|
-
|
|
82
|
+
|
|
83
|
+
const hasError = !!validationMessage && status === "error"
|
|
84
|
+
const descriptionId = hasError ? `${id}-field-message` : undefined
|
|
83
85
|
|
|
84
86
|
const inputRef = React.useRef(null)
|
|
85
87
|
const { fieldProps, labelProps } = useTimeField(
|
|
@@ -94,17 +96,13 @@ const TimeFieldComponent = ({
|
|
|
94
96
|
)
|
|
95
97
|
return (
|
|
96
98
|
<div className={classNameOverride}>
|
|
97
|
-
<
|
|
98
|
-
|
|
99
|
-
variant="heading-6"
|
|
99
|
+
<Label
|
|
100
|
+
disabled={state.isDisabled}
|
|
100
101
|
{...labelProps}
|
|
101
|
-
classNameOverride={
|
|
102
|
-
styles.heading,
|
|
103
|
-
state.isDisabled && styles.isDisabled
|
|
104
|
-
)}
|
|
102
|
+
classNameOverride={styles.label}
|
|
105
103
|
>
|
|
106
104
|
{label}
|
|
107
|
-
</
|
|
105
|
+
</Label>
|
|
108
106
|
<div className={styles.wrapper}>
|
|
109
107
|
{/* eslint-disable-next-line jsx-a11y/no-static-element-interactions, jsx-a11y/click-events-have-key-events */}
|
|
110
108
|
<div
|
|
@@ -123,7 +121,7 @@ const TimeFieldComponent = ({
|
|
|
123
121
|
<div className={styles.focusRing} />
|
|
124
122
|
</div>
|
|
125
123
|
</div>
|
|
126
|
-
{
|
|
124
|
+
{hasError && (
|
|
127
125
|
<FieldMessage
|
|
128
126
|
id={descriptionId}
|
|
129
127
|
message={validationMessage}
|
|
@@ -615,6 +615,47 @@ describe("<TitleBlockZen />", () => {
|
|
|
615
615
|
})
|
|
616
616
|
})
|
|
617
617
|
|
|
618
|
+
describe("when autoHideMobileActionsMenu is true", () => {
|
|
619
|
+
const secondaryActionWithLink = {
|
|
620
|
+
label: "secondaryActionLabel",
|
|
621
|
+
href: "#secondaryActionHref",
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
it("hides the other actions menu when user clicks a menu item", async () => {
|
|
625
|
+
const { getAllByTestId } = render(
|
|
626
|
+
<TitleBlockZen
|
|
627
|
+
title="Test Title"
|
|
628
|
+
secondaryActions={[secondaryActionWithLink]}
|
|
629
|
+
autoHideMobileActionsMenu
|
|
630
|
+
>
|
|
631
|
+
Example
|
|
632
|
+
</TitleBlockZen>
|
|
633
|
+
)
|
|
634
|
+
|
|
635
|
+
const mobileActionsButton = screen.getByRole("button", {
|
|
636
|
+
name: "Other actions",
|
|
637
|
+
})
|
|
638
|
+
|
|
639
|
+
expect(mobileActionsButton.getAttribute("aria-expanded")).toEqual("false")
|
|
640
|
+
await user.click(mobileActionsButton)
|
|
641
|
+
await waitFor(() => {
|
|
642
|
+
expect(mobileActionsButton.getAttribute("aria-expanded")).toEqual(
|
|
643
|
+
"true"
|
|
644
|
+
)
|
|
645
|
+
})
|
|
646
|
+
|
|
647
|
+
const btn = getAllByTestId("title-block-mobile-actions-secondary-action")
|
|
648
|
+
expect(btn.length).toEqual(1)
|
|
649
|
+
await user.click(btn[0])
|
|
650
|
+
|
|
651
|
+
await waitFor(() => {
|
|
652
|
+
expect(mobileActionsButton.getAttribute("aria-expanded")).toEqual(
|
|
653
|
+
"false"
|
|
654
|
+
)
|
|
655
|
+
})
|
|
656
|
+
})
|
|
657
|
+
})
|
|
658
|
+
|
|
618
659
|
describe("when a disabled secondary action is passed with only an href", () => {
|
|
619
660
|
const secondaryActionWithLink = {
|
|
620
661
|
label: "secondaryActionLabel",
|
|
@@ -260,6 +260,7 @@ export const TitleBlockZen = ({
|
|
|
260
260
|
collapseNavigationAreaWhenPossible = false,
|
|
261
261
|
textDirection,
|
|
262
262
|
surveyStatus,
|
|
263
|
+
id,
|
|
263
264
|
titleAutomationId = "TitleBlock__Title",
|
|
264
265
|
avatarAutomationId = "TitleBlock__Avatar",
|
|
265
266
|
subtitleAutomationId = "TitleBlock__Subtitle",
|
|
@@ -267,6 +268,7 @@ export const TitleBlockZen = ({
|
|
|
267
268
|
sectionTitleDescriptionAutomationId = "TitleBlock__SectionTitleDescription",
|
|
268
269
|
breadcrumbAutomationId = "TitleBlock__Breadcrumb",
|
|
269
270
|
breadcrumbTextAutomationId = "TitleBlock__BreadcrumbText",
|
|
271
|
+
autoHideMobileActionsMenu = false,
|
|
270
272
|
}: TitleBlockProps): JSX.Element => {
|
|
271
273
|
const hasNavigationTabs = navigationTabs && navigationTabs.length > 0
|
|
272
274
|
const collapseNavigationArea =
|
|
@@ -281,6 +283,7 @@ export const TitleBlockZen = ({
|
|
|
281
283
|
return (
|
|
282
284
|
<>
|
|
283
285
|
<div
|
|
286
|
+
id={id}
|
|
284
287
|
className={classnames(
|
|
285
288
|
styles.titleBlock,
|
|
286
289
|
styles[`${variant}Variant`],
|
|
@@ -432,6 +435,7 @@ export const TitleBlockZen = ({
|
|
|
432
435
|
? primaryAction.iconPosition
|
|
433
436
|
: undefined
|
|
434
437
|
}
|
|
438
|
+
autoHide={autoHideMobileActionsMenu}
|
|
435
439
|
/>
|
|
436
440
|
</div>
|
|
437
441
|
</>
|
|
@@ -2,6 +2,7 @@ import React from "react"
|
|
|
2
2
|
import { Button, IconButton } from "~components/Button"
|
|
3
3
|
import { ChevronDownIcon, MeatballsIcon } from "~components/Icon"
|
|
4
4
|
import { Menu, MenuList } from "~components/Menu"
|
|
5
|
+
import { TITLE_BLOCK_ZEN_SECONDARY_MENU_HTML_ID } from "../constants"
|
|
5
6
|
import {
|
|
6
7
|
DefaultActionProps,
|
|
7
8
|
PrimaryActionProps,
|
|
@@ -159,6 +160,7 @@ export const MainActions = ({
|
|
|
159
160
|
align="right"
|
|
160
161
|
button={
|
|
161
162
|
<IconButton
|
|
163
|
+
id={TITLE_BLOCK_ZEN_SECONDARY_MENU_HTML_ID}
|
|
162
164
|
label="Open secondary menu"
|
|
163
165
|
reversed={reversed}
|
|
164
166
|
icon={<MeatballsIcon role="presentation" />}
|
|
@@ -36,6 +36,13 @@ const SECONDARY_ACTIONS = [
|
|
|
36
36
|
},
|
|
37
37
|
]
|
|
38
38
|
|
|
39
|
+
const SECONDARY_OVERFLOW_ACTIONS = [
|
|
40
|
+
{
|
|
41
|
+
onClick: (): void => alert("test"),
|
|
42
|
+
label: "Secondary overflow action",
|
|
43
|
+
},
|
|
44
|
+
]
|
|
45
|
+
|
|
39
46
|
describe("<MobileActions />", () => {
|
|
40
47
|
describe("Case 1: Primary Action is a menu", () => {
|
|
41
48
|
it("makes aria-expanded toggles between true and false when user toggles the menu", async () => {
|
|
@@ -137,3 +144,83 @@ describe("<MobileActions />", () => {
|
|
|
137
144
|
})
|
|
138
145
|
})
|
|
139
146
|
})
|
|
147
|
+
|
|
148
|
+
describe("when autoHide is true", () => {
|
|
149
|
+
beforeEach(() => {
|
|
150
|
+
window.alert = jest.fn()
|
|
151
|
+
render(
|
|
152
|
+
<MobileActions
|
|
153
|
+
primaryAction={{
|
|
154
|
+
label: "Primary menu",
|
|
155
|
+
}}
|
|
156
|
+
defaultAction={{
|
|
157
|
+
label: "Default link",
|
|
158
|
+
href: "#",
|
|
159
|
+
}}
|
|
160
|
+
secondaryActions={SECONDARY_ACTIONS}
|
|
161
|
+
secondaryOverflowMenuItems={SECONDARY_OVERFLOW_ACTIONS}
|
|
162
|
+
autoHide
|
|
163
|
+
/>
|
|
164
|
+
)
|
|
165
|
+
})
|
|
166
|
+
it("hides the menu when user clicks a default action item", async () => {
|
|
167
|
+
const mobileActionsButton = screen.getByRole("button", {
|
|
168
|
+
name: "Other actions",
|
|
169
|
+
})
|
|
170
|
+
expect(mobileActionsButton.getAttribute("aria-expanded")).toEqual("false")
|
|
171
|
+
|
|
172
|
+
await user.click(mobileActionsButton)
|
|
173
|
+
await waitFor(() => {
|
|
174
|
+
expect(mobileActionsButton.getAttribute("aria-expanded")).toEqual("true")
|
|
175
|
+
})
|
|
176
|
+
const btn = screen.getAllByTestId(/title-block-mobile-actions-default-/)
|
|
177
|
+
expect(btn.length).toEqual(1)
|
|
178
|
+
await user.click(btn[0])
|
|
179
|
+
|
|
180
|
+
await waitFor(() => {
|
|
181
|
+
expect(mobileActionsButton.getAttribute("aria-expanded")).toEqual("false")
|
|
182
|
+
})
|
|
183
|
+
})
|
|
184
|
+
|
|
185
|
+
it("hides the menu when user clicks a secondary action item", async () => {
|
|
186
|
+
const mobileActionsButton = screen.getByRole("button", {
|
|
187
|
+
name: "Other actions",
|
|
188
|
+
})
|
|
189
|
+
expect(mobileActionsButton.getAttribute("aria-expanded")).toEqual("false")
|
|
190
|
+
|
|
191
|
+
await user.click(mobileActionsButton)
|
|
192
|
+
await waitFor(() => {
|
|
193
|
+
expect(mobileActionsButton.getAttribute("aria-expanded")).toEqual("true")
|
|
194
|
+
})
|
|
195
|
+
const btn = screen.getAllByTestId(
|
|
196
|
+
"title-block-mobile-actions-secondary-action"
|
|
197
|
+
)
|
|
198
|
+
expect(btn.length).toEqual(3)
|
|
199
|
+
await user.click(btn[0])
|
|
200
|
+
|
|
201
|
+
await waitFor(() => {
|
|
202
|
+
expect(mobileActionsButton.getAttribute("aria-expanded")).toEqual("false")
|
|
203
|
+
})
|
|
204
|
+
})
|
|
205
|
+
|
|
206
|
+
it("hides the menu when user clicks a secondary overflow item", async () => {
|
|
207
|
+
const mobileActionsButton = screen.getByRole("button", {
|
|
208
|
+
name: "Other actions",
|
|
209
|
+
})
|
|
210
|
+
expect(mobileActionsButton.getAttribute("aria-expanded")).toEqual("false")
|
|
211
|
+
|
|
212
|
+
await user.click(mobileActionsButton)
|
|
213
|
+
await waitFor(() => {
|
|
214
|
+
expect(mobileActionsButton.getAttribute("aria-expanded")).toEqual("true")
|
|
215
|
+
})
|
|
216
|
+
const btn = screen.getAllByTestId(
|
|
217
|
+
"title-block-mobile-actions-overflow-menu-item"
|
|
218
|
+
)
|
|
219
|
+
expect(btn.length).toEqual(1)
|
|
220
|
+
await user.click(btn[0])
|
|
221
|
+
|
|
222
|
+
await waitFor(() => {
|
|
223
|
+
expect(mobileActionsButton.getAttribute("aria-expanded")).toEqual("false")
|
|
224
|
+
})
|
|
225
|
+
})
|
|
226
|
+
})
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import React, { useState } from "react"
|
|
1
|
+
import React, { useCallback, useEffect, useState } from "react"
|
|
2
2
|
import classnames from "classnames"
|
|
3
3
|
import { FocusOn } from "react-focus-on"
|
|
4
4
|
import { ButtonProps } from "~components/Button"
|
|
5
5
|
import { ChevronDownIcon, ChevronUpIcon } from "~components/Icon"
|
|
6
6
|
import { MenuItem, MenuList, MenuHeading } from "~components/Menu"
|
|
7
|
+
import { TITLE_BLOCK_ZEN_OTHER_ACTIONS_HTML_ID } from "../constants"
|
|
7
8
|
import {
|
|
8
9
|
DefaultActionProps,
|
|
9
10
|
PrimaryActionProps,
|
|
@@ -88,6 +89,7 @@ const renderDefaultLink = (
|
|
|
88
89
|
key="title-block-mobile-actions-default-link"
|
|
89
90
|
data-automation-id="title-block-mobile-actions-default-link"
|
|
90
91
|
data-testid="title-block-mobile-actions-default-link"
|
|
92
|
+
id={defaultAction.id}
|
|
91
93
|
/>
|
|
92
94
|
)
|
|
93
95
|
}
|
|
@@ -398,6 +400,7 @@ const DrawerHandle = ({
|
|
|
398
400
|
className={styles.mobileActionsExpandButton}
|
|
399
401
|
onClick={toggleDisplay}
|
|
400
402
|
aria-expanded={isOpen}
|
|
403
|
+
id={TITLE_BLOCK_ZEN_OTHER_ACTIONS_HTML_ID}
|
|
401
404
|
aria-label="Other actions"
|
|
402
405
|
>
|
|
403
406
|
{isOpen ? (
|
|
@@ -429,6 +432,7 @@ const DrawerHandle = ({
|
|
|
429
432
|
)}
|
|
430
433
|
onClick={toggleDisplay}
|
|
431
434
|
aria-expanded={isOpen}
|
|
435
|
+
id={TITLE_BLOCK_ZEN_OTHER_ACTIONS_HTML_ID}
|
|
432
436
|
>
|
|
433
437
|
{renderDrawerHandleLabel("Other actions")}
|
|
434
438
|
<span className={styles.mobileActionsChevronSquare}>
|
|
@@ -451,6 +455,7 @@ export type MobileActionsProps = {
|
|
|
451
455
|
secondaryActions?: SecondaryActionsProps
|
|
452
456
|
secondaryOverflowMenuItems?: TitleBlockMenuItemProps[]
|
|
453
457
|
drawerHandleLabelIconPosition?: ButtonProps["iconPosition"]
|
|
458
|
+
autoHide?: boolean
|
|
454
459
|
}
|
|
455
460
|
|
|
456
461
|
export const MobileActions = ({
|
|
@@ -459,13 +464,44 @@ export const MobileActions = ({
|
|
|
459
464
|
secondaryActions,
|
|
460
465
|
secondaryOverflowMenuItems,
|
|
461
466
|
drawerHandleLabelIconPosition,
|
|
467
|
+
autoHide = false,
|
|
462
468
|
}: MobileActionsProps): JSX.Element => {
|
|
463
469
|
const [isOpen, setIsOpen] = useState<boolean>(false)
|
|
464
|
-
|
|
470
|
+
const menuContent = React.createRef<HTMLDivElement>()
|
|
465
471
|
const toggleDisplay = (): void => {
|
|
466
472
|
setIsOpen(!isOpen)
|
|
467
473
|
}
|
|
468
474
|
|
|
475
|
+
// This callback handler will not run when autoHide === "off"
|
|
476
|
+
const handleDocumentClickForAutoHide = useCallback(
|
|
477
|
+
(e: MouseEvent) => {
|
|
478
|
+
if (
|
|
479
|
+
isOpen &&
|
|
480
|
+
e.target instanceof Node &&
|
|
481
|
+
menuContent.current?.contains(e.target)
|
|
482
|
+
) {
|
|
483
|
+
setIsOpen(false)
|
|
484
|
+
}
|
|
485
|
+
},
|
|
486
|
+
[menuContent]
|
|
487
|
+
)
|
|
488
|
+
|
|
489
|
+
useEffect(() => {
|
|
490
|
+
if (autoHide) {
|
|
491
|
+
document.addEventListener("click", handleDocumentClickForAutoHide, true)
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
return () => {
|
|
495
|
+
if (autoHide) {
|
|
496
|
+
document.removeEventListener(
|
|
497
|
+
"click",
|
|
498
|
+
handleDocumentClickForAutoHide,
|
|
499
|
+
true
|
|
500
|
+
)
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
}, [autoHide, handleDocumentClickForAutoHide])
|
|
504
|
+
|
|
469
505
|
return (
|
|
470
506
|
<div
|
|
471
507
|
className={classnames(
|
|
@@ -487,7 +523,7 @@ export const MobileActions = ({
|
|
|
487
523
|
secondaryActions ||
|
|
488
524
|
secondaryOverflowMenuItems ||
|
|
489
525
|
(primaryAction && isMenuGroupNotButton(primaryAction))) && (
|
|
490
|
-
<div className={styles.mobileActionsMenuContainer}>
|
|
526
|
+
<div ref={menuContent} className={styles.mobileActionsMenuContainer}>
|
|
491
527
|
<DrawerMenuContent
|
|
492
528
|
primaryAction={primaryAction}
|
|
493
529
|
defaultAction={defaultAction}
|
|
@@ -3,6 +3,7 @@ import { Button, IconButton } from "~components/Button"
|
|
|
3
3
|
import { ChevronDownIcon, MeatballsIcon } from "~components/Icon"
|
|
4
4
|
import { Menu, MenuList } from "~components/Menu"
|
|
5
5
|
import styles from "../TitleBlockZen.module.scss"
|
|
6
|
+
import { TITLE_BLOCK_ZEN_SECONDARY_MENU_HTML_ID } from "../constants"
|
|
6
7
|
import { SecondaryActionsProps, TitleBlockMenuItemProps } from "../types"
|
|
7
8
|
import { TitleBlockMenuItem } from "./TitleBlockMenuItem"
|
|
8
9
|
import { Toolbar } from "./Toolbar"
|
|
@@ -26,6 +27,7 @@ const renderSecondaryOverflowMenu = (
|
|
|
26
27
|
label="Open secondary menu"
|
|
27
28
|
reversed={reversed}
|
|
28
29
|
icon={<MeatballsIcon role="presentation" />}
|
|
30
|
+
id={TITLE_BLOCK_ZEN_SECONDARY_MENU_HTML_ID}
|
|
29
31
|
/>
|
|
30
32
|
}
|
|
31
33
|
>
|
|
@@ -34,6 +34,7 @@ export type TitleBlockProps = {
|
|
|
34
34
|
collapseNavigationAreaWhenPossible?: boolean
|
|
35
35
|
textDirection?: TextDirection
|
|
36
36
|
surveyStatus?: SurveyStatus
|
|
37
|
+
id?: string
|
|
37
38
|
titleAutomationId?: string
|
|
38
39
|
breadcrumbAutomationId?: string
|
|
39
40
|
breadcrumbTextAutomationId?: string
|
|
@@ -41,6 +42,7 @@ export type TitleBlockProps = {
|
|
|
41
42
|
subtitleAutomationId?: string
|
|
42
43
|
sectionTitleAutomationId?: string
|
|
43
44
|
sectionTitleDescriptionAutomationId?: string
|
|
45
|
+
autoHideMobileActionsMenu?: boolean
|
|
44
46
|
}
|
|
45
47
|
|
|
46
48
|
/**
|