@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,2 +1,2 @@
1
- import{jsxs as e,jsx as t,Fragment as i}from"react/jsx-runtime";import{useSortable as a}from"../../external/@dnd-kit/sortable/dist/sortable.esm.js";import{CSS as l}from"../../external/@dnd-kit/utilities/dist/utilities.esm.js";import{BinIcon as r}from"@lifesg/react-icons/bin";import{DragHandleIcon as s}from"@lifesg/react-icons/drag-handle";import{ExclamationCircleFillIcon as d}from"@lifesg/react-icons/exclamation-circle-fill";import{PencilIcon as n}from"@lifesg/react-icons/pencil";import{memo as o,useState as c,useContext as m,useRef as h,useCallback as p,useEffect as b}from"react";import{Button as u}from"../../button/button.js";import{ProgressBar as y}from"../../shared/progress-bar/progress-bar.js";import{Typography as f}from"../../typography/index.js";import"../../util/calendar-helper.js";import"../../external/dayjs/dayjs.min.js";import"../../util/simple-id-generator.js";import{StringHelper as g}from"../../util/string-helper.js";import"@react-aria/live-announcer";import{FileUploadContext as N}from"../context.js";import{FileUploadHelper as v}from"../helper.js";import{item as j,dragHandleIcon as D,box as M,contentSection as T,iconButton as $,actionContainer as B,nameSection as x,desktopErrorMessage as w,errorIcon as k,fileSizeSection as z,fileSizeText as C,mobileErrorMessage as P,descriptionFileSizeText as I,itemDescriptionLabel as E,itemDescriptionText as O,extendedNameSection as K,inlineActionContainer as S}from"./file-list-item.styles.js";import{FileListItemThumbnail as _}from"./file-list-item-thumbnail.js";const F=o((({fileItem:o,editable:F,sortable:L,wrapperWidth:R,disabled:U,readOnly:Y,descriptionLabel:W,onDelete:q,onEditClick:A})=>{const{id:G,name:H,size:J,description:Q,progress:V=1,errorMessage:X,thumbnailImageDataUrl:Z,truncateText:ee=!0}=o,[te,ie]=c(),{activeId:ae}=m(N),{attributes:le,listeners:re,setNodeRef:se,transform:de,transition:ne}=a({id:G}),oe=h(null),ce={transform:l.Translate.toString(de),transition:ne},me=Object.assign(Object.assign({style:ce},le),re),he=V<1,pe=v.formatFileSizeDisplay(J),be=!!Q&&!!F,ue=ae?ae===G?"self":"others":"none",ye=p((e=>{if(!ee)return e;const t=oe&&oe.current?oe.current.getBoundingClientRect().width:0;return g.truncateOneLine(e,t,t/2,t/2/8,16)}),[ee]);b((()=>{ie(ye(H))}),[R,ye,H]);const fe=()=>{q()},ge=()=>{A&&A()},Ne=e=>{L&&e.stopPropagation()},ve=()=>U||!!ae,je=()=>!!L&&!Y,De=()=>{var a;return e(i,{children:[t(f.BodyMD,{weight:Q?"semibold":"regular",children:te}),Q&&e(i,{children:[t(f.BodyMD,{className:E,children:null!==(a=null==W?void 0:W.children)&&void 0!==a?a:"Photo description"}),t(f.BodyMD,{className:O,children:Q})]})]})};return e("li",Object.assign({id:G,ref:se,className:j,"data-item-state":ve()&&"none"===ue?"disabled":je()&&"self"===ue?"sortable-active":je()?"sortable":void 0,"data-testid":`${G}-item`},je()?me:{},{children:[je()&&t(s,{"data-testid":`${G}-drag-handle`,className:D,"data-drag-handle-state":"self"===ue?"active":ve()?"disabled":void 0}),e("div",{className:M,"data-box-state":"self"===ue?"focused":ve()?"disabled":X?"error":void 0,"data-stack-mobile":!X&&(he||F),children:[(()=>{const a=!!Z||o.type===v.PDF_MIME_TYPE,l=X?e(i,{children:[e("div",{ref:oe,className:x,children:[De(),X&&e(f.BodySM,{className:w,weight:"semibold",children:[t(d,{className:k,"aria-hidden":!0}),X]})]}),t("div",{className:z,"data-mobile-visibility":he?"hidden":"expand",children:t(f.BodyMD,{className:C,children:pe})}),X&&e(f.BodySM,{className:P,weight:"semibold",children:[t(d,{className:k,"aria-hidden":!0}),X]})]}):(a=>{const l=a||o.type===v.PDF_MIME_TYPE?t(_,{thumbnailImageDataUrl:a||"",fileType:o.type,"data-testid":`${G}-thumbnail`}):null;return e(i,be?{children:[l,e("div",{ref:oe,className:K,children:[t(f.BodyMD,{weight:"semibold",children:te}),t(f.BodyMD,{className:E,children:null!==(s=null==W?void 0:W.children)&&void 0!==s?s:"Photo description"}),t(f.BodyMD,{className:O,children:Q}),t(f.BodyMD,{className:I,children:pe}),!Y&&be&&e("div",{className:S,children:[t(u,{"data-testid":`${G}-edit-button`,"data-no-dnd":"true",type:"button",styleType:"light",sizeType:"small","aria-label":`edit ${H}`,disabled:ve(),onClick:ge,onKeyDown:Ne,icon:t(n,{"aria-hidden":!0}),className:$},"edit"),t(u,{"data-testid":`${G}-delete-button`,"data-no-dnd":"true",type:"button",styleType:"light",sizeType:"small","aria-label":`delete ${H}`,disabled:ve(),onClick:fe,onKeyDown:Ne,icon:t(r,{"aria-hidden":!0}),className:$},"delete")]})]})]}:{children:[l,e("div",{ref:oe,className:x,children:[De(),!he&&t(f.BodyMD,{className:I,children:pe})]})]});var s})(Z);return t("div",{className:T,"data-has-thumbnail":a,children:l})})(),!Y&&!be&&(()=>{let a;return a=X?t(u,{"data-testid":`${G}-error-delete-button`,"data-no-dnd":"true",type:"button",styleType:"light",sizeType:"small","aria-label":`delete ${H}, error: ${X}`,onClick:fe,className:$,icon:t(r,{"aria-hidden":!0})}):he?t(y,{progress:V,"data-testid":`${G}-progress-bar`}):e(i,{children:[F&&t(u,{"data-testid":`${G}-edit-button`,"data-no-dnd":"true",type:"button",styleType:"light",sizeType:"small","aria-label":`edit ${H}`,disabled:ve(),onClick:ge,onKeyDown:Ne,icon:t(n,{"aria-hidden":!0}),className:$},"edit"),t(u,{"data-testid":`${G}-delete-button`,"data-no-dnd":"true",type:"button",styleType:"light",sizeType:"small","aria-label":`delete ${H}`,disabled:ve(),onClick:fe,onKeyDown:Ne,icon:t(r,{"aria-hidden":!0}),className:$},"delete")]}),t("div",{className:B,"data-mobile-layout":!X&&he?"loading":!X&&F?"editable":void 0,children:a})})()]})]}))}));export{F as FileListItem};
1
+ import{jsxs as e,jsx as t}from"react/jsx-runtime";import{useSortable as i}from"../../external/@dnd-kit/sortable/dist/sortable.esm.js";import{CSS as a}from"../../external/@dnd-kit/utilities/dist/utilities.esm.js";import{DragHandleIcon as r}from"@lifesg/react-icons/drag-handle";import{memo as l,useContext as s,useRef as d,useState as n,useMemo as o,useEffect as m}from"react";import{Form as c}from"../../form/index.js";import{Typography as p}from"../../typography/index.js";import{FileUploadContext as u}from"../context.js";import{FileUploadHelper as f}from"../helper.js";import{FileItemActions as b}from"./file-item-actions.js";import{FileItemDetails as h}from"./file-item-details.js";import{editItem as g,editContentSection as y,editDetailsSection as v,editNameSection as x,editFileNameText as j,editFileSizeText as D,item as S,dragHandleIcon as N,box as M,contentSection as L}from"./file-list-item.styles.js";import{FileListItemThumbnail as T}from"./file-list-item-thumbnail.js";import{useTruncatedName as w}from"./use-truncated-name.js";const I=l((({fileItem:l,wrapperWidth:I,editable:$,sortable:B,disabled:C,readOnly:E,descriptionLabel:O,fileDescriptionMaxLength:P,descriptionRequired:k=!0,onDelete:z,onSave:R,onCancel:U,onBlur:F,onModeChange:H})=>{const{id:K,name:_,size:q,description:W,progress:Y=1,errorMessage:A,thumbnailImageDataUrl:G,truncateText:J=!0}=l,{activeId:Q}=s(u),V=d(null),X=w(_,I,J,V),Z=()=>{if(A)return"error";return(null!=Y?Y:1)>=1&&$&&!W?"edit":"display"},[ee,te]=n(Z),{attributes:ie,listeners:ae,setNodeRef:re,transform:le,transition:se}=i({id:K,disabled:"edit"===ee}),de=d(null),[ne,oe]=n(l.description||""),me=Y<1,ce=f.formatFileSizeDisplay(q),pe=!!G||l.type===f.PDF_MIME_TYPE,ue="display"===ee&&!!W&&!!$,fe=!!B&&!E,be=C||!!Q,he=o((()=>{const e=Q?Q===K?"self":"others":"none";return{itemState:be&&"none"===e?"disabled":fe&&"self"===e?"sortable-active":fe?"sortable":void 0,dragHandleState:"self"===e?"active":be?"disabled":void 0,boxState:"self"===e?"focused":be?"disabled":A?"error":void 0}}),[Q,K,be,fe,A]),ge=k&&0===ne.trim().length,ye=d(ee);ye.current=ee;const ve=d(H);ve.current=H,m((()=>("edit"===ee&&(null==H||H("edit")),()=>{var e;"edit"===ye.current&&(null===(e=ve.current)||void 0===e||e.call(ve,"display"))})),[]),m((()=>{if(A&&"error"!==ee)"edit"===ee&&(null==H||H("display")),te("error");else if(!A&&"error"===ee){const e=Z();"edit"===e&&(null==H||H("edit")),te(e)}}),[A]),m((()=>{"edit"===ee&&oe(l.description||"")}),[ee,l.description]);const xe=()=>{te("edit"),null==H||H("edit")},je=e=>{B&&e.stopPropagation()},De=()=>{de.current&&(te("display"),null==H||H("display"),null==R||R(de.current.value.trim()))},Se=()=>{te("display"),null==H||H("display"),null==U||U()},Ne=e=>{oe(e.target.value)},Me=e=>{null==F||F(e.target.value)};if("edit"===ee)return e("li",{"data-testid":`${K}-edit-display`,className:g,children:[e("div",{className:y,children:[pe&&t(T,{thumbnailImageDataUrl:G,fileType:l.type}),e("div",{className:v,children:[e("div",{ref:V,className:x,children:[t(p.BodyMD,{className:j,weight:"semibold",children:X}),t(p.BodyMD,{className:D,children:ce})]}),t(c.Textarea,{ref:de,id:`${K}-description-textarea`,"data-testid":`${K}-textarea`,value:ne,maxLength:P,onChange:Ne,onBlur:Me,rows:3,label:null!=O?O:{children:"Photo description",subtitle:"Describe this photo to users who may not be able to see the image."}})]})]}),t(b,{mode:"edit",id:K,name:_,hasThumbnail:pe,disableSave:ge,onSave:De,onCancel:Se})]});const Le={transform:a.Translate.toString(le),transition:se},Te=Object.assign(Object.assign({style:Le},ie),ae),we=pe?t(T,{thumbnailImageDataUrl:G||"",fileType:l.type,"data-testid":`${K}-thumbnail`}):null;return e("li",Object.assign({id:K,ref:re,className:S,"data-item-state":he.itemState,"data-testid":`${K}-item`},fe?Te:{},{children:[fe&&t(r,{"data-testid":`${K}-drag-handle`,className:N,"data-drag-handle-state":he.dragHandleState}),e("div",{className:M,"data-box-state":he.boxState,"data-stack-mobile":!A&&(me||$),children:[e("div",{className:L,"data-has-thumbnail":"display"===ee&&pe,children:["display"===ee&&we,t(h,{mode:ee,formattedName:X,description:W,fileSize:ce,errorMessage:A,isLoading:me,descriptionLabel:O,detailSectionRef:V,children:!E&&ue&&t(b,{mode:"display",inline:!0,id:K,name:_,editable:!!$,isLoading:me,progress:Y,disabled:be,onDelete:z,onEdit:xe,onKeyDown:je})})]}),!E&&!ue&&t(b,"error"===ee?{mode:"error",id:K,name:_,errorMessage:A,onDelete:z}:{mode:"display",id:K,name:_,editable:!!$,isLoading:me,progress:Y,disabled:be,onDelete:z,onEdit:xe,onKeyDown:je})]})]}))}));export{I as FileListItem};
2
2
  //# sourceMappingURL=file-list-item.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"file-list-item.js","sources":["../../../src/file-upload/file-list-item/file-list-item.tsx"],"sourcesContent":["import { useSortable } from \"@dnd-kit/sortable\";\nimport { CSS } from \"@dnd-kit/utilities\";\nimport { BinIcon } from \"@lifesg/react-icons/bin\";\nimport { DragHandleIcon as DSDragHandleIcon } from \"@lifesg/react-icons/drag-handle\";\nimport { ExclamationCircleFillIcon } from \"@lifesg/react-icons/exclamation-circle-fill\";\nimport { PencilIcon } from \"@lifesg/react-icons/pencil\";\nimport {\n memo,\n useCallback,\n useContext,\n useEffect,\n useRef,\n useState,\n} from \"react\";\n\nimport { Button } from \"../../button\";\nimport type { FormLabelProps } from \"../../form/form-label/types\";\nimport { ProgressBar } from \"../../shared/progress-bar\";\nimport { Typography } from \"../../typography\";\nimport { StringHelper } from \"../../util\";\nimport { FileUploadContext } from \"../context\";\nimport { FileUploadHelper } from \"../helper\";\nimport type { ItemFocusType } from \"./file-list-item.styles\";\nimport * as styles from \"./file-list-item.styles\";\nimport { FileListItemThumbnail } from \"./file-list-item-thumbnail\";\nimport type { FileListItemProps } from \"./types\";\n\ninterface Props extends FileListItemProps {\n readOnly?: boolean | undefined;\n descriptionLabel?: FormLabelProps | undefined;\n}\n\nconst Component = ({\n fileItem,\n editable,\n sortable,\n wrapperWidth,\n disabled,\n readOnly,\n descriptionLabel,\n onDelete,\n onEditClick,\n}: Props) => {\n // =========================================================================\n // CONST, STATE, REFS\n // =========================================================================\n const {\n id,\n name,\n size,\n description,\n progress = 1,\n errorMessage,\n thumbnailImageDataUrl,\n truncateText = true,\n } = fileItem;\n const [formattedName, setFormattedName] = useState<string>();\n const { activeId } = useContext(FileUploadContext);\n\n // Sortable mechanism\n const { attributes, listeners, setNodeRef, transform, transition } =\n useSortable({ id });\n const detailSectionRef = useRef<HTMLDivElement>(null);\n const style = {\n transform: CSS.Translate.toString(transform),\n transition,\n };\n\n const sortableProps = {\n style,\n ...attributes,\n ...listeners,\n };\n\n // Local variables\n const isLoading = progress < 1;\n const fileSize = FileUploadHelper.formatFileSizeDisplay(size);\n const hasInlineActions = !!description && !!editable;\n const focusType: ItemFocusType = activeId\n ? activeId === id\n ? \"self\"\n : \"others\"\n : \"none\";\n\n // =========================================================================\n // HELPER FUNCTIONS\n // =========================================================================\n const getTruncatedText = useCallback(\n (value: string) => {\n if (!truncateText) return value;\n\n const widthOfElement =\n detailSectionRef && detailSectionRef.current\n ? detailSectionRef.current.getBoundingClientRect().width\n : 0;\n\n return StringHelper.truncateOneLine(\n value,\n widthOfElement,\n widthOfElement / 2,\n widthOfElement / 2 / 8, // Arbitrary\n 16 // Font size\n );\n },\n [truncateText]\n );\n\n // =========================================================================\n // EFFECTS\n // =========================================================================\n useEffect(() => {\n setFormattedName(getTruncatedText(name));\n }, [wrapperWidth, getTruncatedText, name]);\n\n // =========================================================================\n // EVENT HANDLERS\n // =========================================================================\n const handleDelete = () => {\n onDelete();\n };\n\n const handleEdit = () => {\n if (onEditClick) {\n onEditClick();\n }\n };\n\n const handleKeyDown = (event: React.KeyboardEvent<HTMLButtonElement>) => {\n /**\n * Circumvent issue of keydown action activating the sort mechanism\n * rather than the actual action\n */\n if (sortable) {\n event.stopPropagation();\n }\n };\n\n const shouldDisable = () => disabled || !!activeId;\n\n const shouldEnableSort = () => !!sortable && !readOnly;\n\n const getItemState = () => {\n if (shouldDisable() && focusType === \"none\") {\n return \"disabled\";\n }\n\n if (shouldEnableSort() && focusType === \"self\") {\n return \"sortable-active\";\n }\n\n if (shouldEnableSort()) {\n return \"sortable\";\n }\n\n return undefined;\n };\n\n const getDragHandleState = () => {\n if (focusType === \"self\") {\n return \"active\";\n }\n\n if (shouldDisable()) {\n return \"disabled\";\n }\n\n return undefined;\n };\n\n const getBoxState = () => {\n if (focusType === \"self\") {\n return \"focused\";\n }\n\n if (shouldDisable()) {\n return \"disabled\";\n }\n\n if (errorMessage) {\n return \"error\";\n }\n\n return undefined;\n };\n\n const getActionContainerLayout = () => {\n if (!errorMessage && isLoading) {\n return \"loading\";\n }\n\n if (!errorMessage && editable) {\n return \"editable\";\n }\n\n return undefined;\n };\n\n // =========================================================================\n // RENDER FUNCTIONS\n // =========================================================================\n const renderNameDescription = () => (\n <>\n <Typography.BodyMD weight={description ? \"semibold\" : \"regular\"}>\n {formattedName}\n </Typography.BodyMD>\n {description && (\n <>\n <Typography.BodyMD className={styles.itemDescriptionLabel}>\n {descriptionLabel?.children ?? \"Photo description\"}\n </Typography.BodyMD>\n <Typography.BodyMD className={styles.itemDescriptionText}>\n {description}\n </Typography.BodyMD>\n </>\n )}\n </>\n );\n\n const renderErrorState = () => (\n <>\n <div ref={detailSectionRef} className={styles.nameSection}>\n {renderNameDescription()}\n {errorMessage && (\n <Typography.BodySM\n className={styles.desktopErrorMessage}\n weight=\"semibold\"\n >\n <ExclamationCircleFillIcon\n className={styles.errorIcon}\n aria-hidden\n />\n {errorMessage}\n </Typography.BodySM>\n )}\n </div>\n <div\n className={styles.fileSizeSection}\n data-mobile-visibility={isLoading ? \"hidden\" : \"expand\"}\n >\n <Typography.BodyMD className={styles.fileSizeText}>\n {fileSize}\n </Typography.BodyMD>\n </div>\n {errorMessage && (\n <Typography.BodySM\n className={styles.mobileErrorMessage}\n weight=\"semibold\"\n >\n <ExclamationCircleFillIcon\n className={styles.errorIcon}\n aria-hidden\n />\n {errorMessage}\n </Typography.BodySM>\n )}\n </>\n );\n\n const renderInlineActions = () => (\n <div className={styles.inlineActionContainer}>\n <Button\n key=\"edit\"\n data-testid={`${id}-edit-button`}\n data-no-dnd=\"true\"\n type=\"button\"\n styleType=\"light\"\n sizeType=\"small\"\n aria-label={`edit ${name}`}\n disabled={shouldDisable()}\n onClick={handleEdit}\n onKeyDown={handleKeyDown}\n icon={<PencilIcon aria-hidden />}\n className={styles.iconButton}\n />\n <Button\n key=\"delete\"\n data-testid={`${id}-delete-button`}\n data-no-dnd=\"true\"\n type=\"button\"\n styleType=\"light\"\n sizeType=\"small\"\n aria-label={`delete ${name}`}\n disabled={shouldDisable()}\n onClick={handleDelete}\n onKeyDown={handleKeyDown}\n icon={<BinIcon aria-hidden />}\n className={styles.iconButton}\n />\n </div>\n );\n\n const renderDescriptionContent = () => (\n <div ref={detailSectionRef} className={styles.extendedNameSection}>\n <Typography.BodyMD weight=\"semibold\">\n {formattedName}\n </Typography.BodyMD>\n <Typography.BodyMD className={styles.itemDescriptionLabel}>\n {descriptionLabel?.children ?? \"Photo description\"}\n </Typography.BodyMD>\n <Typography.BodyMD className={styles.itemDescriptionText}>\n {description}\n </Typography.BodyMD>\n <Typography.BodyMD className={styles.descriptionFileSizeText}>\n {fileSize}\n </Typography.BodyMD>\n {!readOnly && hasInlineActions && renderInlineActions()}\n </div>\n );\n\n const renderFileContent = (thumbnailImageDataUrl?: string) => {\n const shouldShowThumbnail =\n !!thumbnailImageDataUrl ||\n fileItem.type === FileUploadHelper.PDF_MIME_TYPE;\n\n const thumbnail = shouldShowThumbnail ? (\n <FileListItemThumbnail\n thumbnailImageDataUrl={thumbnailImageDataUrl || \"\"}\n fileType={fileItem.type}\n data-testid={`${id}-thumbnail`}\n />\n ) : null;\n\n if (hasInlineActions) {\n return (\n <>\n {thumbnail}\n {renderDescriptionContent()}\n </>\n );\n }\n\n return (\n <>\n {thumbnail}\n <div ref={detailSectionRef} className={styles.nameSection}>\n {renderNameDescription()}\n {!isLoading && (\n <Typography.BodyMD\n className={styles.descriptionFileSizeText}\n >\n {fileSize}\n </Typography.BodyMD>\n )}\n </div>\n </>\n );\n };\n\n const renderContents = () => {\n const shouldShowThumbnail =\n !!thumbnailImageDataUrl ||\n fileItem.type === FileUploadHelper.PDF_MIME_TYPE;\n\n const content = errorMessage\n ? renderErrorState()\n : renderFileContent(thumbnailImageDataUrl);\n\n return (\n <div\n className={styles.contentSection}\n data-has-thumbnail={shouldShowThumbnail}\n >\n {content}\n </div>\n );\n };\n\n const renderActions = () => {\n let content: JSX.Element;\n\n if (errorMessage) {\n content = (\n <Button\n data-testid={`${id}-error-delete-button`}\n data-no-dnd=\"true\"\n type=\"button\"\n styleType=\"light\"\n sizeType=\"small\"\n aria-label={`delete ${name}, error: ${errorMessage}`}\n onClick={handleDelete}\n className={styles.iconButton}\n icon={<BinIcon aria-hidden />}\n />\n );\n } else if (isLoading) {\n content = (\n <ProgressBar\n progress={progress}\n data-testid={`${id}-progress-bar`}\n />\n );\n } else {\n content = (\n <>\n {editable && (\n <Button\n key=\"edit\"\n data-testid={`${id}-edit-button`}\n data-no-dnd=\"true\"\n type=\"button\"\n styleType=\"light\"\n sizeType=\"small\"\n aria-label={`edit ${name}`}\n disabled={shouldDisable()}\n onClick={handleEdit}\n onKeyDown={handleKeyDown}\n icon={<PencilIcon aria-hidden />}\n className={styles.iconButton}\n />\n )}\n <Button\n key=\"delete\"\n data-testid={`${id}-delete-button`}\n data-no-dnd=\"true\"\n type=\"button\"\n styleType=\"light\"\n sizeType=\"small\"\n aria-label={`delete ${name}`}\n disabled={shouldDisable()}\n onClick={handleDelete}\n onKeyDown={handleKeyDown}\n icon={<BinIcon aria-hidden />}\n className={styles.iconButton}\n />\n </>\n );\n }\n\n return (\n <div\n className={styles.actionContainer}\n data-mobile-layout={getActionContainerLayout()}\n >\n {content}\n </div>\n );\n };\n\n return (\n <li\n id={id}\n ref={setNodeRef}\n className={styles.item}\n data-item-state={getItemState()}\n data-testid={`${id}-item`}\n {...(shouldEnableSort() ? sortableProps : {})}\n >\n {shouldEnableSort() && (\n <DSDragHandleIcon\n data-testid={`${id}-drag-handle`}\n className={styles.dragHandleIcon}\n data-drag-handle-state={getDragHandleState()}\n />\n )}\n <div\n className={styles.box}\n data-box-state={getBoxState()}\n data-stack-mobile={!errorMessage && (isLoading || editable)}\n >\n {renderContents()}\n {!readOnly && !hasInlineActions && renderActions()}\n </div>\n </li>\n );\n};\n\nexport const FileListItem = memo(Component);\n"],"names":["FileListItem","memo","fileItem","editable","sortable","wrapperWidth","disabled","readOnly","descriptionLabel","onDelete","onEditClick","id","name","size","description","progress","errorMessage","thumbnailImageDataUrl","truncateText","formattedName","setFormattedName","useState","activeId","useContext","FileUploadContext","attributes","listeners","setNodeRef","transform","transition","useSortable","detailSectionRef","useRef","style","CSS","Translate","toString","sortableProps","isLoading","fileSize","FileUploadHelper","formatFileSizeDisplay","hasInlineActions","focusType","getTruncatedText","useCallback","value","widthOfElement","current","getBoundingClientRect","width","StringHelper","truncateOneLine","useEffect","handleDelete","handleEdit","handleKeyDown","event","stopPropagation","shouldDisable","shouldEnableSort","renderNameDescription","_jsxs","_Fragment","children","_jsx","Typography","BodyMD","weight","className","styles.itemDescriptionLabel","_a","styles.itemDescriptionText","Object","assign","ref","styles.item","DSDragHandleIcon","styles.dragHandleIcon","styles.box","shouldShowThumbnail","type","PDF_MIME_TYPE","content","styles.nameSection","BodySM","styles.desktopErrorMessage","ExclamationCircleFillIcon","styles.errorIcon","styles.fileSizeSection","styles.fileSizeText","styles.mobileErrorMessage","thumbnail","FileListItemThumbnail","fileType","styles.extendedNameSection","styles.descriptionFileSizeText","styles.inlineActionContainer","Button","styleType","sizeType","onClick","onKeyDown","icon","PencilIcon","styles.iconButton","BinIcon","renderFileContent","styles.contentSection","renderContents","ProgressBar","styles.actionContainer","renderActions"],"mappings":"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"}
1
+ {"version":3,"file":"file-list-item.js","sources":["../../../src/file-upload/file-list-item/file-list-item.tsx"],"sourcesContent":["import { useSortable } from \"@dnd-kit/sortable\";\nimport { CSS } from \"@dnd-kit/utilities\";\nimport { DragHandleIcon as DSDragHandleIcon } from \"@lifesg/react-icons/drag-handle\";\nimport { memo, useContext, useEffect, useMemo, useRef, useState } from \"react\";\n\nimport { Form } from \"../../form\";\nimport { Typography } from \"../../typography\";\nimport { FileUploadContext } from \"../context\";\nimport { FileUploadHelper } from \"../helper\";\nimport { FileItemActions } from \"./file-item-actions\";\nimport { FileItemDetails } from \"./file-item-details\";\nimport * as styles from \"./file-list-item.styles\";\nimport { FileListItemThumbnail } from \"./file-list-item-thumbnail\";\nimport type { FileItemMode, FileListItemProps } from \"./types\";\nimport { useTruncatedName } from \"./use-truncated-name\";\n\nconst Component = ({\n fileItem,\n wrapperWidth,\n editable,\n sortable,\n disabled,\n readOnly,\n descriptionLabel,\n fileDescriptionMaxLength,\n descriptionRequired = true,\n onDelete,\n onSave,\n onCancel,\n onBlur,\n onModeChange,\n}: FileListItemProps) => {\n const {\n id,\n name,\n size,\n description,\n progress = 1,\n errorMessage,\n thumbnailImageDataUrl,\n truncateText = true,\n } = fileItem;\n\n // =========================================================================\n // CONST, STATE, REFS\n // =========================================================================\n const { activeId } = useContext(FileUploadContext);\n const detailSectionRef = useRef<HTMLDivElement>(null);\n const formattedName = useTruncatedName(\n name,\n wrapperWidth,\n truncateText,\n detailSectionRef\n );\n\n const computeMode = (): FileItemMode => {\n if (errorMessage) return \"error\";\n\n const isUploaded = (progress ?? 1) >= 1;\n if (isUploaded && editable && !description) return \"edit\";\n\n return \"display\";\n };\n\n const [currentMode, setCurrentMode] = useState<FileItemMode>(computeMode);\n\n // Sortable mechanism\n const { attributes, listeners, setNodeRef, transform, transition } =\n useSortable({ id, disabled: currentMode === \"edit\" });\n\n // Edit mode state\n const textareaRef = useRef<HTMLTextAreaElement>(null);\n const [currentDescription, setCurrentDescription] = useState(\n fileItem.description || \"\"\n );\n\n // =========================================================================\n // DERIVED STATE\n // =========================================================================\n const isLoading = progress < 1;\n const fileSize = FileUploadHelper.formatFileSizeDisplay(size);\n const shouldShowThumbnail =\n !!thumbnailImageDataUrl ||\n fileItem.type === FileUploadHelper.PDF_MIME_TYPE;\n\n const hasInlineActions =\n currentMode === \"display\" && !!description && !!editable;\n const shouldEnableSort = !!sortable && !readOnly;\n const isDisabled = disabled || !!activeId;\n\n const visualStates = useMemo(() => {\n const focusType = activeId\n ? activeId === id\n ? \"self\"\n : \"others\"\n : \"none\";\n\n const itemState = (() => {\n if (isDisabled && focusType === \"none\") return \"disabled\";\n if (shouldEnableSort && focusType === \"self\")\n return \"sortable-active\";\n if (shouldEnableSort) return \"sortable\";\n return undefined;\n })();\n\n const dragHandleState = (() => {\n if (focusType === \"self\") return \"active\";\n if (isDisabled) return \"disabled\";\n return undefined;\n })();\n\n const boxState = (() => {\n if (focusType === \"self\") return \"focused\";\n if (isDisabled) return \"disabled\";\n if (errorMessage) return \"error\";\n return undefined;\n })();\n\n return { itemState, dragHandleState, boxState };\n }, [activeId, id, isDisabled, shouldEnableSort, errorMessage]);\n\n const disableSave =\n descriptionRequired && currentDescription.trim().length === 0;\n\n // =========================================================================\n // EFFECTS\n // =========================================================================\n const currentModeRef = useRef(currentMode);\n currentModeRef.current = currentMode;\n const onModeChangeRef = useRef(onModeChange);\n onModeChangeRef.current = onModeChange;\n\n useEffect(() => {\n if (currentMode === \"edit\") {\n onModeChange?.(\"edit\");\n }\n return () => {\n if (currentModeRef.current === \"edit\") {\n onModeChangeRef.current?.(\"display\");\n }\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n useEffect(() => {\n if (errorMessage && currentMode !== \"error\") {\n if (currentMode === \"edit\") {\n onModeChange?.(\"display\");\n }\n setCurrentMode(\"error\");\n } else if (!errorMessage && currentMode === \"error\") {\n const nextMode = computeMode();\n if (nextMode === \"edit\") {\n onModeChange?.(\"edit\");\n }\n setCurrentMode(nextMode);\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [errorMessage]);\n\n useEffect(() => {\n if (currentMode === \"edit\") {\n setCurrentDescription(fileItem.description || \"\");\n }\n }, [currentMode, fileItem.description]);\n\n // =========================================================================\n // EVENT HANDLERS\n // =========================================================================\n const handleEdit = () => {\n setCurrentMode(\"edit\");\n onModeChange?.(\"edit\");\n };\n\n const handleKeyDown = (event: React.KeyboardEvent<HTMLButtonElement>) => {\n /**\n * Circumvent issue of keydown action activating the sort mechanism\n * rather than the actual action\n */\n if (sortable) {\n event.stopPropagation();\n }\n };\n\n const handleSave = () => {\n if (textareaRef.current) {\n setCurrentMode(\"display\");\n onModeChange?.(\"display\");\n onSave?.(textareaRef.current.value.trim());\n }\n };\n\n const handleCancel = () => {\n setCurrentMode(\"display\");\n onModeChange?.(\"display\");\n onCancel?.();\n };\n\n const handleTextareaChange = (\n event: React.ChangeEvent<HTMLTextAreaElement>\n ) => {\n setCurrentDescription(event.target.value);\n };\n\n const handleTextareaBlur = (\n event: React.FocusEvent<HTMLTextAreaElement>\n ) => {\n onBlur?.(event.target.value);\n };\n\n // =========================================================================\n // RENDER: EDIT MODE\n // =========================================================================\n if (currentMode === \"edit\") {\n return (\n <li data-testid={`${id}-edit-display`} className={styles.editItem}>\n <div className={styles.editContentSection}>\n {shouldShowThumbnail && (\n <FileListItemThumbnail\n thumbnailImageDataUrl={thumbnailImageDataUrl}\n fileType={fileItem.type}\n />\n )}\n <div className={styles.editDetailsSection}>\n <div\n ref={detailSectionRef}\n className={styles.editNameSection}\n >\n <Typography.BodyMD\n className={styles.editFileNameText}\n weight=\"semibold\"\n >\n {formattedName}\n </Typography.BodyMD>\n <Typography.BodyMD\n className={styles.editFileSizeText}\n >\n {fileSize}\n </Typography.BodyMD>\n </div>\n <Form.Textarea\n ref={textareaRef}\n id={`${id}-description-textarea`}\n data-testid={`${id}-textarea`}\n value={currentDescription}\n maxLength={fileDescriptionMaxLength}\n onChange={handleTextareaChange}\n onBlur={handleTextareaBlur}\n rows={3}\n label={\n descriptionLabel ?? {\n children: \"Photo description\",\n subtitle:\n \"Describe this photo to users who may not be able to see the image.\",\n }\n }\n />\n </div>\n </div>\n <FileItemActions\n mode=\"edit\"\n id={id}\n name={name}\n hasThumbnail={shouldShowThumbnail}\n disableSave={disableSave}\n onSave={handleSave}\n onCancel={handleCancel}\n />\n </li>\n );\n }\n\n // =========================================================================\n // RENDER: DISPLAY / ERROR MODE\n // =========================================================================\n const sortableStyle = {\n transform: CSS.Translate.toString(transform),\n transition,\n };\n\n const sortableProps = {\n style: sortableStyle,\n ...attributes,\n ...listeners,\n };\n\n const thumbnail = shouldShowThumbnail ? (\n <FileListItemThumbnail\n thumbnailImageDataUrl={thumbnailImageDataUrl || \"\"}\n fileType={fileItem.type}\n data-testid={`${id}-thumbnail`}\n />\n ) : null;\n\n return (\n <li\n id={id}\n ref={setNodeRef}\n className={styles.item}\n data-item-state={visualStates.itemState}\n data-testid={`${id}-item`}\n {...(shouldEnableSort ? sortableProps : {})}\n >\n {shouldEnableSort && (\n <DSDragHandleIcon\n data-testid={`${id}-drag-handle`}\n className={styles.dragHandleIcon}\n data-drag-handle-state={visualStates.dragHandleState}\n />\n )}\n <div\n className={styles.box}\n data-box-state={visualStates.boxState}\n data-stack-mobile={!errorMessage && (isLoading || editable)}\n >\n <div\n className={styles.contentSection}\n data-has-thumbnail={\n currentMode === \"display\" && shouldShowThumbnail\n }\n >\n {currentMode === \"display\" && thumbnail}\n <FileItemDetails\n mode={currentMode}\n formattedName={formattedName}\n description={description}\n fileSize={fileSize}\n errorMessage={errorMessage}\n isLoading={isLoading}\n descriptionLabel={descriptionLabel}\n detailSectionRef={detailSectionRef}\n >\n {!readOnly && hasInlineActions && (\n <FileItemActions\n mode=\"display\"\n inline\n id={id}\n name={name}\n editable={!!editable}\n isLoading={isLoading}\n progress={progress}\n disabled={isDisabled}\n onDelete={onDelete}\n onEdit={handleEdit}\n onKeyDown={handleKeyDown}\n />\n )}\n </FileItemDetails>\n </div>\n {!readOnly &&\n !hasInlineActions &&\n (currentMode === \"error\" ? (\n <FileItemActions\n mode=\"error\"\n id={id}\n name={name}\n errorMessage={errorMessage}\n onDelete={onDelete}\n />\n ) : (\n <FileItemActions\n mode=\"display\"\n id={id}\n name={name}\n editable={!!editable}\n isLoading={isLoading}\n progress={progress}\n disabled={isDisabled}\n onDelete={onDelete}\n onEdit={handleEdit}\n onKeyDown={handleKeyDown}\n />\n ))}\n </div>\n </li>\n );\n};\n\nexport const FileListItem = memo(Component);\n"],"names":["FileListItem","memo","fileItem","wrapperWidth","editable","sortable","disabled","readOnly","descriptionLabel","fileDescriptionMaxLength","descriptionRequired","onDelete","onSave","onCancel","onBlur","onModeChange","id","name","size","description","progress","errorMessage","thumbnailImageDataUrl","truncateText","activeId","useContext","FileUploadContext","detailSectionRef","useRef","formattedName","useTruncatedName","computeMode","currentMode","setCurrentMode","useState","attributes","listeners","setNodeRef","transform","transition","useSortable","textareaRef","currentDescription","setCurrentDescription","isLoading","fileSize","FileUploadHelper","formatFileSizeDisplay","shouldShowThumbnail","type","PDF_MIME_TYPE","hasInlineActions","shouldEnableSort","isDisabled","visualStates","useMemo","focusType","itemState","dragHandleState","boxState","disableSave","trim","length","currentModeRef","current","onModeChangeRef","useEffect","_a","call","nextMode","handleEdit","handleKeyDown","event","stopPropagation","handleSave","value","handleCancel","handleTextareaChange","target","handleTextareaBlur","_jsxs","className","styles.editItem","children","styles.editContentSection","_jsx","FileListItemThumbnail","fileType","styles.editDetailsSection","ref","styles.editNameSection","Typography","BodyMD","styles.editFileNameText","weight","styles.editFileSizeText","Form","Textarea","maxLength","onChange","rows","label","subtitle","FileItemActions","mode","hasThumbnail","sortableStyle","CSS","Translate","toString","sortableProps","Object","assign","style","thumbnail","styles.item","DSDragHandleIcon","styles.dragHandleIcon","styles.box","styles.contentSection","FileItemDetails","inline","onEdit","onKeyDown"],"mappings":"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"}
@@ -1,18 +1,11 @@
1
+ export declare const editItem: import("@linaria/core").LinariaClassName;
2
+ export declare const editContentSection: import("@linaria/core").LinariaClassName;
3
+ export declare const editDetailsSection: import("@linaria/core").LinariaClassName;
4
+ export declare const editNameSection: import("@linaria/core").LinariaClassName;
5
+ export declare const editFileNameText: import("@linaria/core").LinariaClassName;
6
+ export declare const editFileSizeText: import("@linaria/core").LinariaClassName;
1
7
  export type ItemFocusType = "self" | "others" | "none";
2
8
  export declare const item: import("@linaria/core").LinariaClassName;
3
9
  export declare const dragHandleIcon: import("@linaria/core").LinariaClassName;
4
10
  export declare const box: import("@linaria/core").LinariaClassName;
5
11
  export declare const contentSection: import("@linaria/core").LinariaClassName;
6
- export declare const nameSection: import("@linaria/core").LinariaClassName;
7
- export declare const extendedNameSection: import("@linaria/core").LinariaClassName;
8
- export declare const fileSizeSection: import("@linaria/core").LinariaClassName;
9
- export declare const fileSizeText: import("@linaria/core").LinariaClassName;
10
- export declare const descriptionFileSizeText: import("@linaria/core").LinariaClassName;
11
- export declare const itemDescriptionLabel: import("@linaria/core").LinariaClassName;
12
- export declare const itemDescriptionText: import("@linaria/core").LinariaClassName;
13
- export declare const errorIcon: import("@linaria/core").LinariaClassName;
14
- export declare const desktopErrorMessage: import("@linaria/core").LinariaClassName;
15
- export declare const mobileErrorMessage: import("@linaria/core").LinariaClassName;
16
- export declare const actionContainer: import("@linaria/core").LinariaClassName;
17
- export declare const inlineActionContainer: import("@linaria/core").LinariaClassName;
18
- export declare const iconButton: import("@linaria/core").LinariaClassName;
@@ -1,2 +1,2 @@
1
- import"./file-list-item.styles_kgtfke.css";const i="i18pxk0j",e="dqb8x5u",l="bddx9rr",o="c1dhzflv",t="nk38w4a",f="elwke9e",d="f14h64yt",k="f1wv8fjl",s="divlkvo",v="i1jm950n",p="i1vgco4e",m="eap0p9n",r="d1gk2zsk",a="m1wh4bod",c="a3rvfgv",g="i5ozu70",n="ilou5qo";export{c as actionContainer,l as box,o as contentSection,s as descriptionFileSizeText,r as desktopErrorMessage,e as dragHandleIcon,m as errorIcon,f as extendedNameSection,d as fileSizeSection,k as fileSizeText,n as iconButton,g as inlineActionContainer,i as item,v as itemDescriptionLabel,p as itemDescriptionText,a as mobileErrorMessage,t as nameSection};
1
+ import"./file-list-item.styles_x3a500.css";const e="e18pxk0j",l="eqb8x5u",i="eddx9rr",t="e1dhzflv",s="ek38w4a",d="elwke9e",f="i14h64yt",o="d1wv8fjl",x="bivlkvo",k="c1jm950n";export{x as box,k as contentSection,o as dragHandleIcon,l as editContentSection,i as editDetailsSection,s as editFileNameText,d as editFileSizeText,e as editItem,t as editNameSection,f as item};
2
2
  //# sourceMappingURL=file-list-item.styles.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"file-list-item.styles.js","sources":["../../../src/file-upload/file-list-item/file-list-item.styles.ts"],"sourcesContent":["import { css } from \"@linaria/core\";\n\nimport {\n Border,\n Colour,\n Font,\n MediaQuery,\n Radius,\n Shadow,\n Spacing,\n} from \"../../theme\";\n\nexport type ItemFocusType = \"self\" | \"others\" | \"none\";\n\nexport const item = css`\n display: flex;\n align-items: center;\n width: 100%;\n border: none;\n\n &:not(:last-child) {\n margin-bottom: ${Spacing[\"spacing-16\"]};\n }\n &[data-item-state=\"disabled\"] {\n cursor: not-allowed;\n }\n\n &[data-item-state=\"sortable\"] {\n &:hover {\n cursor: grab;\n }\n\n // Following recommendation by the library for touch events\n // https://docs.dndkit.com/api-documentation/sensors/touch#recommendations\n touch-action: manipulation;\n }\n\n &[data-item-state=\"sortable-active\"] {\n cursor: grabbing;\n\n // Following recommendation by the library for touch events\n // https://docs.dndkit.com/api-documentation/sensors/touch#recommendations\n touch-action: manipulation;\n }\n`;\n\nexport const dragHandleIcon = css`\n margin-right: ${Spacing[\"spacing-16\"]};\n height: 1.5rem;\n width: 1.5rem;\n color: ${Colour[\"icon\"]};\n\n &[data-drag-handle-state=\"active\"] {\n color: ${Colour[\"icon-primary\"]};\n }\n\n &[data-drag-handle-state=\"disabled\"] {\n color: ${Colour[\"icon-disabled\"]};\n }\n`;\n\nexport const box = css`\n background: ${Colour[\"bg-primary-subtlest\"]};\n border: ${Border[\"width-010\"]} ${Border[\"solid\"]} ${Colour[\"border\"]};\n border-radius: ${Radius[\"sm\"]};\n padding: ${Spacing[\"spacing-16\"]} ${Spacing[\"spacing-32\"]};\n display: flex;\n align-items: center;\n width: 100%;\n\n ${MediaQuery.MaxWidth.md} {\n padding: ${Spacing[\"spacing-16\"]};\n }\n\n &[data-box-state=\"focused\"] {\n border-color: ${Colour[\"border-focus\"]};\n box-shadow: ${Shadow[\"xs-focus-strong\"]};\n }\n\n &[data-box-state=\"disabled\"] {\n border-color: ${Colour[\"border-disabled\"]};\n }\n\n &[data-box-state=\"error\"] {\n background: ${Colour[\"bg-error\"]};\n border-color: ${Colour[\"border-error\"]};\n }\n\n &[data-stack-mobile=\"true\"] {\n ${MediaQuery.MaxWidth.md} {\n flex-direction: column;\n align-items: flex-start;\n }\n }\n`;\n\nexport const contentSection = css`\n display: flex;\n flex: 1;\n align-items: center;\n\n ${MediaQuery.MaxWidth.md} {\n flex-direction: column;\n width: 100%;\n align-items: flex-start;\n }\n\n &[data-has-thumbnail=\"true\"] {\n ${MediaQuery.MaxWidth.md} {\n flex-direction: row;\n align-items: center;\n }\n }\n`;\n\nexport const nameSection = css`\n display: flex;\n flex: 1;\n flex-direction: column;\n width: 100%;\n`;\n\nexport const extendedNameSection = css`\n display: flex;\n flex: 1;\n flex-direction: column;\n align-items: flex-start;\n\n ${MediaQuery.MaxWidth.md} {\n width: 100%;\n }\n`;\n\nexport const fileSizeSection = css`\n display: flex;\n width: 5rem;\n margin-left: ${Spacing[\"spacing-8\"]};\n justify-content: flex-end;\n\n &[data-mobile-visibility=\"hidden\"] {\n ${MediaQuery.MaxWidth.md} {\n display: none;\n visibility: hidden;\n }\n }\n\n &[data-mobile-visibility=\"expand\"] {\n ${MediaQuery.MaxWidth.md} {\n width: 100%;\n margin-left: 0;\n margin-top: ${Spacing[\"spacing-8\"]};\n justify-content: flex-start;\n }\n }\n`;\n\nexport const fileSizeText = css`\n color: ${Colour[\"text-subtler\"]};\n`;\n\nexport const descriptionFileSizeText = css`\n color: ${Colour[\"text-subtler\"]};\n margin-top: ${Spacing[\"spacing-16\"]};\n`;\n\nexport const itemDescriptionLabel = css`\n ${Font[\"form-label\"]}\n font-weight: ${Font.Spec[\"weight-semibold\"]};\n color: ${Colour[\"text-subtle\"]};\n margin-top: ${Spacing[\"spacing-16\"]};\n`;\n\nexport const itemDescriptionText = css`\n margin-top: ${Spacing[\"spacing-4\"]};\n overflow-wrap: anywhere;\n`;\n\nexport const errorIcon = css`\n height: 1lh;\n width: 1em;\n flex-shrink: 0;\n color: ${Colour[\"icon-error-strong\"]};\n`;\n\nexport const desktopErrorMessage = css`\n color: ${Colour[\"text-error\"]};\n margin-top: ${Spacing[\"spacing-4\"]};\n display: flex;\n gap: ${Spacing[\"spacing-4\"]};\n\n ${MediaQuery.MaxWidth.md} {\n display: none;\n visibility: hidden;\n }\n`;\n\nexport const mobileErrorMessage = css`\n color: ${Colour[\"text-error\"]};\n display: none;\n visibility: hidden;\n\n ${MediaQuery.MaxWidth.md} {\n display: flex;\n gap: ${Spacing[\"spacing-4\"]};\n visibility: visible;\n margin-top: ${Spacing[\"spacing-8\"]};\n }\n`;\n\nexport const actionContainer = css`\n width: 6rem;\n margin-left: ${Spacing[\"spacing-32\"]};\n display: flex;\n justify-content: flex-end;\n align-items: center;\n\n ${MediaQuery.MaxWidth.md} {\n width: fit-content;\n }\n\n &[data-mobile-layout=\"loading\"] {\n ${MediaQuery.MaxWidth.md} {\n margin-left: 0;\n margin-top: ${Spacing[\"spacing-16\"]};\n width: 100%;\n }\n }\n\n &[data-mobile-layout=\"editable\"] {\n ${MediaQuery.MaxWidth.md} {\n margin-left: 0;\n margin-top: ${Spacing[\"spacing-16\"]};\n align-self: flex-end;\n }\n }\n`;\n\nexport const inlineActionContainer = css`\n width: 100%;\n margin-top: ${Spacing[\"spacing-16\"]};\n display: flex;\n justify-content: flex-end;\n align-items: center;\n`;\n\nexport const iconButton = css`\n min-width: unset;\n\n &:not(:last-child) {\n margin-right: ${Spacing[\"spacing-8\"]};\n }\n`;\n"],"names":["item","dragHandleIcon","box","contentSection","nameSection","extendedNameSection","fileSizeSection","fileSizeText","descriptionFileSizeText","itemDescriptionLabel","itemDescriptionText","errorIcon","desktopErrorMessage","mobileErrorMessage","actionContainer","inlineActionContainer","iconButton"],"mappings":"qFAcO,MAAMA,EAAI,WAgCJC,EAAc,UAedC,EAAG,UAmCHC,EAAc,WAmBdC,EAAW,UAOXC,EAAmB,UAWnBC,EAAe,WAuBfC,EAAY,WAIZC,EAAuB,UAKvBC,EAAoB,WAOpBC,EAAmB,WAKnBC,EAAS,UAOTC,EAAmB,WAYnBC,EAAkB,WAalBC,EAAe,UA4BfC,EAAqB,UAQrBC,EAAU"}
1
+ {"version":3,"file":"file-list-item.styles.js","sources":["../../../src/file-upload/file-list-item/file-list-item.styles.ts"],"sourcesContent":["import { css } from \"@linaria/core\";\n\nimport {\n Border,\n Colour,\n MediaQuery,\n Radius,\n Shadow,\n Spacing,\n} from \"../../theme\";\n\n// =============================================================================\n// EDIT MODE STYLES\n// =============================================================================\n\nexport const editItem = css`\n display: flex;\n flex-direction: column;\n padding: ${Spacing[\"spacing-32\"]};\n background: ${Colour[\"bg-primary-subtlest\"]};\n border: ${Border[\"width-010\"]} ${Border.solid} ${Colour.border};\n border-radius: ${Radius[\"sm\"]};\n\n &:not(:last-child) {\n margin-bottom: ${Spacing[\"spacing-16\"]};\n }\n`;\n\nexport const editContentSection = css`\n display: flex;\n align-items: flex-start;\n margin-bottom: ${Spacing[\"spacing-16\"]};\n width: 100%;\n`;\n\nexport const editDetailsSection = css`\n display: flex;\n flex: 1;\n flex-direction: column;\n`;\n\nexport const editNameSection = css`\n width: 100%;\n display: flex;\n justify-content: space-between;\n margin-bottom: ${Spacing[\"spacing-16\"]};\n\n ${MediaQuery.MaxWidth.md} {\n flex-direction: column;\n justify-content: flex-start;\n }\n`;\n\nexport const editFileNameText = css`\n display: flex;\n flex: 1;\n margin-right: ${Spacing[\"spacing-16\"]};\n\n ${MediaQuery.MaxWidth.md} {\n margin-right: 0;\n margin-bottom: ${Spacing[\"spacing-8\"]};\n }\n`;\n\nexport const editFileSizeText = css`\n color: ${Colour[\"text-subtler\"]};\n`;\n\n// =============================================================================\n// DISPLAY / ERROR MODE STYLES\n// =============================================================================\n\nexport type ItemFocusType = \"self\" | \"others\" | \"none\";\n\nexport const item = css`\n display: flex;\n align-items: center;\n width: 100%;\n border: none;\n\n &:not(:last-child) {\n margin-bottom: ${Spacing[\"spacing-16\"]};\n }\n &[data-item-state=\"disabled\"] {\n cursor: not-allowed;\n }\n\n &[data-item-state=\"sortable\"] {\n &:hover {\n cursor: grab;\n }\n\n // Following recommendation by the library for touch events\n // https://docs.dndkit.com/api-documentation/sensors/touch#recommendations\n touch-action: manipulation;\n }\n\n &[data-item-state=\"sortable-active\"] {\n cursor: grabbing;\n\n // Following recommendation by the library for touch events\n // https://docs.dndkit.com/api-documentation/sensors/touch#recommendations\n touch-action: manipulation;\n }\n`;\n\nexport const dragHandleIcon = css`\n margin-right: ${Spacing[\"spacing-16\"]};\n height: 1.5rem;\n width: 1.5rem;\n color: ${Colour[\"icon\"]};\n\n &[data-drag-handle-state=\"active\"] {\n color: ${Colour[\"icon-primary\"]};\n }\n\n &[data-drag-handle-state=\"disabled\"] {\n color: ${Colour[\"icon-disabled\"]};\n }\n`;\n\nexport const box = css`\n background: ${Colour[\"bg-primary-subtlest\"]};\n border: ${Border[\"width-010\"]} ${Border[\"solid\"]} ${Colour[\"border\"]};\n border-radius: ${Radius[\"sm\"]};\n padding: ${Spacing[\"spacing-16\"]} ${Spacing[\"spacing-32\"]};\n display: flex;\n align-items: center;\n width: 100%;\n\n ${MediaQuery.MaxWidth.md} {\n padding: ${Spacing[\"spacing-16\"]};\n }\n\n &[data-box-state=\"focused\"] {\n border-color: ${Colour[\"border-focus\"]};\n box-shadow: ${Shadow[\"xs-focus-strong\"]};\n }\n\n &[data-box-state=\"disabled\"] {\n border-color: ${Colour[\"border-disabled\"]};\n }\n\n &[data-box-state=\"error\"] {\n background: ${Colour[\"bg-error\"]};\n border-color: ${Colour[\"border-error\"]};\n }\n\n &[data-stack-mobile=\"true\"] {\n ${MediaQuery.MaxWidth.md} {\n flex-direction: column;\n align-items: flex-start;\n }\n }\n`;\n\nexport const contentSection = css`\n display: flex;\n flex: 1;\n align-items: center;\n\n ${MediaQuery.MaxWidth.md} {\n flex-direction: column;\n width: 100%;\n align-items: flex-start;\n }\n\n &[data-has-thumbnail=\"true\"] {\n align-items: center;\n\n ${MediaQuery.MaxWidth.md} {\n flex-direction: row;\n align-items: center;\n }\n }\n`;\n"],"names":["editItem","editContentSection","editDetailsSection","editNameSection","editFileNameText","editFileSizeText","item","dragHandleIcon","box","contentSection"],"mappings":"qFAeO,MAAMA,EAAQ,WAaRC,EAAkB,UAOlBC,EAAkB,UAMlBC,EAAe,WAYfC,EAAgB,UAWhBC,EAAgB,UAUhBC,EAAI,WAgCJC,EAAc,WAedC,EAAG,UAmCHC,EAAc"}
@@ -0,0 +1,10 @@
1
+ @layer fds{.e18pxk0j{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-32);background:var(--fds-colour-bg-primary-subtlest);border:var(--fds-border-width-010) var(--fds-border-style-solid) var(--fds-colour-border);border-radius:var(--fds-radius-sm);}.e18pxk0j:not(:last-child){margin-bottom:var(--fds-spacing-16);}
2
+ .eqb8x5u{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:flex-start;-webkit-box-align:flex-start;-ms-flex-align:flex-start;align-items:flex-start;margin-bottom:var(--fds-spacing-16);width:100%;}
3
+ .eddx9rr{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex:1;-ms-flex:1;flex:1;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;}
4
+ .e1dhzflv{width:100%;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-ms-flex-pack:space-between;-webkit-justify-content:space-between;justify-content:space-between;margin-bottom:var(--fds-spacing-16);}:where(body.fds-breakpoint-md-max) .e1dhzflv{-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;-webkit-box-pack:start;-ms-flex-pack:start;-webkit-justify-content:flex-start;justify-content:flex-start;}
5
+ .ek38w4a{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex:1;-ms-flex:1;flex:1;margin-right:var(--fds-spacing-16);}:where(body.fds-breakpoint-md-max) .ek38w4a{margin-right:0;margin-bottom:var(--fds-spacing-8);}
6
+ .elwke9e{color:var(--fds-colour-text-subtler);}
7
+ .i14h64yt{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;width:100%;border:none;}.i14h64yt:not(:last-child){margin-bottom:var(--fds-spacing-16);}.i14h64yt[data-item-state="disabled"]{cursor:not-allowed;}.i14h64yt[data-item-state="sortable"]{touch-action:manipulation;}.i14h64yt[data-item-state="sortable"]:hover{cursor:-webkit-grab;cursor:grab;}.i14h64yt[data-item-state="sortable-active"]{cursor:-webkit-grabbing;cursor:grabbing;touch-action:manipulation;}
8
+ .d1wv8fjl{margin-right:var(--fds-spacing-16);height:1.5rem;width:1.5rem;color:var(--fds-colour-icon);}.d1wv8fjl[data-drag-handle-state="active"]{color:var(--fds-colour-icon-primary);}.d1wv8fjl[data-drag-handle-state="disabled"]{color:var(--fds-colour-icon-disabled);}
9
+ .bivlkvo{background:var(--fds-colour-bg-primary-subtlest);border:var(--fds-border-width-010) var(--fds-border-style-solid) var(--fds-colour-border);border-radius:var(--fds-radius-sm);padding:var(--fds-spacing-16) var(--fds-spacing-32);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;width:100%;}:where(body.fds-breakpoint-md-max) .bivlkvo{padding:var(--fds-spacing-16);}.bivlkvo[data-box-state="focused"]{border-color:var(--fds-colour-border-focus);box-shadow:var(--fds-shadow-xs-focus-strong);}.bivlkvo[data-box-state="disabled"]{border-color:var(--fds-colour-border-disabled);}.bivlkvo[data-box-state="error"]{background:var(--fds-colour-bg-error);border-color:var(--fds-colour-border-error);}:where(body.fds-breakpoint-md-max) .bivlkvo[data-stack-mobile="true"]{-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;-webkit-align-items:flex-start;-webkit-box-align:flex-start;-ms-flex-align:flex-start;align-items:flex-start;}
10
+ .c1jm950n{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex:1;-ms-flex:1;flex:1;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;}:where(body.fds-breakpoint-md-max) .c1jm950n{-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;width:100%;-webkit-align-items:flex-start;-webkit-box-align:flex-start;-ms-flex-align:flex-start;align-items:flex-start;}.c1jm950n[data-has-thumbnail="true"]{-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;}:where(body.fds-breakpoint-md-max) .c1jm950n[data-has-thumbnail="true"]{-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;}}
@@ -1,12 +1,19 @@
1
+ import type { FormLabelProps } from "../../form/form-label/types";
1
2
  import type { FileItemProps } from "../types";
3
+ export type FileItemMode = "display" | "edit" | "error";
2
4
  export interface FileListItemProps {
3
5
  fileItem: FileItemProps;
4
6
  wrapperWidth: number;
5
- /** If specified, the edit buttons will be rendered */
6
7
  editable?: boolean | undefined;
7
- /** If specified, drag handles will be rendered */
8
8
  sortable?: boolean | undefined;
9
9
  disabled?: boolean | undefined;
10
+ readOnly?: boolean | undefined;
11
+ descriptionLabel?: FormLabelProps | undefined;
12
+ fileDescriptionMaxLength?: number | undefined;
13
+ descriptionRequired?: boolean | undefined;
10
14
  onDelete: () => void;
11
- onEditClick?: (() => void) | undefined;
15
+ onSave?: ((description: string) => void) | undefined;
16
+ onCancel?: (() => void) | undefined;
17
+ onBlur?: ((value: string) => void) | undefined;
18
+ onModeChange?: ((mode: FileItemMode) => void) | undefined;
12
19
  }
@@ -0,0 +1 @@
1
+ export declare function useTruncatedName(name: string, wrapperWidth: number, truncateText: boolean, elementRef: React.RefObject<HTMLElement | null>): string | undefined;
@@ -0,0 +1,2 @@
1
+ import{useState as r,useCallback as t,useEffect as e}from"react";import"../../util/calendar-helper.js";import"../../external/dayjs/dayjs.min.js";import"../../util/simple-id-generator.js";import{StringHelper as n}from"../../util/string-helper.js";import"@react-aria/live-announcer";function i(i,o,u,a){const[l,c]=r(),m=t((r=>{if(!u)return r;const t=(null==a?void 0:a.current)?a.current.getBoundingClientRect().width:0;return n.truncateOneLine(r,t,t/2,t/2/8,16)}),[u,a]);return e((()=>{c(m(i))}),[o,m,i]),l}export{i as useTruncatedName};
2
+ //# sourceMappingURL=use-truncated-name.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-truncated-name.js","sources":["../../../src/file-upload/file-list-item/use-truncated-name.ts"],"sourcesContent":["import { useCallback, useEffect, useState } from \"react\";\n\nimport { StringHelper } from \"../../util\";\n\nexport function useTruncatedName(\n name: string,\n wrapperWidth: number,\n truncateText: boolean,\n elementRef: React.RefObject<HTMLElement | null>\n): string | undefined {\n const [formattedName, setFormattedName] = useState<string>();\n\n const getTruncatedText = useCallback(\n (value: string) => {\n if (!truncateText) return value;\n\n const widthOfElement = elementRef?.current\n ? elementRef.current.getBoundingClientRect().width\n : 0;\n\n return StringHelper.truncateOneLine(\n value,\n widthOfElement,\n widthOfElement / 2,\n widthOfElement / 2 / 8,\n 16\n );\n },\n [truncateText, elementRef]\n );\n\n useEffect(() => {\n setFormattedName(getTruncatedText(name));\n }, [wrapperWidth, getTruncatedText, name]);\n\n return formattedName;\n}\n"],"names":["useTruncatedName","name","wrapperWidth","truncateText","elementRef","formattedName","setFormattedName","useState","getTruncatedText","useCallback","value","widthOfElement","current","getBoundingClientRect","width","StringHelper","truncateOneLine","useEffect"],"mappings":"yRAIM,SAAUA,EACZC,EACAC,EACAC,EACAC,GAEA,MAAOC,EAAeC,GAAoBC,IAEpCC,EAAmBC,GACpBC,IACG,IAAKP,EAAc,OAAOO,EAE1B,MAAMC,GAAiBP,aAAU,EAAVA,EAAYQ,SAC7BR,EAAWQ,QAAQC,wBAAwBC,MAC3C,EAEN,OAAOC,EAAaC,gBAChBN,EACAC,EACAA,EAAiB,EACjBA,EAAiB,EAAI,EACrB,GACH,GAEL,CAACR,EAAcC,IAOnB,OAJAa,GAAU,KACNX,EAAiBE,EAAiBP,GAAM,GACzC,CAACC,EAAcM,EAAkBP,IAE7BI,CACX"}
@@ -55,7 +55,10 @@ export interface ListAddon<T, V> extends DropdownDisplayProps<T, V>, DropdownSea
55
55
  onSelectOption?: ((option: T, extractedValue: T | V) => void) | undefined;
56
56
  /** Indicates the async load state of the options list. */
57
57
  optionsLoadState?: ItemsLoadStateType | undefined;
58
- /** Controls how long option labels are truncated when they overflow. */
58
+ /**
59
+ * Controls how long option labels are truncated when they overflow.
60
+ * Specify `"none"` to display option labels in full.
61
+ */
59
62
  optionTruncationType?: TruncateType | undefined;
60
63
  /** Called when the user activates the retry action while `optionsLoadState` is `"fail"`. */
61
64
  onRetry?: (() => void) | undefined;
@@ -16,6 +16,7 @@ export interface InputSelectOptionsProps<T> {
16
16
  optionsLoadState?: ItemsLoadStateType | undefined;
17
17
  /**
18
18
  * Controls how long option labels are truncated when they overflow.
19
+ * Specify `"none"` to display option labels in full.
19
20
  *
20
21
  * @default "end"
21
22
  */
@@ -1,2 +1,2 @@
1
- import{jsxs as e,Fragment as t,jsx as n}from"react/jsx-runtime";import{ChevronDownIcon as r}from"@lifesg/react-icons/chevron-down";import{TickIcon as o}from"@lifesg/react-icons/tick";import i from"clsx";import s,{useRef as d,useState as l,useImperativeHandle as a,useEffect as c}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{Typography as p}from"../../typography/index.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{tokens as h,navSelectIcon as f,navSelectIconExpanded as v,navSelect as w,navSelectExpanded as y,navItemList as g,backdrop as x,navWrapper as b,navWrapperStickied as k,tickIcon as j,navItemLabel as I,navItemLabelSelected as D,navItem as E,navItemSelected as L}from"./local-nav-dropdown.styles.js";const N=s.forwardRef((({defaultLabel:s,stickyOffset:N=0,onNavItemSelect:B,items:W,selectedItemIndex:z,id:A,"data-testid":H,className:K,renderItem:M},O)=>{const R=d(null),S=d(null),T=d(null),q=d(null),U=d([]),[F,G]=l(!1),[J,P]=l(!1),[Q,V]=l(0),[X,Y]=l(0),[Z,_]=l(0),[ee,te]=l(0),ne=H||"local-nav-dropdown",re=u();a(O,(()=>T.current)),m(T,{[h.navWrapper.stickyOffset]:`${N}px`,[h.navWrapper.sideMargin]:`${Z}px`}),m(q,{[h.navItemList.viewportHeight]:Q-X-N+"px"});const oe="number"==typeof z&&z>=0&&F?W[z].title:s;c((()=>{if(S.current){const e=S.current.getBoundingClientRect().height;Y(e)}}),[]),c((()=>(ie(),()=>{se("remove")})),[]),c((()=>{se(J&&F?"add":"remove")}),[J,F]),c((()=>{V(window.innerHeight);const e=()=>{V(window.innerHeight)};return window.addEventListener("resize",e),()=>window.removeEventListener("resize",e)}),[]),c((()=>{const e=new IntersectionObserver((e=>{const[t]=e;G(!t.isIntersecting)}),{threshold:1,rootMargin:`-${N}px 0px 0px 0px`});return R.current&&e.observe(R.current),()=>e.disconnect()}),[N]),c((()=>{const e=()=>{const e=null==T?void 0:T.current;if(e){const t=e.getBoundingClientRect(),n=document.body.clientWidth-t.right,r=t.left,o=Math.max(n,r);_(o)}};return e(),window.addEventListener("resize",e),()=>{window.removeEventListener("resize",e)}}),[]),c((()=>{var e;J&&(null===(e=U.current[ee])||void 0===e||e.focus())}),[J,ee]);const ie=()=>{if(!document.getElementById(C)){const e=document.createElement("style");e.id=C;const t=document.documentElement.clientWidth,n=window.innerWidth-t;e.innerHTML=`\n\t\t\t\t.${$} {\n\t\t\t\t\toverflow: hidden;\n\t\t\t\t\tpadding-right: ${n}px !important;\n\t\t\t\t\t-ms-overflow-style: none;\n\t\t\t\t\tscrollbar-width: none;\n\t\t\t\t}\n\n\t\t\t\t.${$}::-webkit-scrollbar {\n\t\t\t\t\tdisplay: none;\n\t\t\t\t}\n\t\t\t`,document.body.appendChild(e)}},se=e=>{const t=document.body.classList.contains($);"add"!==e||t?"remove"===e&&t&&document.body.classList.remove($):document.body.classList.add($)},de=(e,t)=>{const{key:n}=e;"Enter"!==n&&" "!==n||(e.preventDefault(),t(e))};return e(t,{children:[n("span",{ref:R,"data-testid":"sticky-ref"}),e("nav",{ref:T,id:A,"data-testid":ne,className:i(b,F&&k,K),children:[e("div",{ref:S,role:"button",onClick:()=>{P((e=>!e))},onKeyDown:e=>{const{key:t}=e;"ArrowDown"===t?(e.preventDefault(),J||P(!0),te(0)):"ArrowUp"===t?(e.preventDefault(),J||P(!0),te(W.length-1)):"Enter"===t||" "===t?(e.preventDefault(),P(!0),te(0)):("Tab"===t||"Escape"===t)&&P(!1)},"data-testid":`${ne}-label`,className:i(w,J&&y),"aria-haspopup":"true","aria-expanded":J,"aria-controls":re,tabIndex:0,children:[n(p.BodyBL,{weight:"semibold",children:oe}),n(r,{className:i(f,J&&v)})]}),J&&n("ul",{ref:q,id:re,role:"menu",onKeyDown:e=>{var t;const{key:n}=e;if("ArrowDown"===n){e.preventDefault();const t=(ee+1)%W.length;te(t)}else if("ArrowUp"===n){e.preventDefault();const t=ee>0?ee-1:W.length-1;te(t)}else"Tab"===n?P(!1):"Escape"===n&&(P(!1),null===(t=S.current)||void 0===t||t.focus())},"data-testid":`${ne}-dropdown-list`,className:g,children:W.map(((t,r)=>(({handleClick:t,isSelected:r,item:s,renderItem:d,index:l})=>{const{id:a,title:c}=s;return d?n("li",{id:a,role:"menuitem",onClick:t,onKeyDown:e=>de(e,t),"aria-current":!!r||void 0,tabIndex:-1,ref:e=>{U.current[l]=e},children:d(s,{selected:r,stickied:F})},l):e("li",{id:a,role:"menuitem",className:i(E,r&&F&&L),onClick:t,onKeyDown:e=>de(e,t),"aria-current":!!r||void 0,tabIndex:-1,ref:e=>{U.current[l]=e},children:[r&&n(o,{className:j}),n("div",{className:i(I,r&&D),children:c})]},l)})({handleClick:e=>((e,t,n)=>{B&&B(e,t,n),P(!1)})(e,t,r),isSelected:r===z,item:t,renderItem:M,index:r})))}),J&&F&&n("div",{className:x,onClick:()=>{P(!1)}})]})]})})),C="lifesg-ds-local-nav-dropdown-stylesheet",$="lifesg-ds-local-nav-dropdown-open";export{N as LocalNavDropdown};
1
+ import{jsxs as e,Fragment as t,jsx as n}from"react/jsx-runtime";import{ChevronDownIcon as r}from"@lifesg/react-icons/chevron-down";import{TickIcon as i}from"@lifesg/react-icons/tick";import o from"clsx";import s,{useRef as d,useState as l,useImperativeHandle as a,useEffect as c}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{Typography as p}from"../../typography/index.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{tokens as h,navSelectIcon as f,navSelectIconExpanded as v,navSelect as w,navSelectExpanded as y,navItemList as g,backdrop as x,navWrapper as b,navWrapperStickied as k,leftAddon as j,tickIcon as N,titleContainer as I,navItemLabel as D,navItemLabelSelected as E,rightAddon as L,navItem as C,navItemSelected as $}from"./local-nav-dropdown.styles.js";const A=s.forwardRef((({defaultLabel:s,stickyOffset:A=0,onNavItemSelect:z,items:H,selectedItemIndex:K,id:M,"data-testid":O,className:R,renderItem:S},T)=>{const q=d(null),U=d(null),F=d(null),G=d(null),J=d([]),[P,Q]=l(!1),[V,X]=l(!1),[Y,Z]=l(0),[_,ee]=l(0),[te,ne]=l(0),[re,ie]=l(0),oe=O||"local-nav-dropdown",se=u();a(T,(()=>F.current)),m(F,{[h.navWrapper.stickyOffset]:`${A}px`,[h.navWrapper.sideMargin]:`${te}px`}),m(G,{[h.navItemList.viewportHeight]:Y-_-A+"px"});const de="number"==typeof K&&K>=0&&P?H[K].title:s;c((()=>{if(U.current){const e=U.current.getBoundingClientRect().height;ee(e)}}),[]),c((()=>(le(),()=>{ae("remove")})),[]),c((()=>{ae(V&&P?"add":"remove")}),[V,P]),c((()=>{Z(window.innerHeight);const e=()=>{Z(window.innerHeight)};return window.addEventListener("resize",e),()=>window.removeEventListener("resize",e)}),[]),c((()=>{const e=new IntersectionObserver((e=>{const[t]=e;Q(!t.isIntersecting)}),{threshold:1,rootMargin:`-${A}px 0px 0px 0px`});return q.current&&e.observe(q.current),()=>e.disconnect()}),[A]),c((()=>{const e=()=>{const e=null==F?void 0:F.current;if(e){const t=e.getBoundingClientRect(),n=document.body.clientWidth-t.right,r=t.left,i=Math.max(n,r);ne(i)}};return e(),window.addEventListener("resize",e),()=>{window.removeEventListener("resize",e)}}),[]),c((()=>{var e;V&&(null===(e=J.current[re])||void 0===e||e.focus())}),[V,re]);const le=()=>{if(!document.getElementById(B)){const e=document.createElement("style");e.id=B;const t=document.documentElement.clientWidth,n=window.innerWidth-t;e.innerHTML=`\n\t\t\t\t.${W} {\n\t\t\t\t\toverflow: hidden;\n\t\t\t\t\tpadding-right: ${n}px !important;\n\t\t\t\t\t-ms-overflow-style: none;\n\t\t\t\t\tscrollbar-width: none;\n\t\t\t\t}\n\n\t\t\t\t.${W}::-webkit-scrollbar {\n\t\t\t\t\tdisplay: none;\n\t\t\t\t}\n\t\t\t`,document.body.appendChild(e)}},ae=e=>{const t=document.body.classList.contains(W);"add"!==e||t?"remove"===e&&t&&document.body.classList.remove(W):document.body.classList.add(W)},ce=(e,t)=>{const{key:n}=e;"Enter"!==n&&" "!==n||(e.preventDefault(),t(e))};return e(t,{children:[n("span",{ref:q,"data-testid":"sticky-ref"}),e("nav",{ref:F,id:M,"data-testid":oe,className:o(b,P&&k,R),children:[e("div",{ref:U,role:"button",onClick:()=>{X((e=>!e))},onKeyDown:e=>{const{key:t}=e;"ArrowDown"===t?(e.preventDefault(),V||X(!0),ie(0)):"ArrowUp"===t?(e.preventDefault(),V||X(!0),ie(H.length-1)):"Enter"===t||" "===t?(e.preventDefault(),X(!0),ie(0)):("Tab"===t||"Escape"===t)&&X(!1)},"data-testid":`${oe}-label`,className:o(w,V&&y),"aria-haspopup":"true","aria-expanded":V,"aria-controls":se,tabIndex:0,children:[n(p.BodyBL,{weight:"semibold",children:de}),n(r,{className:o(f,V&&v)})]}),V&&n("ul",{ref:G,id:se,role:"menu",onKeyDown:e=>{var t;const{key:n}=e;if("ArrowDown"===n){e.preventDefault();const t=(re+1)%H.length;ie(t)}else if("ArrowUp"===n){e.preventDefault();const t=re>0?re-1:H.length-1;ie(t)}else"Tab"===n?X(!1):"Escape"===n&&(X(!1),null===(t=U.current)||void 0===t||t.focus())},"data-testid":`${oe}-dropdown-list`,className:g,children:H.map(((t,r)=>(({handleClick:t,isSelected:r,item:s,renderItem:d,index:l})=>{const{id:a,title:c,titleAddon:m}=s;return d?n("li",{id:a,role:"menuitem",onClick:t,onKeyDown:e=>ce(e,t),"aria-current":!!r||void 0,tabIndex:-1,ref:e=>{J.current[l]=e},children:d(s,{selected:r,stickied:P})},l):e("li",{id:a,role:"menuitem",className:o(C,r&&P&&$),onClick:t,onKeyDown:e=>ce(e,t),"aria-current":!!r||void 0,tabIndex:-1,ref:e=>{J.current[l]=e},children:[r&&n("span",{className:j,children:n(i,{className:N})}),m?e("span",{className:I,children:[m.left&&n("span",{className:j,children:m.left}),n("div",{className:o(D,r&&E),children:c}),m.right&&n("span",{className:L,children:m.right})]}):n("div",{className:o(D,r&&E),children:c})]},l)})({handleClick:e=>((e,t,n)=>{z&&z(e,t,n),X(!1)})(e,t,r),isSelected:r===K,item:t,renderItem:S,index:r})))}),V&&P&&n("div",{className:x,onClick:()=>{X(!1)}})]})]})})),B="lifesg-ds-local-nav-dropdown-stylesheet",W="lifesg-ds-local-nav-dropdown-open";export{A as LocalNavDropdown};
2
2
  //# sourceMappingURL=local-nav-dropdown.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"local-nav-dropdown.js","sources":["../../../src/local-nav/local-nav-dropdown/local-nav-dropdown.tsx"],"sourcesContent":["import { ChevronDownIcon } from \"@lifesg/react-icons/chevron-down\";\nimport { TickIcon } from \"@lifesg/react-icons/tick\";\nimport clsx from \"clsx\";\nimport React, { useEffect, useImperativeHandle, useRef, useState } from \"react\";\n\nimport { useApplyStyle } from \"../../theme\";\nimport { Typography } from \"../../typography\";\nimport { useId } from \"../../util\";\nimport type { LocalNavDropdownItemComponentProps } from \"../internal-types\";\nimport type { LocalNavDropdownProps, LocalNavItemProps } from \"../types\";\nimport * as styles from \"./local-nav-dropdown.styles\";\n\nconst Component = (\n {\n defaultLabel,\n stickyOffset = 0,\n onNavItemSelect,\n items,\n selectedItemIndex,\n id,\n \"data-testid\": testId,\n className,\n renderItem,\n }: LocalNavDropdownProps,\n ref: React.Ref<HTMLElement>\n): JSX.Element => {\n // =============================================================================\n // CONST, STATE, REF\n // =============================================================================\n const detectStickyRef = useRef<HTMLSpanElement>(null);\n const dropdownRef = useRef<HTMLDivElement>(null);\n const navWrapperRef = useRef<HTMLElement>(null);\n const navItemListRef = useRef<HTMLUListElement>(null);\n const listItemRefs = useRef<(HTMLLIElement | null)[]>([]);\n const [isStickied, setIsStickied] = useState<boolean>(false);\n const [isDropdownExpanded, setIsDropdownExpanded] =\n useState<boolean>(false);\n const [viewportHeight, setViewportHeight] = useState(0);\n const [dropdowntHeight, setDropdownHeight] = useState(0);\n const [dynamicMargin, setDynamicMargin] = useState(0);\n const [focusedIndex, setFocusedIndex] = useState(0);\n const navTestId = testId || \"local-nav-dropdown\";\n const dropdownListId = useId();\n\n useImperativeHandle(ref, () => navWrapperRef.current!);\n\n useApplyStyle(navWrapperRef, {\n [styles.tokens.navWrapper.stickyOffset]: `${stickyOffset}px`,\n [styles.tokens.navWrapper.sideMargin]: `${dynamicMargin}px`,\n });\n\n useApplyStyle(navItemListRef, {\n [styles.tokens.navItemList.viewportHeight]: `${\n viewportHeight - dropdowntHeight - stickyOffset\n }px`,\n });\n\n const labelText =\n typeof selectedItemIndex === \"number\" &&\n selectedItemIndex >= 0 &&\n isStickied\n ? items[selectedItemIndex].title\n : defaultLabel;\n\n // =============================================================================\n // EFFECTS, EVENT LISTENERS\n // ============================================================================\n\n useEffect(() => {\n if (dropdownRef.current) {\n const dropdownHeight =\n dropdownRef.current.getBoundingClientRect().height;\n setDropdownHeight(dropdownHeight);\n }\n }, []);\n\n useEffect(() => {\n addStylesheetForDocumentBody();\n return () => {\n applyBodyStyleClass(\"remove\");\n };\n }, []);\n\n useEffect(() => {\n if (isDropdownExpanded && isStickied) {\n applyBodyStyleClass(\"add\");\n } else {\n applyBodyStyleClass(\"remove\");\n }\n }, [isDropdownExpanded, isStickied]);\n\n useEffect(() => {\n setViewportHeight(window.innerHeight);\n const handleResize = () => {\n setViewportHeight(window.innerHeight);\n };\n window.addEventListener(\"resize\", handleResize);\n return () => window.removeEventListener(\"resize\", handleResize);\n }, []);\n\n useEffect(() => {\n const callback = (entries: IntersectionObserverEntry[]) => {\n const [entry] = entries;\n setIsStickied(!entry.isIntersecting);\n };\n\n const observer = new IntersectionObserver(callback, {\n threshold: 1,\n rootMargin: `-${stickyOffset}px 0px 0px 0px`,\n });\n\n if (detectStickyRef.current) {\n observer.observe(detectStickyRef.current);\n }\n\n return () => observer.disconnect();\n }, [stickyOffset]);\n\n useEffect(() => {\n const adjustPadding = () => {\n const dropdown = navWrapperRef?.current;\n if (dropdown) {\n const dropdownRect = dropdown.getBoundingClientRect();\n const spaceToRight =\n document.body.clientWidth - dropdownRect.right;\n const spaceToLeft = dropdownRect.left;\n // Calculate the padding needed to balance the dropdown in the viewport\n const sidePadding = Math.max(spaceToRight, spaceToLeft);\n setDynamicMargin(sidePadding);\n }\n };\n adjustPadding();\n\n window.addEventListener(\"resize\", adjustPadding);\n\n return () => {\n window.removeEventListener(\"resize\", adjustPadding);\n };\n }, []);\n\n useEffect(() => {\n if (isDropdownExpanded) {\n listItemRefs.current[focusedIndex]?.focus();\n }\n }, [isDropdownExpanded, focusedIndex]);\n\n // =============================================================================\n // HELPER FUNCTIONS\n // =============================================================================\n\n const addStylesheetForDocumentBody = () => {\n /**\n * This stylesheet is to manipulate the <body>. We only add once\n */\n if (!document.getElementById(STYLESHEET_ID)) {\n const overlayStyleSheet = document.createElement(\"style\");\n overlayStyleSheet.id = STYLESHEET_ID;\n\n const documentWidth = document.documentElement.clientWidth;\n const windowWidth = window.innerWidth;\n const scrollBarWidth = windowWidth - documentWidth;\n\n overlayStyleSheet.innerHTML = `\n\t\t\t\t.${DROPDOWN_OPEN_CLASSNAME} {\n\t\t\t\t\toverflow: hidden;\n\t\t\t\t\tpadding-right: ${scrollBarWidth}px !important;\n\t\t\t\t\t-ms-overflow-style: none;\n\t\t\t\t\tscrollbar-width: none;\n\t\t\t\t}\n\n\t\t\t\t.${DROPDOWN_OPEN_CLASSNAME}::-webkit-scrollbar {\n\t\t\t\t\tdisplay: none;\n\t\t\t\t}\n\t\t\t`;\n\n document.body.appendChild(overlayStyleSheet);\n }\n };\n\n const applyBodyStyleClass = (action: \"add\" | \"remove\") => {\n const isOverlayStyleClassApplied = document.body.classList.contains(\n DROPDOWN_OPEN_CLASSNAME\n );\n\n if (action === \"add\" && !isOverlayStyleClassApplied) {\n document.body.classList.add(DROPDOWN_OPEN_CLASSNAME);\n } else if (action === \"remove\" && isOverlayStyleClassApplied) {\n document.body.classList.remove(DROPDOWN_OPEN_CLASSNAME);\n }\n };\n\n // =============================================================================\n // EVENT HANDLERS\n // =============================================================================\n\n const handleToggleDropdown = () => {\n setIsDropdownExpanded((prev) => !prev);\n };\n\n const handleDismissBackdrop = () => {\n setIsDropdownExpanded(false);\n };\n\n const handleNavItemClick = (\n e: React.MouseEvent<HTMLElement> | React.KeyboardEvent<HTMLElement>,\n item: LocalNavItemProps,\n index: number\n ) => {\n if (onNavItemSelect) {\n onNavItemSelect(e, item, index);\n }\n setIsDropdownExpanded(false);\n };\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 const handleNavSelectKeyDown = (e: React.KeyboardEvent<HTMLElement>) => {\n const { key } = e;\n\n if (key === \"ArrowDown\") {\n e.preventDefault();\n if (!isDropdownExpanded) {\n setIsDropdownExpanded(true);\n }\n setFocusedIndex(0);\n } else if (key === \"ArrowUp\") {\n e.preventDefault();\n if (!isDropdownExpanded) {\n setIsDropdownExpanded(true);\n }\n setFocusedIndex(items.length - 1);\n } else if (key === \"Enter\" || key === \" \") {\n e.preventDefault();\n setIsDropdownExpanded(true);\n setFocusedIndex(0);\n } else if (key === \"Tab\") {\n setIsDropdownExpanded(false);\n } else if (key === \"Escape\") {\n setIsDropdownExpanded(false);\n }\n };\n\n const handleNavItemListKeyDown = (e: React.KeyboardEvent<HTMLElement>) => {\n const { key } = e;\n\n if (key === \"ArrowDown\") {\n e.preventDefault();\n const nextIndex = (focusedIndex + 1) % items.length;\n setFocusedIndex(nextIndex);\n } else if (key === \"ArrowUp\") {\n e.preventDefault();\n const prevIndex =\n focusedIndex > 0 ? focusedIndex - 1 : items.length - 1;\n setFocusedIndex(prevIndex);\n } else if (key === \"Tab\") {\n setIsDropdownExpanded(false);\n } else if (key === \"Escape\") {\n setIsDropdownExpanded(false);\n dropdownRef.current?.focus();\n }\n };\n\n // =============================================================================\n // RENDER FUNCTIONS\n // =============================================================================\n\n const renderDropdownNavItem = ({\n handleClick,\n isSelected,\n item,\n renderItem,\n index,\n }: LocalNavDropdownItemComponentProps) => {\n const { id, title } = item;\n\n if (renderItem) {\n return (\n <li\n id={id}\n key={index}\n role=\"menuitem\"\n onClick={handleClick}\n onKeyDown={(e) => handleNavItemKeyDown(e, handleClick)}\n aria-current={isSelected ? true : undefined}\n tabIndex={-1}\n ref={(el) => {\n listItemRefs.current[index] = el;\n }}\n >\n {renderItem(item, {\n selected: isSelected,\n stickied: isStickied,\n })}\n </li>\n );\n }\n\n return (\n <li\n id={id}\n key={index}\n role=\"menuitem\"\n className={clsx(\n styles.navItem,\n isSelected && isStickied && styles.navItemSelected\n )}\n onClick={handleClick}\n onKeyDown={(e) => handleNavItemKeyDown(e, handleClick)}\n aria-current={isSelected ? true : undefined}\n tabIndex={-1}\n ref={(el) => {\n listItemRefs.current[index] = el as HTMLLIElement;\n }}\n >\n {isSelected && <TickIcon className={styles.tickIcon} />}\n <div\n className={clsx(\n styles.navItemLabel,\n isSelected && styles.navItemLabelSelected\n )}\n >\n {title}\n </div>\n </li>\n );\n };\n\n return (\n <>\n <span ref={detectStickyRef} data-testid={\"sticky-ref\"} />\n <nav\n ref={navWrapperRef}\n id={id}\n data-testid={navTestId}\n className={clsx(\n styles.navWrapper,\n isStickied && styles.navWrapperStickied,\n className\n )}\n >\n <div\n ref={dropdownRef}\n role=\"button\"\n onClick={handleToggleDropdown}\n onKeyDown={handleNavSelectKeyDown}\n data-testid={`${navTestId}-label`}\n className={clsx(\n styles.navSelect,\n isDropdownExpanded && styles.navSelectExpanded\n )}\n aria-haspopup=\"true\"\n aria-expanded={isDropdownExpanded}\n aria-controls={dropdownListId}\n tabIndex={0}\n >\n <Typography.BodyBL weight=\"semibold\">\n {labelText}\n </Typography.BodyBL>\n <ChevronDownIcon\n className={clsx(\n styles.navSelectIcon,\n isDropdownExpanded && styles.navSelectIconExpanded\n )}\n />\n </div>\n {isDropdownExpanded && (\n <ul\n ref={navItemListRef}\n id={dropdownListId}\n role=\"menu\"\n onKeyDown={handleNavItemListKeyDown}\n data-testid={`${navTestId}-dropdown-list`}\n className={styles.navItemList}\n >\n {items.map((item, i) =>\n renderDropdownNavItem({\n handleClick: (e) =>\n handleNavItemClick(e, item, i),\n isSelected: i === selectedItemIndex,\n item,\n renderItem,\n index: i,\n })\n )}\n </ul>\n )}\n {isDropdownExpanded && isStickied && (\n <div\n className={styles.backdrop}\n onClick={handleDismissBackdrop}\n />\n )}\n </nav>\n </>\n );\n};\n// @catalog\n/**\n * A collapsible dropdown used for in-page navigation on mobile viewports.\n *\n * Use `LocalNavDropdown` when the page has multiple named sections and screen\n * width is insufficient for a persistent sidebar.\n *\n * @remarks\n * This component adopts a fundamentally different interaction model from\n * `LocalNavMenu`: it collapses into a single trigger button and uses a menu\n * overlay, making it suited for mobile while `LocalNavMenu` suits desktop.\n * @keywords in-page navigation, sections\n */\nexport const LocalNavDropdown = React.forwardRef(Component);\n\n// =============================================================================\n// CONSTANTS\n// =============================================================================\nconst STYLESHEET_ID = \"lifesg-ds-local-nav-dropdown-stylesheet\";\nconst DROPDOWN_OPEN_CLASSNAME = \"lifesg-ds-local-nav-dropdown-open\";\n"],"names":["LocalNavDropdown","React","forwardRef","defaultLabel","stickyOffset","onNavItemSelect","items","selectedItemIndex","id","testId","className","renderItem","ref","detectStickyRef","useRef","dropdownRef","navWrapperRef","navItemListRef","listItemRefs","isStickied","setIsStickied","useState","isDropdownExpanded","setIsDropdownExpanded","viewportHeight","setViewportHeight","dropdowntHeight","setDropdownHeight","dynamicMargin","setDynamicMargin","focusedIndex","setFocusedIndex","navTestId","dropdownListId","useId","useImperativeHandle","current","useApplyStyle","styles.tokens","navWrapper","sideMargin","navItemList","labelText","title","useEffect","dropdownHeight","getBoundingClientRect","height","addStylesheetForDocumentBody","applyBodyStyleClass","window","innerHeight","handleResize","addEventListener","removeEventListener","observer","IntersectionObserver","entries","entry","isIntersecting","threshold","rootMargin","observe","disconnect","adjustPadding","dropdown","dropdownRect","spaceToRight","document","body","clientWidth","right","spaceToLeft","left","sidePadding","Math","max","_a","focus","getElementById","STYLESHEET_ID","overlayStyleSheet","createElement","documentWidth","documentElement","scrollBarWidth","innerWidth","innerHTML","DROPDOWN_OPEN_CLASSNAME","appendChild","action","isOverlayStyleClassApplied","classList","contains","remove","add","handleNavItemKeyDown","e","handleClick","key","preventDefault","_jsxs","_Fragment","children","_jsx","clsx","styles.navWrapper","styles.navWrapperStickied","role","onClick","prev","onKeyDown","length","styles.navSelect","styles.navSelectExpanded","tabIndex","Typography","BodyBL","weight","ChevronDownIcon","styles.navSelectIcon","styles.navSelectIconExpanded","nextIndex","prevIndex","styles.navItemList","map","item","i","isSelected","index","undefined","el","selected","stickied","styles.navItem","styles.navItemSelected","TickIcon","styles.tickIcon","styles.navItemLabel","styles.navItemLabelSelected","renderDropdownNavItem","handleNavItemClick","styles.backdrop"],"mappings":"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"}
1
+ {"version":3,"file":"local-nav-dropdown.js","sources":["../../../src/local-nav/local-nav-dropdown/local-nav-dropdown.tsx"],"sourcesContent":["import { ChevronDownIcon } from \"@lifesg/react-icons/chevron-down\";\nimport { TickIcon } from \"@lifesg/react-icons/tick\";\nimport clsx from \"clsx\";\nimport React, { useEffect, useImperativeHandle, useRef, useState } from \"react\";\n\nimport { useApplyStyle } from \"../../theme\";\nimport { Typography } from \"../../typography\";\nimport { useId } from \"../../util\";\nimport type { LocalNavDropdownItemComponentProps } from \"../internal-types\";\nimport type { LocalNavDropdownProps, LocalNavItemProps } from \"../types\";\nimport * as styles from \"./local-nav-dropdown.styles\";\n\nconst Component = (\n {\n defaultLabel,\n stickyOffset = 0,\n onNavItemSelect,\n items,\n selectedItemIndex,\n id,\n \"data-testid\": testId,\n className,\n renderItem,\n }: LocalNavDropdownProps,\n ref: React.Ref<HTMLElement>\n): JSX.Element => {\n // =============================================================================\n // CONST, STATE, REF\n // =============================================================================\n const detectStickyRef = useRef<HTMLSpanElement>(null);\n const dropdownRef = useRef<HTMLDivElement>(null);\n const navWrapperRef = useRef<HTMLElement>(null);\n const navItemListRef = useRef<HTMLUListElement>(null);\n const listItemRefs = useRef<(HTMLLIElement | null)[]>([]);\n const [isStickied, setIsStickied] = useState<boolean>(false);\n const [isDropdownExpanded, setIsDropdownExpanded] =\n useState<boolean>(false);\n const [viewportHeight, setViewportHeight] = useState(0);\n const [dropdowntHeight, setDropdownHeight] = useState(0);\n const [dynamicMargin, setDynamicMargin] = useState(0);\n const [focusedIndex, setFocusedIndex] = useState(0);\n const navTestId = testId || \"local-nav-dropdown\";\n const dropdownListId = useId();\n\n useImperativeHandle(ref, () => navWrapperRef.current!);\n\n useApplyStyle(navWrapperRef, {\n [styles.tokens.navWrapper.stickyOffset]: `${stickyOffset}px`,\n [styles.tokens.navWrapper.sideMargin]: `${dynamicMargin}px`,\n });\n\n useApplyStyle(navItemListRef, {\n [styles.tokens.navItemList.viewportHeight]: `${\n viewportHeight - dropdowntHeight - stickyOffset\n }px`,\n });\n\n const labelText =\n typeof selectedItemIndex === \"number\" &&\n selectedItemIndex >= 0 &&\n isStickied\n ? items[selectedItemIndex].title\n : defaultLabel;\n\n // =============================================================================\n // EFFECTS, EVENT LISTENERS\n // ============================================================================\n\n useEffect(() => {\n if (dropdownRef.current) {\n const dropdownHeight =\n dropdownRef.current.getBoundingClientRect().height;\n setDropdownHeight(dropdownHeight);\n }\n }, []);\n\n useEffect(() => {\n addStylesheetForDocumentBody();\n return () => {\n applyBodyStyleClass(\"remove\");\n };\n }, []);\n\n useEffect(() => {\n if (isDropdownExpanded && isStickied) {\n applyBodyStyleClass(\"add\");\n } else {\n applyBodyStyleClass(\"remove\");\n }\n }, [isDropdownExpanded, isStickied]);\n\n useEffect(() => {\n setViewportHeight(window.innerHeight);\n const handleResize = () => {\n setViewportHeight(window.innerHeight);\n };\n window.addEventListener(\"resize\", handleResize);\n return () => window.removeEventListener(\"resize\", handleResize);\n }, []);\n\n useEffect(() => {\n const callback = (entries: IntersectionObserverEntry[]) => {\n const [entry] = entries;\n setIsStickied(!entry.isIntersecting);\n };\n\n const observer = new IntersectionObserver(callback, {\n threshold: 1,\n rootMargin: `-${stickyOffset}px 0px 0px 0px`,\n });\n\n if (detectStickyRef.current) {\n observer.observe(detectStickyRef.current);\n }\n\n return () => observer.disconnect();\n }, [stickyOffset]);\n\n useEffect(() => {\n const adjustPadding = () => {\n const dropdown = navWrapperRef?.current;\n if (dropdown) {\n const dropdownRect = dropdown.getBoundingClientRect();\n const spaceToRight =\n document.body.clientWidth - dropdownRect.right;\n const spaceToLeft = dropdownRect.left;\n // Calculate the padding needed to balance the dropdown in the viewport\n const sidePadding = Math.max(spaceToRight, spaceToLeft);\n setDynamicMargin(sidePadding);\n }\n };\n adjustPadding();\n\n window.addEventListener(\"resize\", adjustPadding);\n\n return () => {\n window.removeEventListener(\"resize\", adjustPadding);\n };\n }, []);\n\n useEffect(() => {\n if (isDropdownExpanded) {\n listItemRefs.current[focusedIndex]?.focus();\n }\n }, [isDropdownExpanded, focusedIndex]);\n\n // =============================================================================\n // HELPER FUNCTIONS\n // =============================================================================\n\n const addStylesheetForDocumentBody = () => {\n /**\n * This stylesheet is to manipulate the <body>. We only add once\n */\n if (!document.getElementById(STYLESHEET_ID)) {\n const overlayStyleSheet = document.createElement(\"style\");\n overlayStyleSheet.id = STYLESHEET_ID;\n\n const documentWidth = document.documentElement.clientWidth;\n const windowWidth = window.innerWidth;\n const scrollBarWidth = windowWidth - documentWidth;\n\n overlayStyleSheet.innerHTML = `\n\t\t\t\t.${DROPDOWN_OPEN_CLASSNAME} {\n\t\t\t\t\toverflow: hidden;\n\t\t\t\t\tpadding-right: ${scrollBarWidth}px !important;\n\t\t\t\t\t-ms-overflow-style: none;\n\t\t\t\t\tscrollbar-width: none;\n\t\t\t\t}\n\n\t\t\t\t.${DROPDOWN_OPEN_CLASSNAME}::-webkit-scrollbar {\n\t\t\t\t\tdisplay: none;\n\t\t\t\t}\n\t\t\t`;\n\n document.body.appendChild(overlayStyleSheet);\n }\n };\n\n const applyBodyStyleClass = (action: \"add\" | \"remove\") => {\n const isOverlayStyleClassApplied = document.body.classList.contains(\n DROPDOWN_OPEN_CLASSNAME\n );\n\n if (action === \"add\" && !isOverlayStyleClassApplied) {\n document.body.classList.add(DROPDOWN_OPEN_CLASSNAME);\n } else if (action === \"remove\" && isOverlayStyleClassApplied) {\n document.body.classList.remove(DROPDOWN_OPEN_CLASSNAME);\n }\n };\n\n // =============================================================================\n // EVENT HANDLERS\n // =============================================================================\n\n const handleToggleDropdown = () => {\n setIsDropdownExpanded((prev) => !prev);\n };\n\n const handleDismissBackdrop = () => {\n setIsDropdownExpanded(false);\n };\n\n const handleNavItemClick = (\n e: React.MouseEvent<HTMLElement> | React.KeyboardEvent<HTMLElement>,\n item: LocalNavItemProps,\n index: number\n ) => {\n if (onNavItemSelect) {\n onNavItemSelect(e, item, index);\n }\n setIsDropdownExpanded(false);\n };\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 const handleNavSelectKeyDown = (e: React.KeyboardEvent<HTMLElement>) => {\n const { key } = e;\n\n if (key === \"ArrowDown\") {\n e.preventDefault();\n if (!isDropdownExpanded) {\n setIsDropdownExpanded(true);\n }\n setFocusedIndex(0);\n } else if (key === \"ArrowUp\") {\n e.preventDefault();\n if (!isDropdownExpanded) {\n setIsDropdownExpanded(true);\n }\n setFocusedIndex(items.length - 1);\n } else if (key === \"Enter\" || key === \" \") {\n e.preventDefault();\n setIsDropdownExpanded(true);\n setFocusedIndex(0);\n } else if (key === \"Tab\") {\n setIsDropdownExpanded(false);\n } else if (key === \"Escape\") {\n setIsDropdownExpanded(false);\n }\n };\n\n const handleNavItemListKeyDown = (e: React.KeyboardEvent<HTMLElement>) => {\n const { key } = e;\n\n if (key === \"ArrowDown\") {\n e.preventDefault();\n const nextIndex = (focusedIndex + 1) % items.length;\n setFocusedIndex(nextIndex);\n } else if (key === \"ArrowUp\") {\n e.preventDefault();\n const prevIndex =\n focusedIndex > 0 ? focusedIndex - 1 : items.length - 1;\n setFocusedIndex(prevIndex);\n } else if (key === \"Tab\") {\n setIsDropdownExpanded(false);\n } else if (key === \"Escape\") {\n setIsDropdownExpanded(false);\n dropdownRef.current?.focus();\n }\n };\n\n // =============================================================================\n // RENDER FUNCTIONS\n // =============================================================================\n\n const renderDropdownNavItem = ({\n handleClick,\n isSelected,\n item,\n renderItem,\n index,\n }: LocalNavDropdownItemComponentProps) => {\n const { id, title, titleAddon } = item;\n\n if (renderItem) {\n return (\n <li\n id={id}\n key={index}\n role=\"menuitem\"\n onClick={handleClick}\n onKeyDown={(e) => handleNavItemKeyDown(e, handleClick)}\n aria-current={isSelected ? true : undefined}\n tabIndex={-1}\n ref={(el) => {\n listItemRefs.current[index] = el;\n }}\n >\n {renderItem(item, {\n selected: isSelected,\n stickied: isStickied,\n })}\n </li>\n );\n }\n\n return (\n <li\n id={id}\n key={index}\n role=\"menuitem\"\n className={clsx(\n styles.navItem,\n isSelected && isStickied && styles.navItemSelected\n )}\n onClick={handleClick}\n onKeyDown={(e) => handleNavItemKeyDown(e, handleClick)}\n aria-current={isSelected ? true : undefined}\n tabIndex={-1}\n ref={(el) => {\n listItemRefs.current[index] = el as HTMLLIElement;\n }}\n >\n {isSelected && (\n <span className={styles.leftAddon}>\n <TickIcon className={styles.tickIcon} />\n </span>\n )}\n {titleAddon ? (\n <span className={styles.titleContainer}>\n {titleAddon.left && (\n <span className={styles.leftAddon}>\n {titleAddon.left}\n </span>\n )}\n <div\n className={clsx(\n styles.navItemLabel,\n isSelected && styles.navItemLabelSelected\n )}\n >\n {title}\n </div>\n {titleAddon.right && (\n <span className={styles.rightAddon}>\n {titleAddon.right}\n </span>\n )}\n </span>\n ) : (\n <div\n className={clsx(\n styles.navItemLabel,\n isSelected && styles.navItemLabelSelected\n )}\n >\n {title}\n </div>\n )}\n </li>\n );\n };\n\n return (\n <>\n <span ref={detectStickyRef} data-testid={\"sticky-ref\"} />\n <nav\n ref={navWrapperRef}\n id={id}\n data-testid={navTestId}\n className={clsx(\n styles.navWrapper,\n isStickied && styles.navWrapperStickied,\n className\n )}\n >\n <div\n ref={dropdownRef}\n role=\"button\"\n onClick={handleToggleDropdown}\n onKeyDown={handleNavSelectKeyDown}\n data-testid={`${navTestId}-label`}\n className={clsx(\n styles.navSelect,\n isDropdownExpanded && styles.navSelectExpanded\n )}\n aria-haspopup=\"true\"\n aria-expanded={isDropdownExpanded}\n aria-controls={dropdownListId}\n tabIndex={0}\n >\n <Typography.BodyBL weight=\"semibold\">\n {labelText}\n </Typography.BodyBL>\n <ChevronDownIcon\n className={clsx(\n styles.navSelectIcon,\n isDropdownExpanded && styles.navSelectIconExpanded\n )}\n />\n </div>\n {isDropdownExpanded && (\n <ul\n ref={navItemListRef}\n id={dropdownListId}\n role=\"menu\"\n onKeyDown={handleNavItemListKeyDown}\n data-testid={`${navTestId}-dropdown-list`}\n className={styles.navItemList}\n >\n {items.map((item, i) =>\n renderDropdownNavItem({\n handleClick: (e) =>\n handleNavItemClick(e, item, i),\n isSelected: i === selectedItemIndex,\n item,\n renderItem,\n index: i,\n })\n )}\n </ul>\n )}\n {isDropdownExpanded && isStickied && (\n <div\n className={styles.backdrop}\n onClick={handleDismissBackdrop}\n />\n )}\n </nav>\n </>\n );\n};\n// @catalog\n/**\n * A collapsible dropdown used for in-page navigation on mobile viewports.\n *\n * Use `LocalNavDropdown` when the page has multiple named sections and screen\n * width is insufficient for a persistent sidebar.\n *\n * @remarks\n * This component adopts a fundamentally different interaction model from\n * `LocalNavMenu`: it collapses into a single trigger button and uses a menu\n * overlay, making it suited for mobile while `LocalNavMenu` suits desktop.\n * @keywords in-page navigation, sections\n */\nexport const LocalNavDropdown = React.forwardRef(Component);\n\n// =============================================================================\n// CONSTANTS\n// =============================================================================\nconst STYLESHEET_ID = \"lifesg-ds-local-nav-dropdown-stylesheet\";\nconst DROPDOWN_OPEN_CLASSNAME = \"lifesg-ds-local-nav-dropdown-open\";\n"],"names":["LocalNavDropdown","React","forwardRef","defaultLabel","stickyOffset","onNavItemSelect","items","selectedItemIndex","id","testId","className","renderItem","ref","detectStickyRef","useRef","dropdownRef","navWrapperRef","navItemListRef","listItemRefs","isStickied","setIsStickied","useState","isDropdownExpanded","setIsDropdownExpanded","viewportHeight","setViewportHeight","dropdowntHeight","setDropdownHeight","dynamicMargin","setDynamicMargin","focusedIndex","setFocusedIndex","navTestId","dropdownListId","useId","useImperativeHandle","current","useApplyStyle","styles.tokens","navWrapper","sideMargin","navItemList","labelText","title","useEffect","dropdownHeight","getBoundingClientRect","height","addStylesheetForDocumentBody","applyBodyStyleClass","window","innerHeight","handleResize","addEventListener","removeEventListener","observer","IntersectionObserver","entries","entry","isIntersecting","threshold","rootMargin","observe","disconnect","adjustPadding","dropdown","dropdownRect","spaceToRight","document","body","clientWidth","right","spaceToLeft","left","sidePadding","Math","max","_a","focus","getElementById","STYLESHEET_ID","overlayStyleSheet","createElement","documentWidth","documentElement","scrollBarWidth","innerWidth","innerHTML","DROPDOWN_OPEN_CLASSNAME","appendChild","action","isOverlayStyleClassApplied","classList","contains","remove","add","handleNavItemKeyDown","e","handleClick","key","preventDefault","_jsxs","_Fragment","children","_jsx","clsx","styles.navWrapper","styles.navWrapperStickied","role","onClick","prev","onKeyDown","length","styles.navSelect","styles.navSelectExpanded","tabIndex","Typography","BodyBL","weight","ChevronDownIcon","styles.navSelectIcon","styles.navSelectIconExpanded","nextIndex","prevIndex","styles.navItemList","map","item","i","isSelected","index","titleAddon","undefined","el","selected","stickied","styles.navItem","styles.navItemSelected","styles.leftAddon","TickIcon","styles.tickIcon","styles.titleContainer","styles.navItemLabel","styles.navItemLabelSelected","styles.rightAddon","renderDropdownNavItem","handleNavItemClick","styles.backdrop"],"mappings":"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"}
@@ -14,6 +14,9 @@ export declare const navSelectExpanded: import("@linaria/core").LinariaClassName
14
14
  export declare const navItem: import("@linaria/core").LinariaClassName;
15
15
  export declare const navItemSelected: import("@linaria/core").LinariaClassName;
16
16
  export declare const navItemList: import("@linaria/core").LinariaClassName;
17
+ export declare const titleContainer: import("@linaria/core").LinariaClassName;
18
+ export declare const leftAddon: import("@linaria/core").LinariaClassName;
19
+ export declare const rightAddon: import("@linaria/core").LinariaClassName;
17
20
  export declare const navItemLabel: import("@linaria/core").LinariaClassName;
18
21
  export declare const navItemLabelSelected: import("@linaria/core").LinariaClassName;
19
22
  export declare const tickIcon: import("@linaria/core").LinariaClassName;
@@ -1,2 +1,2 @@
1
- import"./local-nav-dropdown.styles_uhd4xl.css";const n={navWrapper:{stickyOffset:"--fds-internal-localNavDropdown-navWrapper-stickyOffset",sideMargin:"--fds-internal-localNavDropdown-navWrapper-sideMargin"},navItemList:{viewportHeight:"--fds-internal-localNavDropdown-navItemList-viewportHeight"}},a="nczumix",r="n1mayi9n",e="n1fsscye",o="n10li8ea",i="n1rgfmu8",l="n122w1r6",s="ny6lx9v",t="n1lmzf88",p="nc4nyiy",v="thuuy8a",c="beqsxqe",d="ns92rya",y="np844yu";export{c as backdrop,i as navItem,t as navItemLabel,p as navItemLabelSelected,s as navItemList,l as navItemSelected,e as navSelect,o as navSelectExpanded,a as navSelectIcon,r as navSelectIconExpanded,d as navWrapper,y as navWrapperStickied,v as tickIcon,n as tokens};
1
+ import"./local-nav-dropdown.styles_kpel1m.css";const n={navWrapper:{stickyOffset:"--fds-internal-localNavDropdown-navWrapper-stickyOffset",sideMargin:"--fds-internal-localNavDropdown-navWrapper-sideMargin"},navItemList:{viewportHeight:"--fds-internal-localNavDropdown-navItemList-viewportHeight"}},a="nczumix",r="n1mayi9n",e="n1fsscye",t="n10li8ea",l="n1rgfmu8",o="n122w1r6",s="ny6lx9v",i="t1lmzf88",p="lc4nyiy",v="rhuuy8a",c="neqsxqe",d="ns92rya",y="tp844yu",f="b7u5vs",m="nb4z8rf",w="n1y3g4t3";export{f as backdrop,p as leftAddon,l as navItem,c as navItemLabel,d as navItemLabelSelected,s as navItemList,o as navItemSelected,e as navSelect,t as navSelectExpanded,a as navSelectIcon,r as navSelectIconExpanded,m as navWrapper,w as navWrapperStickied,v as rightAddon,y as tickIcon,i as titleContainer,n as tokens};
2
2
  //# sourceMappingURL=local-nav-dropdown.styles.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"local-nav-dropdown.styles.js","sources":["../../../src/local-nav/local-nav-dropdown/local-nav-dropdown.styles.ts"],"sourcesContent":["import { css } from \"@linaria/core\";\n\nimport { Border, Colour, Font, Motion, Radius, Spacing } from \"../../theme\";\n\nexport const tokens = {\n navWrapper: {\n stickyOffset: \"--fds-internal-localNavDropdown-navWrapper-stickyOffset\",\n sideMargin: \"--fds-internal-localNavDropdown-navWrapper-sideMargin\",\n },\n navItemList: {\n viewportHeight:\n \"--fds-internal-localNavDropdown-navItemList-viewportHeight\",\n },\n};\n\n// -----------------------------------------------------------------------------\n// NAV SELECT\n// -----------------------------------------------------------------------------\n\nexport const navSelectIcon = css`\n color: ${Colour[\"icon\"]};\n transition: transform ${Motion[\"duration-250\"]} ${Motion[\"ease-default\"]};\n transform: rotate(0deg);\n`;\n\nexport const navSelectIconExpanded = css`\n transform: rotate(180deg);\n`;\n\nexport const navSelect = css`\n cursor: pointer;\n background: ${Colour[\"bg\"]};\n padding: ${Spacing[\"spacing-12\"]} ${Spacing[\"spacing-16\"]};\n overflow: hidden;\n box-shadow: 0 0 ${Border[\"width-010\"]} ${Border[\"width-010\"]}\n ${Colour[\"border\"]};\n border-radius: ${Radius[\"sm\"]};\n display: flex;\n justify-content: space-between;\n align-items: center;\n transition: all ${Motion[\"duration-250\"]} ${Motion[\"ease-default\"]};\n transition-property: background, border-radius, box-shadow, transform;\n\n &:focus-visible {\n outline: 2px solid ${Colour[\"focus-ring\"]};\n outline-offset: 2px;\n border-radius: ${Radius[\"sm\"]};\n }\n`;\n\nexport const navSelectExpanded = css`\n border-bottom-left-radius: ${Radius[\"none\"]};\n border-bottom-right-radius: ${Radius[\"none\"]};\n`;\n\n// -----------------------------------------------------------------------------\n// NAV ITEMS\n// -----------------------------------------------------------------------------\n\nexport const navItem = css`\n padding: ${Spacing[\"spacing-12\"]} ${Spacing[\"spacing-8\"]}\n ${Spacing[\"spacing-12\"]} ${Spacing[\"spacing-32\"]};\n background: ${Colour[\"bg\"]};\n /* Ensures that the tick mark is positioned relative to the selected item */\n position: relative;\n display: flex;\n /* Vertically align text and tick */\n align-items: center;\n\n &:focus-visible {\n outline: 2px solid ${Colour[\"focus-ring\"]};\n outline-offset: 0px;\n border-radius: ${Radius[\"sm\"]};\n }\n`;\n\nexport const navItemSelected = css`\n padding: ${Spacing[\"spacing-12\"]} ${Spacing[\"spacing-8\"]}\n ${Spacing[\"spacing-12\"]} 0;\n background: ${Colour[\"bg-primary-subtlest\"]};\n`;\n\nexport const navItemList = css`\n ${tokens.navItemList.viewportHeight}: initial;\n transition: all ${Motion[\"duration-250\"]} ${Motion[\"ease-default\"]};\n transform-origin: top;\n list-style-type: none;\n padding: 0 ${Spacing[\"spacing-8\"]};\n margin: 0;\n background: ${Colour[\"bg\"]};\n cursor: pointer;\n box-shadow: 0 0 ${Border[\"width-010\"]} ${Border[\"width-010\"]}\n ${Colour[\"border\"]};\n border-bottom-right-radius: ${Radius[\"sm\"]};\n border-bottom-left-radius: ${Radius[\"sm\"]};\n /* Enables vertical scrolling */\n overflow-y: auto;\n /* Set a max height for the dropdown list */\n max-height: var(${tokens.navItemList.viewportHeight});\n`;\n\nexport const navItemLabel = css`\n ${Font[\"body-baseline-regular\"]}\n color: ${Colour[\"text\"]};\n`;\n\nexport const navItemLabelSelected = css`\n color: ${Colour[\"text-selected\"]};\n`;\n\nexport const tickIcon = css`\n color: ${Colour[\"icon-selected\"]};\n margin: 0 ${Spacing[\"spacing-8\"]};\n`;\n\n// -----------------------------------------------------------------------------\n// MAIN\n// -----------------------------------------------------------------------------\n\nexport const backdrop = css`\n position: fixed;\n top: 0;\n right: 0;\n left: 0;\n bottom: 0;\n background-color: ${Colour[\"overlay-strong\"]};\n z-index: -1;\n`;\n\nexport const navWrapper = css`\n ${tokens.navWrapper.stickyOffset}: initial;\n ${tokens.navWrapper.sideMargin}: initial;\n display: block;\n position: sticky;\n top: var(${tokens.navWrapper.stickyOffset});\n width: 100%;\n z-index: 10;\n`;\n\nexport const navWrapperStickied = css`\n .${navSelect} {\n margin: 0 calc(var(${tokens.navWrapper.sideMargin}, 0px) * -1);\n padding: ${Spacing[\"spacing-12\"]} ${Spacing[\"spacing-16\"]};\n border-radius: ${Radius[\"none\"]};\n }\n\n .${navItemList} {\n margin-left: calc(var(${tokens.navWrapper.sideMargin}, 0px) * -1);\n margin-right: calc(var(${tokens.navWrapper.sideMargin}, 0px) * -1);\n border-bottom-left-radius: ${Radius[\"sm\"]};\n border-bottom-right-radius: ${Radius[\"sm\"]};\n }\n`;\n"],"names":["tokens","navWrapper","stickyOffset","sideMargin","navItemList","viewportHeight","navSelectIcon","navSelectIconExpanded","navSelect","navSelectExpanded","navItem","navItemSelected","navItemLabel","navItemLabelSelected","tickIcon","backdrop","navWrapperStickied"],"mappings":"2FAIO,MAAMA,EAAS,CAClBC,WAAY,CACRC,aAAc,0DACdC,WAAY,yDAEhBC,YAAa,CACTC,eACI,+DAQCC,EAAa,UAMbC,EAAqB,WAIrBC,EAAS,WAqBTC,EAAiB,WASjBC,EAAO,WAiBPC,EAAe,WAMfP,EAAW,UAmBXQ,EAAY,WAKZC,EAAoB,UAIpBC,EAAQ,UASRC,EAAQ,UAURd,EAAU,UAUVe,EAAkB"}
1
+ {"version":3,"file":"local-nav-dropdown.styles.js","sources":["../../../src/local-nav/local-nav-dropdown/local-nav-dropdown.styles.ts"],"sourcesContent":["import { css } from \"@linaria/core\";\n\nimport { Border, Colour, Font, Motion, Radius, Spacing } from \"../../theme\";\n\nexport const tokens = {\n navWrapper: {\n stickyOffset: \"--fds-internal-localNavDropdown-navWrapper-stickyOffset\",\n sideMargin: \"--fds-internal-localNavDropdown-navWrapper-sideMargin\",\n },\n navItemList: {\n viewportHeight:\n \"--fds-internal-localNavDropdown-navItemList-viewportHeight\",\n },\n};\n\n// -----------------------------------------------------------------------------\n// NAV SELECT\n// -----------------------------------------------------------------------------\n\nexport const navSelectIcon = css`\n color: ${Colour[\"icon\"]};\n transition: transform ${Motion[\"duration-250\"]} ${Motion[\"ease-default\"]};\n transform: rotate(0deg);\n`;\n\nexport const navSelectIconExpanded = css`\n transform: rotate(180deg);\n`;\n\nexport const navSelect = css`\n cursor: pointer;\n background: ${Colour[\"bg\"]};\n padding: ${Spacing[\"spacing-12\"]} ${Spacing[\"spacing-16\"]};\n overflow: hidden;\n box-shadow: 0 0 ${Border[\"width-010\"]} ${Border[\"width-010\"]}\n ${Colour[\"border\"]};\n border-radius: ${Radius[\"sm\"]};\n display: flex;\n justify-content: space-between;\n align-items: center;\n transition: all ${Motion[\"duration-250\"]} ${Motion[\"ease-default\"]};\n transition-property: background, border-radius, box-shadow, transform;\n\n &:focus-visible {\n outline: 2px solid ${Colour[\"focus-ring\"]};\n outline-offset: 2px;\n border-radius: ${Radius[\"sm\"]};\n }\n`;\n\nexport const navSelectExpanded = css`\n border-bottom-left-radius: ${Radius[\"none\"]};\n border-bottom-right-radius: ${Radius[\"none\"]};\n`;\n\n// -----------------------------------------------------------------------------\n// NAV ITEMS\n// -----------------------------------------------------------------------------\n\nexport const navItem = css`\n padding: ${Spacing[\"spacing-12\"]} ${Spacing[\"spacing-8\"]}\n ${Spacing[\"spacing-12\"]} ${Spacing[\"spacing-32\"]};\n background: ${Colour[\"bg\"]};\n /* Ensures that the tick mark is positioned relative to the selected item */\n position: relative;\n display: flex;\n /* Vertically align text and tick */\n align-items: center;\n\n &:focus-visible {\n outline: 2px solid ${Colour[\"focus-ring\"]};\n outline-offset: 0px;\n border-radius: ${Radius[\"sm\"]};\n }\n`;\n\nexport const navItemSelected = css`\n padding: ${Spacing[\"spacing-12\"]} ${Spacing[\"spacing-8\"]}\n ${Spacing[\"spacing-12\"]} 0;\n background: ${Colour[\"bg-primary-subtlest\"]};\n`;\n\nexport const navItemList = css`\n ${tokens.navItemList.viewportHeight}: initial;\n transition: all ${Motion[\"duration-250\"]} ${Motion[\"ease-default\"]};\n transform-origin: top;\n list-style-type: none;\n padding: 0 ${Spacing[\"spacing-8\"]};\n margin: 0;\n background: ${Colour[\"bg\"]};\n cursor: pointer;\n box-shadow: 0 0 ${Border[\"width-010\"]} ${Border[\"width-010\"]}\n ${Colour[\"border\"]};\n border-bottom-right-radius: ${Radius[\"sm\"]};\n border-bottom-left-radius: ${Radius[\"sm\"]};\n /* Enables vertical scrolling */\n overflow-y: auto;\n /* Set a max height for the dropdown list */\n max-height: var(${tokens.navItemList.viewportHeight});\n`;\n\nexport const titleContainer = css`\n display: flex;\n align-items: center;\n gap: ${Spacing[\"spacing-8\"]};\n flex: 1;\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 navItemLabel = css`\n ${Font[\"body-baseline-regular\"]}\n color: ${Colour[\"text\"]};\n`;\n\nexport const navItemLabelSelected = css`\n color: ${Colour[\"text-selected\"]};\n`;\n\nexport const tickIcon = css`\n color: ${Colour[\"icon-selected\"]};\n margin: 0 ${Spacing[\"spacing-8\"]};\n`;\n\n// -----------------------------------------------------------------------------\n// MAIN\n// -----------------------------------------------------------------------------\n\nexport const backdrop = css`\n position: fixed;\n top: 0;\n right: 0;\n left: 0;\n bottom: 0;\n background-color: ${Colour[\"overlay-strong\"]};\n z-index: -1;\n`;\n\nexport const navWrapper = css`\n ${tokens.navWrapper.stickyOffset}: initial;\n ${tokens.navWrapper.sideMargin}: initial;\n display: block;\n position: sticky;\n top: var(${tokens.navWrapper.stickyOffset});\n width: 100%;\n z-index: 10;\n`;\n\nexport const navWrapperStickied = css`\n .${navSelect} {\n margin: 0 calc(var(${tokens.navWrapper.sideMargin}, 0px) * -1);\n padding: ${Spacing[\"spacing-12\"]} ${Spacing[\"spacing-16\"]};\n border-radius: ${Radius[\"none\"]};\n }\n\n .${navItemList} {\n margin-left: calc(var(${tokens.navWrapper.sideMargin}, 0px) * -1);\n margin-right: calc(var(${tokens.navWrapper.sideMargin}, 0px) * -1);\n border-bottom-left-radius: ${Radius[\"sm\"]};\n border-bottom-right-radius: ${Radius[\"sm\"]};\n }\n`;\n"],"names":["tokens","navWrapper","stickyOffset","sideMargin","navItemList","viewportHeight","navSelectIcon","navSelectIconExpanded","navSelect","navSelectExpanded","navItem","navItemSelected","titleContainer","leftAddon","rightAddon","navItemLabel","navItemLabelSelected","tickIcon","backdrop","navWrapperStickied"],"mappings":"2FAIO,MAAMA,EAAS,CAClBC,WAAY,CACRC,aAAc,0DACdC,WAAY,yDAEhBC,YAAa,CACTC,eACI,+DAQCC,EAAa,UAMbC,EAAqB,WAIrBC,EAAS,WAqBTC,EAAiB,WASjBC,EAAO,WAiBPC,EAAe,WAMfP,EAAW,UAmBXQ,EAAc,WAQdC,EAAS,UAQTC,EAAU,UAMVC,EAAY,UAKZC,EAAoB,UAIpBC,EAAQ,UASRC,EAAQ,SAURjB,EAAU,UAUVkB,EAAkB"}
@@ -5,9 +5,12 @@
5
5
  .n1rgfmu8{padding:var(--fds-spacing-12) var(--fds-spacing-8) var(--fds-spacing-12) var(--fds-spacing-32);background:var(--fds-colour-bg);position:relative;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;}.n1rgfmu8:focus-visible{outline:2px solid var(--fds-colour-focus-ring);outline-offset:0px;border-radius:var(--fds-radius-sm);}
6
6
  .n122w1r6{padding:var(--fds-spacing-12) var(--fds-spacing-8) var(--fds-spacing-12) 0;background:var(--fds-colour-bg-primary-subtlest);}
7
7
  .ny6lx9v{--fds-internal-localNavDropdown-navItemList-viewportHeight:initial;-webkit-transition:all var(--fds-motion-duration-250) var(--fds-motion-timing-ease-default);transition:all var(--fds-motion-duration-250) var(--fds-motion-timing-ease-default);transform-origin:top;list-style-type:none;padding:0 var(--fds-spacing-8);margin:0;background:var(--fds-colour-bg);cursor:pointer;box-shadow:0 0 var(--fds-border-width-010) var(--fds-border-width-010) var(--fds-colour-border);border-bottom-right-radius:var(--fds-radius-sm);border-bottom-left-radius:var(--fds-radius-sm);overflow-y:auto;max-height:var(--fds-internal-localNavDropdown-navItemList-viewportHeight);}
8
- .n1lmzf88{font-family:var(--fds-font-family-body);font-variant:var(--fds-font-variant);font-size:var(--fds-font-body-size-baseline);font-weight:var(--fds-font-weight-regular);line-height:var(--fds-font-body-lh-baseline);letter-spacing:var(--fds-font-body-ls-baseline);color:var(--fds-colour-text);}
9
- .nc4nyiy{color:var(--fds-colour-text-selected);}
10
- .thuuy8a{color:var(--fds-colour-icon-selected);margin:0 var(--fds-spacing-8);}
11
- .beqsxqe{position:fixed;top:0;right:0;left:0;bottom:0;background-color:var(--fds-colour-overlay-strong);z-index:-1;}
12
- .ns92rya{--fds-internal-localNavDropdown-navWrapper-stickyOffset:initial;--fds-internal-localNavDropdown-navWrapper-sideMargin:initial;display:block;position:-webkit-sticky;position:sticky;top:var(--fds-internal-localNavDropdown-navWrapper-stickyOffset);width:100%;z-index:10;}
13
- .np844yu .n1fsscye{margin:0 calc(var(--fds-internal-localNavDropdown-navWrapper-sideMargin, 0px) * -1);padding:var(--fds-spacing-12) var(--fds-spacing-16);border-radius:var(--fds-radius-none);}.np844yu .ny6lx9v{margin-left:calc(var(--fds-internal-localNavDropdown-navWrapper-sideMargin, 0px) * -1);margin-right:calc(var(--fds-internal-localNavDropdown-navWrapper-sideMargin, 0px) * -1);border-bottom-left-radius:var(--fds-radius-sm);border-bottom-right-radius:var(--fds-radius-sm);}}
8
+ .t1lmzf88{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);-webkit-flex:1;-ms-flex:1;flex:1;}
9
+ .lc4nyiy{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);}
10
+ .rhuuy8a{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;}
11
+ .neqsxqe{font-family:var(--fds-font-family-body);font-variant:var(--fds-font-variant);font-size:var(--fds-font-body-size-baseline);font-weight:var(--fds-font-weight-regular);line-height:var(--fds-font-body-lh-baseline);letter-spacing:var(--fds-font-body-ls-baseline);color:var(--fds-colour-text);}
12
+ .ns92rya{color:var(--fds-colour-text-selected);}
13
+ .tp844yu{color:var(--fds-colour-icon-selected);margin:0 var(--fds-spacing-8);}
14
+ .b7u5vs{position:fixed;top:0;right:0;left:0;bottom:0;background-color:var(--fds-colour-overlay-strong);z-index:-1;}
15
+ .nb4z8rf{--fds-internal-localNavDropdown-navWrapper-stickyOffset:initial;--fds-internal-localNavDropdown-navWrapper-sideMargin:initial;display:block;position:-webkit-sticky;position:sticky;top:var(--fds-internal-localNavDropdown-navWrapper-stickyOffset);width:100%;z-index:10;}
16
+ .n1y3g4t3 .n1fsscye{margin:0 calc(var(--fds-internal-localNavDropdown-navWrapper-sideMargin, 0px) * -1);padding:var(--fds-spacing-12) var(--fds-spacing-16);border-radius:var(--fds-radius-none);}.n1y3g4t3 .ny6lx9v{margin-left:calc(var(--fds-internal-localNavDropdown-navWrapper-sideMargin, 0px) * -1);margin-right:calc(var(--fds-internal-localNavDropdown-navWrapper-sideMargin, 0px) * -1);border-bottom-left-radius:var(--fds-radius-sm);border-bottom-right-radius:var(--fds-radius-sm);}}
@@ -1,2 +1,2 @@
1
- import{jsx as e}from"react/jsx-runtime";import t from"clsx";import r from"react";import{Typography as i}from"../../typography/index.js";import{nav as l,navItemContent as n,navItem as a,navItemSelected as d,textLabel as m}from"./local-nav-menu.styles.js";const s=r.forwardRef((({onNavItemSelect:r,items:s,selectedItemIndex:c,id:o,"data-testid":p,className:f,renderItem:u},h)=>{const x=p||"local-nav-menu";return e("ul",{ref:h,id:o,className:t(l,f),"data-testid":x,children:s.map(((l,s)=>(({handleClick:r,isSelected:l,item:s,renderItem:c,index:o})=>{const{id:p,title:f}=s;return e("li",{id:p,className:t(a,l&&d),children:e("div",{className:n,role:"link",onClick:r,onKeyDown:e=>((e,t)=>{const{key:r}=e;"Enter"!==r&&" "!==r||(e.preventDefault(),t(e))})(e,r),tabIndex:0,"aria-current":!!l||void 0,children:c?c(s,{selected:l}):e(i.BodyBL,{className:m,weight:l?"semibold":"regular",children:f})})},o)})({handleClick:e=>r(e,l,s),isSelected:s===c,item:l,renderItem:u,index:s})))})}));export{s as LocalNavMenu};
1
+ import{jsx as e,jsxs as t}from"react/jsx-runtime";import r from"clsx";import n from"react";import{Typography as i}from"../../typography/index.js";import{nav as l,navItemContent as a,navItem as s,navItemSelected as d,textLabel as c,titleContainer as m,leftAddon as o,rightAddon as h}from"./local-nav-menu.styles.js";const p=n.forwardRef((({onNavItemSelect:n,items:p,selectedItemIndex:f,id:u,"data-testid":N,className:x,renderItem:I},v)=>{const y=N||"local-nav-menu";return e("ul",{ref:v,id:u,className:r(l,x),"data-testid":y,children:p.map(((l,p)=>(({handleClick:n,isSelected:l,item:p,renderItem:f,index:u})=>{const{id:N,title:x,titleAddon:I}=p;return e("li",{id:N,className:r(s,l&&d),children:e("div",{className:a,role:"link",onClick:n,onKeyDown:e=>((e,t)=>{const{key:r}=e;"Enter"!==r&&" "!==r||(e.preventDefault(),t(e))})(e,n),tabIndex:0,"aria-current":!!l||void 0,children:(()=>{if(f)return f(p,{selected:l});const r=e(i.BodyBL,{className:c,weight:l?"semibold":"regular",children:x});return I?t("span",{className:m,children:[I.left&&e("span",{className:o,children:I.left}),r,I.right&&e("span",{className:h,children:I.right})]}):r})()})},u)})({handleClick:e=>n(e,l,p),isSelected:p===f,item:l,renderItem:I,index:p})))})}));export{p as LocalNavMenu};
2
2
  //# sourceMappingURL=local-nav-menu.js.map