@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.
Files changed (63) hide show
  1. package/dist/cjs/Menu/subcomponents/MenuItem/MenuItem.cjs +5 -1
  2. package/dist/cjs/Menu/subcomponents/MenuItem/MenuItem.cjs.map +1 -1
  3. package/dist/cjs/TimeField/TimeField.cjs +7 -7
  4. package/dist/cjs/TimeField/TimeField.cjs.map +1 -1
  5. package/dist/cjs/TimeField/TimeField.module.scss.cjs +1 -1
  6. package/dist/cjs/TitleBlockZen/TitleBlockZen.cjs +10 -5
  7. package/dist/cjs/TitleBlockZen/TitleBlockZen.cjs.map +1 -1
  8. package/dist/cjs/TitleBlockZen/constants.cjs +7 -0
  9. package/dist/cjs/TitleBlockZen/constants.cjs.map +1 -0
  10. package/dist/cjs/TitleBlockZen/subcomponents/MainActions.cjs +2 -0
  11. package/dist/cjs/TitleBlockZen/subcomponents/MainActions.cjs.map +1 -1
  12. package/dist/cjs/TitleBlockZen/subcomponents/MobileActions.cjs +31 -6
  13. package/dist/cjs/TitleBlockZen/subcomponents/MobileActions.cjs.map +1 -1
  14. package/dist/cjs/TitleBlockZen/subcomponents/SecondaryActions.cjs +3 -1
  15. package/dist/cjs/TitleBlockZen/subcomponents/SecondaryActions.cjs.map +1 -1
  16. package/dist/cjs/dts/Menu/subcomponents/MenuItem/MenuItem.d.ts +2 -1
  17. package/dist/cjs/dts/TitleBlockZen/TitleBlockZen.d.ts +1 -1
  18. package/dist/cjs/dts/TitleBlockZen/constants.d.ts +2 -0
  19. package/dist/cjs/dts/TitleBlockZen/index.d.ts +1 -0
  20. package/dist/cjs/dts/TitleBlockZen/subcomponents/MobileActions.d.ts +2 -1
  21. package/dist/cjs/dts/TitleBlockZen/types.d.ts +2 -0
  22. package/dist/cjs/index.cjs +3 -0
  23. package/dist/cjs/index.cjs.map +1 -1
  24. package/dist/cjs/index.css +5 -5
  25. package/dist/esm/Menu/subcomponents/MenuItem/MenuItem.mjs +5 -1
  26. package/dist/esm/Menu/subcomponents/MenuItem/MenuItem.mjs.map +1 -1
  27. package/dist/esm/TimeField/TimeField.mjs +7 -7
  28. package/dist/esm/TimeField/TimeField.mjs.map +1 -1
  29. package/dist/esm/TimeField/TimeField.module.scss.mjs +1 -1
  30. package/dist/esm/TitleBlockZen/TitleBlockZen.mjs +10 -5
  31. package/dist/esm/TitleBlockZen/TitleBlockZen.mjs.map +1 -1
  32. package/dist/esm/TitleBlockZen/constants.mjs +4 -0
  33. package/dist/esm/TitleBlockZen/constants.mjs.map +1 -0
  34. package/dist/esm/TitleBlockZen/subcomponents/MainActions.mjs +2 -0
  35. package/dist/esm/TitleBlockZen/subcomponents/MainActions.mjs.map +1 -1
  36. package/dist/esm/TitleBlockZen/subcomponents/MobileActions.mjs +32 -7
  37. package/dist/esm/TitleBlockZen/subcomponents/MobileActions.mjs.map +1 -1
  38. package/dist/esm/TitleBlockZen/subcomponents/SecondaryActions.mjs +3 -1
  39. package/dist/esm/TitleBlockZen/subcomponents/SecondaryActions.mjs.map +1 -1
  40. package/dist/esm/dts/Menu/subcomponents/MenuItem/MenuItem.d.ts +2 -1
  41. package/dist/esm/dts/TitleBlockZen/TitleBlockZen.d.ts +1 -1
  42. package/dist/esm/dts/TitleBlockZen/constants.d.ts +2 -0
  43. package/dist/esm/dts/TitleBlockZen/index.d.ts +1 -0
  44. package/dist/esm/dts/TitleBlockZen/subcomponents/MobileActions.d.ts +2 -1
  45. package/dist/esm/dts/TitleBlockZen/types.d.ts +2 -0
  46. package/dist/esm/index.css +4 -4
  47. package/dist/esm/index.mjs +1 -0
  48. package/dist/esm/index.mjs.map +1 -1
  49. package/dist/index.d.ts +9 -3
  50. package/dist/styles.css +1 -1
  51. package/package.json +24 -24
  52. package/src/Menu/subcomponents/MenuItem/MenuItem.tsx +5 -0
  53. package/src/TimeField/TimeField.module.scss +2 -1
  54. package/src/TimeField/TimeField.tsx +9 -11
  55. package/src/TitleBlockZen/TitleBlockZen.spec.tsx +41 -0
  56. package/src/TitleBlockZen/TitleBlockZen.tsx +4 -0
  57. package/src/TitleBlockZen/constants.ts +3 -0
  58. package/src/TitleBlockZen/index.ts +1 -0
  59. package/src/TitleBlockZen/subcomponents/MainActions.tsx +2 -0
  60. package/src/TitleBlockZen/subcomponents/MobileActions.spec.tsx +87 -0
  61. package/src/TitleBlockZen/subcomponents/MobileActions.tsx +39 -3
  62. package/src/TitleBlockZen/subcomponents/SecondaryActions.tsx +2 -0
  63. 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.4",
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.0",
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.0",
52
- "@react-aria/datepicker": "^3.9.0",
53
- "@react-aria/focus": "^3.15.0",
54
- "@react-aria/i18n": "^3.9.0",
55
- "@react-aria/listbox": "^3.11.2",
56
- "@react-aria/menu": "^3.11.2",
57
- "@react-aria/overlays": "^3.19.0",
58
- "@react-aria/select": "^3.14.0",
59
- "@react-aria/utils": "^3.22.0",
60
- "@react-stately/collections": "^3.10.3",
61
- "@react-stately/datepicker": "^3.9.0",
62
- "@react-stately/list": "^3.10.1",
63
- "@react-stately/menu": "^3.5.7",
64
- "@react-stately/select": "^3.6.0",
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.3.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.0.2",
100
- "@cultureamp/i18n-react-intl": "^2.1.5",
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.1",
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.17",
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.6.0",
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.5",
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.5",
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}
@@ -18,7 +18,8 @@ $input-height: 48px;
18
18
  color: $color-purple-800;
19
19
  }
20
20
 
21
- .heading {
21
+ .label {
22
+ display: block;
22
23
  margin-bottom: $spacing-6;
23
24
  }
24
25
 
@@ -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 { Heading } from "~components/Heading"
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
- const descriptionId = `${id}-field-message`
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
- <Heading
98
- tag="div"
99
- variant="heading-6"
99
+ <Label
100
+ disabled={state.isDisabled}
100
101
  {...labelProps}
101
- classNameOverride={classnames(
102
- styles.heading,
103
- state.isDisabled && styles.isDisabled
104
- )}
102
+ classNameOverride={styles.label}
105
103
  >
106
104
  {label}
107
- </Heading>
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
- {validationMessage && status === "error" && (
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
  </>
@@ -0,0 +1,3 @@
1
+ export const TITLE_BLOCK_ZEN_SECONDARY_MENU_HTML_ID =
2
+ "title-block-secondary-menu"
3
+ export const TITLE_BLOCK_ZEN_OTHER_ACTIONS_HTML_ID = "title-block-other-actions"
@@ -1,3 +1,4 @@
1
1
  export * from "./TitleBlockZen"
2
2
  export * from "./subcomponents/NavigationTabs"
3
3
  export * from "./types"
4
+ export * from "./constants"
@@ -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
  /**