@lifesg/react-design-system 4.0.0-alpha.7 → 4.0.0-alpha.9

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 (268) hide show
  1. package/accordion/accordion-item.js.map +1 -1
  2. package/accordion/accordion.js.map +1 -1
  3. package/alert/alert.js.map +1 -1
  4. package/button/button.js +1 -1
  5. package/button/button.js.map +1 -1
  6. package/button/button.styles.d.ts +1 -0
  7. package/button/button.styles.js +1 -1
  8. package/button/button.styles.js.map +1 -1
  9. package/button/button.styles_19i4dfq.css +21 -0
  10. package/cjs/accordion/accordion-item.js.map +1 -1
  11. package/cjs/accordion/accordion.js.map +1 -1
  12. package/cjs/alert/alert.js.map +1 -1
  13. package/cjs/button/button.js +1 -1
  14. package/cjs/button/button.js.map +1 -1
  15. package/cjs/button/button.styles.js +1 -1
  16. package/cjs/button/button.styles.js.map +1 -1
  17. package/cjs/button/button.styles_19i4dfq.css +21 -0
  18. package/cjs/countdown-timer/countdown-timer.js.map +1 -1
  19. package/cjs/data-table/data-table.js +1 -1
  20. package/cjs/data-table/data-table.js.map +1 -1
  21. package/cjs/data-table/data-table.styles.js +1 -1
  22. package/cjs/data-table/data-table.styles.js.map +1 -1
  23. package/{data-table/data-table.styles_rxganh.css → cjs/data-table/data-table.styles_1tnlmhe.css} +7 -6
  24. package/cjs/date-range-input/date-range-input.js.map +1 -1
  25. package/cjs/e-signature/e-signature-canvas.js.map +1 -1
  26. package/cjs/error-display/error-display-data.js +1 -1
  27. package/cjs/error-display/error-display-data.js.map +1 -1
  28. package/cjs/error-display/inactivity-timer.js.map +1 -1
  29. package/cjs/external/dompurify/dist/purify.es.js +2 -2
  30. package/cjs/external/dompurify/dist/purify.es.js.map +1 -1
  31. package/cjs/file-download/file-list-card/file-list-card.js.map +1 -1
  32. package/cjs/file-upload/custom-sensors.js.map +1 -1
  33. package/cjs/file-upload/file-list/file-list.js.map +1 -1
  34. package/cjs/filter/addons/filter-item-checkbox-helpers.js.map +1 -1
  35. package/cjs/filter/addons/filter-item-checkbox.js.map +1 -1
  36. package/cjs/filter/addons/filter-item-checkbox.styles.js +1 -1
  37. package/cjs/filter/addons/filter-item-checkbox.styles.js.map +1 -1
  38. package/{filter/addons/filter-item-checkbox.styles_7degw7.css → cjs/filter/addons/filter-item-checkbox.styles_6nbpdl.css} +1 -1
  39. package/cjs/filter/filter-item.js.map +1 -1
  40. package/cjs/filter/filter-item.styles.js +1 -1
  41. package/cjs/filter/filter-item.styles.js.map +1 -1
  42. package/cjs/filter/{filter-item.styles_cphjnj.css → filter-item.styles_1yixp8h.css} +1 -1
  43. package/cjs/filter/filter-modal.styles.js +1 -1
  44. package/cjs/filter/filter-modal.styles.js.map +1 -1
  45. package/{filter/filter-modal.styles_qw3xlg.css → cjs/filter/filter-modal.styles_kuth21.css} +1 -1
  46. package/cjs/filter/filter-sidebar.styles.js +1 -1
  47. package/cjs/filter/filter-sidebar.styles.js.map +1 -1
  48. package/cjs/filter/{filter-sidebar.styles_1otwpjl.css → filter-sidebar.styles_rbfq4f.css} +1 -1
  49. package/cjs/filter/filter.js.map +1 -1
  50. package/cjs/form/form-textarea/form-textarea.js +1 -1
  51. package/cjs/form/form-textarea/form-textarea.js.map +1 -1
  52. package/cjs/fullscreen-image-carousel/stateful-image.js.map +1 -1
  53. package/cjs/histogram-slider/histogram-slider.js.map +1 -1
  54. package/cjs/input-range-slider/input-range-slider.js.map +1 -1
  55. package/cjs/input-slider/input-slider.js.map +1 -1
  56. package/cjs/input-textarea/textarea-counter.js.map +1 -1
  57. package/cjs/input-textarea/textarea.js +1 -1
  58. package/cjs/input-textarea/textarea.js.map +1 -1
  59. package/cjs/input-textarea/textarea.styles.js +1 -1
  60. package/cjs/input-textarea/textarea.styles.js.map +1 -1
  61. package/cjs/input-textarea/{textarea.styles_q77m5x.css → textarea.styles_6we7bs.css} +3 -1
  62. package/cjs/modal/index.js.map +1 -1
  63. package/cjs/modal-v2/modal-v2.js +1 -1
  64. package/cjs/modal-v2/modal-v2.js.map +1 -1
  65. package/cjs/modal-v2/slots/card.js +1 -1
  66. package/cjs/modal-v2/slots/card.js.map +1 -1
  67. package/cjs/modal-v2/slots/header.js +2 -0
  68. package/cjs/modal-v2/slots/header.js.map +1 -0
  69. package/cjs/modal-v2/slots/slot-styles.js +1 -1
  70. package/cjs/modal-v2/slots/slot-styles.js.map +1 -1
  71. package/cjs/modal-v2/slots/{slot-styles_13sd376.css → slot-styles_10ut1v7.css} +5 -1
  72. package/cjs/navbar/navbar-items.js +1 -1
  73. package/cjs/navbar/navbar-items.js.map +1 -1
  74. package/cjs/navbar/navbar-items.styles.js +1 -1
  75. package/cjs/navbar/navbar-items.styles.js.map +1 -1
  76. package/cjs/navbar/{navbar-items.styles_1i3ltot.css → navbar-items.styles_1b1zx.css} +9 -8
  77. package/cjs/navbar/navbar-logo-data.js +1 -1
  78. package/cjs/navbar/navbar-logo-data.js.map +1 -1
  79. package/cjs/navbar/navbar.js.map +1 -1
  80. package/cjs/otp-input/otp-input.js.map +1 -1
  81. package/cjs/overlay/overlay.js.map +1 -1
  82. package/cjs/pagination/pagination.js.map +1 -1
  83. package/cjs/phone-number-input/phone-number-input.js.map +1 -1
  84. package/cjs/predictive-text-input/predictive-text-input.js.map +1 -1
  85. package/cjs/shared/dropdown-list/dropdown-list.js.map +1 -1
  86. package/cjs/shared/internal-calendar/calendar-manager.js.map +1 -1
  87. package/cjs/shared/standalone-date-input/standalone-date-input.js.map +1 -1
  88. package/cjs/singpass-button/singpass-button.styles.js +1 -1
  89. package/cjs/singpass-button/singpass-button.styles.js.map +1 -1
  90. package/cjs/singpass-button/{singpass-button.styles_1miyex3.css → singpass-button.styles_1fj2lru.css} +1 -1
  91. package/cjs/smart-app-banner/smart-app-banner.styles.js +1 -1
  92. package/cjs/smart-app-banner/smart-app-banner.styles.js.map +1 -1
  93. package/cjs/smart-app-banner/{smart-app-banner.styles_15u6yv4.css → smart-app-banner.styles_r6yjq9.css} +1 -1
  94. package/cjs/theme/types.js +1 -1
  95. package/cjs/theme/types.js.map +1 -1
  96. package/cjs/time-slot-bar/time-slot-bar.js.map +1 -1
  97. package/cjs/time-slot-bar-week/time-slot-bar-week-days.js.map +1 -1
  98. package/cjs/timetable/timetable.js.map +1 -1
  99. package/cjs/toast/toast.styles.js +1 -1
  100. package/cjs/toast/toast.styles.js.map +1 -1
  101. package/{toast/toast.styles_1e0l60w.css → cjs/toast/toast.styles_57j3lf.css} +1 -1
  102. package/cjs/toggle/toggle-icon.js +1 -1
  103. package/cjs/toggle/toggle-icon.js.map +1 -1
  104. package/cjs/toggle/toggle-icon.styles.js +1 -1
  105. package/cjs/toggle/toggle-icon.styles.js.map +1 -1
  106. package/cjs/toggle/{toggle-icon.styles_ba71y.css → toggle-icon.styles_o6dxr3.css} +3 -2
  107. package/cjs/toggle/toggle.js +1 -1
  108. package/cjs/toggle/toggle.js.map +1 -1
  109. package/cjs/toggle/toggle.styles.js +1 -1
  110. package/cjs/toggle/toggle.styles.js.map +1 -1
  111. package/cjs/toggle/toggle.styles_11tmfsr.css +41 -0
  112. package/cjs/unit-number/unit-number-input.js.map +1 -1
  113. package/cjs/util/is-styled-components.js.map +1 -1
  114. package/cjs/util/string-helper.js +1 -1
  115. package/cjs/util/string-helper.js.map +1 -1
  116. package/cjs/util/use-event-listener.js.map +1 -1
  117. package/cjs/util/use-state-actions.js.map +1 -1
  118. package/countdown-timer/countdown-timer.js.map +1 -1
  119. package/data-table/data-table.d.ts +1 -1
  120. package/data-table/data-table.js +1 -1
  121. package/data-table/data-table.js.map +1 -1
  122. package/data-table/data-table.styles.d.ts +1 -0
  123. package/data-table/data-table.styles.js +1 -1
  124. package/data-table/data-table.styles.js.map +1 -1
  125. package/{cjs/data-table/data-table.styles_rxganh.css → data-table/data-table.styles_1tnlmhe.css} +7 -6
  126. package/data-table/types.d.ts +4 -2
  127. package/date-range-input/date-range-input.js.map +1 -1
  128. package/docs/component-catalog.json +1 -1
  129. package/e-signature/e-signature-canvas.js.map +1 -1
  130. package/error-display/error-display-data.js +1 -1
  131. package/error-display/error-display-data.js.map +1 -1
  132. package/error-display/inactivity-timer.js.map +1 -1
  133. package/external/dompurify/dist/purify.es.js +2 -2
  134. package/external/dompurify/dist/purify.es.js.map +1 -1
  135. package/file-download/file-list-card/file-list-card.js.map +1 -1
  136. package/file-upload/custom-sensors.d.ts +2 -2
  137. package/file-upload/custom-sensors.js.map +1 -1
  138. package/file-upload/file-list/file-list.js.map +1 -1
  139. package/filter/addons/filter-item-checkbox-helpers.js.map +1 -1
  140. package/filter/addons/filter-item-checkbox.js.map +1 -1
  141. package/filter/addons/filter-item-checkbox.styles.js +1 -1
  142. package/filter/addons/filter-item-checkbox.styles.js.map +1 -1
  143. package/{cjs/filter/addons/filter-item-checkbox.styles_7degw7.css → filter/addons/filter-item-checkbox.styles_6nbpdl.css} +1 -1
  144. package/filter/filter-item.js.map +1 -1
  145. package/filter/filter-item.styles.js +1 -1
  146. package/filter/filter-item.styles.js.map +1 -1
  147. package/filter/{filter-item.styles_cphjnj.css → filter-item.styles_1yixp8h.css} +1 -1
  148. package/filter/filter-modal.styles.js +1 -1
  149. package/filter/filter-modal.styles.js.map +1 -1
  150. package/{cjs/filter/filter-modal.styles_qw3xlg.css → filter/filter-modal.styles_kuth21.css} +1 -1
  151. package/filter/filter-sidebar.styles.js +1 -1
  152. package/filter/filter-sidebar.styles.js.map +1 -1
  153. package/filter/{filter-sidebar.styles_1otwpjl.css → filter-sidebar.styles_rbfq4f.css} +1 -1
  154. package/filter/filter.js.map +1 -1
  155. package/form/form-textarea/form-textarea.js +1 -1
  156. package/form/form-textarea/form-textarea.js.map +1 -1
  157. package/fullscreen-image-carousel/stateful-image.js.map +1 -1
  158. package/fullscreen-image-carousel/types.d.ts +2 -2
  159. package/histogram-slider/histogram-slider.js.map +1 -1
  160. package/input-range-slider/input-range-slider.js.map +1 -1
  161. package/input-slider/input-slider.js.map +1 -1
  162. package/input-textarea/textarea-counter.js.map +1 -1
  163. package/input-textarea/textarea.js +1 -1
  164. package/input-textarea/textarea.js.map +1 -1
  165. package/input-textarea/textarea.styles.d.ts +2 -0
  166. package/input-textarea/textarea.styles.js +1 -1
  167. package/input-textarea/textarea.styles.js.map +1 -1
  168. package/input-textarea/{textarea.styles_q77m5x.css → textarea.styles_6we7bs.css} +3 -1
  169. package/input-textarea/types.d.ts +7 -0
  170. package/modal/index.d.ts +4 -0
  171. package/modal/index.js.map +1 -1
  172. package/modal/types.d.ts +2 -0
  173. package/modal-v2/modal-v2.d.ts +6 -0
  174. package/modal-v2/modal-v2.js +1 -1
  175. package/modal-v2/modal-v2.js.map +1 -1
  176. package/modal-v2/slots/card.js +1 -1
  177. package/modal-v2/slots/card.js.map +1 -1
  178. package/modal-v2/slots/header.d.ts +5 -0
  179. package/modal-v2/slots/header.js +2 -0
  180. package/modal-v2/slots/header.js.map +1 -0
  181. package/modal-v2/slots/index.d.ts +1 -0
  182. package/modal-v2/slots/slot-styles.d.ts +4 -0
  183. package/modal-v2/slots/slot-styles.js +1 -1
  184. package/modal-v2/slots/slot-styles.js.map +1 -1
  185. package/modal-v2/slots/{slot-styles_13sd376.css → slot-styles_10ut1v7.css} +5 -1
  186. package/modal-v2/types.d.ts +21 -0
  187. package/navbar/navbar-items.js +1 -1
  188. package/navbar/navbar-items.js.map +1 -1
  189. package/navbar/navbar-items.styles.d.ts +2 -1
  190. package/navbar/navbar-items.styles.js +1 -1
  191. package/navbar/navbar-items.styles.js.map +1 -1
  192. package/navbar/{navbar-items.styles_1i3ltot.css → navbar-items.styles_1b1zx.css} +9 -8
  193. package/navbar/navbar-logo-data.js +1 -1
  194. package/navbar/navbar-logo-data.js.map +1 -1
  195. package/navbar/navbar.js.map +1 -1
  196. package/otp-input/otp-input.js.map +1 -1
  197. package/overlay/overlay.js.map +1 -1
  198. package/package.json +1 -1
  199. package/pagination/pagination.js.map +1 -1
  200. package/phone-number-input/phone-number-input.js.map +1 -1
  201. package/predictive-text-input/predictive-text-input.js.map +1 -1
  202. package/shared/dropdown-list/dropdown-list.js.map +1 -1
  203. package/shared/internal-calendar/calendar-manager.js.map +1 -1
  204. package/shared/standalone-date-input/standalone-date-input.js.map +1 -1
  205. package/singpass-button/singpass-button.styles.js +1 -1
  206. package/singpass-button/singpass-button.styles.js.map +1 -1
  207. package/singpass-button/{singpass-button.styles_1miyex3.css → singpass-button.styles_1fj2lru.css} +1 -1
  208. package/smart-app-banner/smart-app-banner.styles.js +1 -1
  209. package/smart-app-banner/smart-app-banner.styles.js.map +1 -1
  210. package/smart-app-banner/{smart-app-banner.styles_15u6yv4.css → smart-app-banner.styles_r6yjq9.css} +1 -1
  211. package/theme/styles/a11y-playground.css +358 -87
  212. package/theme/styles/bookingsg.css +391 -85
  213. package/theme/styles/careercompass.css +396 -90
  214. package/theme/styles/ccube.css +402 -45
  215. package/theme/styles/imda.css +348 -85
  216. package/theme/styles/lifesg.css +377 -87
  217. package/theme/styles/mylegacy.css +382 -85
  218. package/theme/styles/oneservice.css +349 -86
  219. package/theme/styles/pa.css +172 -104
  220. package/theme/styles/rbs.css +403 -46
  221. package/theme/styles/sgw-digital-lobby.css +352 -87
  222. package/theme/styles/smgs.css +401 -95
  223. package/theme/styles/spf.css +208 -99
  224. package/theme/styles/supportgowhere.css +387 -90
  225. package/theme/styles/tote-board.css +816 -0
  226. package/theme/types.d.ts +1 -1
  227. package/theme/types.js +1 -1
  228. package/theme/types.js.map +1 -1
  229. package/time-slot-bar/time-slot-bar.js.map +1 -1
  230. package/time-slot-bar-week/time-slot-bar-week-days.js.map +1 -1
  231. package/timetable/timetable.js.map +1 -1
  232. package/toast/toast.styles.js +1 -1
  233. package/toast/toast.styles.js.map +1 -1
  234. package/{cjs/toast/toast.styles_1e0l60w.css → toast/toast.styles_57j3lf.css} +1 -1
  235. package/toggle/toggle-icon.d.ts +2 -1
  236. package/toggle/toggle-icon.js +1 -1
  237. package/toggle/toggle-icon.js.map +1 -1
  238. package/toggle/toggle-icon.styles.d.ts +1 -0
  239. package/toggle/toggle-icon.styles.js +1 -1
  240. package/toggle/toggle-icon.styles.js.map +1 -1
  241. package/toggle/{toggle-icon.styles_ba71y.css → toggle-icon.styles_o6dxr3.css} +3 -2
  242. package/toggle/toggle.js +1 -1
  243. package/toggle/toggle.js.map +1 -1
  244. package/toggle/toggle.styles.d.ts +18 -15
  245. package/toggle/toggle.styles.js +1 -1
  246. package/toggle/toggle.styles.js.map +1 -1
  247. package/toggle/toggle.styles_11tmfsr.css +41 -0
  248. package/tools/storybook-argtypes/services/arg-types-row-builder.d.ts +6 -0
  249. package/tools/storybook-argtypes/types.d.ts +13 -1
  250. package/unit-number/unit-number-input.js.map +1 -1
  251. package/util/is-styled-components.js.map +1 -1
  252. package/util/string-helper.d.ts +2 -2
  253. package/util/string-helper.js +1 -1
  254. package/util/string-helper.js.map +1 -1
  255. package/util/use-event-listener.js.map +1 -1
  256. package/util/use-state-actions.js.map +1 -1
  257. package/button/button.styles_1pxy0co.css +0 -20
  258. package/cjs/button/button.styles_1pxy0co.css +0 -20
  259. package/cjs/form/form-textarea/form-textarea.styles.js +0 -2
  260. package/cjs/form/form-textarea/form-textarea.styles.js.map +0 -1
  261. package/cjs/form/form-textarea/form-textarea.styles_1kneyif.css +0 -3
  262. package/cjs/toggle/toggle.styles_1t5qrye.css +0 -38
  263. package/form/form-textarea/form-textarea.styles.d.ts +0 -3
  264. package/form/form-textarea/form-textarea.styles.js +0 -2
  265. package/form/form-textarea/form-textarea.styles.js.map +0 -1
  266. package/form/form-textarea/form-textarea.styles_1kneyif.css +0 -3
  267. package/theme/styles/default.css +0 -158
  268. package/toggle/toggle.styles_1t5qrye.css +0 -38
@@ -1 +1 @@
1
- {"version":3,"file":"countdown-timer.js","sources":["../../src/countdown-timer/countdown-timer.tsx"],"sourcesContent":["import { ClockIcon } from \"@lifesg/react-icons\";\nimport clsx from \"clsx\";\nimport throttle from \"lodash/throttle\";\nimport { useEffect, useRef, useState } from \"react\";\nimport { useInView } from \"react-intersection-observer\";\n\nimport { inertValue, VisuallyHidden } from \"../shared/accessibility\";\nimport {\n formatUnitValue,\n useApplyStyle,\n useMaxWidthMediaQuery,\n} from \"../theme\";\nimport { useIsMounted } from \"../util\";\nimport { TimeHelper } from \"../util/time-helper\";\nimport * as styles from \"./countdown-timer.styles\";\nimport type { CountdownTimerProps } from \"./types\";\nimport { useTimer } from \"./use-timer\";\n\n// @catalog\n/**\n * Displays a live countdown of time remaining until a deadline.\n *\n * Use when a time-limited interaction — such as a session timeout or a timed\n * form — needs a persistent visual reminder.\n */\nexport const CountdownTimer = ({\n className,\n align = \"right\",\n timer,\n timestamp,\n notifyTimer,\n offset,\n mobileOffset,\n show,\n fixed = true,\n reminderInterval = 120,\n \"data-testid\": testId,\n onFinish,\n onNotify,\n onTick,\n ...otherProps\n}: CountdownTimerProps) => {\n // =============================================================================\n // CONST, STATE, REF\n // =============================================================================\n\n const wrapperRef = useRef<HTMLDivElement>(null);\n const fixedCountdownRef = useRef<HTMLDivElement>(null);\n\n const isNotified = useRef<boolean>(false);\n const [offsetY, setOffsetY] = useState<number>(0);\n const [clientRectRight, setClientRectRight] = useState<number>(0);\n const [clientRectX, setClientRectX] = useState<number>(0);\n const [isPlaying, setIsPlaying] = useState(false);\n const [announcement, setAnnouncement] = useState<string>(\"\");\n\n const isMounted = useIsMounted();\n const [remainingSeconds, initialSeconds] = useTimer(\n timer,\n timestamp,\n isPlaying\n );\n const { ref: stickyRef, inView } = useInView({\n threshold: 1,\n rootMargin: `${offsetY * -1}px 0px 0px 0px`,\n initialInView: true,\n });\n const isVisible = !fixed || inView;\n const warn =\n typeof notifyTimer === \"number\" && remainingSeconds <= notifyTimer;\n\n const isMobile = useMaxWidthMediaQuery(\"sm\");\n\n // =============================================================================\n // EFFECTS\n // =============================================================================\n\n useApplyStyle(fixedCountdownRef, {\n [styles.tokens.fixedCountdown.top]: formatUnitValue(offsetY, \"px\"),\n [styles.tokens.fixedCountdown.left]: formatUnitValue(\n getOffsetLeft(),\n \"px\"\n ),\n [styles.tokens.fixedCountdown.right]: formatUnitValue(\n getOffsetRight(),\n \"px\"\n ),\n });\n\n useEffect(() => {\n setIsPlaying(show);\n }, [show]);\n\n useEffect(() => {\n if (remainingSeconds === 0) {\n performOnFinishHandler();\n } else if (\n typeof notifyTimer === \"number\" &&\n remainingSeconds <= notifyTimer\n ) {\n performOnTickHandler();\n performOnNotifyHandler();\n }\n }, [remainingSeconds]);\n\n useEffect(() => {\n const y = getOffsetY();\n setOffsetY(y);\n }, [isMobile, offset?.top, mobileOffset?.top]);\n\n useEffect(() => {\n if (wrapperRef.current) {\n const handleResize = throttle(handleWindowResize, 300);\n handleWindowResize();\n\n window.addEventListener(\"resize\", handleResize);\n\n return () => {\n window.removeEventListener(\"resize\", handleResize);\n };\n }\n }, [wrapperRef.current]);\n\n // Announcements\n useEffect(() => {\n const timeElapsed = initialSeconds - remainingSeconds;\n if (timeElapsed === 0) return;\n // Polite notification\n if (timeElapsed % reminderInterval === 0) {\n if (\n typeof notifyTimer !== \"number\" ||\n remainingSeconds > notifyTimer\n ) {\n setAnnouncement(getAccessibleTimeText(remainingSeconds));\n }\n }\n\n // Assertive notification\n if (\n typeof notifyTimer === \"number\" &&\n remainingSeconds === notifyTimer\n ) {\n setAnnouncement(getAccessibleTimeText(remainingSeconds));\n }\n }, [remainingSeconds, initialSeconds, reminderInterval, notifyTimer]);\n\n useEffect(() => {\n // reset\n isNotified.current = false;\n }, [initialSeconds, show]);\n\n // =============================================================================\n // EVENT HANDLERS\n // =============================================================================\n const handleWindowResize = () => {\n if (!wrapperRef.current) return;\n\n const clientRect = wrapperRef.current.getBoundingClientRect();\n\n setClientRectX(clientRect.x);\n setClientRectRight(clientRect.right);\n };\n\n const handleOnFocus = () => {\n const focusMessage = getAccessibleTimeText(remainingSeconds);\n setAnnouncement(focusMessage);\n };\n\n // =============================================================================\n // HELPER FUNCTIONS\n // =============================================================================\n\n const performOnTickHandler = () => {\n if (onTick) {\n onTick(remainingSeconds);\n }\n };\n\n const performOnNotifyHandler = () => {\n if (onNotify && !isNotified.current) {\n isNotified.current = true;\n onNotify();\n }\n };\n\n const performOnFinishHandler = () => {\n setIsPlaying(false);\n\n if (onFinish) onFinish();\n };\n\n function getOffsetY() {\n const desktopTop = offset?.top ?? 168;\n const mobileTop = mobileOffset?.top ?? 80;\n const offsetY = isMobile ? mobileTop : desktopTop;\n\n return offsetY;\n }\n\n function getOffsetLeft() {\n if (!isMounted || align !== \"left\") return undefined;\n return offset?.left ?? clientRectX;\n }\n\n function getOffsetRight() {\n if (!isMounted || align !== \"right\") return undefined;\n return (\n offset?.right ??\n Math.floor(document.body.clientWidth - clientRectRight)\n );\n }\n\n const getAccessibleTimeText = (seconds: number): string => {\n const { minutes, seconds: secs } = TimeHelper.toMinutesSeconds(seconds);\n\n const minuteText = minutes === 1 ? \"minute\" : \"minutes\";\n const secondText = secs === 1 ? \"second\" : \"seconds\";\n\n if (minutes > 0 && secs > 0) {\n return `Time left: ${minutes} ${minuteText} and ${secs} ${secondText}`;\n } else if (minutes > 0) {\n return `Time left: ${minutes} ${minuteText}`;\n } else {\n return `Time left: ${secs} ${secondText}`;\n }\n };\n // =============================================================================\n // RENDER FUNCTION\n // =============================================================================\n\n const renderPeriodicAndWarningAnnouncement = () => (\n <VisuallyHidden\n aria-live={\n typeof notifyTimer === \"number\" &&\n remainingSeconds <= notifyTimer\n ? \"assertive\"\n : \"polite\"\n }\n aria-atomic=\"true\"\n >\n {announcement}\n </VisuallyHidden>\n );\n\n const renderTimer = () => {\n const { minutes, seconds } =\n TimeHelper.toMinutesSeconds(remainingSeconds);\n const m = minutes !== 1 ? \"mins\" : \"min\";\n const s = seconds !== 1 ? \"secs\" : \"sec\";\n return (\n <>\n <ClockIcon className={styles.timerIcon} data-warn={!!warn} />\n <div className={styles.timeLeft}>Time left:</div>\n <div\n className={styles.timer}\n aria-label={getAccessibleTimeText(remainingSeconds)}\n >\n {minutes} {m} {String(seconds).padStart(2, \"0\")} {s}\n </div>\n {renderPeriodicAndWarningAnnouncement()}\n </>\n );\n };\n\n const renderInlineCountdown = () => {\n return (\n <div\n data-testid={testId}\n data-id=\"countdown-wrapper\"\n data-warn={!!warn}\n ref={wrapperRef}\n inert={inertValue(!isVisible)}\n className={clsx(\n styles.countdown,\n styles.countdownInline,\n !isVisible && styles.countdownHidden\n )}\n tabIndex={0}\n role=\"timer\"\n aria-label=\"Countdown timer\"\n onFocus={handleOnFocus}\n >\n {renderTimer()}\n </div>\n );\n };\n\n const renderFixedCountdown = () => {\n return (\n <div\n ref={fixedCountdownRef}\n data-testid={testId}\n data-id=\"fixed-countdown-wrapper\"\n data-warn={!!warn}\n className={clsx(styles.countdown, styles.countdownFixed)}\n tabIndex={0}\n role=\"timer\"\n aria-label=\"Countdown timer\"\n onFocus={handleOnFocus}\n >\n {renderTimer()}\n </div>\n );\n };\n\n if (!isPlaying && remainingSeconds !== 0) return <></>;\n\n return (\n <div className={clsx(styles.wrapper, className)} {...otherProps}>\n <div ref={stickyRef}></div>\n {renderInlineCountdown()}\n {wrapperRef.current && !isVisible && renderFixedCountdown()}\n </div>\n );\n};\n"],"names":["CountdownTimer","_a","className","align","timer","timestamp","notifyTimer","offset","mobileOffset","show","fixed","reminderInterval","testId","onFinish","onNotify","onTick","otherProps","__rest","wrapperRef","useRef","fixedCountdownRef","isNotified","offsetY","setOffsetY","useState","clientRectRight","setClientRectRight","clientRectX","setClientRectX","isPlaying","setIsPlaying","announcement","setAnnouncement","isMounted","useIsMounted","remainingSeconds","initialSeconds","useTimer","ref","stickyRef","inView","useInView","threshold","rootMargin","initialInView","isVisible","warn","isMobile","useMaxWidthMediaQuery","useApplyStyle","styles.tokens","fixedCountdown","top","formatUnitValue","left","getOffsetLeft","right","Math","floor","document","body","clientWidth","getOffsetRight","useEffect","performOnFinishHandler","performOnTickHandler","performOnNotifyHandler","y","desktopTop","mobileTop","_b","getOffsetY","current","handleResize","throttle","handleWindowResize","window","addEventListener","removeEventListener","timeElapsed","getAccessibleTimeText","clientRect","getBoundingClientRect","x","handleOnFocus","focusMessage","seconds","minutes","secs","TimeHelper","toMinutesSeconds","minuteText","secondText","renderTimer","m","s","_jsxs","_Fragment","children","_jsx","ClockIcon","styles.timerIcon","styles.timeLeft","styles.timer","String","padStart","VisuallyHidden","Object","assign","clsx","styles.wrapper","inert","inertValue","styles.countdown","styles.countdownInline","styles.countdownHidden","tabIndex","role","onFocus","styles.countdownFixed"],"mappings":"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"}
1
+ {"version":3,"file":"countdown-timer.js","sources":["../../src/countdown-timer/countdown-timer.tsx"],"sourcesContent":["import { ClockIcon } from \"@lifesg/react-icons\";\nimport clsx from \"clsx\";\nimport throttle from \"lodash/throttle\";\nimport { useEffect, useRef, useState } from \"react\";\nimport { useInView } from \"react-intersection-observer\";\n\nimport { inertValue, VisuallyHidden } from \"../shared/accessibility\";\nimport {\n formatUnitValue,\n useApplyStyle,\n useMaxWidthMediaQuery,\n} from \"../theme\";\nimport { useIsMounted } from \"../util\";\nimport { TimeHelper } from \"../util/time-helper\";\nimport * as styles from \"./countdown-timer.styles\";\nimport type { CountdownTimerProps } from \"./types\";\nimport { useTimer } from \"./use-timer\";\n\n// @catalog\n/**\n * Displays a live countdown of time remaining until a deadline.\n *\n * Use when a time-limited interaction — such as a session timeout or a timed\n * form — needs a persistent visual reminder.\n */\nexport const CountdownTimer = ({\n className,\n align = \"right\",\n timer,\n timestamp,\n notifyTimer,\n offset,\n mobileOffset,\n show,\n fixed = true,\n reminderInterval = 120,\n \"data-testid\": testId,\n onFinish,\n onNotify,\n onTick,\n ...otherProps\n}: CountdownTimerProps) => {\n // =============================================================================\n // CONST, STATE, REF\n // =============================================================================\n\n const wrapperRef = useRef<HTMLDivElement>(null);\n const fixedCountdownRef = useRef<HTMLDivElement>(null);\n\n const isNotified = useRef<boolean>(false);\n const [offsetY, setOffsetY] = useState<number>(0);\n const [clientRectRight, setClientRectRight] = useState<number>(0);\n const [clientRectX, setClientRectX] = useState<number>(0);\n const [isPlaying, setIsPlaying] = useState(false);\n const [announcement, setAnnouncement] = useState<string>(\"\");\n\n const isMounted = useIsMounted();\n const [remainingSeconds, initialSeconds] = useTimer(\n timer,\n timestamp,\n isPlaying\n );\n const { ref: stickyRef, inView } = useInView({\n threshold: 1,\n rootMargin: `${offsetY * -1}px 0px 0px 0px`,\n initialInView: true,\n });\n const isVisible = !fixed || inView;\n const warn =\n typeof notifyTimer === \"number\" && remainingSeconds <= notifyTimer;\n\n const isMobile = useMaxWidthMediaQuery(\"sm\");\n\n // =============================================================================\n // EFFECTS\n // =============================================================================\n\n useApplyStyle(fixedCountdownRef, {\n [styles.tokens.fixedCountdown.top]: formatUnitValue(offsetY, \"px\"),\n [styles.tokens.fixedCountdown.left]: formatUnitValue(\n getOffsetLeft(),\n \"px\"\n ),\n [styles.tokens.fixedCountdown.right]: formatUnitValue(\n getOffsetRight(),\n \"px\"\n ),\n });\n\n useEffect(() => {\n setIsPlaying(show);\n }, [show]);\n\n useEffect(() => {\n if (remainingSeconds === 0) {\n performOnFinishHandler();\n } else if (\n typeof notifyTimer === \"number\" &&\n remainingSeconds <= notifyTimer\n ) {\n performOnTickHandler();\n performOnNotifyHandler();\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [remainingSeconds]);\n\n useEffect(() => {\n const y = getOffsetY();\n setOffsetY(y);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [isMobile, offset?.top, mobileOffset?.top]);\n\n useEffect(() => {\n if (wrapperRef.current) {\n const handleResize = throttle(handleWindowResize, 300);\n handleWindowResize();\n\n window.addEventListener(\"resize\", handleResize);\n\n return () => {\n window.removeEventListener(\"resize\", handleResize);\n };\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [wrapperRef.current]);\n\n // Announcements\n useEffect(() => {\n const timeElapsed = initialSeconds - remainingSeconds;\n if (timeElapsed === 0) return;\n // Polite notification\n if (timeElapsed % reminderInterval === 0) {\n if (\n typeof notifyTimer !== \"number\" ||\n remainingSeconds > notifyTimer\n ) {\n setAnnouncement(getAccessibleTimeText(remainingSeconds));\n }\n }\n\n // Assertive notification\n if (\n typeof notifyTimer === \"number\" &&\n remainingSeconds === notifyTimer\n ) {\n setAnnouncement(getAccessibleTimeText(remainingSeconds));\n }\n }, [remainingSeconds, initialSeconds, reminderInterval, notifyTimer]);\n\n useEffect(() => {\n // reset\n isNotified.current = false;\n }, [initialSeconds, show]);\n\n // =============================================================================\n // EVENT HANDLERS\n // =============================================================================\n const handleWindowResize = () => {\n if (!wrapperRef.current) return;\n\n const clientRect = wrapperRef.current.getBoundingClientRect();\n\n setClientRectX(clientRect.x);\n setClientRectRight(clientRect.right);\n };\n\n const handleOnFocus = () => {\n const focusMessage = getAccessibleTimeText(remainingSeconds);\n setAnnouncement(focusMessage);\n };\n\n // =============================================================================\n // HELPER FUNCTIONS\n // =============================================================================\n\n const performOnTickHandler = () => {\n if (onTick) {\n onTick(remainingSeconds);\n }\n };\n\n const performOnNotifyHandler = () => {\n if (onNotify && !isNotified.current) {\n isNotified.current = true;\n onNotify();\n }\n };\n\n const performOnFinishHandler = () => {\n setIsPlaying(false);\n\n if (onFinish) onFinish();\n };\n\n function getOffsetY() {\n const desktopTop = offset?.top ?? 168;\n const mobileTop = mobileOffset?.top ?? 80;\n const offsetY = isMobile ? mobileTop : desktopTop;\n\n return offsetY;\n }\n\n function getOffsetLeft() {\n if (!isMounted || align !== \"left\") return undefined;\n return offset?.left ?? clientRectX;\n }\n\n function getOffsetRight() {\n if (!isMounted || align !== \"right\") return undefined;\n return (\n offset?.right ??\n Math.floor(document.body.clientWidth - clientRectRight)\n );\n }\n\n const getAccessibleTimeText = (seconds: number): string => {\n const { minutes, seconds: secs } = TimeHelper.toMinutesSeconds(seconds);\n\n const minuteText = minutes === 1 ? \"minute\" : \"minutes\";\n const secondText = secs === 1 ? \"second\" : \"seconds\";\n\n if (minutes > 0 && secs > 0) {\n return `Time left: ${minutes} ${minuteText} and ${secs} ${secondText}`;\n } else if (minutes > 0) {\n return `Time left: ${minutes} ${minuteText}`;\n } else {\n return `Time left: ${secs} ${secondText}`;\n }\n };\n // =============================================================================\n // RENDER FUNCTION\n // =============================================================================\n\n const renderPeriodicAndWarningAnnouncement = () => (\n <VisuallyHidden\n aria-live={\n typeof notifyTimer === \"number\" &&\n remainingSeconds <= notifyTimer\n ? \"assertive\"\n : \"polite\"\n }\n aria-atomic=\"true\"\n >\n {announcement}\n </VisuallyHidden>\n );\n\n const renderTimer = () => {\n const { minutes, seconds } =\n TimeHelper.toMinutesSeconds(remainingSeconds);\n const m = minutes !== 1 ? \"mins\" : \"min\";\n const s = seconds !== 1 ? \"secs\" : \"sec\";\n return (\n <>\n <ClockIcon className={styles.timerIcon} data-warn={!!warn} />\n <div className={styles.timeLeft}>Time left:</div>\n <div\n className={styles.timer}\n aria-label={getAccessibleTimeText(remainingSeconds)}\n >\n {minutes} {m} {String(seconds).padStart(2, \"0\")} {s}\n </div>\n {renderPeriodicAndWarningAnnouncement()}\n </>\n );\n };\n\n const renderInlineCountdown = () => {\n return (\n <div\n data-testid={testId}\n data-id=\"countdown-wrapper\"\n data-warn={!!warn}\n ref={wrapperRef}\n inert={inertValue(!isVisible)}\n className={clsx(\n styles.countdown,\n styles.countdownInline,\n !isVisible && styles.countdownHidden\n )}\n tabIndex={0}\n role=\"timer\"\n aria-label=\"Countdown timer\"\n onFocus={handleOnFocus}\n >\n {renderTimer()}\n </div>\n );\n };\n\n const renderFixedCountdown = () => {\n return (\n <div\n ref={fixedCountdownRef}\n data-testid={testId}\n data-id=\"fixed-countdown-wrapper\"\n data-warn={!!warn}\n className={clsx(styles.countdown, styles.countdownFixed)}\n tabIndex={0}\n role=\"timer\"\n aria-label=\"Countdown timer\"\n onFocus={handleOnFocus}\n >\n {renderTimer()}\n </div>\n );\n };\n\n if (!isPlaying && remainingSeconds !== 0) return <></>;\n\n return (\n <div className={clsx(styles.wrapper, className)} {...otherProps}>\n <div ref={stickyRef}></div>\n {renderInlineCountdown()}\n {wrapperRef.current && !isVisible && renderFixedCountdown()}\n </div>\n );\n};\n"],"names":["CountdownTimer","_a","className","align","timer","timestamp","notifyTimer","offset","mobileOffset","show","fixed","reminderInterval","testId","onFinish","onNotify","onTick","otherProps","__rest","wrapperRef","useRef","fixedCountdownRef","isNotified","offsetY","setOffsetY","useState","clientRectRight","setClientRectRight","clientRectX","setClientRectX","isPlaying","setIsPlaying","announcement","setAnnouncement","isMounted","useIsMounted","remainingSeconds","initialSeconds","useTimer","ref","stickyRef","inView","useInView","threshold","rootMargin","initialInView","isVisible","warn","isMobile","useMaxWidthMediaQuery","useApplyStyle","styles.tokens","fixedCountdown","top","formatUnitValue","left","getOffsetLeft","right","Math","floor","document","body","clientWidth","getOffsetRight","useEffect","performOnFinishHandler","performOnTickHandler","performOnNotifyHandler","y","desktopTop","mobileTop","_b","getOffsetY","current","handleResize","throttle","handleWindowResize","window","addEventListener","removeEventListener","timeElapsed","getAccessibleTimeText","clientRect","getBoundingClientRect","x","handleOnFocus","focusMessage","seconds","minutes","secs","TimeHelper","toMinutesSeconds","minuteText","secondText","renderTimer","m","s","_jsxs","_Fragment","children","_jsx","ClockIcon","styles.timerIcon","styles.timeLeft","styles.timer","String","padStart","VisuallyHidden","Object","assign","clsx","styles.wrapper","inert","inertValue","styles.countdown","styles.countdownInline","styles.countdownHidden","tabIndex","role","onFocus","styles.countdownFixed"],"mappings":"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"}
@@ -7,4 +7,4 @@ import type { DataTableProps } from "./types";
7
7
  * content are all externally controlled; the component manages scroll detection, sticky-header
8
8
  * positioning, and floating action bar behaviour internally.
9
9
  */
10
- export declare const DataTable: ({ id, headers, rows, className, sortIndicators, alternatingRows, loadState, enableMultiSelect, selectedIds, disabledIds, enableActionBar, enableSelectAll, enableStickyHeader, emptyView, actionBarContent, renderCustomEmptyView, onHeaderClick, onSelect, onSelectAll, onClearSelectionClick, ...otherProps }: DataTableProps) => import("react/jsx-runtime").JSX.Element;
10
+ export declare const DataTable: ({ id, headers, rows, className, sortIndicators, alternatingRows, loadState, enableMultiSelect, selectedIds, disabledIds, enableActionBar, enableActionBarWithoutSelection, enableSelectAll, enableStickyHeader, emptyView, actionBarContent, renderCustomEmptyView, onHeaderClick, onSelect, onSelectAll, onClearSelectionClick, ...otherProps }: DataTableProps) => import("react/jsx-runtime").JSX.Element;
@@ -1,2 +1,2 @@
1
- import{__rest as e}from"../_virtual/_tslib.js";import{jsxs as t,jsx as i,Fragment as r}from"react/jsx-runtime";import{ArrowUpIcon as n,ArrowDownIcon as l}from"@lifesg/react-icons";import o from"clsx";import{useRef as a,useState as s,useEffect as d}from"react";import{useResizeDetector as c}from"../external/react-resize-detector/build/index.esm.js";import"../animations/loading-dots/loading-dots.js";import{LoadingDotsSpinner as m}from"../animations/loading-dots-spinner/loading-dots-spinner.js";import"../animations/loading-spinner/loading-spinner.js";import"../theme/theme-provider/context.js";import{Checkbox as h}from"../checkbox/checkbox.js";import{ErrorDisplay as p}from"../error-display/error-display.js";import{VisuallyHidden as u,concatIds as g}from"../shared/accessibility/index.js";import{BasicButton as b}from"../shared/input-wrapper/input-wrapper.js";import"../theme/theme-provider/index.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 f}from"../theme/utils/use-apply-styles.js";import"../theme/utils/use-media-query.js";import{Typography as y}from"../typography/index.js";import"../util/calendar-helper.js";import"../external/dayjs/dayjs.min.js";import{useId as w}from"../util/simple-id-generator.js";import"../util/string-helper.js";import"@react-aria/live-announcer";import{useEvent as v}from"../util/use-event.js";import{useEventListener as j}from"../util/use-event-listener.js";import{useThrottle as N}from"../util/use-throttle.js";import{tokens as S,tableContainer as k,table as $,tableWrapper as C,tableWrapperScrollable as x,stickyHeader as H,headerRow as B,bodyRow as R,emptyStateCell as I,bodyRowWithBottomBorder as A,bodyRowAlternating as M,bodyRowSelectable as W,bodyRowSelected as K,loadingStateWrapper as L,actionBarWrapper as V,actionBarButton as q,actionBar as z,actionBarFloating as D,actionBarSpacer as E,selectionCheckboxWrapper as _,headerCell as O,headerCellCheckbox as P,headerCellContent as T,headerCellClickable as F,emptyStateTitle as G,bodyCell as J,bodyCellCheckbox as Q,bodyCellText as U}from"./data-table.styles.js";const X=X=>{var{id:Y,headers:Z,rows:ee,className:te,sortIndicators:ie,alternatingRows:re,loadState:ne="success",enableMultiSelect:le,selectedIds:oe,disabledIds:ae,enableActionBar:se,enableSelectAll:de,enableStickyHeader:ce,emptyView:me,actionBarContent:he,renderCustomEmptyView:pe,onHeaderClick:ue,onSelect:ge,onSelectAll:be,onClearSelectionClick:fe}=X,ye=e(X,["id","headers","rows","className","sortIndicators","alternatingRows","loadState","enableMultiSelect","selectedIds","disabledIds","enableActionBar","enableSelectAll","enableStickyHeader","emptyView","actionBarContent","renderCustomEmptyView","onHeaderClick","onSelect","onSelectAll","onClearSelectionClick"]);const we=a(null),ve=a(null),je=a(null),Ne=a(null),Se=w(),ke=Z.filter((e=>"string"!=typeof e&&!!e.keyColumn)),[$e,Ce]=s("inline"),[xe,He]=s(!1),[Be,Re]=s(!1);f(je,{[S.actionBarWrapperLeft]:Be&&we.current?`${we.current.getBoundingClientRect().left}px`:void 0,[S.actionBarWrapperWidth]:we.current?`${we.current.clientWidth}px`:void 0});const Ie=v((()=>{Pe()}));d((()=>{Ie()}),[Ie]);const Ae=N((()=>Pe()),100);c({targetRef:Ne,onResize:()=>Ae()}),j("scroll",Ae),j("scroll",Ae,Ne.current);const Me=()=>!!(ee&&ee.length&&oe)&&oe.length===ee.length,We=e=>!!(null==oe?void 0:oe.includes(e)),Ke=e=>!!re&&e%2==1,Le=e=>!!(null==ae?void 0:ae.includes(e)),Ve=e=>{if(ye["data-testid"])return`${ye["data-testid"]}-${e}`},qe=()=>Z.length+(le?1:0),ze=e=>null==ie?void 0:ie[e],De=e=>{const t=ze(e);if(t)return"asc"===t?"ascending":"descending"},Ee=e=>` by ${"asc"===ze(e)?"descending":"ascending"} order`,_e=(e,t)=>`${Se}-row-${e}-${t}-key-column`,Oe=e=>{const t=ke.map((t=>_e(e,t.fieldKey)));return g(...t)},Pe=()=>{if(!Ne.current||!ve.current||!je.current)return;const e=Ne.current.getBoundingClientRect(),t=ve.current.getBoundingClientRect();let i="inline";const r=Ne.current.scrollHeight>Ne.current.clientHeight;if(e.top>window.innerHeight||e.bottom<0?i="inline":r?e.top>0&&e.top<window.innerHeight&&e.bottom>0&&e.bottom<window.innerHeight||e.top<0&&e.bottom>0&&e.bottom<window.innerHeight?i="sticky":e.bottom>window.innerHeight&&Math.max(e.top,t.bottom)+t.height<window.innerHeight&&(i="fixed"):e.bottom>window.innerHeight&&t.bottom+t.height<window.innerHeight&&(i="fixed"),He(r),Ce(i),"fixed"===i)Re(!0);else if("sticky"===i){const e=Ne.current.scrollTop+Ne.current.clientHeight<Ne.current.scrollHeight;Re(e)}else Re(!1)},Te=e=>{const{fieldKey:r,label:n,clickable:l=!1,style:a}="string"==typeof e?{fieldKey:e,label:e,style:void 0}:e,s=!!ze(r),d=(e=>`${Se}-header-${e}`)(r);return t("th",{"data-testid":Ve(`header-${r}`),className:o(O,l&&F),scope:"col","aria-sort":De(r),style:a,onClick:()=>(e=>{null==ue||ue(e)})(r),children:[t("div",{className:T,id:d,children:["string"==typeof n?i(y.BodyBL,{weight:"bold",children:n}):n,Fe(r)]}),(l||s)&&i(u,{children:t("button",{onClick:e=>((e,t)=>{e.stopPropagation(),null==ue||ue(t)})(e,r),children:[s&&"Sort ",i("span",{"aria-labelledby":d}),s&&Ee(r)]})})]},r)},Fe=e=>{const t=null==ie?void 0:ie[e];return t?"asc"===t?i(n,{"aria-hidden":!0,"data-testid":Ve(`header-${e}-arrowup`)}):i(l,{"aria-hidden":!0,"data-testid":Ve(`header-${e}-arrowdown`)}):i(r,{})},Ge=()=>i("th",{"data-testid":Ve("header-selection"),className:o(O,P),scope:"col",children:t("div",{className:_,children:[i(u,{children:"Row selection"}),de&&i(h,{checked:Me(),indeterminate:!!oe&&0!==oe.length&&!Me(),disabled:!ee||!ee.length||!oe,"aria-label":"Select all rows",onClick:()=>{be&&be(Me())}})]})}),Je=(e,t)=>{const r="string"==typeof e?void 0:e.style,n="string"==typeof e?e:e.fieldKey,l=t.id.toString(),o=t[n],a=`${l}-${n}`;let s;return s="string"==typeof o||"number"==typeof o?i(y.BodyBL,{className:U,children:o}):"function"==typeof o?o(t,{isSelected:We(l)}):o,i("td",{"data-testid":Ve(`row-${a}`),id:_e(l,n),className:J,style:r,children:s},a)},Qe=e=>{const t=e.id.toString();return i("td",{"data-testid":Ve(`row-${t}-selection`),className:o(J,Q),children:i("div",{className:_,children:i(h,{checked:We(t),"aria-labelledby":Oe(t),onClick:()=>{ge&&ge(t,!We(t))},disabled:Le(t),focusableWhenDisabled:Le(t)})})})},Ue=()=>{let e;return e=(null==me?void 0:me.title)?"string"==typeof me.title?i(y.HeadingSM,{className:G,weight:"bold",children:me.title}):me.title:i(y.HeadingSM,{className:G,weight:"bold",children:"No <items> found"}),i(p,Object.assign({type:"no-item-found"},me,{title:e,description:(null==me?void 0:me.description)?me.description:"No matching rows"}))};return t("div",{id:Y||"table-wrapper","data-testid":ye["data-testid"]||"table",className:o(C,xe&&x,te),ref:Ne,tabIndex:0,children:[i("div",{className:k,children:t("table",{ref:we,className:$,children:[i("thead",{ref:ve,className:ce?H:void 0,children:t("tr",{className:B,children:[le&&Ge(),Z.map(Te)]})}),i("tbody",{children:"success"===ne?!ee||ee.length<1?i("tr",{className:R,children:i("td",{className:I,colSpan:qe(),children:pe?pe():Ue()})}):i(r,{children:null==ee?void 0:ee.map(((e,i)=>t("tr",{"data-testid":Ve(`row-${e.id.toString()}`),className:o(R,Be&&A,Ke(i)&&M,le&&W,We(e.id.toString())&&K),children:[le&&Qe(e),Z.map((t=>Je(t,e)))]},e.id.toString())))}):i("tr",{className:R,children:i("td",{colSpan:qe(),children:i("div",{className:L,role:"status","aria-live":"polite","aria-label":"Loading table",children:"loading"===ne&&i(m,{})})})})})]})}),se&&oe&&oe.length>0&&(()=>{var e;const n=null!==(e=null==oe?void 0:oe.length)&&void 0!==e?e:0,l="item"+(n>1?"s":"");return t(r,{children:[i("div",{ref:je,className:V,"data-strategy":$e,children:t("div",{"data-testid":"data-table-action-bar",className:o(z,Be&&D),children:[i(y.BodyMD,{weight:"semibold",children:`${n} ${l} selected`}),i(b,{className:q,type:"button","aria-label":`Clear selection of ${n} ${l}`,onClick:fe,children:"Clear selection"}),he]})}),"sticky"!==$e&&i("div",{className:E})]})})()]})};export{X as DataTable};
1
+ import{__rest as e}from"../_virtual/_tslib.js";import{jsxs as t,jsx as i,Fragment as n}from"react/jsx-runtime";import{ArrowUpIcon as r,ArrowDownIcon as l}from"@lifesg/react-icons";import o from"clsx";import{useRef as a,useState as s,useEffect as d}from"react";import{useResizeDetector as c}from"../external/react-resize-detector/build/index.esm.js";import"../animations/loading-dots/loading-dots.js";import{LoadingDotsSpinner as m}from"../animations/loading-dots-spinner/loading-dots-spinner.js";import"../animations/loading-spinner/loading-spinner.js";import"../theme/theme-provider/context.js";import{Checkbox as h}from"../checkbox/checkbox.js";import{ErrorDisplay as p}from"../error-display/error-display.js";import{VisuallyHidden as u,concatIds as g}from"../shared/accessibility/index.js";import{BasicButton as b}from"../shared/input-wrapper/input-wrapper.js";import"../theme/theme-provider/index.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 f}from"../theme/utils/use-apply-styles.js";import"../theme/utils/use-media-query.js";import{Typography as y}from"../typography/index.js";import"../util/calendar-helper.js";import"../external/dayjs/dayjs.min.js";import{useId as w}from"../util/simple-id-generator.js";import"../util/string-helper.js";import"@react-aria/live-announcer";import{useEvent as v}from"../util/use-event.js";import{useEventListener as j}from"../util/use-event-listener.js";import{useThrottle as N}from"../util/use-throttle.js";import{tokens as S,tableContainer as k,table as $,tableWrapper as C,tableWrapperScrollable as x,stickyHeader as H,headerRow as B,bodyRow as A,emptyStateCell as R,bodyRowWithBottomBorder as I,bodyRowAlternating as W,bodyRowSelectable as M,bodyRowSelected as K,loadingStateWrapper as L,actionBarWrapper as V,actionBarButton as q,actionBarGap as z,actionBar as D,actionBarFloating as E,actionBarSpacer as _,selectionCheckboxWrapper as O,headerCell as P,headerCellCheckbox as T,headerCellContent as F,headerCellClickable as G,emptyStateTitle as J,bodyCell as Q,bodyCellCheckbox as U,bodyCellText as X}from"./data-table.styles.js";const Y=Y=>{var{id:Z,headers:ee,rows:te,className:ie,sortIndicators:ne,alternatingRows:re,loadState:le="success",enableMultiSelect:oe,selectedIds:ae,disabledIds:se,enableActionBar:de,enableActionBarWithoutSelection:ce,enableSelectAll:me,enableStickyHeader:he,emptyView:pe,actionBarContent:ue,renderCustomEmptyView:ge,onHeaderClick:be,onSelect:fe,onSelectAll:ye,onClearSelectionClick:we}=Y,ve=e(Y,["id","headers","rows","className","sortIndicators","alternatingRows","loadState","enableMultiSelect","selectedIds","disabledIds","enableActionBar","enableActionBarWithoutSelection","enableSelectAll","enableStickyHeader","emptyView","actionBarContent","renderCustomEmptyView","onHeaderClick","onSelect","onSelectAll","onClearSelectionClick"]);const je=a(null),Ne=a(null),Se=a(null),ke=a(null),$e=w(),Ce=ee.filter((e=>"string"!=typeof e&&!!e.keyColumn)),[xe,He]=s("inline"),[Be,Ae]=s(!1),[Re,Ie]=s(!1);f(Se,{[S.actionBarWrapperLeft]:Re&&je.current?`${je.current.getBoundingClientRect().left}px`:void 0,[S.actionBarWrapperWidth]:je.current?`${je.current.clientWidth}px`:void 0});const We=v((()=>{Fe()}));d((()=>{We()}),[We]);const Me=N((()=>Fe()),100);c({targetRef:ke,onResize:()=>Me()}),j("scroll",Me),j("scroll",Me,ke.current);const Ke=()=>!!(te&&te.length&&ae)&&ae.length===te.length,Le=e=>!!(null==ae?void 0:ae.includes(e)),Ve=e=>!!re&&e%2==1,qe=e=>!!(null==se?void 0:se.includes(e)),ze=e=>{if(ve["data-testid"])return`${ve["data-testid"]}-${e}`},De=()=>ee.length+(oe?1:0),Ee=e=>null==ne?void 0:ne[e],_e=e=>{const t=Ee(e);if(t)return"asc"===t?"ascending":"descending"},Oe=e=>` by ${"asc"===Ee(e)?"descending":"ascending"} order`,Pe=(e,t)=>`${$e}-row-${e}-${t}-key-column`,Te=e=>{const t=Ce.map((t=>Pe(e,t.fieldKey)));return g(...t)},Fe=()=>{if(!ke.current||!Ne.current||!Se.current)return;const e=ke.current.getBoundingClientRect(),t=Ne.current.getBoundingClientRect();let i="inline";const n=ke.current.scrollHeight>ke.current.clientHeight;if(e.top>window.innerHeight||e.bottom<0?i="inline":n?e.top>0&&e.top<window.innerHeight&&e.bottom>0&&e.bottom<window.innerHeight||e.top<0&&e.bottom>0&&e.bottom<window.innerHeight?i="sticky":e.bottom>window.innerHeight&&Math.max(e.top,t.bottom)+t.height<window.innerHeight&&(i="fixed"):e.bottom>window.innerHeight&&t.bottom+t.height<window.innerHeight&&(i="fixed"),Ae(n),He(i),"fixed"===i)Ie(!0);else if("sticky"===i){const e=ke.current.scrollTop+ke.current.clientHeight<ke.current.scrollHeight;Ie(e)}else Ie(!1)},Ge=e=>{const{fieldKey:n,label:r,clickable:l=!1,style:a}="string"==typeof e?{fieldKey:e,label:e,style:void 0}:e,s=!!Ee(n),d=(e=>`${$e}-header-${e}`)(n);return t("th",{"data-testid":ze(`header-${n}`),className:o(P,l&&G),scope:"col","aria-sort":_e(n),style:a,onClick:()=>(e=>{null==be||be(e)})(n),children:[t("div",{className:F,id:d,children:["string"==typeof r?i(y.BodyBL,{weight:"bold",children:r}):r,Je(n)]}),(l||s)&&i(u,{children:t("button",{onClick:e=>((e,t)=>{e.stopPropagation(),null==be||be(t)})(e,n),children:[s&&"Sort ",i("span",{"aria-labelledby":d}),s&&Oe(n)]})})]},n)},Je=e=>{const t=null==ne?void 0:ne[e];return t?"asc"===t?i(r,{"aria-hidden":!0,"data-testid":ze(`header-${e}-arrowup`)}):i(l,{"aria-hidden":!0,"data-testid":ze(`header-${e}-arrowdown`)}):i(n,{})},Qe=()=>i("th",{"data-testid":ze("header-selection"),className:o(P,T),scope:"col",children:t("div",{className:O,children:[i(u,{children:"Row selection"}),me&&i(h,{checked:Ke(),indeterminate:!!ae&&0!==ae.length&&!Ke(),disabled:!te||!te.length,"aria-label":"Select all rows",onClick:()=>{ye&&ye(Ke())}})]})}),Ue=(e,t)=>{const n="string"==typeof e?void 0:e.style,r="string"==typeof e?e:e.fieldKey,l=t.id.toString(),o=t[r],a=`${l}-${r}`;let s;return s="string"==typeof o||"number"==typeof o?i(y.BodyBL,{className:X,children:o}):"function"==typeof o?o(t,{isSelected:Le(l)}):o,i("td",{"data-testid":ze(`row-${a}`),id:Pe(l,r),className:Q,style:n,children:s},a)},Xe=e=>{const t=e.id.toString();return i("td",{"data-testid":ze(`row-${t}-selection`),className:o(Q,U),children:i("div",{className:O,children:i(h,{checked:Le(t),"aria-labelledby":Te(t),onClick:()=>{fe&&fe(t,!Le(t))},disabled:qe(t),focusableWhenDisabled:qe(t)})})})},Ye=()=>{let e;return e=(null==pe?void 0:pe.title)?"string"==typeof pe.title?i(y.HeadingSM,{className:J,weight:"bold",children:pe.title}):pe.title:i(y.HeadingSM,{className:J,weight:"bold",children:"No <items> found"}),i(p,Object.assign({type:"no-item-found"},pe,{title:e,description:(null==pe?void 0:pe.description)?pe.description:"No matching rows"}))};return t("div",{id:Z||"table-wrapper","data-testid":ve["data-testid"]||"table",className:o(C,Be&&x,ie),ref:ke,tabIndex:0,children:[i("div",{className:k,children:t("table",{ref:je,className:$,children:[i("thead",{ref:Ne,className:he?H:void 0,children:t("tr",{className:B,children:[oe&&Qe(),ee.map(Ge)]})}),i("tbody",{children:"success"===le?!te||te.length<1?i("tr",{className:A,children:i("td",{className:R,colSpan:De(),children:ge?ge():Ye()})}):i(n,{children:null==te?void 0:te.map(((e,i)=>t("tr",{"data-testid":ze(`row-${e.id.toString()}`),className:o(A,Re&&I,Ve(i)&&W,oe&&M,Le(e.id.toString())&&K),children:[oe&&Xe(e),ee.map((t=>Ue(t,e)))]},e.id.toString())))}):i("tr",{className:A,children:i("td",{colSpan:De(),children:i("div",{className:L,role:"status","aria-live":"polite","aria-label":"Loading table",children:"loading"===le&&i(m,{})})})})})]})}),de&&(ae&&ae.length>0||ce)&&(()=>{var e;const r=null!==(e=null==ae?void 0:ae.length)&&void 0!==e?e:0,l="item"+(1===r?"":"s");return t(n,{children:[i("div",{ref:Se,className:V,"data-strategy":xe,children:t("div",{"data-testid":"data-table-action-bar",className:o(D,Re&&E),children:[i(y.BodyMD,{weight:"semibold",children:`${r} ${l} selected`}),r>0?i(b,{className:q,type:"button","aria-label":`Clear selection of ${r} ${l}`,onClick:we,children:"Clear selection"}):i("div",{className:z}),ue]})}),"sticky"!==xe&&i("div",{className:_})]})})()]})};export{Y as DataTable};
2
2
  //# sourceMappingURL=data-table.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"data-table.js","sources":["../../src/data-table/data-table.tsx"],"sourcesContent":["import { ArrowDownIcon, ArrowUpIcon } from \"@lifesg/react-icons\";\nimport clsx from \"clsx\";\nimport { useEffect, useRef, useState } from \"react\";\nimport { useResizeDetector } from \"react-resize-detector\";\n\nimport { LoadingDotsSpinner } from \"../animations\";\nimport { Checkbox } from \"../checkbox\";\nimport { ErrorDisplay } from \"../error-display\";\nimport { concatIds, VisuallyHidden } from \"../shared/accessibility\";\nimport { BasicButton } from \"../shared/input-wrapper\";\nimport { useApplyStyle } from \"../theme\";\nimport { Typography } from \"../typography\";\nimport { useEvent, useEventListener, useId, useThrottle } from \"../util\";\nimport * as styles from \"./data-table.styles\";\nimport type { DataTableProps, HeaderProps, RowProps } from \"./types\";\n\n// @catalog\n/**\n * Renders a sortable, selectable data table with scroll-aware action bar and loading state support.\n *\n * Use `DataTable` when presenting structured multi-column data that users may need to sort by\n * column or select rows for bulk actions. Row selection, sort indicators, and the action bar\n * content are all externally controlled; the component manages scroll detection, sticky-header\n * positioning, and floating action bar behaviour internally.\n */\nexport const DataTable = ({\n id,\n headers,\n rows,\n className,\n sortIndicators,\n alternatingRows,\n loadState = \"success\",\n enableMultiSelect,\n selectedIds,\n disabledIds,\n enableActionBar,\n enableSelectAll,\n enableStickyHeader,\n emptyView,\n actionBarContent,\n renderCustomEmptyView,\n onHeaderClick,\n onSelect,\n onSelectAll,\n onClearSelectionClick,\n ...otherProps\n}: DataTableProps) => {\n // =============================================================================\n // CONST, STATE, REF\n // =============================================================================\n const tableRef = useRef<HTMLTableElement>(null);\n const headerRef = useRef<HTMLTableSectionElement>(null);\n const actionBarWrapperRef = useRef<HTMLDivElement>(null);\n const wrapperRef = useRef<HTMLDivElement>(null);\n const internalId = useId();\n const keyColumns = headers.filter(\n (header): header is Exclude<HeaderProps, string> => {\n return typeof header !== \"string\" && !!header.keyColumn;\n }\n );\n\n const [actionBarStrategy, setActionBarStrategy] = useState<\n \"sticky\" | \"fixed\" | \"inline\"\n >(\"inline\");\n const [scrollable, setScrollable] = useState(false);\n const [isFloatingActionBar, setIsFloatingActionBar] = useState(false);\n\n useApplyStyle(actionBarWrapperRef, {\n [styles.tokens.actionBarWrapperLeft]:\n isFloatingActionBar && tableRef.current\n ? `${tableRef.current.getBoundingClientRect().left}px`\n : undefined,\n [styles.tokens.actionBarWrapperWidth]: tableRef.current\n ? `${tableRef.current.clientWidth}px`\n : undefined,\n });\n\n // =============================================================================\n // EFFECTS, EVENT LISTENERS\n // ============================================================================\n const useUpdateActionBarBehaviour = useEvent(() => {\n updateActionBarBehaviour();\n });\n\n useEffect(() => {\n useUpdateActionBarBehaviour();\n }, [useUpdateActionBarBehaviour]);\n\n const updateActionBarBehaviourThrottled = useThrottle(\n () => updateActionBarBehaviour(),\n 100\n );\n\n useResizeDetector({\n targetRef: wrapperRef,\n onResize: () => updateActionBarBehaviourThrottled(),\n });\n\n useEventListener(\"scroll\", updateActionBarBehaviourThrottled);\n useEventListener(\n \"scroll\",\n updateActionBarBehaviourThrottled,\n wrapperRef.current\n );\n\n // ===========================================================================\n // HELPER FUNCTIONS\n // ===========================================================================\n const isAllCheckboxSelected = (): boolean => {\n if (!rows || !rows.length || !selectedIds) {\n return false;\n }\n return selectedIds.length === rows.length;\n };\n\n const isIndeterminateCheckbox = (): boolean => {\n return (\n !!selectedIds &&\n selectedIds.length !== 0 &&\n !isAllCheckboxSelected()\n );\n };\n\n const isHeaderCheckboxDisabled = (): boolean => {\n return !rows || !rows.length || !selectedIds;\n };\n\n const isRowSelected = (rowId: string): boolean => {\n return !!selectedIds?.includes(rowId);\n };\n\n const isAlternatingRow = (index: number): boolean => {\n return !!alternatingRows && index % 2 === 1;\n };\n\n const isDisabledRow = (rowId: string): boolean => {\n return !!disabledIds?.includes(rowId);\n };\n\n const getDataTestId = (subStr: string) => {\n if (!otherProps[\"data-testid\"]) return undefined;\n return `${otherProps[\"data-testid\"]}-${subStr}`;\n };\n\n const getTotalColumns = (): number => {\n return headers.length + (enableMultiSelect ? 1 : 0);\n };\n\n const getSortDirection = (fieldKey: string) => {\n return sortIndicators?.[fieldKey];\n };\n\n const getHeaderAriaSort = (fieldKey: string) => {\n const sortDirection = getSortDirection(fieldKey);\n\n if (!sortDirection) {\n return undefined;\n }\n\n return sortDirection === \"asc\" ? \"ascending\" : \"descending\";\n };\n\n const getSortButtonAriaLabel = (fieldKey: string) => {\n const nextSortDirection =\n getSortDirection(fieldKey) === \"asc\" ? \"descending\" : \"ascending\";\n\n return ` by ${nextSortDirection} order`;\n };\n\n const getHeaderCellId = (fieldKey: string) => {\n return `${internalId}-header-${fieldKey}`;\n };\n const getCellId = (rowId: string, fieldKey: string) => {\n return `${internalId}-row-${rowId}-${fieldKey}-key-column`;\n };\n\n const getRowCheckboxAriaLabelledBy = (rowId: string) => {\n const keyColumnIds = keyColumns.map((header) =>\n getCellId(rowId, header.fieldKey)\n );\n\n return concatIds(...keyColumnIds);\n };\n\n const updateActionBarBehaviour = () => {\n if (\n !wrapperRef.current ||\n !headerRef.current ||\n !actionBarWrapperRef.current\n ) {\n return;\n }\n\n const wrapperBounds = wrapperRef.current.getBoundingClientRect();\n const headerBounds = headerRef.current.getBoundingClientRect();\n\n let strategy: typeof actionBarStrategy = \"inline\";\n\n const scrollable =\n wrapperRef.current.scrollHeight > wrapperRef.current.clientHeight;\n\n if (\n wrapperBounds.top > window.innerHeight ||\n wrapperBounds.bottom < 0\n ) {\n // if fully out of the viewport, disable floating\n strategy = \"inline\";\n } else if (scrollable) {\n if (\n wrapperBounds.top > 0 &&\n wrapperBounds.top < window.innerHeight &&\n wrapperBounds.bottom > 0 &&\n wrapperBounds.bottom < window.innerHeight\n ) {\n // if fully in the viewport, use the native sticky behaviour\n strategy = \"sticky\";\n } else if (\n wrapperBounds.top < 0 &&\n wrapperBounds.bottom > 0 &&\n wrapperBounds.bottom < window.innerHeight\n ) {\n // if partially offscreen at the top, use the native sticky behaviour\n strategy = \"sticky\";\n } else if (\n wrapperBounds.bottom > window.innerHeight &&\n Math.max(wrapperBounds.top, headerBounds.bottom) +\n headerBounds.height <\n window.innerHeight\n ) {\n // if offscreen at the bottom, pin to the viewport, up until the table/header\n strategy = \"fixed\";\n }\n } else if (\n wrapperBounds.bottom > window.innerHeight &&\n headerBounds.bottom + headerBounds.height < window.innerHeight\n ) {\n // if offscreen at the bottom, pin to the viewport, up until the header\n strategy = \"fixed\";\n }\n\n setScrollable(scrollable);\n setActionBarStrategy(strategy);\n\n if (strategy === \"fixed\") {\n setIsFloatingActionBar(true);\n } else if (strategy === \"sticky\") {\n const beforeScrollEnd =\n wrapperRef.current.scrollTop + wrapperRef.current.clientHeight <\n wrapperRef.current.scrollHeight;\n setIsFloatingActionBar(beforeScrollEnd);\n } else {\n setIsFloatingActionBar(false);\n }\n };\n\n // =============================================================================\n // EVENT HANDLERS\n // =============================================================================\n const handleHeaderClick = (fieldKey: string) => {\n onHeaderClick?.(fieldKey);\n };\n\n const handleHeaderButtonClick = (\n event: React.MouseEvent<HTMLButtonElement>,\n fieldKey: string\n ) => {\n event.stopPropagation();\n onHeaderClick?.(fieldKey);\n };\n\n // =============================================================================\n // RENDER FUNCTIONS\n // =============================================================================\n const renderHeaders = () => (\n <thead\n ref={headerRef}\n className={enableStickyHeader ? styles.stickyHeader : undefined}\n >\n <tr className={styles.headerRow}>\n {enableMultiSelect && renderHeaderCheckBox()}\n {headers.map(renderHeaderCell)}\n </tr>\n </thead>\n );\n\n const renderHeaderCell = (header: HeaderProps) => {\n const {\n fieldKey,\n label,\n clickable = false,\n style,\n } = typeof header === \"string\"\n ? {\n fieldKey: header,\n label: header,\n style: undefined,\n }\n : header;\n\n const isSortable = !!getSortDirection(fieldKey);\n const headerCellId = getHeaderCellId(fieldKey);\n return (\n <th\n data-testid={getDataTestId(`header-${fieldKey}`)}\n key={fieldKey}\n className={clsx(\n styles.headerCell,\n clickable && styles.headerCellClickable\n )}\n scope=\"col\"\n aria-sort={getHeaderAriaSort(fieldKey)}\n style={style}\n onClick={() => handleHeaderClick(fieldKey)}\n >\n <div className={styles.headerCellContent} id={headerCellId}>\n {typeof label === \"string\" ? (\n <Typography.BodyBL weight=\"bold\">\n {label}\n </Typography.BodyBL>\n ) : (\n label\n )}\n {renderSortedArrow(fieldKey)}\n </div>\n {(clickable || isSortable) && (\n <VisuallyHidden>\n <button\n onClick={(event) =>\n handleHeaderButtonClick(event, fieldKey)\n }\n >\n {isSortable && \"Sort \"}\n <span aria-labelledby={headerCellId} />\n {isSortable && getSortButtonAriaLabel(fieldKey)}\n </button>\n </VisuallyHidden>\n )}\n </th>\n );\n };\n\n const renderSortedArrow = (fieldKey: string) => {\n const isSorted = sortIndicators?.[fieldKey];\n\n if (!isSorted) {\n return <></>;\n }\n if (isSorted === \"asc\") {\n return (\n <ArrowUpIcon\n aria-hidden\n data-testid={getDataTestId(`header-${fieldKey}-arrowup`)}\n />\n );\n }\n return (\n <ArrowDownIcon\n aria-hidden\n data-testid={getDataTestId(`header-${fieldKey}-arrowdown`)}\n />\n );\n };\n\n const renderHeaderCheckBox = () => {\n return (\n <th\n data-testid={getDataTestId(\"header-selection\")}\n className={clsx(styles.headerCell, styles.headerCellCheckbox)}\n scope=\"col\"\n >\n <div className={styles.selectionCheckboxWrapper}>\n <VisuallyHidden>Row selection</VisuallyHidden>\n {enableSelectAll && (\n <Checkbox\n checked={isAllCheckboxSelected()}\n indeterminate={isIndeterminateCheckbox()}\n disabled={isHeaderCheckboxDisabled()}\n aria-label=\"Select all rows\"\n onClick={() => {\n if (onSelectAll) {\n onSelectAll(isAllCheckboxSelected());\n }\n }}\n />\n )}\n </div>\n </th>\n );\n };\n\n const renderRows = () => {\n return !rows || rows.length < 1 ? (\n <tr className={styles.bodyRow}>\n <td\n className={styles.emptyStateCell}\n colSpan={getTotalColumns()}\n >\n {renderCustomEmptyView\n ? renderCustomEmptyView()\n : renderBasicEmptyView()}\n </td>\n </tr>\n ) : (\n <>\n {rows?.map((row: RowProps, index: number) => (\n <tr\n data-testid={getDataTestId(`row-${row.id.toString()}`)}\n key={row.id.toString()}\n className={clsx(\n styles.bodyRow,\n isFloatingActionBar &&\n styles.bodyRowWithBottomBorder,\n isAlternatingRow(index) &&\n styles.bodyRowAlternating,\n enableMultiSelect && styles.bodyRowSelectable,\n isRowSelected(row.id.toString()) &&\n styles.bodyRowSelected\n )}\n >\n {enableMultiSelect && renderRowCheckBox(row)}\n\n {headers.map((header) => renderRowCell(header, row))}\n </tr>\n ))}\n </>\n );\n };\n\n const renderRowCell = (header: HeaderProps, row: RowProps) => {\n const style = typeof header === \"string\" ? undefined : header.style;\n const fieldKey = typeof header === \"string\" ? header : header.fieldKey;\n const rowId = row.id.toString();\n const cellData = row[fieldKey];\n const cellId = `${rowId}-${fieldKey}`;\n\n let cellContent: React.ReactNode;\n if (typeof cellData === \"string\" || typeof cellData === \"number\") {\n cellContent = (\n <Typography.BodyBL className={styles.bodyCellText}>\n {cellData}\n </Typography.BodyBL>\n );\n } else if (typeof cellData === \"function\") {\n cellContent = cellData(row, { isSelected: isRowSelected(rowId) });\n } else {\n cellContent = cellData;\n }\n\n return (\n <td\n data-testid={getDataTestId(`row-${cellId}`)}\n key={cellId}\n id={getCellId(rowId, fieldKey)}\n className={styles.bodyCell}\n style={style}\n >\n {cellContent}\n </td>\n );\n };\n\n const renderRowCheckBox = (row: RowProps) => {\n const rowId = row.id.toString();\n\n return (\n <td\n data-testid={getDataTestId(`row-${rowId}-selection`)}\n className={clsx(styles.bodyCell, styles.bodyCellCheckbox)}\n >\n <div className={styles.selectionCheckboxWrapper}>\n <Checkbox\n checked={isRowSelected(rowId)}\n aria-labelledby={getRowCheckboxAriaLabelledBy(rowId)}\n onClick={() => {\n if (onSelect) {\n onSelect(rowId, !isRowSelected(rowId));\n }\n }}\n disabled={isDisabledRow(rowId)}\n focusableWhenDisabled={isDisabledRow(rowId)}\n />\n </div>\n </td>\n );\n };\n\n const renderBasicEmptyView = () => {\n let emptyTitle: JSX.Element;\n if (!emptyView?.title) {\n emptyTitle = (\n <Typography.HeadingSM\n className={styles.emptyStateTitle}\n weight=\"bold\"\n >\n {\"No <items> found\"}\n </Typography.HeadingSM>\n );\n } else if (typeof emptyView.title === \"string\") {\n emptyTitle = (\n <Typography.HeadingSM\n className={styles.emptyStateTitle}\n weight=\"bold\"\n >\n {emptyView.title}\n </Typography.HeadingSM>\n );\n } else {\n emptyTitle = emptyView.title;\n }\n\n return (\n <ErrorDisplay\n type={\"no-item-found\"}\n {...emptyView}\n title={emptyTitle}\n description={\n emptyView?.description\n ? emptyView.description\n : \"No matching rows\"\n }\n />\n );\n };\n\n const renderLoader = () => {\n return (\n <tr className={styles.bodyRow}>\n <td colSpan={getTotalColumns()}>\n <div\n className={styles.loadingStateWrapper}\n role=\"status\"\n aria-live=\"polite\"\n aria-label=\"Loading table\"\n >\n {loadState === \"loading\" && <LoadingDotsSpinner />}\n </div>\n </td>\n </tr>\n );\n };\n\n const renderSelectionBar = () => {\n const count = selectedIds?.length ?? 0;\n const counter = `item${count > 1 ? \"s\" : \"\"}`;\n\n return (\n <>\n <div\n ref={actionBarWrapperRef}\n className={styles.actionBarWrapper}\n data-strategy={actionBarStrategy}\n >\n <div\n data-testid=\"data-table-action-bar\"\n className={clsx(\n styles.actionBar,\n isFloatingActionBar && styles.actionBarFloating\n )}\n >\n <Typography.BodyMD weight=\"semibold\">{`${count} ${counter} selected`}</Typography.BodyMD>\n <BasicButton\n className={styles.actionBarButton}\n type=\"button\"\n aria-label={`Clear selection of ${count} ${counter}`}\n onClick={onClearSelectionClick}\n >\n Clear selection\n </BasicButton>\n {actionBarContent}\n </div>\n </div>\n {/* leave a fixed space when action bar floats to avoid layout shift */}\n {actionBarStrategy !== \"sticky\" && (\n <div className={styles.actionBarSpacer} />\n )}\n </>\n );\n };\n\n return (\n <div\n id={id || \"table-wrapper\"}\n data-testid={otherProps[\"data-testid\"] || \"table\"}\n className={clsx(\n styles.tableWrapper,\n scrollable && styles.tableWrapperScrollable,\n className\n )}\n ref={wrapperRef}\n tabIndex={0} // scrollable container must be focusable to support keyboard users\n >\n <div className={styles.tableContainer}>\n <table ref={tableRef} className={styles.table}>\n {renderHeaders()}\n <tbody>\n {loadState === \"success\"\n ? renderRows()\n : renderLoader()}\n </tbody>\n </table>\n </div>\n {enableActionBar &&\n selectedIds &&\n selectedIds.length > 0 &&\n renderSelectionBar()}\n </div>\n );\n};\n"],"names":["DataTable","_a","id","headers","rows","className","sortIndicators","alternatingRows","loadState","enableMultiSelect","selectedIds","disabledIds","enableActionBar","enableSelectAll","enableStickyHeader","emptyView","actionBarContent","renderCustomEmptyView","onHeaderClick","onSelect","onSelectAll","onClearSelectionClick","otherProps","__rest","tableRef","useRef","headerRef","actionBarWrapperRef","wrapperRef","internalId","useId","keyColumns","filter","header","keyColumn","actionBarStrategy","setActionBarStrategy","useState","scrollable","setScrollable","isFloatingActionBar","setIsFloatingActionBar","useApplyStyle","styles.tokens","actionBarWrapperLeft","current","getBoundingClientRect","left","undefined","actionBarWrapperWidth","clientWidth","useUpdateActionBarBehaviour","useEvent","updateActionBarBehaviour","useEffect","updateActionBarBehaviourThrottled","useThrottle","useResizeDetector","targetRef","onResize","useEventListener","isAllCheckboxSelected","length","isRowSelected","rowId","includes","isAlternatingRow","index","isDisabledRow","getDataTestId","subStr","getTotalColumns","getSortDirection","fieldKey","getHeaderAriaSort","sortDirection","getSortButtonAriaLabel","getCellId","getRowCheckboxAriaLabelledBy","keyColumnIds","map","concatIds","wrapperBounds","headerBounds","strategy","scrollHeight","clientHeight","top","window","innerHeight","bottom","Math","max","height","beforeScrollEnd","scrollTop","renderHeaderCell","label","clickable","style","isSortable","headerCellId","getHeaderCellId","_jsxs","clsx","styles.headerCell","styles.headerCellClickable","scope","onClick","handleHeaderClick","children","styles.headerCellContent","_jsx","Typography","BodyBL","weight","renderSortedArrow","VisuallyHidden","event","stopPropagation","handleHeaderButtonClick","isSorted","ArrowUpIcon","ArrowDownIcon","renderHeaderCheckBox","styles.headerCellCheckbox","styles.selectionCheckboxWrapper","Checkbox","checked","indeterminate","disabled","renderRowCell","row","toString","cellData","cellId","cellContent","styles.bodyCellText","isSelected","styles.bodyCell","renderRowCheckBox","styles.bodyCellCheckbox","focusableWhenDisabled","renderBasicEmptyView","emptyTitle","title","HeadingSM","styles.emptyStateTitle","ErrorDisplay","Object","assign","type","description","styles.tableWrapper","styles.tableWrapperScrollable","ref","tabIndex","styles.tableContainer","styles.table","styles.stickyHeader","styles.headerRow","styles.bodyRow","styles.emptyStateCell","colSpan","_Fragment","styles.bodyRowWithBottomBorder","styles.bodyRowAlternating","styles.bodyRowSelectable","styles.bodyRowSelected","styles.loadingStateWrapper","role","LoadingDotsSpinner","count","counter","styles.actionBarWrapper","styles.actionBar","styles.actionBarFloating","BodyMD","BasicButton","styles.actionBarButton","styles.actionBarSpacer","renderSelectionBar"],"mappings":"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"}
1
+ {"version":3,"file":"data-table.js","sources":["../../src/data-table/data-table.tsx"],"sourcesContent":["import { ArrowDownIcon, ArrowUpIcon } from \"@lifesg/react-icons\";\nimport clsx from \"clsx\";\nimport { useEffect, useRef, useState } from \"react\";\nimport { useResizeDetector } from \"react-resize-detector\";\n\nimport { LoadingDotsSpinner } from \"../animations\";\nimport { Checkbox } from \"../checkbox\";\nimport { ErrorDisplay } from \"../error-display\";\nimport { concatIds, VisuallyHidden } from \"../shared/accessibility\";\nimport { BasicButton } from \"../shared/input-wrapper\";\nimport { useApplyStyle } from \"../theme\";\nimport { Typography } from \"../typography\";\nimport { useEvent, useEventListener, useId, useThrottle } from \"../util\";\nimport * as styles from \"./data-table.styles\";\nimport type { DataTableProps, HeaderProps, RowProps } from \"./types\";\n\n// @catalog\n/**\n * Renders a sortable, selectable data table with scroll-aware action bar and loading state support.\n *\n * Use `DataTable` when presenting structured multi-column data that users may need to sort by\n * column or select rows for bulk actions. Row selection, sort indicators, and the action bar\n * content are all externally controlled; the component manages scroll detection, sticky-header\n * positioning, and floating action bar behaviour internally.\n */\nexport const DataTable = ({\n id,\n headers,\n rows,\n className,\n sortIndicators,\n alternatingRows,\n loadState = \"success\",\n enableMultiSelect,\n selectedIds,\n disabledIds,\n enableActionBar,\n enableActionBarWithoutSelection,\n enableSelectAll,\n enableStickyHeader,\n emptyView,\n actionBarContent,\n renderCustomEmptyView,\n onHeaderClick,\n onSelect,\n onSelectAll,\n onClearSelectionClick,\n ...otherProps\n}: DataTableProps) => {\n // =============================================================================\n // CONST, STATE, REF\n // =============================================================================\n const tableRef = useRef<HTMLTableElement>(null);\n const headerRef = useRef<HTMLTableSectionElement>(null);\n const actionBarWrapperRef = useRef<HTMLDivElement>(null);\n const wrapperRef = useRef<HTMLDivElement>(null);\n const internalId = useId();\n const keyColumns = headers.filter(\n (header): header is Exclude<HeaderProps, string> => {\n return typeof header !== \"string\" && !!header.keyColumn;\n }\n );\n\n const [actionBarStrategy, setActionBarStrategy] = useState<\n \"sticky\" | \"fixed\" | \"inline\"\n >(\"inline\");\n const [scrollable, setScrollable] = useState(false);\n const [isFloatingActionBar, setIsFloatingActionBar] = useState(false);\n\n useApplyStyle(actionBarWrapperRef, {\n [styles.tokens.actionBarWrapperLeft]:\n isFloatingActionBar && tableRef.current\n ? `${tableRef.current.getBoundingClientRect().left}px`\n : undefined,\n [styles.tokens.actionBarWrapperWidth]: tableRef.current\n ? `${tableRef.current.clientWidth}px`\n : undefined,\n });\n\n // =============================================================================\n // EFFECTS, EVENT LISTENERS\n // ============================================================================\n const useUpdateActionBarBehaviour = useEvent(() => {\n updateActionBarBehaviour();\n });\n\n useEffect(() => {\n useUpdateActionBarBehaviour();\n }, [useUpdateActionBarBehaviour]);\n\n const updateActionBarBehaviourThrottled = useThrottle(\n () => updateActionBarBehaviour(),\n 100\n );\n\n useResizeDetector({\n targetRef: wrapperRef,\n onResize: () => updateActionBarBehaviourThrottled(),\n });\n\n useEventListener(\"scroll\", updateActionBarBehaviourThrottled);\n useEventListener(\n \"scroll\",\n updateActionBarBehaviourThrottled,\n wrapperRef.current\n );\n\n // ===========================================================================\n // HELPER FUNCTIONS\n // ===========================================================================\n const isAllCheckboxSelected = (): boolean => {\n if (!rows || !rows.length || !selectedIds) {\n return false;\n }\n return selectedIds.length === rows.length;\n };\n\n const isIndeterminateCheckbox = (): boolean => {\n return (\n !!selectedIds &&\n selectedIds.length !== 0 &&\n !isAllCheckboxSelected()\n );\n };\n\n const isHeaderCheckboxDisabled = (): boolean => {\n return !rows || !rows.length;\n };\n\n const isRowSelected = (rowId: string): boolean => {\n return !!selectedIds?.includes(rowId);\n };\n\n const isAlternatingRow = (index: number): boolean => {\n return !!alternatingRows && index % 2 === 1;\n };\n\n const isDisabledRow = (rowId: string): boolean => {\n return !!disabledIds?.includes(rowId);\n };\n\n const getDataTestId = (subStr: string) => {\n if (!otherProps[\"data-testid\"]) return undefined;\n return `${otherProps[\"data-testid\"]}-${subStr}`;\n };\n\n const getTotalColumns = (): number => {\n return headers.length + (enableMultiSelect ? 1 : 0);\n };\n\n const getSortDirection = (fieldKey: string) => {\n return sortIndicators?.[fieldKey];\n };\n\n const getHeaderAriaSort = (fieldKey: string) => {\n const sortDirection = getSortDirection(fieldKey);\n\n if (!sortDirection) {\n return undefined;\n }\n\n return sortDirection === \"asc\" ? \"ascending\" : \"descending\";\n };\n\n const getSortButtonAriaLabel = (fieldKey: string) => {\n const nextSortDirection =\n getSortDirection(fieldKey) === \"asc\" ? \"descending\" : \"ascending\";\n\n return ` by ${nextSortDirection} order`;\n };\n\n const getHeaderCellId = (fieldKey: string) => {\n return `${internalId}-header-${fieldKey}`;\n };\n const getCellId = (rowId: string, fieldKey: string) => {\n return `${internalId}-row-${rowId}-${fieldKey}-key-column`;\n };\n\n const getRowCheckboxAriaLabelledBy = (rowId: string) => {\n const keyColumnIds = keyColumns.map((header) =>\n getCellId(rowId, header.fieldKey)\n );\n\n return concatIds(...keyColumnIds);\n };\n\n const updateActionBarBehaviour = () => {\n if (\n !wrapperRef.current ||\n !headerRef.current ||\n !actionBarWrapperRef.current\n ) {\n return;\n }\n\n const wrapperBounds = wrapperRef.current.getBoundingClientRect();\n const headerBounds = headerRef.current.getBoundingClientRect();\n\n let strategy: typeof actionBarStrategy = \"inline\";\n\n const scrollable =\n wrapperRef.current.scrollHeight > wrapperRef.current.clientHeight;\n\n if (\n wrapperBounds.top > window.innerHeight ||\n wrapperBounds.bottom < 0\n ) {\n // if fully out of the viewport, disable floating\n strategy = \"inline\";\n } else if (scrollable) {\n if (\n wrapperBounds.top > 0 &&\n wrapperBounds.top < window.innerHeight &&\n wrapperBounds.bottom > 0 &&\n wrapperBounds.bottom < window.innerHeight\n ) {\n // if fully in the viewport, use the native sticky behaviour\n strategy = \"sticky\";\n } else if (\n wrapperBounds.top < 0 &&\n wrapperBounds.bottom > 0 &&\n wrapperBounds.bottom < window.innerHeight\n ) {\n // if partially offscreen at the top, use the native sticky behaviour\n strategy = \"sticky\";\n } else if (\n wrapperBounds.bottom > window.innerHeight &&\n Math.max(wrapperBounds.top, headerBounds.bottom) +\n headerBounds.height <\n window.innerHeight\n ) {\n // if offscreen at the bottom, pin to the viewport, up until the table/header\n strategy = \"fixed\";\n }\n } else if (\n wrapperBounds.bottom > window.innerHeight &&\n headerBounds.bottom + headerBounds.height < window.innerHeight\n ) {\n // if offscreen at the bottom, pin to the viewport, up until the header\n strategy = \"fixed\";\n }\n\n setScrollable(scrollable);\n setActionBarStrategy(strategy);\n\n if (strategy === \"fixed\") {\n setIsFloatingActionBar(true);\n } else if (strategy === \"sticky\") {\n const beforeScrollEnd =\n wrapperRef.current.scrollTop + wrapperRef.current.clientHeight <\n wrapperRef.current.scrollHeight;\n setIsFloatingActionBar(beforeScrollEnd);\n } else {\n setIsFloatingActionBar(false);\n }\n };\n\n // =============================================================================\n // EVENT HANDLERS\n // =============================================================================\n const handleHeaderClick = (fieldKey: string) => {\n onHeaderClick?.(fieldKey);\n };\n\n const handleHeaderButtonClick = (\n event: React.MouseEvent<HTMLButtonElement>,\n fieldKey: string\n ) => {\n event.stopPropagation();\n onHeaderClick?.(fieldKey);\n };\n\n // =============================================================================\n // RENDER FUNCTIONS\n // =============================================================================\n const renderHeaders = () => (\n <thead\n ref={headerRef}\n className={enableStickyHeader ? styles.stickyHeader : undefined}\n >\n <tr className={styles.headerRow}>\n {enableMultiSelect && renderHeaderCheckBox()}\n {headers.map(renderHeaderCell)}\n </tr>\n </thead>\n );\n\n const renderHeaderCell = (header: HeaderProps) => {\n const {\n fieldKey,\n label,\n clickable = false,\n style,\n } = typeof header === \"string\"\n ? {\n fieldKey: header,\n label: header,\n style: undefined,\n }\n : header;\n\n const isSortable = !!getSortDirection(fieldKey);\n const headerCellId = getHeaderCellId(fieldKey);\n return (\n <th\n data-testid={getDataTestId(`header-${fieldKey}`)}\n key={fieldKey}\n className={clsx(\n styles.headerCell,\n clickable && styles.headerCellClickable\n )}\n scope=\"col\"\n aria-sort={getHeaderAriaSort(fieldKey)}\n style={style}\n onClick={() => handleHeaderClick(fieldKey)}\n >\n <div className={styles.headerCellContent} id={headerCellId}>\n {typeof label === \"string\" ? (\n <Typography.BodyBL weight=\"bold\">\n {label}\n </Typography.BodyBL>\n ) : (\n label\n )}\n {renderSortedArrow(fieldKey)}\n </div>\n {(clickable || isSortable) && (\n <VisuallyHidden>\n <button\n onClick={(event) =>\n handleHeaderButtonClick(event, fieldKey)\n }\n >\n {isSortable && \"Sort \"}\n <span aria-labelledby={headerCellId} />\n {isSortable && getSortButtonAriaLabel(fieldKey)}\n </button>\n </VisuallyHidden>\n )}\n </th>\n );\n };\n\n const renderSortedArrow = (fieldKey: string) => {\n const isSorted = sortIndicators?.[fieldKey];\n\n if (!isSorted) {\n return <></>;\n }\n if (isSorted === \"asc\") {\n return (\n <ArrowUpIcon\n aria-hidden\n data-testid={getDataTestId(`header-${fieldKey}-arrowup`)}\n />\n );\n }\n return (\n <ArrowDownIcon\n aria-hidden\n data-testid={getDataTestId(`header-${fieldKey}-arrowdown`)}\n />\n );\n };\n\n const renderHeaderCheckBox = () => {\n return (\n <th\n data-testid={getDataTestId(\"header-selection\")}\n className={clsx(styles.headerCell, styles.headerCellCheckbox)}\n scope=\"col\"\n >\n <div className={styles.selectionCheckboxWrapper}>\n <VisuallyHidden>Row selection</VisuallyHidden>\n {enableSelectAll && (\n <Checkbox\n checked={isAllCheckboxSelected()}\n indeterminate={isIndeterminateCheckbox()}\n disabled={isHeaderCheckboxDisabled()}\n aria-label=\"Select all rows\"\n onClick={() => {\n if (onSelectAll) {\n onSelectAll(isAllCheckboxSelected());\n }\n }}\n />\n )}\n </div>\n </th>\n );\n };\n\n const renderRows = () => {\n return !rows || rows.length < 1 ? (\n <tr className={styles.bodyRow}>\n <td\n className={styles.emptyStateCell}\n colSpan={getTotalColumns()}\n >\n {renderCustomEmptyView\n ? renderCustomEmptyView()\n : renderBasicEmptyView()}\n </td>\n </tr>\n ) : (\n <>\n {rows?.map((row: RowProps, index: number) => (\n <tr\n data-testid={getDataTestId(`row-${row.id.toString()}`)}\n key={row.id.toString()}\n className={clsx(\n styles.bodyRow,\n isFloatingActionBar &&\n styles.bodyRowWithBottomBorder,\n isAlternatingRow(index) &&\n styles.bodyRowAlternating,\n enableMultiSelect && styles.bodyRowSelectable,\n isRowSelected(row.id.toString()) &&\n styles.bodyRowSelected\n )}\n >\n {enableMultiSelect && renderRowCheckBox(row)}\n\n {headers.map((header) => renderRowCell(header, row))}\n </tr>\n ))}\n </>\n );\n };\n\n const renderRowCell = (header: HeaderProps, row: RowProps) => {\n const style = typeof header === \"string\" ? undefined : header.style;\n const fieldKey = typeof header === \"string\" ? header : header.fieldKey;\n const rowId = row.id.toString();\n const cellData = row[fieldKey];\n const cellId = `${rowId}-${fieldKey}`;\n\n let cellContent: React.ReactNode;\n if (typeof cellData === \"string\" || typeof cellData === \"number\") {\n cellContent = (\n <Typography.BodyBL className={styles.bodyCellText}>\n {cellData}\n </Typography.BodyBL>\n );\n } else if (typeof cellData === \"function\") {\n cellContent = cellData(row, { isSelected: isRowSelected(rowId) });\n } else {\n cellContent = cellData;\n }\n\n return (\n <td\n data-testid={getDataTestId(`row-${cellId}`)}\n key={cellId}\n id={getCellId(rowId, fieldKey)}\n className={styles.bodyCell}\n style={style}\n >\n {cellContent}\n </td>\n );\n };\n\n const renderRowCheckBox = (row: RowProps) => {\n const rowId = row.id.toString();\n\n return (\n <td\n data-testid={getDataTestId(`row-${rowId}-selection`)}\n className={clsx(styles.bodyCell, styles.bodyCellCheckbox)}\n >\n <div className={styles.selectionCheckboxWrapper}>\n <Checkbox\n checked={isRowSelected(rowId)}\n aria-labelledby={getRowCheckboxAriaLabelledBy(rowId)}\n onClick={() => {\n if (onSelect) {\n onSelect(rowId, !isRowSelected(rowId));\n }\n }}\n disabled={isDisabledRow(rowId)}\n focusableWhenDisabled={isDisabledRow(rowId)}\n />\n </div>\n </td>\n );\n };\n\n const renderBasicEmptyView = () => {\n let emptyTitle: JSX.Element;\n if (!emptyView?.title) {\n emptyTitle = (\n <Typography.HeadingSM\n className={styles.emptyStateTitle}\n weight=\"bold\"\n >\n {\"No <items> found\"}\n </Typography.HeadingSM>\n );\n } else if (typeof emptyView.title === \"string\") {\n emptyTitle = (\n <Typography.HeadingSM\n className={styles.emptyStateTitle}\n weight=\"bold\"\n >\n {emptyView.title}\n </Typography.HeadingSM>\n );\n } else {\n emptyTitle = emptyView.title;\n }\n\n return (\n <ErrorDisplay\n type={\"no-item-found\"}\n {...emptyView}\n title={emptyTitle}\n description={\n emptyView?.description\n ? emptyView.description\n : \"No matching rows\"\n }\n />\n );\n };\n\n const renderLoader = () => {\n return (\n <tr className={styles.bodyRow}>\n <td colSpan={getTotalColumns()}>\n <div\n className={styles.loadingStateWrapper}\n role=\"status\"\n aria-live=\"polite\"\n aria-label=\"Loading table\"\n >\n {loadState === \"loading\" && <LoadingDotsSpinner />}\n </div>\n </td>\n </tr>\n );\n };\n\n const renderSelectionBar = () => {\n const count = selectedIds?.length ?? 0;\n const counter = `item${count === 1 ? \"\" : \"s\"}`;\n\n return (\n <>\n <div\n ref={actionBarWrapperRef}\n className={styles.actionBarWrapper}\n data-strategy={actionBarStrategy}\n >\n <div\n data-testid=\"data-table-action-bar\"\n className={clsx(\n styles.actionBar,\n isFloatingActionBar && styles.actionBarFloating\n )}\n >\n <Typography.BodyMD weight=\"semibold\">{`${count} ${counter} selected`}</Typography.BodyMD>\n {count > 0 ? (\n <BasicButton\n className={styles.actionBarButton}\n type=\"button\"\n aria-label={`Clear selection of ${count} ${counter}`}\n onClick={onClearSelectionClick}\n >\n Clear selection\n </BasicButton>\n ) : (\n <div className={styles.actionBarGap} />\n )}\n {actionBarContent}\n </div>\n </div>\n {/* leave a fixed space when action bar floats to avoid layout shift */}\n {actionBarStrategy !== \"sticky\" && (\n <div className={styles.actionBarSpacer} />\n )}\n </>\n );\n };\n\n return (\n <div\n id={id || \"table-wrapper\"}\n data-testid={otherProps[\"data-testid\"] || \"table\"}\n className={clsx(\n styles.tableWrapper,\n scrollable && styles.tableWrapperScrollable,\n className\n )}\n ref={wrapperRef}\n tabIndex={0} // scrollable container must be focusable to support keyboard users\n >\n <div className={styles.tableContainer}>\n <table ref={tableRef} className={styles.table}>\n {renderHeaders()}\n <tbody>\n {loadState === \"success\"\n ? renderRows()\n : renderLoader()}\n </tbody>\n </table>\n </div>\n {enableActionBar &&\n ((selectedIds && selectedIds.length > 0) ||\n enableActionBarWithoutSelection) &&\n renderSelectionBar()}\n </div>\n );\n};\n"],"names":["DataTable","_a","id","headers","rows","className","sortIndicators","alternatingRows","loadState","enableMultiSelect","selectedIds","disabledIds","enableActionBar","enableActionBarWithoutSelection","enableSelectAll","enableStickyHeader","emptyView","actionBarContent","renderCustomEmptyView","onHeaderClick","onSelect","onSelectAll","onClearSelectionClick","otherProps","__rest","tableRef","useRef","headerRef","actionBarWrapperRef","wrapperRef","internalId","useId","keyColumns","filter","header","keyColumn","actionBarStrategy","setActionBarStrategy","useState","scrollable","setScrollable","isFloatingActionBar","setIsFloatingActionBar","useApplyStyle","styles.tokens","actionBarWrapperLeft","current","getBoundingClientRect","left","undefined","actionBarWrapperWidth","clientWidth","useUpdateActionBarBehaviour","useEvent","updateActionBarBehaviour","useEffect","updateActionBarBehaviourThrottled","useThrottle","useResizeDetector","targetRef","onResize","useEventListener","isAllCheckboxSelected","length","isRowSelected","rowId","includes","isAlternatingRow","index","isDisabledRow","getDataTestId","subStr","getTotalColumns","getSortDirection","fieldKey","getHeaderAriaSort","sortDirection","getSortButtonAriaLabel","getCellId","getRowCheckboxAriaLabelledBy","keyColumnIds","map","concatIds","wrapperBounds","headerBounds","strategy","scrollHeight","clientHeight","top","window","innerHeight","bottom","Math","max","height","beforeScrollEnd","scrollTop","renderHeaderCell","label","clickable","style","isSortable","headerCellId","getHeaderCellId","_jsxs","clsx","styles.headerCell","styles.headerCellClickable","scope","onClick","handleHeaderClick","children","styles.headerCellContent","_jsx","Typography","BodyBL","weight","renderSortedArrow","VisuallyHidden","event","stopPropagation","handleHeaderButtonClick","isSorted","ArrowUpIcon","ArrowDownIcon","renderHeaderCheckBox","styles.headerCellCheckbox","styles.selectionCheckboxWrapper","Checkbox","checked","indeterminate","disabled","renderRowCell","row","toString","cellData","cellId","cellContent","styles.bodyCellText","isSelected","styles.bodyCell","renderRowCheckBox","styles.bodyCellCheckbox","focusableWhenDisabled","renderBasicEmptyView","emptyTitle","title","HeadingSM","styles.emptyStateTitle","ErrorDisplay","Object","assign","type","description","styles.tableWrapper","styles.tableWrapperScrollable","ref","tabIndex","styles.tableContainer","styles.table","styles.stickyHeader","styles.headerRow","styles.bodyRow","styles.emptyStateCell","colSpan","_Fragment","styles.bodyRowWithBottomBorder","styles.bodyRowAlternating","styles.bodyRowSelectable","styles.bodyRowSelected","styles.loadingStateWrapper","role","LoadingDotsSpinner","count","counter","styles.actionBarWrapper","styles.actionBar","styles.actionBarFloating","BodyMD","BasicButton","styles.actionBarButton","styles.actionBarGap","styles.actionBarSpacer","renderSelectionBar"],"mappings":"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"}
@@ -23,6 +23,7 @@ export declare const bodyCellText: import("@linaria/core").LinariaClassName;
23
23
  export declare const emptyStateCell: import("@linaria/core").LinariaClassName;
24
24
  export declare const selectionCheckboxWrapper: import("@linaria/core").LinariaClassName;
25
25
  export declare const actionBarButton: import("@linaria/core").LinariaClassName;
26
+ export declare const actionBarGap: import("@linaria/core").LinariaClassName;
26
27
  export declare const actionBarSpacer: import("@linaria/core").LinariaClassName;
27
28
  export declare const actionBar: import("@linaria/core").LinariaClassName;
28
29
  export declare const actionBarFloating: import("@linaria/core").LinariaClassName;
@@ -1,2 +1,2 @@
1
- import"./data-table.styles_rxganh.css";const a={actionBarWrapperLeft:"--fds-internal-dataTable-actionBarWrapper-left",actionBarWrapperWidth:"--fds-internal-dataTable-actionBarWrapper-width"},t="t188sfx3",e="t1j0mhj",r="t4ucy2z",n="t7u4vf5",c="s1nfqacf",p="h1744qno",b="h1ec4wtd",d="hp15x3z",f="h4ne4e9",s="hfa3d3x",h="b6ks76c",i="b1bceurq",l="b8t2s91",o="bjmthdi",x="b1tvp43a",q="bx1feaw",y="b1g3gl2s",g="b1yxh9il",w="e1w2nktt",W="sxywpxo",m="anoy5c0",u="a1gvi5ye",B="aag0lf9",_="a1euqarq",j="adhafdm",k="l1pcc0nq",v="e1qkofer";export{B as actionBar,m as actionBarButton,_ as actionBarFloating,u as actionBarSpacer,j as actionBarWrapper,h as bodyCell,y as bodyCellCheckbox,g as bodyCellText,i as bodyRow,l as bodyRowAlternating,x as bodyRowSelectable,o as bodyRowSelected,q as bodyRowWithBottomBorder,w as emptyStateCell,v as emptyStateTitle,b as headerCell,f as headerCellCheckbox,d as headerCellClickable,s as headerCellContent,p as headerRow,k as loadingStateWrapper,W as selectionCheckboxWrapper,c as stickyHeader,n as table,r as tableContainer,t as tableWrapper,e as tableWrapperScrollable,a as tokens};
1
+ import"./data-table.styles_1tnlmhe.css";const a={actionBarWrapperLeft:"--fds-internal-dataTable-actionBarWrapper-left",actionBarWrapperWidth:"--fds-internal-dataTable-actionBarWrapper-width"},t="t188sfx3",e="t1j0mhj",r="t4ucy2z",n="t7u4vf5",c="s1nfqacf",l="h1744qno",p="h1ec4wtd",b="hp15x3z",d="h4ne4e9",f="hfa3d3x",s="b6ks76c",h="b1bceurq",i="b8t2s91",o="bjmthdi",x="b1tvp43a",q="bx1feaw",w="b1g3gl2s",y="b1yxh9il",m="e1w2nktt",W="sxywpxo",g="anoy5c0",u="a1gvi5ye",B="aag0lf9",_="a1euqarq",j="adhafdm",k="a1pcc0nq",v="l1qkofer",T="e8l591w";export{_ as actionBar,g as actionBarButton,j as actionBarFloating,u as actionBarGap,B as actionBarSpacer,k as actionBarWrapper,s as bodyCell,w as bodyCellCheckbox,y as bodyCellText,h as bodyRow,i as bodyRowAlternating,x as bodyRowSelectable,o as bodyRowSelected,q as bodyRowWithBottomBorder,m as emptyStateCell,T as emptyStateTitle,p as headerCell,d as headerCellCheckbox,b as headerCellClickable,f as headerCellContent,l as headerRow,v as loadingStateWrapper,W as selectionCheckboxWrapper,c as stickyHeader,n as table,r as tableContainer,t as tableWrapper,e as tableWrapperScrollable,a as tokens};
2
2
  //# sourceMappingURL=data-table.styles.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"data-table.styles.js","sources":["../../src/data-table/data-table.styles.ts"],"sourcesContent":["import { css } from \"@linaria/core\";\n\nimport { lineClampCss } from \"../shared/styles\";\nimport {\n Border,\n Colour,\n Font,\n Motion,\n Radius,\n Shadow,\n Spacing,\n} from \"../theme\";\n\nexport const tokens = {\n actionBarWrapperLeft: \"--fds-internal-dataTable-actionBarWrapper-left\",\n actionBarWrapperWidth: \"--fds-internal-dataTable-actionBarWrapper-width\",\n} as const;\n\n// =============================================================================\n// Layout\n// =============================================================================\nexport const tableWrapper = css`\n /* we separate the overflow styles so that sticky elements can still work\n with horizontal scrolling on supported browsers\n see: https://github.com/w3c/csswg-drafts/issues/12289 */\n overflow-y: clip;\n overflow-x: auto;\n position: relative;\n\n display: flex;\n flex-direction: column;\n border: ${Border[\"width-010\"]} ${Border[\"solid\"]} ${Colour[\"border\"]};\n border-radius: ${Radius[\"md\"]};\n\n /* Hide scrollbar */\n scrollbar-width: none; /* Firefox */\n -ms-overflow-style: none; /* IE 10+ */\n &::-webkit-scrollbar {\n display: none; /* Chrome/Safari/Webkit */\n }\n`;\n\nexport const tableWrapperScrollable = css`\n overflow-y: auto;\n`;\n\nexport const tableContainer = css`\n flex: 1;\n`;\n\nexport const table = css`\n text-align: left;\n border-collapse: separate;\n border-spacing: 0;\n width: 100%;\n`;\n\n// =============================================================================\n// Header\n// =============================================================================\nexport const stickyHeader = css`\n position: sticky;\n top: 0;\n z-index: 20;\n`;\n\nexport const headerRow = css`\n background-color: ${Colour[\"bg-stronger\"]};\n height: 6rem;\n border-bottom: ${Border[\"width-010\"]} ${Border[\"solid\"]} ${Colour[\"border\"]};\n`;\n\nexport const headerCell = css`\n padding: 1.25rem 1rem;\n text-align: left;\n cursor: default;\n vertical-align: middle;\n color: ${Colour[\"text\"]};\n border-bottom: ${Border[\"width-010\"]} ${Border[\"solid\"]} ${Colour[\"border\"]};\n\n &:first-child {\n padding-left: 1.5rem;\n }\n\n &:last-child {\n padding-right: 1.5rem;\n }\n\n &:focus-within {\n outline: 2px solid ${Colour[\"focus-ring\"]};\n outline-offset: -3px;\n }\n`;\n\nexport const headerCellClickable = css`\n cursor: pointer;\n`;\n\nexport const headerCellCheckbox = css`\n width: 4rem;\n padding: 1.25rem 0.5rem 1.25rem 1.5rem;\n`;\n\nexport const headerCellContent = css`\n display: flex;\n flex-direction: row;\n align-items: center;\n\n svg {\n color: ${Colour[\"text\"]};\n margin-left: 0.5rem;\n }\n`;\n\n// =============================================================================\n// Body\n// =============================================================================\nexport const bodyCell = css`\n padding: 1.25rem 1rem;\n vertical-align: middle;\n color: ${Colour[\"text\"]};\n border-bottom: ${Border[\"width-010\"]} ${Border[\"solid\"]} ${Colour[\"border\"]};\n\n &:first-child {\n padding-left: 1.5rem;\n }\n\n &:last-child {\n padding-right: 1.5rem;\n }\n`;\n\nexport const bodyRow = css`\n background-color: ${Colour[\"bg\"]};\n border-top: ${Border[\"width-010\"]} ${Border[\"solid\"]} ${Colour[\"border\"]};\n\n &:last-child {\n .${bodyCell} {\n border-bottom: none;\n }\n }\n`;\n\nexport const bodyRowAlternating = css`\n background-color: ${Colour[\"bg-strong\"]};\n`;\n\nexport const bodyRowSelected = css`\n background-color: ${Colour[\"bg-selected\"]};\n`;\n\nexport const bodyRowSelectable = css`\n &:hover {\n background-color: ${Colour[\"bg-hover-strong\"]};\n }\n`;\n\nexport const bodyRowWithBottomBorder = css`\n &:last-child {\n .${bodyCell} {\n border-bottom: ${Border[\"width-010\"]} ${Border[\"solid\"]}\n ${Colour[\"border\"]};\n }\n }\n`;\n\nexport const bodyCellCheckbox = css`\n padding: 1.25rem 0.5rem 1.25rem 1.5rem;\n`;\n\nexport const bodyCellText = css`\n ${lineClampCss(2)}\n text-overflow: ellipsis;\n`;\n\nexport const emptyStateCell = css`\n padding: 4rem 0;\n\n &:first-child {\n padding-left: 1.5rem;\n }\n\n &:last-child {\n padding-right: 1.5rem;\n }\n`;\n\nexport const selectionCheckboxWrapper = css`\n display: flex;\n align-items: center;\n justify-content: center;\n`;\n\n// =============================================================================\n// Action bar\n// =============================================================================\nexport const actionBarButton = css`\n ${Font[\"body-md-semibold\"]}\n cursor: pointer;\n color: ${Colour[\"text-primary\"]};\n transition: ${Motion[\"duration-150\"]} ${Motion[\"ease-default\"]};\n padding: 0.75rem;\n margin: -0.75rem 0;\n\n &:hover {\n color: ${Colour[\"text-hover\"]};\n }\n`;\n\nexport const actionBarSpacer = css`\n height: 3.5rem;\n`;\n\nexport const actionBar = css`\n overflow: hidden;\n display: flex;\n align-items: center;\n height: 3.5rem;\n padding: ${Spacing[\"spacing-16\"]} ${Spacing[\"spacing-24\"]};\n border-top: ${Border[\"width-010\"]} ${Border[\"solid\"]} ${Colour[\"border\"]};\n background-color: ${Colour[\"bg-selected\"]};\n transition: transform ${Motion[\"duration-350\"]} ${Motion[\"ease-default\"]};\n border-radius: ${Radius[\"none\"]} ${Radius[\"none\"]} ${Radius[\"sm\"]}\n ${Radius[\"sm\"]};\n`;\n\nexport const actionBarFloating = css`\n transform: translateX(0.5rem) translateY(-2rem);\n border-radius: ${Radius[\"sm\"]};\n box-shadow: ${Shadow[\"xs-subtle\"]};\n width: calc(100% - ${Spacing[\"spacing-16\"]});\n border: ${Border[\"width-010\"]} ${Border[\"solid\"]} ${Colour[\"border\"]};\n`;\n\nexport const actionBarWrapper = css`\n ${tokens.actionBarWrapperLeft}: initial;\n ${tokens.actionBarWrapperWidth}: initial;\n\n &[data-strategy=\"inline\"] {\n position: absolute;\n bottom: 0;\n left: 0;\n width: var(${tokens.actionBarWrapperWidth}, 100%);\n }\n\n &[data-strategy=\"fixed\"] {\n position: fixed;\n bottom: 0;\n left: var(${tokens.actionBarWrapperLeft}, 0px);\n width: var(${tokens.actionBarWrapperWidth}, 100%);\n }\n\n &[data-strategy=\"sticky\"] {\n position: sticky;\n bottom: 0;\n }\n`;\n\n// =============================================================================\n// Load and error states\n// =============================================================================\nexport const loadingStateWrapper = css`\n display: flex;\n flex-direction: column;\n align-items: center;\n padding: 4rem 0;\n`;\n\nexport const emptyStateTitle = css`\n margin-top: 2rem;\n margin-bottom: 1rem;\n`;\n"],"names":["tokens","actionBarWrapperLeft","actionBarWrapperWidth","tableWrapper","tableWrapperScrollable","tableContainer","table","stickyHeader","headerRow","headerCell","headerCellClickable","headerCellCheckbox","headerCellContent","bodyCell","bodyRow","bodyRowAlternating","bodyRowSelected","bodyRowSelectable","bodyRowWithBottomBorder","bodyCellCheckbox","bodyCellText","emptyStateCell","selectionCheckboxWrapper","actionBarButton","actionBarSpacer","actionBar","actionBarFloating","actionBarWrapper","loadingStateWrapper","emptyStateTitle"],"mappings":"iEAaO,MAAMA,EAAS,CAClBC,qBAAsB,iDACtBC,sBAAuB,mDAMdC,EAAY,WAqBZC,EAAsB,UAItBC,EAAc,UAIdC,EAAK,UAULC,EAAY,WAMZC,EAAS,WAMTC,EAAU,WAsBVC,EAAmB,UAInBC,EAAkB,UAKlBC,EAAiB,UAcjBC,EAAQ,UAeRC,EAAO,WAWPC,EAAkB,UAIlBC,EAAe,UAIfC,EAAiB,WAMjBC,EAAuB,UASvBC,EAAgB,WAIhBC,EAAY,WAKZC,EAAc,WAYdC,EAAwB,UASxBC,EAAe,UAafC,EAAe,WAIfC,EAAS,UAaTC,EAAiB,WAQjBC,EAAgB,UA2BhBC,EAAmB,WAOnBC,EAAe"}
1
+ {"version":3,"file":"data-table.styles.js","sources":["../../src/data-table/data-table.styles.ts"],"sourcesContent":["import { css } from \"@linaria/core\";\n\nimport { lineClampCss } from \"../shared/styles\";\nimport {\n Border,\n Colour,\n Font,\n Motion,\n Radius,\n Shadow,\n Spacing,\n} from \"../theme\";\n\nexport const tokens = {\n actionBarWrapperLeft: \"--fds-internal-dataTable-actionBarWrapper-left\",\n actionBarWrapperWidth: \"--fds-internal-dataTable-actionBarWrapper-width\",\n} as const;\n\n// =============================================================================\n// Layout\n// =============================================================================\nexport const tableWrapper = css`\n /* we separate the overflow styles so that sticky elements can still work\n with horizontal scrolling on supported browsers\n see: https://github.com/w3c/csswg-drafts/issues/12289 */\n overflow-y: clip;\n overflow-x: auto;\n position: relative;\n\n display: flex;\n flex-direction: column;\n border: ${Border[\"width-010\"]} ${Border[\"solid\"]} ${Colour[\"border\"]};\n border-radius: ${Radius[\"md\"]};\n\n /* Hide scrollbar */\n scrollbar-width: none; /* Firefox */\n -ms-overflow-style: none; /* IE 10+ */\n &::-webkit-scrollbar {\n display: none; /* Chrome/Safari/Webkit */\n }\n`;\n\nexport const tableWrapperScrollable = css`\n overflow-y: auto;\n`;\n\nexport const tableContainer = css`\n flex: 1;\n`;\n\nexport const table = css`\n text-align: left;\n border-collapse: separate;\n border-spacing: 0;\n width: 100%;\n`;\n\n// =============================================================================\n// Header\n// =============================================================================\nexport const stickyHeader = css`\n position: sticky;\n top: 0;\n z-index: 20;\n`;\n\nexport const headerRow = css`\n background-color: ${Colour[\"bg-stronger\"]};\n height: 6rem;\n border-bottom: ${Border[\"width-010\"]} ${Border[\"solid\"]} ${Colour[\"border\"]};\n`;\n\nexport const headerCell = css`\n padding: 1.25rem 1rem;\n text-align: left;\n cursor: default;\n vertical-align: middle;\n color: ${Colour[\"text\"]};\n border-bottom: ${Border[\"width-010\"]} ${Border[\"solid\"]} ${Colour[\"border\"]};\n\n &:first-child {\n padding-left: 1.5rem;\n }\n\n &:last-child {\n padding-right: 1.5rem;\n }\n\n &:focus-within {\n outline: 2px solid ${Colour[\"focus-ring\"]};\n outline-offset: -3px;\n }\n`;\n\nexport const headerCellClickable = css`\n cursor: pointer;\n`;\n\nexport const headerCellCheckbox = css`\n width: 4rem;\n padding: 1.25rem 0.5rem 1.25rem 1.5rem;\n`;\n\nexport const headerCellContent = css`\n display: flex;\n flex-direction: row;\n align-items: center;\n\n svg {\n color: ${Colour[\"text\"]};\n margin-left: 0.5rem;\n }\n`;\n\n// =============================================================================\n// Body\n// =============================================================================\nexport const bodyCell = css`\n padding: 1.25rem 1rem;\n vertical-align: middle;\n color: ${Colour[\"text\"]};\n border-bottom: ${Border[\"width-010\"]} ${Border[\"solid\"]} ${Colour[\"border\"]};\n\n &:first-child {\n padding-left: 1.5rem;\n }\n\n &:last-child {\n padding-right: 1.5rem;\n }\n`;\n\nexport const bodyRow = css`\n background-color: ${Colour[\"bg\"]};\n border-top: ${Border[\"width-010\"]} ${Border[\"solid\"]} ${Colour[\"border\"]};\n\n &:last-child {\n .${bodyCell} {\n border-bottom: none;\n }\n }\n`;\n\nexport const bodyRowAlternating = css`\n background-color: ${Colour[\"bg-strong\"]};\n`;\n\nexport const bodyRowSelected = css`\n background-color: ${Colour[\"bg-selected\"]};\n`;\n\nexport const bodyRowSelectable = css`\n &:hover {\n background-color: ${Colour[\"bg-hover-strong\"]};\n }\n`;\n\nexport const bodyRowWithBottomBorder = css`\n &:last-child {\n .${bodyCell} {\n border-bottom: ${Border[\"width-010\"]} ${Border[\"solid\"]}\n ${Colour[\"border\"]};\n }\n }\n`;\n\nexport const bodyCellCheckbox = css`\n padding: 1.25rem 0.5rem 1.25rem 1.5rem;\n`;\n\nexport const bodyCellText = css`\n ${lineClampCss(2)}\n text-overflow: ellipsis;\n`;\n\nexport const emptyStateCell = css`\n padding: 4rem 0;\n\n &:first-child {\n padding-left: 1.5rem;\n }\n\n &:last-child {\n padding-right: 1.5rem;\n }\n`;\n\nexport const selectionCheckboxWrapper = css`\n display: flex;\n align-items: center;\n justify-content: center;\n`;\n\n// =============================================================================\n// Action bar\n// =============================================================================\nexport const actionBarButton = css`\n ${Font[\"body-md-semibold\"]}\n cursor: pointer;\n color: ${Colour[\"text-primary\"]};\n transition: ${Motion[\"duration-150\"]} ${Motion[\"ease-default\"]};\n padding: 0.75rem;\n margin: -0.75rem 0;\n\n &:hover {\n color: ${Colour[\"text-hover\"]};\n }\n`;\n\nexport const actionBarGap = css`\n width: 0.75rem;\n`;\n\nexport const actionBarSpacer = css`\n height: 3.5rem;\n`;\n\nexport const actionBar = css`\n overflow: hidden;\n display: flex;\n align-items: center;\n height: 3.5rem;\n padding: ${Spacing[\"spacing-16\"]} ${Spacing[\"spacing-24\"]};\n border-top: ${Border[\"width-010\"]} ${Border[\"solid\"]} ${Colour[\"border\"]};\n background-color: ${Colour[\"bg-selected\"]};\n transition: transform ${Motion[\"duration-350\"]} ${Motion[\"ease-default\"]};\n border-radius: ${Radius[\"none\"]} ${Radius[\"none\"]} ${Radius[\"sm\"]}\n ${Radius[\"sm\"]};\n`;\n\nexport const actionBarFloating = css`\n transform: translateX(0.5rem) translateY(-2rem);\n border-radius: ${Radius[\"sm\"]};\n box-shadow: ${Shadow[\"xs-subtle\"]};\n width: calc(100% - ${Spacing[\"spacing-16\"]});\n border: ${Border[\"width-010\"]} ${Border[\"solid\"]} ${Colour[\"border\"]};\n`;\n\nexport const actionBarWrapper = css`\n ${tokens.actionBarWrapperLeft}: initial;\n ${tokens.actionBarWrapperWidth}: initial;\n\n &[data-strategy=\"inline\"] {\n position: absolute;\n bottom: 0;\n left: 0;\n width: var(${tokens.actionBarWrapperWidth}, 100%);\n }\n\n &[data-strategy=\"fixed\"] {\n position: fixed;\n bottom: 0;\n left: var(${tokens.actionBarWrapperLeft}, 0px);\n width: var(${tokens.actionBarWrapperWidth}, 100%);\n }\n\n &[data-strategy=\"sticky\"] {\n position: sticky;\n bottom: 0;\n }\n`;\n\n// =============================================================================\n// Load and error states\n// =============================================================================\nexport const loadingStateWrapper = css`\n display: flex;\n flex-direction: column;\n align-items: center;\n padding: 4rem 0;\n`;\n\nexport const emptyStateTitle = css`\n margin-top: 2rem;\n margin-bottom: 1rem;\n`;\n"],"names":["tokens","actionBarWrapperLeft","actionBarWrapperWidth","tableWrapper","tableWrapperScrollable","tableContainer","table","stickyHeader","headerRow","headerCell","headerCellClickable","headerCellCheckbox","headerCellContent","bodyCell","bodyRow","bodyRowAlternating","bodyRowSelected","bodyRowSelectable","bodyRowWithBottomBorder","bodyCellCheckbox","bodyCellText","emptyStateCell","selectionCheckboxWrapper","actionBarButton","actionBarGap","actionBarSpacer","actionBar","actionBarFloating","actionBarWrapper","loadingStateWrapper","emptyStateTitle"],"mappings":"kEAaO,MAAMA,EAAS,CAClBC,qBAAsB,iDACtBC,sBAAuB,mDAMdC,EAAY,WAqBZC,EAAsB,UAItBC,EAAc,UAIdC,EAAK,UAULC,EAAY,WAMZC,EAAS,WAMTC,EAAU,WAsBVC,EAAmB,UAInBC,EAAkB,UAKlBC,EAAiB,UAcjBC,EAAQ,UAeRC,EAAO,WAWPC,EAAkB,UAIlBC,EAAe,UAIfC,EAAiB,WAMjBC,EAAuB,UASvBC,EAAgB,WAIhBC,EAAY,WAKZC,EAAc,WAYdC,EAAwB,UASxBC,EAAe,UAafC,EAAY,WAIZC,EAAe,UAIfC,EAAS,WAaTC,EAAiB,UAQjBC,EAAgB,WA2BhBC,EAAmB,WAOnBC,EAAe"}
@@ -19,9 +19,10 @@
19
19
  .e1w2nktt{padding:4rem 0;}.e1w2nktt:first-child{padding-left:1.5rem;}.e1w2nktt:last-child{padding-right:1.5rem;}
20
20
  .sxywpxo{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;-webkit-box-pack:center;-ms-flex-pack:center;-webkit-justify-content:center;justify-content:center;}
21
21
  .anoy5c0{font-family:var(--fds-font-family-body);font-variant:var(--fds-font-variant);font-size:var(--fds-font-body-size-md);font-weight:var(--fds-font-weight-semibold);line-height:var(--fds-font-body-lh-md);letter-spacing:var(--fds-font-body-ls-md);cursor:pointer;color:var(--fds-colour-text-primary);-webkit-transition:var(--fds-motion-duration-150) var(--fds-motion-timing-ease-default);transition:var(--fds-motion-duration-150) var(--fds-motion-timing-ease-default);padding:0.75rem;margin:-0.75rem 0;}.anoy5c0:hover{color:var(--fds-colour-text-hover);}
22
- .a1gvi5ye{height:3.5rem;}
23
- .aag0lf9{overflow:hidden;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;height:3.5rem;padding:var(--fds-spacing-16) var(--fds-spacing-24);border-top:var(--fds-border-width-010) var(--fds-border-style-solid) var(--fds-colour-border);background-color:var(--fds-colour-bg-selected);-webkit-transition:-webkit-transform var(--fds-motion-duration-350) var(--fds-motion-timing-ease-default);transition:transform var(--fds-motion-duration-350) var(--fds-motion-timing-ease-default);border-radius:var(--fds-radius-none) var(--fds-radius-none) var(--fds-radius-sm) var(--fds-radius-sm);}
24
- .a1euqarq{-webkit-transform:translateX(0.5rem) translateY(-2rem);-moz-transform:translateX(0.5rem) translateY(-2rem);-ms-transform:translateX(0.5rem) translateY(-2rem);transform:translateX(0.5rem) translateY(-2rem);border-radius:var(--fds-radius-sm);box-shadow:var(--fds-shadow-xs-subtle);width:calc(100% - var(--fds-spacing-16));border:var(--fds-border-width-010) var(--fds-border-style-solid) var(--fds-colour-border);}
25
- .adhafdm{--fds-internal-dataTable-actionBarWrapper-left:initial;--fds-internal-dataTable-actionBarWrapper-width:initial;}.adhafdm[data-strategy="inline"]{position:absolute;bottom:0;left:0;width:var(--fds-internal-dataTable-actionBarWrapper-width, 100%);}.adhafdm[data-strategy="fixed"]{position:fixed;bottom:0;left:var(--fds-internal-dataTable-actionBarWrapper-left, 0px);width:var(--fds-internal-dataTable-actionBarWrapper-width, 100%);}.adhafdm[data-strategy="sticky"]{position:-webkit-sticky;position:sticky;bottom:0;}
26
- .l1pcc0nq{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;padding:4rem 0;}
27
- .e1qkofer{margin-top:2rem;margin-bottom:1rem;}}
22
+ .a1gvi5ye{width:0.75rem;}
23
+ .aag0lf9{height:3.5rem;}
24
+ .a1euqarq{overflow:hidden;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;height:3.5rem;padding:var(--fds-spacing-16) var(--fds-spacing-24);border-top:var(--fds-border-width-010) var(--fds-border-style-solid) var(--fds-colour-border);background-color:var(--fds-colour-bg-selected);-webkit-transition:-webkit-transform var(--fds-motion-duration-350) var(--fds-motion-timing-ease-default);transition:transform var(--fds-motion-duration-350) var(--fds-motion-timing-ease-default);border-radius:var(--fds-radius-none) var(--fds-radius-none) var(--fds-radius-sm) var(--fds-radius-sm);}
25
+ .adhafdm{-webkit-transform:translateX(0.5rem) translateY(-2rem);-moz-transform:translateX(0.5rem) translateY(-2rem);-ms-transform:translateX(0.5rem) translateY(-2rem);transform:translateX(0.5rem) translateY(-2rem);border-radius:var(--fds-radius-sm);box-shadow:var(--fds-shadow-xs-subtle);width:calc(100% - var(--fds-spacing-16));border:var(--fds-border-width-010) var(--fds-border-style-solid) var(--fds-colour-border);}
26
+ .a1pcc0nq{--fds-internal-dataTable-actionBarWrapper-left:initial;--fds-internal-dataTable-actionBarWrapper-width:initial;}.a1pcc0nq[data-strategy="inline"]{position:absolute;bottom:0;left:0;width:var(--fds-internal-dataTable-actionBarWrapper-width, 100%);}.a1pcc0nq[data-strategy="fixed"]{position:fixed;bottom:0;left:var(--fds-internal-dataTable-actionBarWrapper-left, 0px);width:var(--fds-internal-dataTable-actionBarWrapper-width, 100%);}.a1pcc0nq[data-strategy="sticky"]{position:-webkit-sticky;position:sticky;bottom:0;}
27
+ .l1qkofer{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;padding:4rem 0;}
28
+ .e8l591w{margin-top:2rem;margin-bottom:1rem;}}
@@ -10,8 +10,8 @@ export interface DataTableProps {
10
10
  rows?: RowProps[] | undefined;
11
11
  className?: string | undefined;
12
12
  /**
13
- * Controlled set of row IDs that are currently selected.
14
- *
13
+ * The ids of selected items. If undefined, the Select All checkbox remains
14
+ * enabled when rows are non-empty.
15
15
  * @remarks Must be provided alongside `enableMultiSelect` for selection to work. Pass an
16
16
  * empty array (not `undefined`) to enable the select-all checkbox while having no rows
17
17
  * selected.
@@ -25,6 +25,8 @@ export interface DataTableProps {
25
25
  enableSelectAll?: boolean | undefined;
26
26
  /** Shows the action bar whenever one or more rows are selected. */
27
27
  enableActionBar?: boolean | undefined;
28
+ /** Shows the action bar even when no rows are selected. Requires `enableActionBar`. */
29
+ enableActionBarWithoutSelection?: boolean | undefined;
28
30
  /** Keeps the header row visible as the user scrolls down through the table. */
29
31
  enableStickyHeader?: boolean | undefined;
30
32
  /** Additional content rendered inside the action bar. */