@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.
Files changed (27) hide show
  1. package/dist/cjs/TitleBlockZen/TitleBlockZen.cjs +8 -5
  2. package/dist/cjs/TitleBlockZen/TitleBlockZen.cjs.map +1 -1
  3. package/dist/cjs/TitleBlockZen/constants.cjs.map +1 -1
  4. package/dist/cjs/TitleBlockZen/subcomponents/MobileActions.cjs +25 -4
  5. package/dist/cjs/TitleBlockZen/subcomponents/MobileActions.cjs.map +1 -1
  6. package/dist/cjs/dts/TitleBlockZen/TitleBlockZen.d.ts +1 -1
  7. package/dist/cjs/dts/TitleBlockZen/subcomponents/MobileActions.d.ts +2 -1
  8. package/dist/cjs/dts/TitleBlockZen/types.d.ts +1 -0
  9. package/dist/cjs/index.css +3 -3
  10. package/dist/esm/TitleBlockZen/TitleBlockZen.mjs +8 -5
  11. package/dist/esm/TitleBlockZen/TitleBlockZen.mjs.map +1 -1
  12. package/dist/esm/TitleBlockZen/constants.mjs.map +1 -1
  13. package/dist/esm/TitleBlockZen/subcomponents/MobileActions.mjs +26 -5
  14. package/dist/esm/TitleBlockZen/subcomponents/MobileActions.mjs.map +1 -1
  15. package/dist/esm/dts/TitleBlockZen/TitleBlockZen.d.ts +1 -1
  16. package/dist/esm/dts/TitleBlockZen/subcomponents/MobileActions.d.ts +2 -1
  17. package/dist/esm/dts/TitleBlockZen/types.d.ts +1 -0
  18. package/dist/esm/index.css +2 -2
  19. package/dist/index.d.ts +2 -1
  20. package/dist/styles.css +1 -1
  21. package/package.json +1 -1
  22. package/src/TitleBlockZen/TitleBlockZen.spec.tsx +41 -0
  23. package/src/TitleBlockZen/TitleBlockZen.tsx +2 -0
  24. package/src/TitleBlockZen/constants.ts +2 -1
  25. package/src/TitleBlockZen/subcomponents/MobileActions.spec.tsx +87 -0
  26. package/src/TitleBlockZen/subcomponents/MobileActions.tsx +35 -3
  27. 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-add-ids-to-TitleBlockZen-20240110044439",
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
  </>
@@ -1,2 +1,3 @@
1
- export const TITLE_BLOCK_ZEN_SECONDARY_MENU_HTML_ID = "title-block-secondary-menu"
1
+ export const TITLE_BLOCK_ZEN_SECONDARY_MENU_HTML_ID =
2
+ "title-block-secondary-menu"
2
3
  export const TITLE_BLOCK_ZEN_OTHER_ACTIONS_HTML_ID = "title-block-other-actions"
@@ -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}
@@ -42,6 +42,7 @@ export type TitleBlockProps = {
42
42
  subtitleAutomationId?: string
43
43
  sectionTitleAutomationId?: string
44
44
  sectionTitleDescriptionAutomationId?: string
45
+ autoHideMobileActionsMenu?: boolean
45
46
  }
46
47
 
47
48
  /**