@lifesg/react-design-system 4.0.0-alpha.12 → 4.0.0-alpha.13

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 (228) hide show
  1. package/breadcrumb/breadcrumb.js +1 -1
  2. package/breadcrumb/breadcrumb.js.map +1 -1
  3. package/breadcrumb/breadcrumb.styles.d.ts +0 -8
  4. package/breadcrumb/breadcrumb.styles.js +1 -1
  5. package/breadcrumb/breadcrumb.styles.js.map +1 -1
  6. package/breadcrumb/breadcrumb.styles_1blzn8n.css +7 -0
  7. package/breadcrumb/types.d.ts +2 -13
  8. package/cjs/breadcrumb/breadcrumb.js +1 -1
  9. package/cjs/breadcrumb/breadcrumb.js.map +1 -1
  10. package/cjs/breadcrumb/breadcrumb.styles.js +1 -1
  11. package/cjs/breadcrumb/breadcrumb.styles.js.map +1 -1
  12. package/cjs/breadcrumb/breadcrumb.styles_1blzn8n.css +7 -0
  13. package/cjs/drawer/drawer.js +1 -1
  14. package/cjs/drawer/drawer.js.map +1 -1
  15. package/cjs/drawer/drawer.styles.js +1 -1
  16. package/cjs/drawer/drawer.styles.js.map +1 -1
  17. package/{drawer/drawer.styles_94hx3y.css → cjs/drawer/drawer.styles_a4bwe0.css} +6 -3
  18. package/cjs/file-upload/file-list/file-list.js +1 -1
  19. package/cjs/file-upload/file-list/file-list.js.map +1 -1
  20. package/cjs/file-upload/file-list/file-list.styles.js +1 -1
  21. package/cjs/file-upload/file-list/file-list.styles.js.map +1 -1
  22. package/cjs/file-upload/file-list/file-list.styles_1xbypnh.css +2 -0
  23. package/cjs/file-upload/file-list-item/file-item-actions.js +2 -0
  24. package/cjs/file-upload/file-list-item/file-item-actions.js.map +1 -0
  25. package/cjs/file-upload/file-list-item/file-item-actions.styles.js +2 -0
  26. package/cjs/file-upload/file-list-item/file-item-actions.styles.js.map +1 -0
  27. package/cjs/file-upload/file-list-item/file-item-actions.styles_1quulgy.css +8 -0
  28. package/cjs/file-upload/file-list-item/file-item-details.js +2 -0
  29. package/cjs/file-upload/file-list-item/file-item-details.js.map +1 -0
  30. package/cjs/file-upload/file-list-item/file-item-details.styles.js +2 -0
  31. package/cjs/file-upload/file-list-item/file-item-details.styles.js.map +1 -0
  32. package/cjs/file-upload/file-list-item/file-item-details.styles_1ce9akx.css +7 -0
  33. package/cjs/file-upload/file-list-item/file-list-item.js +1 -1
  34. package/cjs/file-upload/file-list-item/file-list-item.js.map +1 -1
  35. package/cjs/file-upload/file-list-item/file-list-item.styles.js +1 -1
  36. package/cjs/file-upload/file-list-item/file-list-item.styles.js.map +1 -1
  37. package/cjs/file-upload/file-list-item/file-list-item.styles_x3a500.css +10 -0
  38. package/cjs/file-upload/file-list-item/use-truncated-name.js +2 -0
  39. package/cjs/file-upload/file-list-item/use-truncated-name.js.map +1 -0
  40. package/cjs/local-nav/local-nav-dropdown/local-nav-dropdown.js +1 -1
  41. package/cjs/local-nav/local-nav-dropdown/local-nav-dropdown.js.map +1 -1
  42. package/cjs/local-nav/local-nav-dropdown/local-nav-dropdown.styles.js +1 -1
  43. package/cjs/local-nav/local-nav-dropdown/local-nav-dropdown.styles.js.map +1 -1
  44. package/cjs/local-nav/local-nav-dropdown/{local-nav-dropdown.styles_uhd4xl.css → local-nav-dropdown.styles_kpel1m.css} +9 -6
  45. package/cjs/local-nav/local-nav-menu/local-nav-menu.js +1 -1
  46. package/cjs/local-nav/local-nav-menu/local-nav-menu.js.map +1 -1
  47. package/cjs/local-nav/local-nav-menu/local-nav-menu.styles.js +1 -1
  48. package/cjs/local-nav/local-nav-menu/local-nav-menu.styles.js.map +1 -1
  49. package/cjs/local-nav/local-nav-menu/local-nav-menu.styles_67fcyc.css +8 -0
  50. package/cjs/menu/menu-content.js +1 -1
  51. package/cjs/menu/menu-content.js.map +1 -1
  52. package/cjs/menu/menu-content.styles.js +1 -1
  53. package/cjs/menu/menu-content.styles.js.map +1 -1
  54. package/cjs/menu/menu-content.styles_1r8oxtk.css +5 -0
  55. package/cjs/menu/menu-item.styles.js +1 -1
  56. package/cjs/menu/menu-item.styles.js.map +1 -1
  57. package/cjs/menu/{menu-item.styles_liyed8.css → menu-item.styles_eut2j9.css} +1 -1
  58. package/cjs/menu/menu-link.styles.js +1 -1
  59. package/cjs/menu/menu-link.styles.js.map +1 -1
  60. package/cjs/menu/menu-link.styles_rng7n7.css +2 -0
  61. package/cjs/menu/menu-section.js +1 -1
  62. package/cjs/menu/menu-section.js.map +1 -1
  63. package/cjs/menu/menu-section.styles.js +1 -1
  64. package/cjs/menu/menu-section.styles.js.map +1 -1
  65. package/cjs/menu/menu-section.styles_1n0ppxl.css +5 -0
  66. package/cjs/navbar/navbar-items.js +1 -1
  67. package/cjs/navbar/navbar-items.js.map +1 -1
  68. package/cjs/notification-banner/notification-banner-hoc.js +1 -1
  69. package/cjs/notification-banner/notification-banner-hoc.js.map +1 -1
  70. package/cjs/pagination/pagination.js +1 -1
  71. package/cjs/pagination/pagination.js.map +1 -1
  72. package/cjs/shared/dropdown-list/dropdown-label.js +1 -1
  73. package/cjs/shared/dropdown-list/dropdown-label.js.map +1 -1
  74. package/cjs/shared/fade-wrapper/fade-wrapper.js +1 -1
  75. package/cjs/shared/fade-wrapper/fade-wrapper.js.map +1 -1
  76. package/cjs/theme/tokens/colour.js +1 -1
  77. package/cjs/theme/tokens/colour.js.map +1 -1
  78. package/cjs/theme/tokens/radius.js +1 -1
  79. package/cjs/theme/tokens/radius.js.map +1 -1
  80. package/codemods/run-codemod.js +8 -2
  81. package/codemods/run-codemod.js.map +1 -1
  82. package/codemods/run-codemod.ts +13 -4
  83. package/drawer/drawer.d.ts +1 -1
  84. package/drawer/drawer.js +1 -1
  85. package/drawer/drawer.js.map +1 -1
  86. package/drawer/drawer.styles.d.ts +3 -0
  87. package/drawer/drawer.styles.js +1 -1
  88. package/drawer/drawer.styles.js.map +1 -1
  89. package/{cjs/drawer/drawer.styles_94hx3y.css → drawer/drawer.styles_a4bwe0.css} +6 -3
  90. package/drawer/types.d.ts +7 -0
  91. package/file-upload/file-list/file-list.js +1 -1
  92. package/file-upload/file-list/file-list.js.map +1 -1
  93. package/file-upload/file-list/file-list.styles.d.ts +0 -1
  94. package/file-upload/file-list/file-list.styles.js +1 -1
  95. package/file-upload/file-list/file-list.styles.js.map +1 -1
  96. package/file-upload/file-list/file-list.styles_1xbypnh.css +2 -0
  97. package/file-upload/file-list-item/file-item-actions.d.ts +30 -0
  98. package/file-upload/file-list-item/file-item-actions.js +2 -0
  99. package/file-upload/file-list-item/file-item-actions.js.map +1 -0
  100. package/file-upload/file-list-item/file-item-actions.styles.d.ts +6 -0
  101. package/file-upload/file-list-item/file-item-actions.styles.js +2 -0
  102. package/file-upload/file-list-item/file-item-actions.styles.js.map +1 -0
  103. package/file-upload/file-list-item/file-item-actions.styles_1quulgy.css +8 -0
  104. package/file-upload/file-list-item/file-item-details.d.ts +15 -0
  105. package/file-upload/file-list-item/file-item-details.js +2 -0
  106. package/file-upload/file-list-item/file-item-details.js.map +1 -0
  107. package/file-upload/file-list-item/file-item-details.styles.d.ts +7 -0
  108. package/file-upload/file-list-item/file-item-details.styles.js +2 -0
  109. package/file-upload/file-list-item/file-item-details.styles.js.map +1 -0
  110. package/file-upload/file-list-item/file-item-details.styles_1ce9akx.css +7 -0
  111. package/file-upload/file-list-item/file-list-item.d.ts +1 -7
  112. package/file-upload/file-list-item/file-list-item.js +1 -1
  113. package/file-upload/file-list-item/file-list-item.js.map +1 -1
  114. package/file-upload/file-list-item/file-list-item.styles.d.ts +6 -13
  115. package/file-upload/file-list-item/file-list-item.styles.js +1 -1
  116. package/file-upload/file-list-item/file-list-item.styles.js.map +1 -1
  117. package/file-upload/file-list-item/file-list-item.styles_x3a500.css +10 -0
  118. package/file-upload/file-list-item/types.d.ts +10 -3
  119. package/file-upload/file-list-item/use-truncated-name.d.ts +1 -0
  120. package/file-upload/file-list-item/use-truncated-name.js +2 -0
  121. package/file-upload/file-list-item/use-truncated-name.js.map +1 -0
  122. package/input-group/types.d.ts +4 -1
  123. package/input-select/types.d.ts +1 -0
  124. package/local-nav/local-nav-dropdown/local-nav-dropdown.js +1 -1
  125. package/local-nav/local-nav-dropdown/local-nav-dropdown.js.map +1 -1
  126. package/local-nav/local-nav-dropdown/local-nav-dropdown.styles.d.ts +3 -0
  127. package/local-nav/local-nav-dropdown/local-nav-dropdown.styles.js +1 -1
  128. package/local-nav/local-nav-dropdown/local-nav-dropdown.styles.js.map +1 -1
  129. package/local-nav/local-nav-dropdown/{local-nav-dropdown.styles_uhd4xl.css → local-nav-dropdown.styles_kpel1m.css} +9 -6
  130. package/local-nav/local-nav-menu/local-nav-menu.js +1 -1
  131. package/local-nav/local-nav-menu/local-nav-menu.js.map +1 -1
  132. package/local-nav/local-nav-menu/local-nav-menu.styles.d.ts +3 -0
  133. package/local-nav/local-nav-menu/local-nav-menu.styles.js +1 -1
  134. package/local-nav/local-nav-menu/local-nav-menu.styles.js.map +1 -1
  135. package/local-nav/local-nav-menu/local-nav-menu.styles_67fcyc.css +8 -0
  136. package/local-nav/types.d.ts +17 -0
  137. package/masked-input/types.d.ts +1 -2
  138. package/menu/menu-content.js +1 -1
  139. package/menu/menu-content.js.map +1 -1
  140. package/menu/menu-content.styles.d.ts +1 -0
  141. package/menu/menu-content.styles.js +1 -1
  142. package/menu/menu-content.styles.js.map +1 -1
  143. package/menu/menu-content.styles_1r8oxtk.css +5 -0
  144. package/menu/menu-item.styles.js +1 -1
  145. package/menu/menu-item.styles.js.map +1 -1
  146. package/menu/{menu-item.styles_liyed8.css → menu-item.styles_eut2j9.css} +1 -1
  147. package/menu/menu-link.styles.js +1 -1
  148. package/menu/menu-link.styles.js.map +1 -1
  149. package/menu/menu-link.styles_rng7n7.css +2 -0
  150. package/menu/menu-section.d.ts +1 -1
  151. package/menu/menu-section.js +1 -1
  152. package/menu/menu-section.js.map +1 -1
  153. package/menu/menu-section.styles.d.ts +7 -0
  154. package/menu/menu-section.styles.js +1 -1
  155. package/menu/menu-section.styles.js.map +1 -1
  156. package/menu/menu-section.styles_1n0ppxl.css +5 -0
  157. package/menu/menu.d.ts +1 -1
  158. package/menu/types.d.ts +10 -2
  159. package/navbar/navbar-items.js +1 -1
  160. package/navbar/navbar-items.js.map +1 -1
  161. package/navbar/types.d.ts +9 -0
  162. package/notification-banner/notification-banner-hoc.js +1 -1
  163. package/notification-banner/notification-banner-hoc.js.map +1 -1
  164. package/package.json +2 -3
  165. package/pagination/pagination.js +1 -1
  166. package/pagination/pagination.js.map +1 -1
  167. package/pagination/types.d.ts +8 -1
  168. package/select-histogram/types.d.ts +1 -0
  169. package/shared/dropdown-list/dropdown-label.d.ts +2 -2
  170. package/shared/dropdown-list/dropdown-label.js +1 -1
  171. package/shared/dropdown-list/dropdown-label.js.map +1 -1
  172. package/shared/dropdown-list/types.d.ts +6 -2
  173. package/shared/fade-wrapper/fade-wrapper.js +1 -1
  174. package/shared/fade-wrapper/fade-wrapper.js.map +1 -1
  175. package/shared/fade-wrapper/types.d.ts +1 -0
  176. package/shared/styles/index.d.ts +5 -0
  177. package/theme/styles/a11y-playground.css +52 -40
  178. package/theme/styles/bookingsg.css +52 -40
  179. package/theme/styles/careercompass.css +52 -40
  180. package/theme/styles/ccube.css +52 -40
  181. package/theme/styles/imda.css +52 -40
  182. package/theme/styles/lifesg.css +52 -40
  183. package/theme/styles/mylegacy.css +52 -40
  184. package/theme/styles/oneservice.css +52 -40
  185. package/theme/styles/pa.css +28 -22
  186. package/theme/styles/rbs.css +52 -40
  187. package/theme/styles/sgw-digital-lobby.css +52 -40
  188. package/theme/styles/smgs.css +52 -40
  189. package/theme/styles/spf.css +28 -27
  190. package/theme/styles/sportsg-orange.css +52 -40
  191. package/theme/styles/supportgowhere.css +52 -40
  192. package/theme/styles/tote-board.css +52 -40
  193. package/theme/styles/vica.css +52 -40
  194. package/theme/styles/websg.css +52 -40
  195. package/theme/styles/wise.css +52 -40
  196. package/theme/styles/wogaa.css +52 -40
  197. package/theme/tokens/colour.d.ts +6 -0
  198. package/theme/tokens/colour.js +1 -1
  199. package/theme/tokens/colour.js.map +1 -1
  200. package/theme/tokens/radius.d.ts +3 -0
  201. package/theme/tokens/radius.js +1 -1
  202. package/theme/tokens/radius.js.map +1 -1
  203. package/breadcrumb/breadcrumb.styles_1nl4aua.css +0 -18
  204. package/cjs/breadcrumb/breadcrumb.styles_1nl4aua.css +0 -18
  205. package/cjs/file-upload/file-item-edit.js +0 -2
  206. package/cjs/file-upload/file-item-edit.js.map +0 -1
  207. package/cjs/file-upload/file-item-edit.styles.js +0 -2
  208. package/cjs/file-upload/file-item-edit.styles.js.map +0 -1
  209. package/cjs/file-upload/file-item-edit.styles_19bvztn.css +0 -11
  210. package/cjs/file-upload/file-list/file-list.styles_1w7so98.css +0 -3
  211. package/cjs/file-upload/file-list-item/file-list-item.styles_kgtfke.css +0 -17
  212. package/cjs/local-nav/local-nav-menu/local-nav-menu.styles_pq19dh.css +0 -5
  213. package/cjs/menu/menu-content.styles_p7ijll.css +0 -2
  214. package/cjs/menu/menu-link.styles_hfxoez.css +0 -2
  215. package/cjs/menu/menu-section.styles_g7my4d.css +0 -3
  216. package/file-upload/file-item-edit.d.ts +0 -14
  217. package/file-upload/file-item-edit.js +0 -2
  218. package/file-upload/file-item-edit.js.map +0 -1
  219. package/file-upload/file-item-edit.styles.d.ts +0 -9
  220. package/file-upload/file-item-edit.styles.js +0 -2
  221. package/file-upload/file-item-edit.styles.js.map +0 -1
  222. package/file-upload/file-item-edit.styles_19bvztn.css +0 -11
  223. package/file-upload/file-list/file-list.styles_1w7so98.css +0 -3
  224. package/file-upload/file-list-item/file-list-item.styles_kgtfke.css +0 -17
  225. package/local-nav/local-nav-menu/local-nav-menu.styles_pq19dh.css +0 -5
  226. package/menu/menu-content.styles_p7ijll.css +0 -2
  227. package/menu/menu-link.styles_hfxoez.css +0 -2
  228. package/menu/menu-section.styles_g7my4d.css +0 -3
@@ -1 +1 @@
1
- {"version":3,"file":"local-nav-menu.js","sources":["../../../src/local-nav/local-nav-menu/local-nav-menu.tsx"],"sourcesContent":["import clsx from \"clsx\";\nimport React from \"react\";\n\nimport { Typography } from \"../../typography\";\nimport type { LocalNavMenuItemComponentProps } from \"../internal-types\";\nimport type { LocalNavMenuProps } from \"../types\";\nimport * as styles from \"./local-nav-menu.styles\";\n\nconst Component = (\n {\n onNavItemSelect,\n items,\n selectedItemIndex,\n id,\n \"data-testid\": dataTestId,\n className,\n renderItem,\n }: LocalNavMenuProps,\n ref: React.Ref<HTMLUListElement>\n): JSX.Element => {\n // =============================================================================\n // CONST, STATE, REF\n // =============================================================================\n const localNavMenuId = dataTestId || \"local-nav-menu\";\n\n // =============================================================================\n // EVENT HANDLERS\n // ============================================================================\n const handleNavItemKeyDown = (\n e: React.KeyboardEvent<HTMLElement>,\n handleClick: (\n e: React.MouseEvent<HTMLElement> | React.KeyboardEvent<HTMLElement>\n ) => void\n ) => {\n const { key } = e;\n\n if (key === \"Enter\" || key === \" \") {\n e.preventDefault();\n handleClick(e);\n }\n };\n\n // =============================================================================\n // RENDER FUNCTIONS\n // =============================================================================\n\n const renderLocalNavItem = ({\n handleClick,\n isSelected,\n item,\n renderItem,\n index,\n }: LocalNavMenuItemComponentProps) => {\n const { id, title } = item;\n\n const renderTitle = () => {\n if (renderItem) {\n return renderItem(item, { selected: isSelected });\n }\n return (\n <Typography.BodyBL\n className={styles.textLabel}\n weight={isSelected ? \"semibold\" : \"regular\"}\n >\n {title}\n </Typography.BodyBL>\n );\n };\n\n return (\n <li\n id={id}\n key={index}\n className={clsx(\n styles.navItem,\n isSelected && styles.navItemSelected\n )}\n >\n <div\n className={styles.navItemContent}\n role=\"link\"\n onClick={handleClick}\n onKeyDown={(e) => handleNavItemKeyDown(e, handleClick)}\n tabIndex={0}\n aria-current={isSelected ? true : undefined}\n >\n {renderTitle()}\n </div>\n </li>\n );\n };\n return (\n <ul\n ref={ref}\n id={id}\n className={clsx(styles.nav, className)}\n data-testid={localNavMenuId}\n >\n {items.map((item, i) => {\n const isSelected = i === selectedItemIndex;\n return renderLocalNavItem({\n handleClick: (e) => onNavItemSelect(e, item, i),\n isSelected,\n item,\n renderItem,\n index: i,\n });\n })}\n </ul>\n );\n};\n\n// @catalog\n/**\n * A sidebar navigation list that highlights the currently selected section.\n *\n * Use `LocalNavMenu` for desktop in-page navigation where the list is always\n * visible.\n * @keywords in-page navigation, sections\n */\nexport const LocalNavMenu = React.forwardRef(Component);\n"],"names":["LocalNavMenu","React","forwardRef","onNavItemSelect","items","selectedItemIndex","id","dataTestId","className","renderItem","ref","localNavMenuId","_jsx","clsx","styles.nav","map","item","i","handleClick","isSelected","index","title","styles.navItem","styles.navItemSelected","children","styles.navItemContent","role","onClick","onKeyDown","e","key","preventDefault","handleNavItemKeyDown","tabIndex","undefined","selected","Typography","BodyBL","styles.textLabel","weight","renderLocalNavItem"],"mappings":"8PAQA,MAgHaA,EAAeC,EAAMC,YAhHhB,EAEVC,kBACAC,QACAC,oBACAC,KACA,cAAeC,EACfC,YACAC,cAEJC,KAKA,MAAMC,EAAiBJ,GAAc,iBAoErC,OACIK,EAAA,KAAA,CACIF,IAAKA,EACLJ,GAAIA,EACJE,UAAWK,EAAKC,EAAYN,GAAU,cACzBG,WAEZP,EAAMW,KAAI,CAACC,EAAMC,IApDC,GACvBC,cACAC,aACAH,OACAP,aACAW,YAEA,MAAMd,GAAEA,EAAEe,MAAEA,GAAUL,EAgBtB,OACIJ,EAAA,KAAA,CACIN,GAAIA,EAEJE,UAAWK,EACPS,EACAH,GAAcI,GACjBC,SAEDZ,EAAA,MAAA,CACIJ,UAAWiB,EACXC,KAAK,OACLC,QAAST,EACTU,UAAYC,GAtDC,EACzBA,EACAX,KAIA,MAAMY,IAAEA,GAAQD,EAEJ,UAARC,GAA2B,MAARA,IACnBD,EAAEE,iBACFb,EAAYW,GAChB,EA2C8BG,CAAqBH,EAAGX,GAC1Ce,SAAU,EAAC,iBACGd,QAAoBe,EAASV,SA5B/Cf,EACOA,EAAWO,EAAM,CAAEmB,SAAUhB,IAGpCP,EAACwB,EAAWC,OAAM,CACd7B,UAAW8B,EACXC,OAAQpB,EAAa,WAAa,UAASK,SAE1CH,OAQAD,EAgBJ,EAYMoB,CAAmB,CACtBtB,YAAcW,GAAM1B,EAAgB0B,EAAGb,EAAMC,GAC7CE,WAHeF,IAAMZ,EAIrBW,OACAP,aACAW,MAAOH,OAGd"}
1
+ {"version":3,"file":"local-nav-menu.js","sources":["../../../src/local-nav/local-nav-menu/local-nav-menu.tsx"],"sourcesContent":["import clsx from \"clsx\";\nimport React from \"react\";\n\nimport { Typography } from \"../../typography\";\nimport type { LocalNavMenuItemComponentProps } from \"../internal-types\";\nimport type { LocalNavMenuProps } from \"../types\";\nimport * as styles from \"./local-nav-menu.styles\";\n\nconst Component = (\n {\n onNavItemSelect,\n items,\n selectedItemIndex,\n id,\n \"data-testid\": dataTestId,\n className,\n renderItem,\n }: LocalNavMenuProps,\n ref: React.Ref<HTMLUListElement>\n): JSX.Element => {\n // =============================================================================\n // CONST, STATE, REF\n // =============================================================================\n const localNavMenuId = dataTestId || \"local-nav-menu\";\n\n // =============================================================================\n // EVENT HANDLERS\n // ============================================================================\n const handleNavItemKeyDown = (\n e: React.KeyboardEvent<HTMLElement>,\n handleClick: (\n e: React.MouseEvent<HTMLElement> | React.KeyboardEvent<HTMLElement>\n ) => void\n ) => {\n const { key } = e;\n\n if (key === \"Enter\" || key === \" \") {\n e.preventDefault();\n handleClick(e);\n }\n };\n\n // =============================================================================\n // RENDER FUNCTIONS\n // =============================================================================\n\n const renderLocalNavItem = ({\n handleClick,\n isSelected,\n item,\n renderItem,\n index,\n }: LocalNavMenuItemComponentProps) => {\n const { id, title, titleAddon } = item;\n\n const renderTitle = () => {\n if (renderItem) {\n return renderItem(item, { selected: isSelected });\n }\n const label = (\n <Typography.BodyBL\n className={styles.textLabel}\n weight={isSelected ? \"semibold\" : \"regular\"}\n >\n {title}\n </Typography.BodyBL>\n );\n if (!titleAddon) {\n return label;\n }\n return (\n <span className={styles.titleContainer}>\n {titleAddon.left && (\n <span className={styles.leftAddon}>\n {titleAddon.left}\n </span>\n )}\n {label}\n {titleAddon.right && (\n <span className={styles.rightAddon}>\n {titleAddon.right}\n </span>\n )}\n </span>\n );\n };\n\n return (\n <li\n id={id}\n key={index}\n className={clsx(\n styles.navItem,\n isSelected && styles.navItemSelected\n )}\n >\n <div\n className={styles.navItemContent}\n role=\"link\"\n onClick={handleClick}\n onKeyDown={(e) => handleNavItemKeyDown(e, handleClick)}\n tabIndex={0}\n aria-current={isSelected ? true : undefined}\n >\n {renderTitle()}\n </div>\n </li>\n );\n };\n return (\n <ul\n ref={ref}\n id={id}\n className={clsx(styles.nav, className)}\n data-testid={localNavMenuId}\n >\n {items.map((item, i) => {\n const isSelected = i === selectedItemIndex;\n return renderLocalNavItem({\n handleClick: (e) => onNavItemSelect(e, item, i),\n isSelected,\n item,\n renderItem,\n index: i,\n });\n })}\n </ul>\n );\n};\n\n// @catalog\n/**\n * A sidebar navigation list that highlights the currently selected section.\n *\n * Use `LocalNavMenu` for desktop in-page navigation where the list is always\n * visible.\n * @keywords in-page navigation, sections\n */\nexport const LocalNavMenu = React.forwardRef(Component);\n"],"names":["LocalNavMenu","React","forwardRef","onNavItemSelect","items","selectedItemIndex","id","dataTestId","className","renderItem","ref","localNavMenuId","_jsx","clsx","styles.nav","map","item","i","handleClick","isSelected","index","title","titleAddon","styles.navItem","styles.navItemSelected","children","styles.navItemContent","role","onClick","onKeyDown","e","key","preventDefault","handleNavItemKeyDown","tabIndex","undefined","selected","label","Typography","BodyBL","styles.textLabel","weight","_jsxs","styles.titleContainer","left","styles.leftAddon","right","styles.rightAddon","renderTitle","renderLocalNavItem"],"mappings":"2TAQA,MAkIaA,EAAeC,EAAMC,YAlIhB,EAEVC,kBACAC,QACAC,oBACAC,KACA,cAAeC,EACfC,YACAC,cAEJC,KAKA,MAAMC,EAAiBJ,GAAc,iBAsFrC,OACIK,EAAA,KAAA,CACIF,IAAKA,EACLJ,GAAIA,EACJE,UAAWK,EAAKC,EAAYN,GAAU,cACzBG,WAEZP,EAAMW,KAAI,CAACC,EAAMC,IAtEC,GACvBC,cACAC,aACAH,OACAP,aACAW,YAEA,MAAMd,GAAEA,EAAEe,MAAEA,EAAKC,WAAEA,GAAeN,EAkClC,OACIJ,EAAA,KAAA,CACIN,GAAIA,EAEJE,UAAWK,EACPU,EACAJ,GAAcK,GACjBC,SAEDb,EAAA,MAAA,CACIJ,UAAWkB,EACXC,KAAK,OACLC,QAASV,EACTW,UAAYC,GAxEC,EACzBA,EACAZ,KAIA,MAAMa,IAAEA,GAAQD,EAEJ,UAARC,GAA2B,MAARA,IACnBD,EAAEE,iBACFd,EAAYY,GAChB,EA6D8BG,CAAqBH,EAAGZ,GAC1CgB,SAAU,EAAC,iBACGf,QAAoBgB,EAASV,SA/CnC,MAChB,GAAIhB,EACA,OAAOA,EAAWO,EAAM,CAAEoB,SAAUjB,IAExC,MAAMkB,EACFzB,EAAC0B,EAAWC,OAAM,CACd/B,UAAWgC,EACXC,OAAQtB,EAAa,WAAa,UAASM,SAE1CJ,IAGT,OAAKC,EAIDoB,UAAMlC,UAAWmC,YACZrB,EAAWsB,MACRhC,UAAMJ,UAAWqC,EAAgBpB,SAC5BH,EAAWsB,OAGnBP,EACAf,EAAWwB,OACRlC,EAAA,OAAA,CAAMJ,UAAWuC,WACZzB,EAAWwB,WAZjBT,CAeA,EAqBFW,MAdA5B,EAgBJ,EAYM6B,CAAmB,CACtB/B,YAAcY,GAAM3B,EAAgB2B,EAAGd,EAAMC,GAC7CE,WAHeF,IAAMZ,EAIrBW,OACAP,aACAW,MAAOH,OAGd"}
@@ -1,5 +1,8 @@
1
1
  export declare const nav: import("@linaria/core").LinariaClassName;
2
2
  export declare const textLabel: import("@linaria/core").LinariaClassName;
3
+ export declare const titleContainer: import("@linaria/core").LinariaClassName;
4
+ export declare const leftAddon: import("@linaria/core").LinariaClassName;
5
+ export declare const rightAddon: import("@linaria/core").LinariaClassName;
3
6
  export declare const navItem: import("@linaria/core").LinariaClassName;
4
7
  export declare const navItemSelected: import("@linaria/core").LinariaClassName;
5
8
  export declare const navItemContent: import("@linaria/core").LinariaClassName;
@@ -1,2 +1,2 @@
1
- import"./local-nav-menu.styles_pq19dh.css";const n="nflnesd",a="tun9y1j",l="n1ocymwf",o="naf0oif",c="n8uzvfa";export{n as nav,l as navItem,c as navItemContent,o as navItemSelected,a as textLabel};
1
+ import"./local-nav-menu.styles_67fcyc.css";const n="nflnesd",l="tun9y1j",c="t1ocymwf",a="laf0oif",o="r8uzvfa",f="n5rg3yw",s="nduzi41",t="n1qylgc6";export{a as leftAddon,n as nav,f as navItem,t as navItemContent,s as navItemSelected,o as rightAddon,l as textLabel,c as titleContainer};
2
2
  //# sourceMappingURL=local-nav-menu.styles.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"local-nav-menu.styles.js","sources":["../../../src/local-nav/local-nav-menu/local-nav-menu.styles.ts"],"sourcesContent":["import { css } from \"@linaria/core\";\n\nimport { Colour, Radius, Spacing } from \"../../theme\";\n\nexport const nav = css`\n list-style-type: none;\n padding: 0;\n margin-top: 0;\n`;\n\nexport const textLabel = css`\n margin: 0;\n`;\n\nexport const navItem = css`\n display: block;\n position: relative;\n margin: 0;\n padding: 0;\n cursor: pointer;\n\n &::before {\n content: \"\";\n position: absolute;\n left: 0;\n width: 4px;\n height: 100%;\n top: 0;\n background-color: ${Colour[\"bg-primary-subtler\"]};\n transition: all 250ms linear;\n }\n\n &:hover,\n &:focus-within {\n background-color: ${Colour[\"bg-hover-subtle\"]};\n }\n`;\n\nexport const navItemSelected = css`\n &::before {\n background-color: ${Colour[\"bg-primary\"]};\n }\n`;\n\nexport const navItemContent = css`\n display: block;\n padding: ${Spacing[\"spacing-16\"]};\n padding-left: ${Spacing[\"spacing-20\"]};\n\n &:focus-visible {\n outline: 2px solid ${Colour[\"focus-ring\"]};\n outline-offset: 2px;\n border-radius: ${Radius[\"sm\"]};\n }\n`;\n"],"names":["nav","textLabel","navItem","navItemSelected","navItemContent"],"mappings":"mFAIO,MAAMA,EAAG,UAMHC,EAAS,UAITC,EAAO,WAwBPC,EAAe,UAMfC,EAAc"}
1
+ {"version":3,"file":"local-nav-menu.styles.js","sources":["../../../src/local-nav/local-nav-menu/local-nav-menu.styles.ts"],"sourcesContent":["import { css } from \"@linaria/core\";\n\nimport { Colour, Font, Radius, Spacing } from \"../../theme\";\n\nexport const nav = css`\n list-style-type: none;\n padding: 0;\n margin-top: 0;\n`;\n\nexport const textLabel = css`\n margin: 0;\n`;\n\nexport const titleContainer = css`\n display: flex;\n align-items: center;\n gap: ${Spacing[\"spacing-8\"]};\n width: 100%;\n`;\n\n/* Keeps the left addon aligned with the first line when the title wraps. */\nexport const leftAddon = css`\n display: inline-flex;\n align-items: center;\n align-self: flex-start;\n min-height: ${Font.Spec[\"body-lh-baseline\"]};\n`;\n\n/* Flushed right; stays vertically centred against the (possibly wrapped) title. */\nexport const rightAddon = css`\n display: inline-flex;\n align-items: center;\n margin-left: auto;\n`;\n\nexport const navItem = css`\n display: block;\n position: relative;\n margin: 0;\n padding: 0;\n cursor: pointer;\n\n &::before {\n content: \"\";\n position: absolute;\n left: 0;\n width: 4px;\n height: 100%;\n top: 0;\n background-color: ${Colour[\"bg-primary-subtler\"]};\n transition: all 250ms linear;\n }\n\n &:hover,\n &:focus-within {\n background-color: ${Colour[\"bg-hover-subtle\"]};\n }\n`;\n\nexport const navItemSelected = css`\n &::before {\n background-color: ${Colour[\"bg-primary\"]};\n }\n`;\n\nexport const navItemContent = css`\n display: block;\n padding: ${Spacing[\"spacing-16\"]};\n padding-left: ${Spacing[\"spacing-20\"]};\n\n &:focus-visible {\n outline: 2px solid ${Colour[\"focus-ring\"]};\n outline-offset: 2px;\n border-radius: ${Radius[\"sm\"]};\n }\n`;\n"],"names":["nav","textLabel","titleContainer","leftAddon","rightAddon","navItem","navItemSelected","navItemContent"],"mappings":"mFAIO,MAAMA,EAAG,UAMHC,EAAS,UAITC,EAAc,WAQdC,EAAS,UAQTC,EAAU,UAMVC,EAAO,UAwBPC,EAAe,UAMfC,EAAc"}
@@ -0,0 +1,8 @@
1
+ @layer fds{.nflnesd{list-style-type:none;padding:0;margin-top:0;}
2
+ .tun9y1j{margin:0;}
3
+ .t1ocymwf{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;gap:var(--fds-spacing-8);width:100%;}
4
+ .laf0oif{display:-webkit-inline-box;display:-webkit-inline-flex;display:-ms-inline-flexbox;display:inline-flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-align-self:flex-start;-ms-flex-item-align:start;align-self:flex-start;min-height:var(--fds-font-body-lh-baseline);}
5
+ .r8uzvfa{display:-webkit-inline-box;display:-webkit-inline-flex;display:-ms-inline-flexbox;display:inline-flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;margin-left:auto;}
6
+ .n5rg3yw{display:block;position:relative;margin:0;padding:0;cursor:pointer;}.n5rg3yw::before{content:"";position:absolute;left:0;width:4px;height:100%;top:0;background-color:var(--fds-colour-bg-primary-subtler);-webkit-transition:all 250ms linear;transition:all 250ms linear;}.n5rg3yw:hover,.n5rg3yw:focus-within{background-color:var(--fds-colour-bg-hover-subtle);}
7
+ .nduzi41::before{background-color:var(--fds-colour-bg-primary);}
8
+ .n1qylgc6{display:block;padding:var(--fds-spacing-16);padding-left:var(--fds-spacing-20);}.n1qylgc6:focus-visible{outline:2px solid var(--fds-colour-focus-ring);outline-offset:2px;border-radius:var(--fds-radius-sm);}}
@@ -1,9 +1,26 @@
1
+ /**
2
+ * Configuration for the optional addon elements displayed alongside a
3
+ * navigation item's title. Both slots may be used at the same time.
4
+ */
5
+ export interface TitleAddonProps {
6
+ /** Element rendered immediately before the title. */
7
+ left?: JSX.Element | undefined;
8
+ /** Element rendered after the title, flushed to the far right of the item. */
9
+ right?: JSX.Element | undefined;
10
+ }
1
11
  /**
2
12
  * Data for a single local navigation item.
3
13
  */
4
14
  export interface LocalNavItemProps {
5
15
  title: string | React.ReactNode;
6
16
  id?: string | undefined;
17
+ /**
18
+ * Optional addon element rendered alongside the item title.
19
+ *
20
+ * Ignored when a custom `renderItem` is provided, since the caller then
21
+ * controls the item's layout.
22
+ */
23
+ titleAddon?: TitleAddonProps | undefined;
7
24
  }
8
25
  /**
9
26
  * Base props for local navigation components.
@@ -71,8 +71,7 @@ export interface MaskedInputProps extends InputProps, MaskAttributeProps {
71
71
  */
72
72
  iconInactiveColor?: string | undefined;
73
73
  /**
74
- * When `true`, masking is permanently disabled and the raw value is
75
- * always shown. The toggle icon is not rendered.
74
+ * When `true`, the value is permanently unmasked.
76
75
  *
77
76
  * @default false
78
77
  */
@@ -1,2 +1,2 @@
1
- import{__rest as e}from"../_virtual/_tslib.js";import{jsx as t}from"react/jsx-runtime";import r from"clsx";import{useRef as o}from"react";import"../theme/theme-provider/index.js";import"../theme/theme-provider/context.js";import"../theme/tokens/border.js";import"../theme/tokens/colour.js";import"../theme/tokens/font.js";import"../theme/tokens/media-query.js";import{useApplyStyle as n}from"../theme/utils/use-apply-styles.js";import"../theme/utils/use-media-query.js";import{tokens as i,panel as s}from"./menu-content.styles.js";const m=m=>{var{children:l,className:a,"data-testid":d="menu-content",overflow:u,maxHeight:c}=m,p=e(m,["children","className","data-testid","overflow","maxHeight"]);const h=o(null);n(h,{[i.panel.maxHeight]:void 0!==c?`${c}px`:null,[i.panel.overflow]:u||null});return t("div",Object.assign({ref:h,"data-testid":d,tabIndex:-1,onKeyDown:e=>{var t;const r="ArrowDown"===e.key||"ArrowRight"===e.key,o="ArrowUp"===e.key||"ArrowLeft"===e.key;if(!r&&!o)return;const n=(e=>Array.from(e.querySelectorAll('a[href], button:not([disabled]), [tabindex]:not([tabindex="-1"])')).filter((e=>!e.hasAttribute("disabled"))))(e.currentTarget);if(!n.length)return;const i=document.activeElement,s=i?n.indexOf(i):-1;e.preventDefault();const m=r?1:-1;null===(t=n[-1===s?r?0:n.length-1:(s+m+n.length)%n.length])||void 0===t||t.focus()},className:r(s,a)},p,{children:l}))};m.displayName="Menu.Content";export{m as MenuContent};
1
+ import{__rest as e}from"../_virtual/_tslib.js";import{jsx as t}from"react/jsx-runtime";import r from"clsx";import{useRef as o,useMemo as n,Children as s,isValidElement as i}from"react";import"../theme/theme-provider/index.js";import"../theme/theme-provider/context.js";import"../theme/tokens/border.js";import"../theme/tokens/colour.js";import"../theme/tokens/font.js";import"../theme/tokens/media-query.js";import{useApplyStyle as m}from"../theme/utils/use-apply-styles.js";import"../theme/utils/use-media-query.js";import{tokens as l,panel as a}from"./menu-content.styles.js";import{GRID_COLUMN_WIDTH_PX as u,GRID_COLUMN_GAP_PX as d}from"./menu-section.styles.js";const p=p=>{var{children:c,className:h,"data-testid":f="menu-content",overflow:v,maxHeight:x}=p,y=e(p,["children","className","data-testid","overflow","maxHeight"]);const j=o(null),b=n((()=>{const e=s.toArray(c).filter((e=>i(e)&&!!e.props.columns)).reduce(((e,t)=>{var r;return Math.max(e,null!==(r=t.props.columns)&&void 0!==r?r:0)}),0);if(e)return e*u+(e-1)*d+2}),[c]);m(j,{[l.panel.maxHeight]:void 0!==x?`${x}px`:null,[l.panel.maxWidth]:void 0!==b?`${b}px`:null,[l.panel.overflow]:v||null});return t("div",Object.assign({ref:j,"data-testid":f,tabIndex:-1,onKeyDown:e=>{var t;const r="ArrowDown"===e.key||"ArrowRight"===e.key,o="ArrowUp"===e.key||"ArrowLeft"===e.key;if(!r&&!o)return;const n=(e=>Array.from(e.querySelectorAll('a[href], button:not([disabled]), [tabindex]:not([tabindex="-1"])')).filter((e=>!e.hasAttribute("disabled"))))(e.currentTarget);if(!n.length)return;const s=document.activeElement,i=s?n.indexOf(s):-1;e.preventDefault();const m=r?1:-1;null===(t=n[-1===i?r?0:n.length-1:(i+m+n.length)%n.length])||void 0===t||t.focus()},className:r(a,h)},y,{children:c}))};p.displayName="Menu.Content";export{p as MenuContent};
2
2
  //# sourceMappingURL=menu-content.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"menu-content.js","sources":["../../src/menu/menu-content.tsx"],"sourcesContent":["import clsx from \"clsx\";\nimport type React from \"react\";\nimport { useRef } from \"react\";\n\nimport { useApplyStyle } from \"../theme\";\nimport * as styles from \"./menu-content.styles\";\nimport type { MenuContentProps } from \"./types\";\n\n// =============================================================================\n// HELPERS\n// =============================================================================\nconst getFocusables = (container: HTMLElement) => {\n return Array.from(\n container.querySelectorAll<HTMLElement>(\n 'a[href], button:not([disabled]), [tabindex]:not([tabindex=\"-1\"])'\n )\n ).filter((el) => !el.hasAttribute(\"disabled\"));\n};\n\nexport const MenuContent = ({\n children,\n className,\n \"data-testid\": testId = \"menu-content\",\n overflow,\n maxHeight,\n ...otherProps\n}: MenuContentProps): JSX.Element => {\n // =============================================================================\n // CONST, STATE, REF\n // =============================================================================\n const panelRef = useRef<HTMLDivElement>(null);\n\n useApplyStyle(panelRef, {\n [styles.tokens.panel.maxHeight]:\n maxHeight !== undefined ? `${maxHeight}px` : null,\n [styles.tokens.panel.overflow]: overflow || null,\n });\n // =============================================================================\n // EVENT HANDLERS\n // =============================================================================\n const handleKeyDown = (e: React.KeyboardEvent<HTMLElement>) => {\n const isNextKey = e.key === \"ArrowDown\" || e.key === \"ArrowRight\";\n const isPrevKey = e.key === \"ArrowUp\" || e.key === \"ArrowLeft\";\n\n if (!isNextKey && !isPrevKey) return;\n\n const container = e.currentTarget as HTMLElement;\n const focusables = getFocusables(container);\n if (!focusables.length) return;\n\n const active = document.activeElement as HTMLElement | null;\n const idx = active ? focusables.indexOf(active) : -1;\n\n e.preventDefault();\n\n const delta = isNextKey ? 1 : -1;\n\n const nextIndex =\n idx === -1\n ? isNextKey\n ? 0\n : focusables.length - 1\n : (idx + delta + focusables.length) % focusables.length;\n\n focusables[nextIndex]?.focus();\n };\n // =============================================================================\n // RENDER FUNCTIONS\n // =============================================================================\n return (\n <div\n ref={panelRef}\n data-testid={testId}\n tabIndex={-1}\n onKeyDown={handleKeyDown}\n className={clsx(styles.panel, className)}\n {...otherProps}\n >\n {children}\n </div>\n );\n};\n\nMenuContent.displayName = \"Menu.Content\";\n"],"names":["MenuContent","_a","children","className","testId","overflow","maxHeight","otherProps","__rest","panelRef","useRef","useApplyStyle","styles.tokens","panel","undefined","_jsx","Object","assign","ref","tabIndex","onKeyDown","e","isNextKey","key","isPrevKey","focusables","container","Array","from","querySelectorAll","filter","el","hasAttribute","getFocusables","currentTarget","length","active","document","activeElement","idx","indexOf","preventDefault","delta","focus","clsx","styles.panel","displayName"],"mappings":"mhBAWA,MAQaA,EAAeC,IAAA,IAAAC,SACxBA,EAAQC,UACRA,EACA,cAAeC,EAAS,eAAcC,SACtCA,EAAQC,UACRA,GAASL,EACNM,EAAUC,EAAAP,EANW,+DAWxB,MAAMQ,EAAWC,EAAuB,MAExCC,EAAcF,EAAU,CACpB,CAACG,EAAcC,MAAMP,gBACHQ,IAAdR,EAA0B,GAAGA,MAAgB,KACjD,CAACM,EAAcC,MAAMR,UAAWA,GAAY,OAkChD,OACIU,EAAA,MAAAC,OAAAC,OAAA,CACIC,IAAKT,EAAQ,cACAL,EACbe,UAAU,EACVC,UAlCeC,UACnB,MAAMC,EAAsB,cAAVD,EAAEE,KAAiC,eAAVF,EAAEE,IACvCC,EAAsB,YAAVH,EAAEE,KAA+B,cAAVF,EAAEE,IAE3C,IAAKD,IAAcE,EAAW,OAE9B,MACMC,EApCQ,CAACC,GACZC,MAAMC,KACTF,EAAUG,iBACN,qEAENC,QAAQC,IAAQA,EAAGC,aAAa,cA+BXC,CADDZ,EAAEa,eAEpB,IAAKT,EAAWU,OAAQ,OAExB,MAAMC,EAASC,SAASC,cAClBC,EAAMH,EAASX,EAAWe,QAAQJ,IAAU,EAElDf,EAAEoB,iBAEF,MAAMC,EAAQpB,EAAY,GAAI,EAST,QAArBrB,EAAAwB,GANY,IAARc,EACMjB,EACI,EACAG,EAAWU,OAAS,GACvBI,EAAMG,EAAQjB,EAAWU,QAAUV,EAAWU,eAEpC,IAAAlC,GAAAA,EAAE0C,OAAO,EAW1BxC,UAAWyC,EAAKC,EAAc1C,IAC1BI,EAAU,CAAAL,SAEbA,IACC,EAIdF,EAAY8C,YAAc"}
1
+ {"version":3,"file":"menu-content.js","sources":["../../src/menu/menu-content.tsx"],"sourcesContent":["import clsx from \"clsx\";\nimport type React from \"react\";\nimport {\n Children,\n isValidElement,\n type ReactElement,\n useMemo,\n useRef,\n} from \"react\";\n\nimport { useApplyStyle } from \"../theme\";\nimport * as styles from \"./menu-content.styles\";\nimport * as sectionStyles from \"./menu-section.styles\";\nimport type { MenuContentProps, MenuSectionProps } from \"./types\";\n\n// =============================================================================\n// HELPERS\n// =============================================================================\nconst getFocusables = (container: HTMLElement) => {\n return Array.from(\n container.querySelectorAll<HTMLElement>(\n 'a[href], button:not([disabled]), [tabindex]:not([tabindex=\"-1\"])'\n )\n ).filter((el) => !el.hasAttribute(\"disabled\"));\n};\n\nexport const MenuContent = ({\n children,\n className,\n \"data-testid\": testId = \"menu-content\",\n overflow,\n maxHeight,\n ...otherProps\n}: MenuContentProps): JSX.Element => {\n // =============================================================================\n // CONST, STATE, REF\n // =============================================================================\n const panelRef = useRef<HTMLDivElement>(null);\n\n const gridMaxWidth = useMemo(() => {\n const maxColumns = Children.toArray(children)\n .filter(\n (child): child is ReactElement<MenuSectionProps> =>\n isValidElement(child) &&\n !!(child.props as MenuSectionProps).columns\n )\n .reduce((max, child) => Math.max(max, child.props.columns ?? 0), 0);\n if (!maxColumns) return undefined;\n return (\n maxColumns * sectionStyles.GRID_COLUMN_WIDTH_PX +\n (maxColumns - 1) * sectionStyles.GRID_COLUMN_GAP_PX +\n 2 // 1px border × 2 sides\n );\n }, [children]);\n\n useApplyStyle(panelRef, {\n [styles.tokens.panel.maxHeight]:\n maxHeight !== undefined ? `${maxHeight}px` : null,\n [styles.tokens.panel.maxWidth]:\n gridMaxWidth !== undefined ? `${gridMaxWidth}px` : null,\n [styles.tokens.panel.overflow]: overflow || null,\n });\n // =============================================================================\n // EVENT HANDLERS\n // =============================================================================\n const handleKeyDown = (e: React.KeyboardEvent<HTMLElement>) => {\n const isNextKey = e.key === \"ArrowDown\" || e.key === \"ArrowRight\";\n const isPrevKey = e.key === \"ArrowUp\" || e.key === \"ArrowLeft\";\n\n if (!isNextKey && !isPrevKey) return;\n\n const container = e.currentTarget as HTMLElement;\n const focusables = getFocusables(container);\n if (!focusables.length) return;\n\n const active = document.activeElement as HTMLElement | null;\n const idx = active ? focusables.indexOf(active) : -1;\n\n e.preventDefault();\n\n const delta = isNextKey ? 1 : -1;\n\n const nextIndex =\n idx === -1\n ? isNextKey\n ? 0\n : focusables.length - 1\n : (idx + delta + focusables.length) % focusables.length;\n\n focusables[nextIndex]?.focus();\n };\n // =============================================================================\n // RENDER FUNCTIONS\n // =============================================================================\n return (\n <div\n ref={panelRef}\n data-testid={testId}\n tabIndex={-1}\n onKeyDown={handleKeyDown}\n className={clsx(styles.panel, className)}\n {...otherProps}\n >\n {children}\n </div>\n );\n};\n\nMenuContent.displayName = \"Menu.Content\";\n"],"names":["MenuContent","_a","children","className","testId","overflow","maxHeight","otherProps","__rest","panelRef","useRef","gridMaxWidth","useMemo","maxColumns","Children","toArray","filter","child","isValidElement","props","columns","reduce","max","Math","sectionStyles.GRID_COLUMN_WIDTH_PX","sectionStyles.GRID_COLUMN_GAP_PX","useApplyStyle","styles.tokens","panel","undefined","maxWidth","_jsx","Object","assign","ref","tabIndex","onKeyDown","e","isNextKey","key","isPrevKey","focusables","container","Array","from","querySelectorAll","el","hasAttribute","getFocusables","currentTarget","length","active","document","activeElement","idx","indexOf","preventDefault","delta","focus","clsx","styles.panel","displayName"],"mappings":"0pBAkBA,MAQaA,EAAeC,IAAA,IAAAC,SACxBA,EAAQC,UACRA,EACA,cAAeC,EAAS,eAAcC,SACtCA,EAAQC,UACRA,GAASL,EACNM,EAAUC,EAAAP,EANW,+DAWxB,MAAMQ,EAAWC,EAAuB,MAElCC,EAAeC,GAAQ,KACzB,MAAMC,EAAaC,EAASC,QAAQb,GAC/Bc,QACIC,GACGC,EAAeD,MACZA,EAAME,MAA2BC,UAE3CC,QAAO,CAACC,EAAKL,KAAS,IAAAhB,EAAC,OAAAsB,KAAKD,IAAIA,EAAwB,QAAnBrB,EAAAgB,EAAME,MAAMC,eAAO,IAAAnB,EAAAA,EAAI,EAAE,GAAE,GACrE,GAAKY,EACL,OACIA,EAAaW,GACZX,EAAa,GAAKY,EACnB,IAEL,CAACvB,IAEJwB,EAAcjB,EAAU,CACpB,CAACkB,EAAcC,MAAMtB,gBACHuB,IAAdvB,EAA0B,GAAGA,MAAgB,KACjD,CAACqB,EAAcC,MAAME,eACAD,IAAjBlB,EAA6B,GAAGA,MAAmB,KACvD,CAACgB,EAAcC,MAAMvB,UAAWA,GAAY,OAkChD,OACI0B,EAAA,MAAAC,OAAAC,OAAA,CACIC,IAAKzB,EAAQ,cACAL,EACb+B,UAAU,EACVC,UAlCeC,UACnB,MAAMC,EAAsB,cAAVD,EAAEE,KAAiC,eAAVF,EAAEE,IACvCC,EAAsB,YAAVH,EAAEE,KAA+B,cAAVF,EAAEE,IAE3C,IAAKD,IAAcE,EAAW,OAE9B,MACMC,EAtDQ,CAACC,GACZC,MAAMC,KACTF,EAAUG,iBACN,qEAEN7B,QAAQ8B,IAAQA,EAAGC,aAAa,cAiDXC,CADDX,EAAEY,eAEpB,IAAKR,EAAWS,OAAQ,OAExB,MAAMC,EAASC,SAASC,cAClBC,EAAMH,EAASV,EAAWc,QAAQJ,IAAU,EAElDd,EAAEmB,iBAEF,MAAMC,EAAQnB,EAAY,GAAI,EAST,QAArBrC,EAAAwC,GANY,IAARa,EACMhB,EACI,EACAG,EAAWS,OAAS,GACvBI,EAAMG,EAAQhB,EAAWS,QAAUT,EAAWS,eAEpC,IAAAjD,GAAAA,EAAEyD,OAAO,EAW1BvD,UAAWwD,EAAKC,EAAczD,IAC1BI,EAAU,CAAAL,SAEbA,IACC,EAIdF,EAAY6D,YAAc"}
@@ -2,6 +2,7 @@ export declare const tokens: {
2
2
  readonly panel: {
3
3
  readonly availableWidth: "--fds-internal-menu-panel-availableWidth";
4
4
  readonly maxHeight: "--fds-internal-menu-panel-maxHeight";
5
+ readonly maxWidth: "--fds-internal-menu-panel-maxWidth";
5
6
  readonly overflow: "--fds-internal-menu-panel-overflow";
6
7
  readonly xSpacing: "--fds-internal-menu-panel-xSpacing";
7
8
  };
@@ -1,2 +1,2 @@
1
- import"./menu-content.styles_p7ijll.css";const e={panel:{maxHeight:"--fds-internal-menu-panel-maxHeight",overflow:"--fds-internal-menu-panel-overflow"}},n="pmssexq";export{n as panel,e as tokens};
1
+ import"./menu-content.styles_1r8oxtk.css";const e={panel:{maxHeight:"--fds-internal-menu-panel-maxHeight",maxWidth:"--fds-internal-menu-panel-maxWidth",overflow:"--fds-internal-menu-panel-overflow"}},n="pmssexq";export{n as panel,e as tokens};
2
2
  //# sourceMappingURL=menu-content.styles.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"menu-content.styles.js","sources":["../../src/menu/menu-content.styles.ts"],"sourcesContent":["import { css } from \"@linaria/core\";\n\nimport {\n Border,\n Breakpoint,\n Colour,\n MediaQuery,\n Radius,\n Shadow,\n} from \"../theme/tokens\";\n\nexport const tokens = {\n panel: {\n availableWidth: \"--fds-internal-menu-panel-availableWidth\",\n maxHeight: \"--fds-internal-menu-panel-maxHeight\",\n overflow: \"--fds-internal-menu-panel-overflow\",\n xSpacing: \"--fds-internal-menu-panel-xSpacing\",\n },\n} as const;\n\nexport const panel = css`\n border-radius: ${Radius[\"md\"]};\n border: ${Border[\"width-010\"]} ${Border[\"solid\"]} ${Colour[\"border\"]};\n background: ${Colour[\"bg\"]};\n box-shadow: ${Shadow[\"md-subtle\"]};\n\n ${tokens.panel.maxHeight}: initial;\n ${tokens.panel.overflow}: initial;\n ${tokens.panel.xSpacing}: 0px;\n ${tokens.panel.availableWidth}: calc(100vw - var(${tokens.panel\n .xSpacing}) * 2);\n\n ${MediaQuery.MaxWidth.sm} {\n ${tokens.panel.xSpacing}: ${Breakpoint[\"sm-margin\"]};\n }\n\n ${MediaQuery.MaxWidth.xs} {\n ${tokens.panel.xSpacing}: ${Breakpoint[\"xs-margin\"]};\n }\n\n ${MediaQuery.MaxWidth.xxs} {\n ${tokens.panel.xSpacing}: ${Breakpoint[\"xxs-margin\"]};\n }\n\n min-width: min(15rem, var(${tokens.panel.availableWidth}));\n max-width: min(24rem, var(${tokens.panel.availableWidth}));\n max-height: var(${tokens.panel.maxHeight});\n overflow-y: var(${tokens.panel.overflow});\n\n &:focus {\n outline: none;\n }\n\n &::-webkit-scrollbar {\n width: 14px;\n }\n\n &::-webkit-scrollbar-track {\n background: transparent;\n }\n\n &::-webkit-scrollbar-thumb {\n background: ${Colour[\"bg-inverse-subtlest\"]};\n border: 5px solid transparent;\n border-radius: ${Radius[\"full\"]};\n background-clip: padding-box;\n }\n`;\n"],"names":["tokens","panel","maxHeight","overflow"],"mappings":"6DAWO,MAAMA,EAAS,CAClBC,MAAO,CAEHC,UAAW,sCACXC,SAAU,uCAKLF,EAAK"}
1
+ {"version":3,"file":"menu-content.styles.js","sources":["../../src/menu/menu-content.styles.ts"],"sourcesContent":["import { css } from \"@linaria/core\";\n\nimport { scrollbarCss } from \"../shared/styles\";\nimport {\n Border,\n Breakpoint,\n Colour,\n MediaQuery,\n Radius,\n Shadow,\n} from \"../theme/tokens\";\n\nexport const tokens = {\n panel: {\n availableWidth: \"--fds-internal-menu-panel-availableWidth\",\n maxHeight: \"--fds-internal-menu-panel-maxHeight\",\n maxWidth: \"--fds-internal-menu-panel-maxWidth\",\n overflow: \"--fds-internal-menu-panel-overflow\",\n xSpacing: \"--fds-internal-menu-panel-xSpacing\",\n },\n} as const;\n\nexport const panel = css`\n border-radius: ${Radius[\"md\"]};\n border: ${Border[\"width-010\"]} ${Border[\"solid\"]} ${Colour[\"border\"]};\n background: ${Colour[\"bg\"]};\n box-shadow: ${Shadow[\"md-subtle\"]};\n\n ${tokens.panel.maxHeight}: initial;\n ${tokens.panel.maxWidth}: initial;\n ${tokens.panel.overflow}: initial;\n ${tokens.panel.xSpacing}: 0px;\n ${tokens.panel.availableWidth}: calc(100vw - var(${tokens.panel\n .xSpacing}) * 2);\n\n ${MediaQuery.MaxWidth.sm} {\n ${tokens.panel.xSpacing}: ${Breakpoint[\"sm-margin\"]};\n }\n\n ${MediaQuery.MaxWidth.xs} {\n ${tokens.panel.xSpacing}: ${Breakpoint[\"xs-margin\"]};\n }\n\n ${MediaQuery.MaxWidth.xxs} {\n ${tokens.panel.xSpacing}: ${Breakpoint[\"xxs-margin\"]};\n }\n\n min-width: min(15rem, var(${tokens.panel.availableWidth}));\n max-width: min(\n var(${tokens.panel.maxWidth}, 24rem),\n var(${tokens.panel.availableWidth})\n );\n max-height: var(${tokens.panel.maxHeight});\n overflow-y: var(${tokens.panel.overflow});\n\n &:focus {\n outline: none;\n }\n\n ${scrollbarCss(\"vertical\")}\n`;\n"],"names":["tokens","panel","maxHeight","maxWidth","overflow"],"mappings":"8DAYO,MAAMA,EAAS,CAClBC,MAAO,CAEHC,UAAW,sCACXC,SAAU,qCACVC,SAAU,uCAKLH,EAAK"}
@@ -0,0 +1,5 @@
1
+ @layer fds{.pmssexq{border-radius:var(--fds-radius-md);border:var(--fds-border-width-010) var(--fds-border-style-solid) var(--fds-colour-border);background:var(--fds-colour-bg);box-shadow:var(--fds-shadow-md-subtle);--fds-internal-menu-panel-maxHeight:initial;--fds-internal-menu-panel-maxWidth:initial;--fds-internal-menu-panel-overflow:initial;--fds-internal-menu-panel-xSpacing:0px;--fds-internal-menu-panel-availableWidth:calc(100vw - var(--fds-internal-menu-panel-xSpacing
2
+ ) * 2);min-width:min(15rem, var(--fds-internal-menu-panel-availableWidth));max-width:min(
3
+ var(--fds-internal-menu-panel-maxWidth, 24rem),
4
+ var(--fds-internal-menu-panel-availableWidth)
5
+ );max-height:var(--fds-internal-menu-panel-maxHeight);overflow-y:var(--fds-internal-menu-panel-overflow);}:where(body.fds-breakpoint-sm-max) .pmssexq{--fds-internal-menu-panel-xSpacing:var(--fds-breakpoint-margin-sm);}:where(body.fds-breakpoint-xs-max) .pmssexq{--fds-internal-menu-panel-xSpacing:var(--fds-breakpoint-margin-xs);}:where(body.fds-breakpoint-xxs-max) .pmssexq{--fds-internal-menu-panel-xSpacing:var(--fds-breakpoint-margin-xxs);}.pmssexq:focus{outline:none;}.pmssexq::-webkit-scrollbar{width:14px;}.pmssexq::-webkit-scrollbar-track{background:transparent;}.pmssexq::-webkit-scrollbar-thumb{background:var(--fds-colour-bg-inverse-subtlest);border:5px solid transparent;border-radius:var(--fds-radius-full);-webkit-background-clip:padding-box;background-clip:padding-box;}}
@@ -1,2 +1,2 @@
1
- import"./menu-item.styles_liyed8.css";const s="m1ddqpur",t="tor9xcz",e="s12tso9";export{s as menuItemDiv,e as subLabel,t as text};
1
+ import"./menu-item.styles_eut2j9.css";const t="m1ddqpur",s="tor9xcz",e="s12tso9";export{t as menuItemDiv,e as subLabel,s as text};
2
2
  //# sourceMappingURL=menu-item.styles.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"menu-item.styles.js","sources":["../../src/menu/menu-item.styles.ts"],"sourcesContent":["import { css } from \"@linaria/core\";\n\nimport { Colour, Spacing } from \"../theme/tokens\";\n\nexport const menuItemDiv = css`\n display: flex;\n flex-direction: column;\n padding: ${Spacing[\"spacing-8\"]} ${Spacing[\"spacing-16\"]};\n`;\n\nexport const text = css`\n color: ${Colour[\"text\"]};\n`;\n\nexport const subLabel = css`\n color: ${Colour[\"text-subtler\"]};\n`;\n"],"names":["menuItemDiv","text","subLabel"],"mappings":"0DAIO,MAAMA,EAAW,WAMXC,EAAI,UAIJC,EAAQ"}
1
+ {"version":3,"file":"menu-item.styles.js","sources":["../../src/menu/menu-item.styles.ts"],"sourcesContent":["import { css } from \"@linaria/core\";\n\nimport { Colour, Spacing } from \"../theme/tokens\";\n\nexport const menuItemDiv = css`\n display: flex;\n flex-direction: column;\n padding: ${Spacing[\"spacing-12\"]} ${Spacing[\"spacing-16\"]};\n`;\n\nexport const text = css`\n color: ${Colour[\"text\"]};\n`;\n\nexport const subLabel = css`\n color: ${Colour[\"text-subtler\"]};\n`;\n"],"names":["menuItemDiv","text","subLabel"],"mappings":"0DAIO,MAAMA,EAAW,WAMXC,EAAI,UAIJC,EAAQ"}
@@ -1,3 +1,3 @@
1
- @layer fds{.m1ddqpur{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;padding:var(--fds-spacing-8) var(--fds-spacing-16);}
1
+ @layer fds{.m1ddqpur{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;padding:var(--fds-spacing-12) var(--fds-spacing-16);}
2
2
  .tor9xcz{color:var(--fds-colour-text);}
3
3
  .s12tso9{color:var(--fds-colour-text-subtler);}}
@@ -1,2 +1,2 @@
1
- import"./menu-link.styles_hfxoez.css";const m="mmmrhdq",e="l5rk4za";export{e as link,m as menuLinkDiv};
1
+ import"./menu-link.styles_rng7n7.css";const m="mmmrhdq",n="l5rk4za";export{n as link,m as menuLinkDiv};
2
2
  //# sourceMappingURL=menu-link.styles.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"menu-link.styles.js","sources":["../../src/menu/menu-link.styles.ts"],"sourcesContent":["import { css } from \"@linaria/core\";\n\nimport { lineClampCss } from \"../shared/styles\";\nimport { Border, Colour, Radius, Spacing } from \"../theme/tokens\";\n\nexport const menuLinkDiv = css`\n display: flex;\n flex-direction: column;\n`;\n\nexport const link = css`\n color: ${Colour[\"text\"]};\n\n margin: 0 ${Spacing[\"spacing-8\"]};\n\n border: ${Border[\"solid\"]} transparent;\n border-width: ${Spacing[\"spacing-8\"]} ${Spacing[\"spacing-8\"]};\n\n border-radius: ${Radius[\"md\"]};\n\n ${lineClampCss(2)}\n white-space: pre-wrap;\n\n &:hover,\n &:active,\n &:focus {\n background-color: ${Colour[\"bg-hover\"]};\n color: ${Colour[\"text\"]};\n }\n\n &:focus-visible {\n outline: 2px solid ${Colour[\"focus-ring\"]};\n outline-offset: 0;\n }\n`;\n"],"names":["menuLinkDiv","link"],"mappings":"0DAKO,MAAMA,EAAW,UAKXC,EAAI"}
1
+ {"version":3,"file":"menu-link.styles.js","sources":["../../src/menu/menu-link.styles.ts"],"sourcesContent":["import { css } from \"@linaria/core\";\n\nimport { lineClampCss } from \"../shared/styles\";\nimport { Border, Colour, Radius, Spacing } from \"../theme/tokens\";\n\nexport const menuLinkDiv = css`\n display: flex;\n flex-direction: column;\n`;\n\nexport const link = css`\n color: ${Colour[\"text\"]};\n\n margin: 0 ${Spacing[\"spacing-8\"]};\n\n border: ${Border[\"solid\"]} transparent;\n border-width: ${Spacing[\"spacing-12\"]} ${Spacing[\"spacing-8\"]};\n\n border-radius: ${Radius[\"md\"]};\n\n ${lineClampCss(2)}\n white-space: pre-wrap;\n\n &:hover,\n &:active,\n &:focus {\n background-color: ${Colour[\"bg-hover\"]};\n color: ${Colour[\"text\"]};\n }\n\n &:focus-visible {\n outline: 2px solid ${Colour[\"focus-ring\"]};\n outline-offset: 0;\n }\n`;\n"],"names":["menuLinkDiv","link"],"mappings":"0DAKO,MAAMA,EAAW,UAKXC,EAAI"}
@@ -0,0 +1,2 @@
1
+ @layer fds{.mmmrhdq{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;}
2
+ .l5rk4za{color:var(--fds-colour-text);margin:0 var(--fds-spacing-8);border:var(--fds-border-style-solid) transparent;border-width:var(--fds-spacing-12) var(--fds-spacing-8);border-radius:var(--fds-radius-md);display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;white-space:pre-wrap;}.l5rk4za:hover,.l5rk4za:active,.l5rk4za:focus{background-color:var(--fds-colour-bg-hover);color:var(--fds-colour-text);}.l5rk4za:focus-visible{outline:2px solid var(--fds-colour-focus-ring);outline-offset:0;}}
@@ -1,5 +1,5 @@
1
1
  import type { MenuSectionProps } from "./types";
2
2
  export declare const MenuSection: {
3
- ({ children, label, showDivider, className, "data-testid": testId, ...otherProps }: MenuSectionProps): JSX.Element;
3
+ ({ children, label, showDivider, className, columns, "data-testid": testId, ...otherProps }: MenuSectionProps): JSX.Element;
4
4
  displayName: string;
5
5
  };
@@ -1,2 +1,2 @@
1
- import{__rest as e}from"../_virtual/_tslib.js";import{jsxs as i,jsx as r}from"react/jsx-runtime";import t from"clsx";import{Typography as a}from"../typography/index.js";import"../util/calendar-helper.js";import"../external/dayjs/dayjs.min.js";import"react";import{useId as s}from"../util/simple-id-generator.js";import"../util/string-helper.js";import"@react-aria/live-announcer";import{section as l,sectionWithDivider as o,label as m}from"./menu-section.styles.js";const n=n=>{var{children:d,label:c,showDivider:p=!0,className:j,"data-testid":u="menu-section"}=n,h=e(n,["children","label","showDivider","className","data-testid"]);const y=s();return i("ul",Object.assign({"data-testid":u,"aria-labelledby":y,className:t(l,p&&o,j)},h,{children:[c&&r(a.BodyXS,{className:m,weight:"semibold",id:y,children:c}),d]}))};n.displayName="Menu.Section";export{n as MenuSection};
1
+ import{__rest as e}from"../_virtual/_tslib.js";import{jsx as t,jsxs as i}from"react/jsx-runtime";import r from"clsx";import{useRef as s,useMemo as o,Children as m}from"react";import"../theme/theme-provider/index.js";import"../theme/theme-provider/context.js";import"../theme/tokens/border.js";import"../theme/tokens/colour.js";import"../theme/tokens/font.js";import"../theme/tokens/media-query.js";import{useApplyStyle as a}from"../theme/utils/use-apply-styles.js";import"../theme/utils/use-media-query.js";import{Typography as l}from"../typography/index.js";import"../util/calendar-helper.js";import"../external/dayjs/dayjs.min.js";import{useId as n}from"../util/simple-id-generator.js";import"../util/string-helper.js";import"@react-aria/live-announcer";import{gridTokens as d,label as p,list as c,listColumns as h,section as u,sectionWithDivider as j}from"./menu-section.styles.js";const v=v=>{var{children:y,label:f,showDivider:b=!0,className:x,columns:g,"data-testid":N="menu-section"}=v,k=e(v,["children","label","showDivider","className","columns","data-testid"]);const w=n(),M=s(null),S=o((()=>void 0!==g?Math.ceil(m.count(y)/Math.max(1,g)):void 0),[g,y]);a(M,void 0!==S?{[d.rows]:String(S)}:void 0);const q=f?t(l.BodyXS,{className:p,weight:"semibold",id:w,children:f}):null;return i("div",{className:r(u,b&&j,x),children:[q,t("ul",Object.assign({ref:M,"data-testid":N,"aria-labelledby":w,className:r(c,g&&h)},k,{children:y}))]})};v.displayName="Menu.Section";export{v as MenuSection};
2
2
  //# sourceMappingURL=menu-section.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"menu-section.js","sources":["../../src/menu/menu-section.tsx"],"sourcesContent":["import clsx from \"clsx\";\n\nimport { Typography } from \"../typography\";\nimport { useId } from \"../util\";\nimport * as styles from \"./menu-section.styles\";\nimport type { MenuSectionProps } from \"./types\";\n\nexport const MenuSection = ({\n children,\n label,\n showDivider = true,\n className,\n \"data-testid\": testId = \"menu-section\",\n ...otherProps\n}: MenuSectionProps): JSX.Element => {\n // =============================================================================\n // CONST, STATE, REF\n // =============================================================================\n const internalId = useId();\n\n // =============================================================================\n // RENDER FUNCTIONS\n // =============================================================================\n return (\n <ul\n data-testid={testId}\n aria-labelledby={internalId}\n className={clsx(\n styles.section,\n showDivider && styles.sectionWithDivider,\n className\n )}\n {...otherProps}\n >\n {label && (\n <Typography.BodyXS\n className={styles.label}\n weight=\"semibold\"\n id={internalId}\n >\n {label}\n </Typography.BodyXS>\n )}\n {children}\n </ul>\n );\n};\n\nMenuSection.displayName = \"Menu.Section\";\n"],"names":["MenuSection","_a","children","label","showDivider","className","testId","otherProps","__rest","internalId","useId","_jsxs","Object","assign","clsx","styles.section","styles.sectionWithDivider","_jsx","Typography","BodyXS","styles.label","weight","id","displayName"],"mappings":"kdAOO,MAAMA,EAAeC,QAAAC,SACxBA,EAAQC,MACRA,EAAKC,YACLA,GAAc,EAAIC,UAClBA,EACA,cAAeC,EAAS,gBAAcL,EACnCM,EAAUC,EAAAP,EANW,8DAWxB,MAAMQ,EAAaC,IAKnB,OACIC,EAAA,KAAAC,OAAAC,OAAA,CAAA,cACiBP,EAAM,kBACFG,EACjBJ,UAAWS,EACPC,EACAX,GAAeY,EACfX,IAEAE,EAAU,CAAAL,SAAA,CAEbC,GACGc,EAACC,EAAWC,OAAM,CACdd,UAAWe,EACXC,OAAO,WACPC,GAAIb,EAAUP,SAEbC,IAGRD,KACA,EAIbF,EAAYuB,YAAc"}
1
+ {"version":3,"file":"menu-section.js","sources":["../../src/menu/menu-section.tsx"],"sourcesContent":["import clsx from \"clsx\";\nimport { Children, useMemo, useRef } from \"react\";\n\nimport { useApplyStyle } from \"../theme\";\nimport { Typography } from \"../typography\";\nimport { useId } from \"../util\";\nimport * as styles from \"./menu-section.styles\";\nimport type { MenuSectionProps } from \"./types\";\n\nexport const MenuSection = ({\n children,\n label,\n showDivider = true,\n className,\n columns,\n \"data-testid\": testId = \"menu-section\",\n ...otherProps\n}: MenuSectionProps): JSX.Element => {\n // =============================================================================\n // CONST, STATE, REF\n // =============================================================================\n const internalId = useId();\n const ulRef = useRef<HTMLUListElement>(null);\n const gridRows = useMemo(\n () =>\n columns !== undefined\n ? Math.ceil(Children.count(children) / Math.max(1, columns))\n : undefined,\n [columns, children]\n );\n\n // =========================================================================\n // EFFECTS\n // =========================================================================\n useApplyStyle(\n ulRef,\n gridRows !== undefined\n ? { [styles.gridTokens.rows]: String(gridRows) }\n : undefined\n );\n\n // =============================================================================\n // RENDER FUNCTIONS\n // =============================================================================\n const labelElement = label ? (\n <Typography.BodyXS\n className={styles.label}\n weight=\"semibold\"\n id={internalId}\n >\n {label}\n </Typography.BodyXS>\n ) : null;\n\n return (\n <div\n className={clsx(\n styles.section,\n showDivider && styles.sectionWithDivider,\n className\n )}\n >\n {labelElement}\n <ul\n ref={ulRef}\n data-testid={testId}\n aria-labelledby={internalId}\n className={clsx(styles.list, columns && styles.listColumns)}\n {...otherProps}\n >\n {children}\n </ul>\n </div>\n );\n};\n\nMenuSection.displayName = \"Menu.Section\";\n"],"names":["MenuSection","_a","children","label","showDivider","className","columns","testId","otherProps","__rest","internalId","useId","ulRef","useRef","gridRows","useMemo","undefined","Math","ceil","Children","count","max","useApplyStyle","styles.gridTokens","rows","String","labelElement","_jsx","Typography","BodyXS","styles.label","weight","id","_jsxs","clsx","styles.section","styles.sectionWithDivider","Object","assign","ref","styles.list","styles.listColumns","displayName"],"mappings":"q3BASO,MAAMA,EAAeC,QAAAC,SACxBA,QACAC,EAAKC,YACLA,GAAc,EAAIC,UAClBA,EAASC,QACTA,EACA,cAAeC,EAAS,kBACrBC,EAAUC,EAAAR,EAPW,CAAA,WAAA,QAAA,cAAA,YAAA,UAAA,gBAYxB,MAAMS,EAAaC,IACbC,EAAQC,EAAyB,MACjCC,EAAWC,GACb,SACgBC,IAAZV,EACMW,KAAKC,KAAKC,EAASC,MAAMlB,GAAYe,KAAKI,IAAI,EAAGf,SACjDU,GACV,CAACV,EAASJ,IAMdoB,EACIV,OACaI,IAAbF,EACM,CAAE,CAACS,EAAkBC,MAAOC,OAAOX,SACnCE,GAMV,MAAMU,EAAevB,EACjBwB,EAACC,EAAWC,OAAM,CACdxB,UAAWyB,EACXC,OAAO,WACPC,GAAItB,EAAUR,SAEbC,IAEL,KAEJ,OACI8B,SACI5B,UAAW6B,EACPC,EACA/B,GAAegC,EACf/B,aAGHqB,EACDC,EAAA,KAAAU,OAAAC,OAAA,CACIC,IAAK3B,gBACQL,EAAM,kBACFG,EACjBL,UAAW6B,EAAKM,EAAalC,GAAWmC,IACpCjC,YAEHN,OAEH,EAIdF,EAAY0C,YAAc"}
@@ -1,3 +1,10 @@
1
+ export declare const gridTokens: {
2
+ readonly rows: "--fds-menu-section-grid-rows";
3
+ };
4
+ export declare const GRID_COLUMN_WIDTH_PX = 383;
5
+ export declare const GRID_COLUMN_GAP_PX = 8;
1
6
  export declare const section: import("@linaria/core").LinariaClassName;
2
7
  export declare const sectionWithDivider: import("@linaria/core").LinariaClassName;
3
8
  export declare const label: import("@linaria/core").LinariaClassName;
9
+ export declare const list: import("@linaria/core").LinariaClassName;
10
+ export declare const listColumns: import("@linaria/core").LinariaClassName;
@@ -1,2 +1,2 @@
1
- import"./menu-section.styles_g7my4d.css";const s="s1fmxqsy",t="s1o971t2",e="llhca5j";export{e as label,s as section,t as sectionWithDivider};
1
+ import"./menu-section.styles_1n0ppxl.css";const s={rows:"--fds-menu-section-grid-rows"},o=383,e=8,l="s1fmxqsy",n="s1o971t2",t="llhca5j",c="l7qikvl",i="l6d0215";export{e as GRID_COLUMN_GAP_PX,o as GRID_COLUMN_WIDTH_PX,s as gridTokens,t as label,c as list,i as listColumns,l as section,n as sectionWithDivider};
2
2
  //# sourceMappingURL=menu-section.styles.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"menu-section.styles.js","sources":["../../src/menu/menu-section.styles.ts"],"sourcesContent":["import { css } from \"@linaria/core\";\n\nimport { Border, Colour, Spacing } from \"../theme/tokens\";\n\nexport const section = css`\n padding: ${Spacing[\"spacing-8\"]} 0;\n margin: 0;\n list-style: none;\n`;\nexport const sectionWithDivider = css`\n border-top: ${Border[\"width-010\"]} ${Border[\"solid\"]} ${Colour[\"border\"]};\n`;\n\nexport const label = css`\n margin: 0 ${Spacing[\"spacing-16\"]} ${Spacing[\"spacing-8\"]};\n color: ${Colour[\"text-subtler\"]};\n`;\n"],"names":["section","sectionWithDivider","label"],"mappings":"6DAIO,MAAMA,EAAO,WAKPC,EAAkB,WAIlBC,EAAK"}
1
+ {"version":3,"file":"menu-section.styles.js","sources":["../../src/menu/menu-section.styles.ts"],"sourcesContent":["import { css } from \"@linaria/core\";\n\nimport { Border, Colour, MediaQuery, Spacing } from \"../theme/tokens\";\n\nexport const gridTokens = {\n rows: \"--fds-menu-section-grid-rows\",\n} as const;\n\n// 367px max content width (Figma) + 8px padding per side; used to cap the panel maxWidth in MenuContent\nexport const GRID_COLUMN_WIDTH_PX = 383;\n// matches Spacing[\"spacing-8\"]\nexport const GRID_COLUMN_GAP_PX = 8;\n\nexport const section = css`\n padding: ${Spacing[\"spacing-8\"]} 0;\n margin: 0;\n`;\n\nexport const sectionWithDivider = css`\n border-top: ${Border[\"width-010\"]} ${Border[\"solid\"]} ${Colour[\"border\"]};\n`;\n\nexport const label = css`\n margin: 0 ${Spacing[\"spacing-16\"]} ${Spacing[\"spacing-8\"]};\n color: ${Colour[\"text-subtler\"]};\n`;\n\nexport const list = css`\n list-style: none;\n`;\n\nexport const listColumns = css`\n ${gridTokens.rows}: initial;\n\n display: grid;\n grid-template-rows: repeat(var(${gridTokens.rows}), auto);\n grid-auto-flow: column;\n grid-auto-columns: minmax(0, 1fr);\n column-gap: ${Spacing[\"spacing-8\"]};\n\n ${MediaQuery.MaxWidth.lg} {\n grid-template-rows: none;\n grid-auto-flow: row;\n }\n`;\n"],"names":["gridTokens","rows","GRID_COLUMN_WIDTH_PX","GRID_COLUMN_GAP_PX","section","sectionWithDivider","label","list","listColumns"],"mappings":"8DAIO,MAAMA,EAAa,CACtBC,KAAM,gCAIGC,EAAuB,IAEvBC,EAAqB,EAErBC,EAAO,WAKPC,EAAkB,WAIlBC,EAAK,UAKLC,EAAI,UAIJC,EAAW"}
@@ -0,0 +1,5 @@
1
+ @layer fds{.s1fmxqsy{padding:var(--fds-spacing-8) 0;margin:0;}
2
+ .s1o971t2{border-top:var(--fds-border-width-010) var(--fds-border-style-solid) var(--fds-colour-border);}
3
+ .llhca5j{margin:0 var(--fds-spacing-16) var(--fds-spacing-8);color:var(--fds-colour-text-subtler);}
4
+ .l7qikvl{list-style:none;}
5
+ .l6d0215{--fds-menu-section-grid-rows:initial;display:-ms-grid;display:grid;-ms-grid-rows:repeat(var(--fds-menu-section-grid-rows), auto);grid-template-rows:repeat(var(--fds-menu-section-grid-rows), auto);-ms-grid-auto-flow:column;grid-auto-flow:column;-ms-grid-auto-columns:minmax(0, 1fr);grid-auto-columns:minmax(0, 1fr);-webkit-column-gap:var(--fds-spacing-8);column-gap:var(--fds-spacing-8);}:where(body.fds-breakpoint-lg-max) .l6d0215{-ms-grid-rows:none;grid-template-rows:none;-ms-grid-auto-flow:row;grid-auto-flow:row;}}
package/menu/menu.d.ts CHANGED
@@ -38,7 +38,7 @@ export declare const Menu: (({ children, position, menuContent, "data-testid": t
38
38
  };
39
39
  /** Groups related menu entries. */
40
40
  Section: {
41
- ({ children, label, showDivider, className, "data-testid": testId, ...otherProps }: import("./types").MenuSectionProps): JSX.Element;
41
+ ({ children, label, showDivider, className, columns, "data-testid": testId, ...otherProps }: import("./types").MenuSectionProps): JSX.Element;
42
42
  displayName: string;
43
43
  };
44
44
  };
package/menu/types.d.ts CHANGED
@@ -2,7 +2,6 @@ import type { AnchorHTMLAttributes, FunctionComponentElement, HTMLAttributes, Re
2
2
  import type { PopoverPosition, PopoverRenderProps, PopoverTriggerProps } from "../popover";
3
3
  import type { MenuItem } from "./menu-item";
4
4
  import type { MenuLink } from "./menu-link";
5
- import type { MenuSection } from "./menu-section";
6
5
  /**
7
6
  * Props for the `Menu` component.
8
7
  *
@@ -24,7 +23,7 @@ export interface MenuProps extends Omit<PopoverTriggerProps, "popoverContent"> {
24
23
  */
25
24
  export interface MenuContentProps extends HTMLAttributes<HTMLDivElement>, PopoverRenderProps {
26
25
  /** One or more `Menu.Section` elements that make up the panel body. */
27
- children: ReactElement<typeof MenuSection> | ReactElement<typeof MenuSection>[];
26
+ children: ReactElement<MenuSectionProps> | ReactElement<MenuSectionProps>[];
28
27
  "data-testid"?: string | undefined;
29
28
  }
30
29
  type MenuSectionItem = ReactElement<typeof MenuItem> | ReactElement<typeof MenuLink>;
@@ -40,6 +39,15 @@ export interface MenuSectionProps extends HTMLAttributes<HTMLUListElement> {
40
39
  * @default true
41
40
  */
42
41
  showDivider?: boolean | undefined;
42
+ /**
43
+ * Renders section children in a grid with the given number of columns
44
+ * on desktop. Items flow vertically (top-to-bottom) within each column
45
+ * before wrapping to the next. Has no effect on mobile viewports, which
46
+ * always render as a single column.
47
+ *
48
+ * @minimum 1
49
+ */
50
+ columns?: number | undefined;
43
51
  /**
44
52
  * Accessible group label rendered above the section items.
45
53
  */
@@ -1,2 +1,2 @@
1
- import{__rest as e}from"../_virtual/_tslib.js";import{jsx as n,Fragment as i,jsxs as r}from"react/jsx-runtime";import{ChevronUpIcon as t}from"@lifesg/react-icons/chevron-up";import l from"clsx";import{useState as a,useRef as s,useEffect as o}from"react";import{Menu as c}from"../menu/menu.js";import{ClickableIcon as d}from"../shared/clickable-icon/clickable-icon.js";import"../util/calendar-helper.js";import"../external/dayjs/dayjs.min.js";import{useId as m}from"../util/simple-id-generator.js";import"../util/string-helper.js";import"@react-aria/live-announcer";import{Menu as u}from"./menu.js";import{mobileWrapper as p,wrapper as h,wrapperAlignLeft as b,link as v,linkSelected as f,linkItem as g,linkItemHiddenBranding as j,linkWeightRegular as N,linkWeightSemibold as k,linkWeightBold as x,linkLabel as I,linkButton as $,chevronIcon as C,chevronIconDesktop as y,chevronIconSelected as M,subMenuExpanded as O,linkIndicator as _,linkIndicatorSelected as L,linkIconContainer as P,expandCollapseButton as w}from"./navbar-items.styles.js";const E=({items:E,selectedId:D,mobile:T=!1,hideNavBranding:A,hideLinkIndicator:B=!1,onItemClick:F})=>{const[H,S]=a(null),q=s(null),z=m(),G=e=>{var n;return!!(null===(n=e.subMenu)||void 0===n?void 0:n.some((e=>e.id===D)))},J=T?E.findIndex((e=>"component"!==e.itemType&&G(e))):-1,K=J<0?null:J;o((()=>{T&&S(K)}),[T,K]),o((()=>{if(T)return;const e=e=>{q.current&&!q.current.contains(e.target)&&S(null)};return document.addEventListener("click",e,!0),()=>{document.removeEventListener("click",e,!0)}}),[T]);const Q=(e,n)=>i=>{i.stopPropagation(),T&&S((i=>{var r;return(null===(r=e.subMenu)||void 0===r?void 0:r.length)&&i!==n?n:null})),F(i,e)},R=(e,n)=>{e.stopPropagation(),F(e,n)},U=(e,i)=>n(c.Content,{id:i,children:n(c.Section,{showDivider:!1,children:e.map(((e,i)=>n(c.Link,{href:e.href,children:e.children},`${e.id}-${i}`)))})}),V=e=>n(u,{items:e,selectedId:D,onItemClick:R}),W=(a,s)=>{const{children:o,options:m,subMenu:u}=a,p=e(a,["children","options","subMenu"]),h=!!(null==u?void 0:u.length),b=(e=>e.id===D||G(e))(a),F=!T&&h&&H===s,q=T&&h&&H===s,J=F||q,K=T||null===H?b:H===s,R=!B&&K,W=T?`link__mobile-${s+1}`:`link__${s+1}`,X=()=>R?n("div",{"data-testid":`${W}-indicator`,className:l(_,K&&L)}):null,Y=l(v,(e=>{switch(e){case"bold":return x;case"semibold":return k;default:return N}})(K?T?"bold":"semibold":"regular"),K&&f);return n("li",{className:l(g,A&&j),children:h?(e=>{const v=`navbar-submenu-${z}-${a.id}`;return T?r(i,{children:[r("a",Object.assign({"data-testid":W,className:Y},p,{"aria-current":b?"page":void 0,"aria-haspopup":"menu","aria-expanded":J,onClick:Q(a,s)},m,{children:[n("div",{className:I,children:o}),X(),T&&h?n("div",{className:P,children:n(d,{"data-testid":`${W}-expand-collapse-button`,className:l(w,q&&O),focusHighlight:!1,focusOutline:"browser","aria-label":q?"Collapse":"Expand",children:n(t,{className:l(C,K&&M)})})}):null]})),q&&V(u)]}):n(c,{position:e?"bottom-end":"bottom",customOffset:0,menuContent:U(u,v),triggerOnFocus:!0,isModal:!1,onPopoverAppear:()=>{S(s)},onPopoverDismiss:()=>{S((e=>e===s?null:e))},children:r("button",Object.assign({type:"button",tabIndex:0,"data-testid":W,className:l(Y,$),"aria-haspopup":"menu","aria-expanded":J},m,{children:[n("div",{className:I,children:o}),X(),n(t,{className:l(C,y,K&&M,F&&O)})]}))})})(s===E.length-1):r("a",Object.assign({tabIndex:0,"data-testid":W,className:Y},p,{"aria-current":b?"page":void 0,onClick:Q(a,s)},m,{children:[n("div",{className:I,children:o}),X()]}))},s)},X=()=>E.map(((e,i)=>{var r;return"component"===e.itemType?n("li",{children:null!==(r=e.children)&&void 0!==r?r:null},i):W(e,i)}));return E&&E.length>0?n("ul",T?{ref:q,className:p,children:X()}:{ref:q,className:l(h,A&&b),children:X()}):n(i,{})};export{E as NavbarItems};
1
+ import{__rest as e}from"../_virtual/_tslib.js";import{jsx as n,Fragment as i,jsxs as r}from"react/jsx-runtime";import{ChevronUpIcon as t}from"@lifesg/react-icons/chevron-up";import l from"clsx";import{useState as a,useRef as s,useEffect as o}from"react";import{Menu as c}from"../menu/menu.js";import{ClickableIcon as d}from"../shared/clickable-icon/clickable-icon.js";import"../util/calendar-helper.js";import"../external/dayjs/dayjs.min.js";import{useId as u}from"../util/simple-id-generator.js";import"../util/string-helper.js";import"@react-aria/live-announcer";import{Menu as m}from"./menu.js";import{mobileWrapper as p,wrapper as h,wrapperAlignLeft as b,link as v,linkSelected as f,linkItem as g,linkItemHiddenBranding as j,linkWeightRegular as N,linkWeightSemibold as k,linkWeightBold as x,linkLabel as C,linkButton as I,chevronIcon as M,chevronIconDesktop as $,chevronIconSelected as y,subMenuExpanded as O,linkIndicator as _,linkIndicatorSelected as L,linkIconContainer as P,expandCollapseButton as w}from"./navbar-items.styles.js";const E=({items:E,selectedId:D,mobile:T=!1,hideNavBranding:z,hideLinkIndicator:A=!1,onItemClick:B})=>{const[F,H]=a(null),R=s(null),S=u(),q=e=>{var n;return!!(null===(n=e.subMenu)||void 0===n?void 0:n.some((e=>e.id===D)))},G=T?E.findIndex((e=>"component"!==e.itemType&&q(e))):-1,J=G<0?null:G;o((()=>{T&&H(J)}),[T,J]),o((()=>{if(T)return;const e=e=>{R.current&&!R.current.contains(e.target)&&H(null)};return document.addEventListener("click",e,!0),()=>{document.removeEventListener("click",e,!0)}}),[T]);const K=(e,n)=>i=>{i.stopPropagation(),T&&H((i=>{var r;return(null===(r=e.subMenu)||void 0===r?void 0:r.length)&&i!==n?n:null})),B(i,e)},Q=(e,n)=>{e.stopPropagation(),B(e,n)},U=(e,i,r)=>n(c.Content,{id:i,children:n(c.Section,{showDivider:!1,columns:r,children:e.map(((e,i)=>n(c.Link,{href:e.href,children:e.children},`${e.id}-${i}`)))})}),V=e=>n(m,{items:e,selectedId:D,onItemClick:Q}),W=(a,s)=>{const{children:o,options:u,subMenu:m,subMenuColumns:p}=a,h=e(a,["children","options","subMenu","subMenuColumns"]),b=!!(null==m?void 0:m.length),B=(e=>e.id===D||q(e))(a),R=!T&&b&&F===s,G=T&&b&&F===s,J=R||G,Q=T||null===F?B:F===s,W=!A&&Q,X=T?`link__mobile-${s+1}`:`link__${s+1}`,Y=()=>W?n("div",{"data-testid":`${X}-indicator`,className:l(_,Q&&L)}):null,Z=l(v,(e=>{switch(e){case"bold":return x;case"semibold":return k;default:return N}})(Q?T?"bold":"semibold":"regular"),Q&&f);return n("li",{className:l(g,z&&j),children:b?(e=>{const v=`navbar-submenu-${S}-${a.id}`;return T?r(i,{children:[r("a",Object.assign({"data-testid":X,className:Z},h,{"aria-current":B?"page":void 0,"aria-haspopup":"menu","aria-expanded":J,onClick:K(a,s)},u,{children:[n("div",{className:C,children:o}),Y(),T&&b?n("div",{className:P,children:n(d,{"data-testid":`${X}-expand-collapse-button`,className:l(w,G&&O),focusHighlight:!1,focusOutline:"browser","aria-label":G?"Collapse":"Expand",children:n(t,{className:l(M,Q&&y)})})}):null]})),G&&V(m)]}):n(c,{position:e?"bottom-end":"bottom",customOffset:0,menuContent:U(m,v,p),enableResize:!0,triggerOnFocus:!0,isModal:!1,onPopoverAppear:()=>{H(s)},onPopoverDismiss:()=>{H((e=>e===s?null:e))},children:r("button",Object.assign({type:"button",tabIndex:0,"data-testid":X,className:l(Z,I),"aria-haspopup":"menu","aria-expanded":J},u,{children:[n("div",{className:C,children:o}),Y(),n(t,{className:l(M,$,Q&&y,R&&O)})]}))})})(s===E.length-1):r("a",Object.assign({tabIndex:0,"data-testid":X,className:Z},h,{"aria-current":B?"page":void 0,onClick:K(a,s)},u,{children:[n("div",{className:C,children:o}),Y()]}))},s)},X=()=>E.map(((e,i)=>{var r;return"component"===e.itemType?n("li",{children:null!==(r=e.children)&&void 0!==r?r:null},i):W(e,i)}));return E&&E.length>0?n("ul",T?{ref:R,className:p,children:X()}:{ref:R,className:l(h,z&&b),children:X()}):n(i,{})};export{E as NavbarItems};
2
2
  //# sourceMappingURL=navbar-items.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"navbar-items.js","sources":["../../src/navbar/navbar-items.tsx"],"sourcesContent":["import { ChevronUpIcon } from \"@lifesg/react-icons/chevron-up\";\nimport clsx from \"clsx\";\nimport type React from \"react\";\nimport { useEffect, useRef, useState } from \"react\";\n\nimport { Menu as DesktopMenu } from \"../menu\";\nimport { ClickableIcon } from \"../shared/clickable-icon\";\nimport type { TypographyWeight } from \"../typography\";\nimport { useId } from \"../util\";\nimport { Menu as MobileMenu } from \"./menu\";\nimport * as styles from \"./navbar-items.styles\";\nimport type {\n NavItemCommonProps,\n NavItemLinkProps,\n NavItemProps,\n} from \"./types\";\n\nconst getLinkWeightClass = (weight: TypographyWeight) => {\n switch (weight) {\n case \"bold\":\n return styles.linkWeightBold;\n case \"semibold\":\n return styles.linkWeightSemibold;\n case \"regular\":\n default:\n return styles.linkWeightRegular;\n }\n};\n\ninterface Props<T> {\n items: NavItemProps<T>[];\n selectedId?: string | undefined;\n /** toggle for mobile or desktop view */\n mobile?: boolean | undefined;\n hideNavBranding?: boolean | undefined;\n /** hide the selected LinkIndicator */\n hideLinkIndicator?: boolean | undefined;\n onItemClick: (\n event: React.MouseEvent<HTMLAnchorElement>,\n item: NavItemProps<T> | NavItemCommonProps<T>\n ) => void;\n}\n\nexport const NavbarItems = <T,>({\n items,\n selectedId,\n mobile = false,\n hideNavBranding,\n hideLinkIndicator = false,\n onItemClick,\n}: Props<T>): JSX.Element => {\n // =============================================================================\n // CONST, STATE, REFS\n // =============================================================================\n const [selectedIndex, setSelectedIndex] = useState<number | null>(null);\n const listRef = useRef<HTMLUListElement>(null);\n const instanceId = useId();\n\n // =============================================================================\n // HELPERS\n // =============================================================================\n const hasSelectedSubMenuItem = (item: NavItemLinkProps<T>): boolean =>\n !!item.subMenu?.some((subItem) => subItem.id === selectedId);\n\n const checkSelected = (item: NavItemLinkProps<T>): boolean =>\n item.id === selectedId || hasSelectedSubMenuItem(item);\n\n const itemIndexWithSelectedSubItem = mobile\n ? items.findIndex(\n (item) =>\n item.itemType !== \"component\" &&\n hasSelectedSubMenuItem(item as NavItemLinkProps<T>)\n )\n : -1;\n const initialExpandedItemIndex =\n itemIndexWithSelectedSubItem < 0 ? null : itemIndexWithSelectedSubItem;\n\n // =========================================================================\n // EFFECTS\n // =========================================================================\n\n useEffect(() => {\n if (!mobile) return;\n\n setSelectedIndex(initialExpandedItemIndex);\n }, [mobile, initialExpandedItemIndex]);\n\n useEffect(() => {\n if (mobile) return;\n\n const handleClickOutside = (event: MouseEvent) => {\n if (\n listRef.current &&\n !listRef.current.contains(event.target as Node)\n ) {\n setSelectedIndex(null);\n }\n };\n document.addEventListener(\"click\", handleClickOutside, true);\n return () => {\n document.removeEventListener(\"click\", handleClickOutside, true);\n };\n }, [mobile]);\n\n // =============================================================================\n // EVENT HANDLERS\n // =============================================================================\n const handleLinkClick = (item: NavItemLinkProps<T>, index: number) => {\n return (event: React.MouseEvent<HTMLAnchorElement>) => {\n event.stopPropagation();\n\n // mobile expands inline when link has submenu\n if (mobile) {\n setSelectedIndex((prev) =>\n item.subMenu?.length && prev !== index ? index : null\n );\n }\n\n onItemClick(event, item);\n };\n };\n\n const handleMobileSubLinkClick = (\n event: React.MouseEvent<HTMLAnchorElement>,\n item: NavItemCommonProps<T>\n ) => {\n event.stopPropagation();\n onItemClick(event, item);\n };\n\n // =============================================================================\n // RENDER FUNCTIONS\n // =============================================================================\n const renderDesktopSubMenu = (\n subMenu: NavItemCommonProps<T>[],\n subMenuId: string\n ) => (\n <DesktopMenu.Content id={subMenuId}>\n <DesktopMenu.Section showDivider={false}>\n {subMenu.map((item, subIndex) => (\n <DesktopMenu.Link\n key={`${item.id}-${subIndex}`}\n href={item.href}\n >\n {item.children}\n </DesktopMenu.Link>\n ))}\n </DesktopMenu.Section>\n </DesktopMenu.Content>\n );\n\n const renderMobileSubMenu = (subMenu: NavItemCommonProps<T>[]) => (\n <MobileMenu\n items={subMenu}\n selectedId={selectedId}\n onItemClick={handleMobileSubLinkClick}\n />\n );\n\n const renderLinkItem = (item: NavItemLinkProps<T>, index: number) => {\n const { children, options, subMenu, ...otherItemAttrs } = item;\n\n const hasSubMenu = !!subMenu?.length;\n\n const isRouteSelected = checkSelected(item);\n\n // desktop popover open state\n const isDesktopExpanded =\n !mobile && hasSubMenu && selectedIndex === index;\n\n // mobile inline expanded state\n const isMobileExpanded =\n mobile && hasSubMenu && selectedIndex === index;\n\n const isExpanded = isDesktopExpanded || isMobileExpanded;\n\n const selected =\n !mobile && selectedIndex !== null\n ? selectedIndex === index\n : isRouteSelected;\n\n const showIndicator = !hideLinkIndicator && selected;\n\n const textWeight: TypographyWeight = selected\n ? mobile\n ? \"bold\"\n : \"semibold\"\n : \"regular\";\n\n const testId = mobile\n ? `link__mobile-${index + 1}`\n : `link__${index + 1}`;\n\n const renderIndicator = () =>\n showIndicator ? (\n <div\n data-testid={`${testId}-indicator`}\n className={clsx(\n styles.linkIndicator,\n selected && styles.linkIndicatorSelected\n )}\n />\n ) : null;\n\n const renderMobileChevron = () =>\n mobile && hasSubMenu ? (\n <div className={styles.linkIconContainer}>\n <ClickableIcon\n data-testid={`${testId}-expand-collapse-button`}\n className={clsx(\n styles.expandCollapseButton,\n isMobileExpanded && styles.subMenuExpanded\n )}\n focusHighlight={false}\n focusOutline=\"browser\"\n aria-label={isMobileExpanded ? \"Collapse\" : \"Expand\"}\n >\n <ChevronUpIcon\n className={clsx(\n styles.chevronIcon,\n selected && styles.chevronIconSelected\n )}\n />\n </ClickableIcon>\n </div>\n ) : null;\n\n const linkClassName = clsx(\n styles.link,\n getLinkWeightClass(textWeight),\n selected && styles.linkSelected\n );\n\n const renderLink = () => (\n <a\n tabIndex={0}\n data-testid={testId}\n className={linkClassName}\n {...otherItemAttrs}\n aria-current={isRouteSelected ? \"page\" : undefined}\n onClick={handleLinkClick(item, index)}\n {...options}\n >\n <div className={styles.linkLabel}>{children}</div>\n {renderIndicator()}\n </a>\n );\n\n const renderLinkWithSubmenu = (isLastItem: boolean) => {\n const subMenuId = `navbar-submenu-${instanceId}-${item.id}`;\n\n if (mobile) {\n return (\n <>\n <a\n data-testid={testId}\n className={linkClassName}\n {...otherItemAttrs}\n aria-current={isRouteSelected ? \"page\" : undefined}\n aria-haspopup=\"menu\"\n aria-expanded={isExpanded}\n onClick={handleLinkClick(item, index)}\n {...options}\n >\n <div className={styles.linkLabel}>{children}</div>\n {renderIndicator()}\n {renderMobileChevron()}\n </a>\n\n {isMobileExpanded && renderMobileSubMenu(subMenu!)}\n </>\n );\n }\n\n return (\n <DesktopMenu\n position={isLastItem ? \"bottom-end\" : \"bottom\"}\n customOffset={0}\n menuContent={renderDesktopSubMenu(subMenu!, subMenuId)}\n triggerOnFocus\n isModal={false}\n onPopoverAppear={() => {\n setSelectedIndex(index);\n }}\n onPopoverDismiss={() => {\n setSelectedIndex((prev) =>\n prev === index ? null : prev\n );\n }}\n >\n <button\n type=\"button\"\n tabIndex={0}\n data-testid={testId}\n className={clsx(linkClassName, styles.linkButton)}\n aria-haspopup=\"menu\"\n aria-expanded={isExpanded}\n {...options}\n >\n <div className={styles.linkLabel}>{children}</div>\n {renderIndicator()}\n <ChevronUpIcon\n className={clsx(\n styles.chevronIcon,\n styles.chevronIconDesktop,\n selected && styles.chevronIconSelected,\n isDesktopExpanded && styles.subMenuExpanded\n )}\n />\n </button>\n </DesktopMenu>\n );\n };\n\n return (\n <li\n key={index}\n className={clsx(\n styles.linkItem,\n hideNavBranding && styles.linkItemHiddenBranding\n )}\n >\n {hasSubMenu\n ? renderLinkWithSubmenu(index === items.length - 1)\n : renderLink()}\n </li>\n );\n };\n\n const renderItems = () =>\n items.map((item, index) => {\n switch (item.itemType) {\n case \"component\": {\n return <li key={index}>{item.children ?? null}</li>;\n }\n case \"link\":\n default: {\n return renderLinkItem(item as NavItemLinkProps<T>, index);\n }\n }\n });\n\n if (items && items.length > 0) {\n return mobile ? (\n <ul ref={listRef} className={styles.mobileWrapper}>\n {renderItems()}\n </ul>\n ) : (\n <ul\n ref={listRef}\n className={clsx(\n styles.wrapper,\n hideNavBranding && styles.wrapperAlignLeft\n )}\n >\n {renderItems()}\n </ul>\n );\n }\n\n return <></>;\n};\n"],"names":["NavbarItems","items","selectedId","mobile","hideNavBranding","hideLinkIndicator","onItemClick","selectedIndex","setSelectedIndex","useState","listRef","useRef","instanceId","useId","hasSelectedSubMenuItem","item","_a","subMenu","some","subItem","id","itemIndexWithSelectedSubItem","findIndex","itemType","initialExpandedItemIndex","useEffect","handleClickOutside","event","current","contains","target","document","addEventListener","removeEventListener","handleLinkClick","index","stopPropagation","prev","length","handleMobileSubLinkClick","renderDesktopSubMenu","subMenuId","_jsx","DesktopMenu","Content","children","Section","showDivider","map","subIndex","Link","href","renderMobileSubMenu","MobileMenu","renderLinkItem","options","otherItemAttrs","__rest","hasSubMenu","isRouteSelected","checkSelected","isDesktopExpanded","isMobileExpanded","isExpanded","selected","showIndicator","testId","renderIndicator","className","clsx","styles.linkIndicator","styles.linkIndicatorSelected","linkClassName","styles.link","weight","styles.linkWeightBold","styles.linkWeightSemibold","styles.linkWeightRegular","getLinkWeightClass","styles.linkSelected","styles.linkItem","styles.linkItemHiddenBranding","isLastItem","_jsxs","_Fragment","Object","assign","undefined","onClick","styles.linkLabel","styles.linkIconContainer","ClickableIcon","styles.expandCollapseButton","styles.subMenuExpanded","focusHighlight","focusOutline","ChevronUpIcon","styles.chevronIcon","styles.chevronIconSelected","position","customOffset","menuContent","triggerOnFocus","isModal","onPopoverAppear","onPopoverDismiss","type","tabIndex","styles.linkButton","styles.chevronIconDesktop","renderLinkWithSubmenu","renderItems","ref","styles.mobileWrapper","styles.wrapper","styles.wrapperAlignLeft"],"mappings":"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"}
1
+ {"version":3,"file":"navbar-items.js","sources":["../../src/navbar/navbar-items.tsx"],"sourcesContent":["import { ChevronUpIcon } from \"@lifesg/react-icons/chevron-up\";\nimport clsx from \"clsx\";\nimport type React from \"react\";\nimport { useEffect, useRef, useState } from \"react\";\n\nimport { Menu as DesktopMenu } from \"../menu\";\nimport { ClickableIcon } from \"../shared/clickable-icon\";\nimport type { TypographyWeight } from \"../typography\";\nimport { useId } from \"../util\";\nimport { Menu as MobileMenu } from \"./menu\";\nimport * as styles from \"./navbar-items.styles\";\nimport type {\n NavItemCommonProps,\n NavItemLinkProps,\n NavItemProps,\n} from \"./types\";\n\nconst getLinkWeightClass = (weight: TypographyWeight) => {\n switch (weight) {\n case \"bold\":\n return styles.linkWeightBold;\n case \"semibold\":\n return styles.linkWeightSemibold;\n case \"regular\":\n default:\n return styles.linkWeightRegular;\n }\n};\n\ninterface Props<T> {\n items: NavItemProps<T>[];\n selectedId?: string | undefined;\n /** toggle for mobile or desktop view */\n mobile?: boolean | undefined;\n hideNavBranding?: boolean | undefined;\n /** hide the selected LinkIndicator */\n hideLinkIndicator?: boolean | undefined;\n onItemClick: (\n event: React.MouseEvent<HTMLAnchorElement>,\n item: NavItemProps<T> | NavItemCommonProps<T>\n ) => void;\n}\n\nexport const NavbarItems = <T,>({\n items,\n selectedId,\n mobile = false,\n hideNavBranding,\n hideLinkIndicator = false,\n onItemClick,\n}: Props<T>): JSX.Element => {\n // =============================================================================\n // CONST, STATE, REFS\n // =============================================================================\n const [selectedIndex, setSelectedIndex] = useState<number | null>(null);\n const listRef = useRef<HTMLUListElement>(null);\n const instanceId = useId();\n\n // =============================================================================\n // HELPERS\n // =============================================================================\n const hasSelectedSubMenuItem = (item: NavItemLinkProps<T>): boolean =>\n !!item.subMenu?.some((subItem) => subItem.id === selectedId);\n\n const checkSelected = (item: NavItemLinkProps<T>): boolean =>\n item.id === selectedId || hasSelectedSubMenuItem(item);\n\n const itemIndexWithSelectedSubItem = mobile\n ? items.findIndex(\n (item) =>\n item.itemType !== \"component\" &&\n hasSelectedSubMenuItem(item as NavItemLinkProps<T>)\n )\n : -1;\n const initialExpandedItemIndex =\n itemIndexWithSelectedSubItem < 0 ? null : itemIndexWithSelectedSubItem;\n\n // =========================================================================\n // EFFECTS\n // =========================================================================\n\n useEffect(() => {\n if (!mobile) return;\n\n setSelectedIndex(initialExpandedItemIndex);\n }, [mobile, initialExpandedItemIndex]);\n\n useEffect(() => {\n if (mobile) return;\n\n const handleClickOutside = (event: MouseEvent) => {\n if (\n listRef.current &&\n !listRef.current.contains(event.target as Node)\n ) {\n setSelectedIndex(null);\n }\n };\n document.addEventListener(\"click\", handleClickOutside, true);\n return () => {\n document.removeEventListener(\"click\", handleClickOutside, true);\n };\n }, [mobile]);\n\n // =============================================================================\n // EVENT HANDLERS\n // =============================================================================\n const handleLinkClick = (item: NavItemLinkProps<T>, index: number) => {\n return (event: React.MouseEvent<HTMLAnchorElement>) => {\n event.stopPropagation();\n\n // mobile expands inline when link has submenu\n if (mobile) {\n setSelectedIndex((prev) =>\n item.subMenu?.length && prev !== index ? index : null\n );\n }\n\n onItemClick(event, item);\n };\n };\n\n const handleMobileSubLinkClick = (\n event: React.MouseEvent<HTMLAnchorElement>,\n item: NavItemCommonProps<T>\n ) => {\n event.stopPropagation();\n onItemClick(event, item);\n };\n\n // =============================================================================\n // RENDER FUNCTIONS\n // =============================================================================\n const renderDesktopSubMenu = (\n subMenu: NavItemCommonProps<T>[],\n subMenuId: string,\n columns?: number\n ) => (\n <DesktopMenu.Content id={subMenuId}>\n <DesktopMenu.Section showDivider={false} columns={columns}>\n {subMenu.map((item, subIndex) => (\n <DesktopMenu.Link\n key={`${item.id}-${subIndex}`}\n href={item.href}\n >\n {item.children}\n </DesktopMenu.Link>\n ))}\n </DesktopMenu.Section>\n </DesktopMenu.Content>\n );\n\n const renderMobileSubMenu = (subMenu: NavItemCommonProps<T>[]) => (\n <MobileMenu\n items={subMenu}\n selectedId={selectedId}\n onItemClick={handleMobileSubLinkClick}\n />\n );\n\n const renderLinkItem = (item: NavItemLinkProps<T>, index: number) => {\n const {\n children,\n options,\n subMenu,\n subMenuColumns,\n ...otherItemAttrs\n } = item;\n\n const hasSubMenu = !!subMenu?.length;\n\n const isRouteSelected = checkSelected(item);\n\n // desktop popover open state\n const isDesktopExpanded =\n !mobile && hasSubMenu && selectedIndex === index;\n\n // mobile inline expanded state\n const isMobileExpanded =\n mobile && hasSubMenu && selectedIndex === index;\n\n const isExpanded = isDesktopExpanded || isMobileExpanded;\n\n const selected =\n !mobile && selectedIndex !== null\n ? selectedIndex === index\n : isRouteSelected;\n\n const showIndicator = !hideLinkIndicator && selected;\n\n const textWeight: TypographyWeight = selected\n ? mobile\n ? \"bold\"\n : \"semibold\"\n : \"regular\";\n\n const testId = mobile\n ? `link__mobile-${index + 1}`\n : `link__${index + 1}`;\n\n const renderIndicator = () =>\n showIndicator ? (\n <div\n data-testid={`${testId}-indicator`}\n className={clsx(\n styles.linkIndicator,\n selected && styles.linkIndicatorSelected\n )}\n />\n ) : null;\n\n const renderMobileChevron = () =>\n mobile && hasSubMenu ? (\n <div className={styles.linkIconContainer}>\n <ClickableIcon\n data-testid={`${testId}-expand-collapse-button`}\n className={clsx(\n styles.expandCollapseButton,\n isMobileExpanded && styles.subMenuExpanded\n )}\n focusHighlight={false}\n focusOutline=\"browser\"\n aria-label={isMobileExpanded ? \"Collapse\" : \"Expand\"}\n >\n <ChevronUpIcon\n className={clsx(\n styles.chevronIcon,\n selected && styles.chevronIconSelected\n )}\n />\n </ClickableIcon>\n </div>\n ) : null;\n\n const linkClassName = clsx(\n styles.link,\n getLinkWeightClass(textWeight),\n selected && styles.linkSelected\n );\n\n const renderLink = () => (\n <a\n tabIndex={0}\n data-testid={testId}\n className={linkClassName}\n {...otherItemAttrs}\n aria-current={isRouteSelected ? \"page\" : undefined}\n onClick={handleLinkClick(item, index)}\n {...options}\n >\n <div className={styles.linkLabel}>{children}</div>\n {renderIndicator()}\n </a>\n );\n\n const renderLinkWithSubmenu = (isLastItem: boolean) => {\n const subMenuId = `navbar-submenu-${instanceId}-${item.id}`;\n\n if (mobile) {\n return (\n <>\n <a\n data-testid={testId}\n className={linkClassName}\n {...otherItemAttrs}\n aria-current={isRouteSelected ? \"page\" : undefined}\n aria-haspopup=\"menu\"\n aria-expanded={isExpanded}\n onClick={handleLinkClick(item, index)}\n {...options}\n >\n <div className={styles.linkLabel}>{children}</div>\n {renderIndicator()}\n {renderMobileChevron()}\n </a>\n\n {isMobileExpanded && renderMobileSubMenu(subMenu!)}\n </>\n );\n }\n\n return (\n <DesktopMenu\n position={isLastItem ? \"bottom-end\" : \"bottom\"}\n customOffset={0}\n menuContent={renderDesktopSubMenu(\n subMenu!,\n subMenuId,\n subMenuColumns\n )}\n enableResize\n triggerOnFocus\n isModal={false}\n onPopoverAppear={() => {\n setSelectedIndex(index);\n }}\n onPopoverDismiss={() => {\n setSelectedIndex((prev) =>\n prev === index ? null : prev\n );\n }}\n >\n <button\n type=\"button\"\n tabIndex={0}\n data-testid={testId}\n className={clsx(linkClassName, styles.linkButton)}\n aria-haspopup=\"menu\"\n aria-expanded={isExpanded}\n {...options}\n >\n <div className={styles.linkLabel}>{children}</div>\n {renderIndicator()}\n <ChevronUpIcon\n className={clsx(\n styles.chevronIcon,\n styles.chevronIconDesktop,\n selected && styles.chevronIconSelected,\n isDesktopExpanded && styles.subMenuExpanded\n )}\n />\n </button>\n </DesktopMenu>\n );\n };\n\n return (\n <li\n key={index}\n className={clsx(\n styles.linkItem,\n hideNavBranding && styles.linkItemHiddenBranding\n )}\n >\n {hasSubMenu\n ? renderLinkWithSubmenu(index === items.length - 1)\n : renderLink()}\n </li>\n );\n };\n\n const renderItems = () =>\n items.map((item, index) => {\n switch (item.itemType) {\n case \"component\": {\n return <li key={index}>{item.children ?? null}</li>;\n }\n case \"link\":\n default: {\n return renderLinkItem(item as NavItemLinkProps<T>, index);\n }\n }\n });\n\n if (items && items.length > 0) {\n return mobile ? (\n <ul ref={listRef} className={styles.mobileWrapper}>\n {renderItems()}\n </ul>\n ) : (\n <ul\n ref={listRef}\n className={clsx(\n styles.wrapper,\n hideNavBranding && styles.wrapperAlignLeft\n )}\n >\n {renderItems()}\n </ul>\n );\n }\n\n return <></>;\n};\n"],"names":["NavbarItems","items","selectedId","mobile","hideNavBranding","hideLinkIndicator","onItemClick","selectedIndex","setSelectedIndex","useState","listRef","useRef","instanceId","useId","hasSelectedSubMenuItem","item","_a","subMenu","some","subItem","id","itemIndexWithSelectedSubItem","findIndex","itemType","initialExpandedItemIndex","useEffect","handleClickOutside","event","current","contains","target","document","addEventListener","removeEventListener","handleLinkClick","index","stopPropagation","prev","length","handleMobileSubLinkClick","renderDesktopSubMenu","subMenuId","columns","_jsx","DesktopMenu","Content","children","Section","showDivider","map","subIndex","Link","href","renderMobileSubMenu","MobileMenu","renderLinkItem","options","subMenuColumns","otherItemAttrs","__rest","hasSubMenu","isRouteSelected","checkSelected","isDesktopExpanded","isMobileExpanded","isExpanded","selected","showIndicator","testId","renderIndicator","className","clsx","styles.linkIndicator","styles.linkIndicatorSelected","linkClassName","styles.link","weight","styles.linkWeightBold","styles.linkWeightSemibold","styles.linkWeightRegular","getLinkWeightClass","styles.linkSelected","styles.linkItem","styles.linkItemHiddenBranding","isLastItem","_jsxs","_Fragment","Object","assign","undefined","onClick","styles.linkLabel","styles.linkIconContainer","ClickableIcon","styles.expandCollapseButton","styles.subMenuExpanded","focusHighlight","focusOutline","ChevronUpIcon","styles.chevronIcon","styles.chevronIconSelected","position","customOffset","menuContent","enableResize","triggerOnFocus","isModal","onPopoverAppear","onPopoverDismiss","type","tabIndex","styles.linkButton","styles.chevronIconDesktop","renderLinkWithSubmenu","renderItems","ref","styles.mobileWrapper","styles.wrapper","styles.wrapperAlignLeft"],"mappings":"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"}
package/navbar/types.d.ts CHANGED
@@ -6,6 +6,15 @@ import type { TypographyLinkProps } from "../typography";
6
6
  export interface NavItemLinkProps<T> extends NavItemCommonProps<T> {
7
7
  itemType?: "link";
8
8
  subMenu?: NavItemCommonProps<T>[] | undefined;
9
+ /**
10
+ * Renders `subMenu` as a multi-column layout on desktop. Items flow
11
+ * vertically (top-to-bottom) within each column before wrapping to the
12
+ * next. Has no effect on the mobile drawer, which always renders `subMenu`
13
+ * as an expandable vertical list.
14
+ *
15
+ * @minimum 1
16
+ */
17
+ subMenuColumns?: number | undefined;
9
18
  }
10
19
  /**
11
20
  * Props for a custom component slot navigation item.
@@ -1,2 +1,2 @@
1
- import{jsx as t}from"react/jsx-runtime";import r from"../external/dompurify/dist/purify.es.js";import e from"react";import{NBComponent as n,NotificationBanner as o}from"./notification-banner.js";const i=i=>e.forwardRef(((e,s)=>t(n,Object.assign({forwardedRef:s},e,{children:i.length>0?i.map(((e,n)=>{if("text"===e.type){const o=e.otherAttributes,i=r.sanitize(e.content);return t("p",Object.assign({},o,{dangerouslySetInnerHTML:{__html:i}}),n)}{const r=e.otherAttributes;return t(o.Link,Object.assign({},r,{children:e.content}),n)}})):(console.error("[NotificationBannerHOC] Empty data passed"),null)}))));export{i as withNotificationBanner};
1
+ import{__rest as t}from"../_virtual/_tslib.js";import{jsx as r}from"react/jsx-runtime";import e from"../external/dompurify/dist/purify.es.js";import n from"react";import{NBComponent as i,NotificationBanner as o}from"./notification-banner.js";const s=s=>n.forwardRef(((n,a)=>r(i,Object.assign({forwardedRef:a},n,{children:s.length>0?s.map(((n,i)=>{var s;if("text"===n.type){const t=n.otherAttributes,o=e.sanitize(n.content);return r("p",Object.assign({},t,{dangerouslySetInnerHTML:{__html:o}}),i)}{const a=function(r){const{href:n}=r,i=t(r,["href"]);return"string"==typeof n&&e.isValidAttribute("a","href",n)?r:i}(null!==(s=n.otherAttributes)&&void 0!==s?s:{});return r(o.Link,Object.assign({},a,{children:n.content}),i)}})):(console.error("[NotificationBannerHOC] Empty data passed"),null)}))));export{s as withNotificationBanner};
2
2
  //# sourceMappingURL=notification-banner-hoc.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"notification-banner-hoc.js","sources":["../../src/notification-banner/notification-banner-hoc.tsx"],"sourcesContent":["import DOMPurify from \"dompurify\";\nimport React from \"react\";\n\nimport { NBComponent, NotificationBanner } from \"./notification-banner\";\nimport type {\n ContentLinkAttributes,\n ContentTextAttributes,\n NotificationBannerWithForwardedRefProps,\n NotificationContentAttributes,\n} from \"./types\";\n\n/**\n * Higher-order component that wraps `NotificationBanner` and renders its\n * content from a structured data array.\n * *\n * @param data Content items to render inside the banner.\n */\nexport const withNotificationBanner = (\n data: NotificationContentAttributes[]\n) => {\n const ComponentToReturn = (\n props: NotificationBannerWithForwardedRefProps,\n ref: React.Ref<HTMLDivElement>\n ) => {\n const renderContent = () => {\n if (data.length > 0) {\n return data.map((attribute, index) => {\n if (attribute.type === \"text\") {\n const otherAttributes =\n attribute.otherAttributes as ContentTextAttributes;\n\n const sanitizedContent = DOMPurify.sanitize(\n attribute.content\n );\n return (\n <p\n key={index}\n {...otherAttributes}\n dangerouslySetInnerHTML={{\n __html: sanitizedContent,\n }}\n />\n );\n } else {\n const otherAttributes =\n attribute.otherAttributes as ContentLinkAttributes;\n return (\n <NotificationBanner.Link\n key={index}\n {...otherAttributes}\n >\n {attribute.content}\n </NotificationBanner.Link>\n );\n }\n });\n }\n\n console.error(\"[NotificationBannerHOC] Empty data passed\");\n return null;\n };\n\n return (\n <NBComponent forwardedRef={ref} {...props}>\n {renderContent()}\n </NBComponent>\n );\n };\n\n return React.forwardRef(ComponentToReturn);\n};\n"],"names":["withNotificationBanner","data","React","forwardRef","props","ref","_jsx","NBComponent","Object","assign","forwardedRef","children","length","map","attribute","index","type","otherAttributes","sanitizedContent","DOMPurify","sanitize","content","dangerouslySetInnerHTML","__html","NotificationBanner","Link","console","error"],"mappings":"mMAiBO,MAAMA,EACTC,GAmDOC,EAAMC,YAjDa,CACtBC,EACAC,IAyCIC,EAACC,EAAWC,OAAAC,OAAA,CAACC,aAAcL,GAASD,EAAK,CAAAO,SAtCrCV,EAAKW,OAAS,EACPX,EAAKY,KAAI,CAACC,EAAWC,KACxB,GAAuB,SAAnBD,EAAUE,KAAiB,CAC3B,MAAMC,EACFH,EAAUG,gBAERC,EAAmBC,EAAUC,SAC/BN,EAAUO,SAEd,OACIf,EAAA,IAAAE,OAAAC,OAAA,GAEQQ,EAAe,CACnBK,wBAAyB,CACrBC,OAAQL,KAHPH,EAOjB,CAAO,CACH,MAAME,EACFH,EAAUG,gBACd,OACIX,EAACkB,EAAmBC,KAAIjB,OAAAC,OAAA,CAAA,EAEhBQ,EAAe,CAAAN,SAElBG,EAAUO,UAHNN,EAMjB,MAIRW,QAAQC,MAAM,6CACP"}
1
+ {"version":3,"file":"notification-banner-hoc.js","sources":["../../src/notification-banner/notification-banner-hoc.tsx"],"sourcesContent":["import DOMPurify from \"dompurify\";\nimport React from \"react\";\n\nimport { NBComponent, NotificationBanner } from \"./notification-banner\";\nimport type {\n ContentLinkAttributes,\n ContentTextAttributes,\n NotificationBannerWithForwardedRefProps,\n NotificationContentAttributes,\n} from \"./types\";\n\nfunction sanitizeLinkAttributes(\n attrs: ContentLinkAttributes\n): ContentLinkAttributes {\n const { href, ...rest } = attrs;\n\n if (\n typeof href !== \"string\" ||\n !DOMPurify.isValidAttribute(\"a\", \"href\", href)\n ) {\n return rest;\n }\n\n return attrs;\n}\n\n/**\n * Higher-order component that wraps `NotificationBanner` and renders its\n * content from a structured data array.\n * *\n * @param data Content items to render inside the banner.\n */\nexport const withNotificationBanner = (\n data: NotificationContentAttributes[]\n) => {\n const ComponentToReturn = (\n props: NotificationBannerWithForwardedRefProps,\n ref: React.Ref<HTMLDivElement>\n ) => {\n const renderContent = () => {\n if (data.length > 0) {\n return data.map((attribute, index) => {\n if (attribute.type === \"text\") {\n const otherAttributes =\n attribute.otherAttributes as ContentTextAttributes;\n\n const sanitizedContent = DOMPurify.sanitize(\n attribute.content\n );\n return (\n <p\n key={index}\n {...otherAttributes}\n dangerouslySetInnerHTML={{\n __html: sanitizedContent,\n }}\n />\n );\n } else {\n const otherAttributes = sanitizeLinkAttributes(\n (attribute.otherAttributes ??\n {}) as ContentLinkAttributes\n );\n return (\n <NotificationBanner.Link\n key={index}\n {...otherAttributes}\n >\n {attribute.content}\n </NotificationBanner.Link>\n );\n }\n });\n }\n\n console.error(\"[NotificationBannerHOC] Empty data passed\");\n return null;\n };\n\n return (\n <NBComponent forwardedRef={ref} {...props}>\n {renderContent()}\n </NBComponent>\n );\n };\n\n return React.forwardRef(ComponentToReturn);\n};\n"],"names":["withNotificationBanner","data","React","forwardRef","props","ref","_jsx","NBComponent","Object","assign","forwardedRef","children","length","map","attribute","index","type","otherAttributes","sanitizedContent","DOMPurify","sanitize","content","dangerouslySetInnerHTML","__html","attrs","href","rest","__rest","isValidAttribute","sanitizeLinkAttributes","_a","NotificationBanner","Link","console","error"],"mappings":"kPAgCO,MAAMA,EACTC,GAqDOC,EAAMC,YAnDa,CACtBC,EACAC,IA2CIC,EAACC,EAAWC,OAAAC,OAAA,CAACC,aAAcL,GAASD,EAAK,CAAAO,SAxCrCV,EAAKW,OAAS,EACPX,EAAKY,KAAI,CAACC,EAAWC,WACxB,GAAuB,SAAnBD,EAAUE,KAAiB,CAC3B,MAAMC,EACFH,EAAUG,gBAERC,EAAmBC,EAAUC,SAC/BN,EAAUO,SAEd,OACIf,EAAA,IAAAE,OAAAC,OAAA,GAEQQ,EAAe,CACnBK,wBAAyB,CACrBC,OAAQL,KAHPH,EAOjB,CAAO,CACH,MAAME,EAhD9B,SACIO,GAEA,MAAMC,KAAEA,GAAkBD,EAATE,EAAIC,EAAKH,EAApB,CAAA,SAEN,MACoB,iBAATC,GACNN,EAAUS,iBAAiB,IAAK,OAAQH,GAKtCD,EAHIE,CAIf,CAmCgDG,CACM,QAAzBC,EAAAhB,EAAUG,uBAAe,IAAAa,EAAAA,EACtB,CAAA,GAER,OACIxB,EAACyB,EAAmBC,KAAIxB,OAAAC,OAAA,CAAA,EAEhBQ,EAAe,CAAAN,SAElBG,EAAUO,UAHNN,EAMjB,MAIRkB,QAAQC,MAAM,6CACP"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lifesg/react-design-system",
3
- "version": "4.0.0-alpha.12",
3
+ "version": "4.0.0-alpha.13",
4
4
  "description": "A component design system for LifeSG web apps",
5
5
  "keywords": [
6
6
  "design-system"
@@ -28,8 +28,7 @@
28
28
  "default": "./index.js"
29
29
  },
30
30
  "./theme/styles/*.css": {
31
- "import": "./theme/styles/*.css",
32
- "require": "./theme/styles/*.css"
31
+ "default": "./theme/styles/*.css"
33
32
  },
34
33
  "./accordion": {
35
34
  "types": "./accordion/index.d.ts",