@kaizen/components 0.0.0-canary-add-ids-to-TitleBlockZen-20240110044439 → 0.0.0-canary-auto-hide-mobile-menu-20240110220109
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/TitleBlockZen/TitleBlockZen.cjs +8 -5
- package/dist/cjs/TitleBlockZen/TitleBlockZen.cjs.map +1 -1
- package/dist/cjs/TitleBlockZen/constants.cjs.map +1 -1
- package/dist/cjs/TitleBlockZen/subcomponents/MobileActions.cjs +25 -4
- package/dist/cjs/TitleBlockZen/subcomponents/MobileActions.cjs.map +1 -1
- package/dist/cjs/dts/TitleBlockZen/TitleBlockZen.d.ts +1 -1
- package/dist/cjs/dts/TitleBlockZen/subcomponents/MobileActions.d.ts +2 -1
- package/dist/cjs/dts/TitleBlockZen/types.d.ts +1 -0
- package/dist/cjs/index.css +3 -3
- package/dist/esm/TitleBlockZen/TitleBlockZen.mjs +8 -5
- package/dist/esm/TitleBlockZen/TitleBlockZen.mjs.map +1 -1
- package/dist/esm/TitleBlockZen/constants.mjs.map +1 -1
- package/dist/esm/TitleBlockZen/subcomponents/MobileActions.mjs +26 -5
- package/dist/esm/TitleBlockZen/subcomponents/MobileActions.mjs.map +1 -1
- package/dist/esm/dts/TitleBlockZen/TitleBlockZen.d.ts +1 -1
- package/dist/esm/dts/TitleBlockZen/subcomponents/MobileActions.d.ts +2 -1
- package/dist/esm/dts/TitleBlockZen/types.d.ts +1 -0
- package/dist/esm/index.css +2 -2
- package/dist/index.d.ts +2 -1
- package/dist/styles.css +1 -1
- package/package.json +1 -1
- package/src/TitleBlockZen/TitleBlockZen.spec.tsx +41 -0
- package/src/TitleBlockZen/TitleBlockZen.tsx +2 -0
- package/src/TitleBlockZen/constants.ts +2 -1
- package/src/TitleBlockZen/subcomponents/MobileActions.spec.tsx +87 -0
- package/src/TitleBlockZen/subcomponents/MobileActions.tsx +35 -3
- package/src/TitleBlockZen/types.ts +1 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kaizen/components",
|
|
3
|
-
"version": "0.0.0-canary-
|
|
3
|
+
"version": "0.0.0-canary-auto-hide-mobile-menu-20240110220109",
|
|
4
4
|
"description": "Kaizen component library",
|
|
5
5
|
"author": "Geoffrey Chong <geoff.chong@cultureamp.com>",
|
|
6
6
|
"homepage": "https://cultureamp.design",
|
|
@@ -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",
|
|
@@ -268,6 +268,7 @@ export const TitleBlockZen = ({
|
|
|
268
268
|
sectionTitleDescriptionAutomationId = "TitleBlock__SectionTitleDescription",
|
|
269
269
|
breadcrumbAutomationId = "TitleBlock__Breadcrumb",
|
|
270
270
|
breadcrumbTextAutomationId = "TitleBlock__BreadcrumbText",
|
|
271
|
+
autoHideMobileActionsMenu = false,
|
|
271
272
|
}: TitleBlockProps): JSX.Element => {
|
|
272
273
|
const hasNavigationTabs = navigationTabs && navigationTabs.length > 0
|
|
273
274
|
const collapseNavigationArea =
|
|
@@ -434,6 +435,7 @@ export const TitleBlockZen = ({
|
|
|
434
435
|
? primaryAction.iconPosition
|
|
435
436
|
: undefined
|
|
436
437
|
}
|
|
438
|
+
autoHide={autoHideMobileActionsMenu}
|
|
437
439
|
/>
|
|
438
440
|
</div>
|
|
439
441
|
</>
|
|
@@ -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,4 +1,4 @@
|
|
|
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"
|
|
@@ -455,6 +455,7 @@ export type MobileActionsProps = {
|
|
|
455
455
|
secondaryActions?: SecondaryActionsProps
|
|
456
456
|
secondaryOverflowMenuItems?: TitleBlockMenuItemProps[]
|
|
457
457
|
drawerHandleLabelIconPosition?: ButtonProps["iconPosition"]
|
|
458
|
+
autoHide?: boolean
|
|
458
459
|
}
|
|
459
460
|
|
|
460
461
|
export const MobileActions = ({
|
|
@@ -463,13 +464,44 @@ export const MobileActions = ({
|
|
|
463
464
|
secondaryActions,
|
|
464
465
|
secondaryOverflowMenuItems,
|
|
465
466
|
drawerHandleLabelIconPosition,
|
|
467
|
+
autoHide = false,
|
|
466
468
|
}: MobileActionsProps): JSX.Element => {
|
|
467
469
|
const [isOpen, setIsOpen] = useState<boolean>(false)
|
|
468
|
-
|
|
470
|
+
const menuContent = React.createRef<HTMLDivElement>()
|
|
469
471
|
const toggleDisplay = (): void => {
|
|
470
472
|
setIsOpen(!isOpen)
|
|
471
473
|
}
|
|
472
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
|
+
|
|
473
505
|
return (
|
|
474
506
|
<div
|
|
475
507
|
className={classnames(
|
|
@@ -491,7 +523,7 @@ export const MobileActions = ({
|
|
|
491
523
|
secondaryActions ||
|
|
492
524
|
secondaryOverflowMenuItems ||
|
|
493
525
|
(primaryAction && isMenuGroupNotButton(primaryAction))) && (
|
|
494
|
-
<div className={styles.mobileActionsMenuContainer}>
|
|
526
|
+
<div ref={menuContent} className={styles.mobileActionsMenuContainer}>
|
|
495
527
|
<DrawerMenuContent
|
|
496
528
|
primaryAction={primaryAction}
|
|
497
529
|
defaultAction={defaultAction}
|