@lifesg/react-design-system 4.0.0-alpha.12 → 4.0.0-alpha.14
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.
- package/breadcrumb/breadcrumb.js +1 -1
- package/breadcrumb/breadcrumb.js.map +1 -1
- package/breadcrumb/breadcrumb.styles.d.ts +0 -8
- package/breadcrumb/breadcrumb.styles.js +1 -1
- package/breadcrumb/breadcrumb.styles.js.map +1 -1
- package/breadcrumb/breadcrumb.styles_1blzn8n.css +7 -0
- package/breadcrumb/types.d.ts +2 -13
- package/cjs/breadcrumb/breadcrumb.js +1 -1
- package/cjs/breadcrumb/breadcrumb.js.map +1 -1
- package/cjs/breadcrumb/breadcrumb.styles.js +1 -1
- package/cjs/breadcrumb/breadcrumb.styles.js.map +1 -1
- package/cjs/breadcrumb/breadcrumb.styles_1blzn8n.css +7 -0
- package/cjs/drawer/drawer.js +1 -1
- package/cjs/drawer/drawer.js.map +1 -1
- package/cjs/drawer/drawer.styles.js +1 -1
- package/cjs/drawer/drawer.styles.js.map +1 -1
- package/{drawer/drawer.styles_94hx3y.css → cjs/drawer/drawer.styles_a4bwe0.css} +6 -3
- package/cjs/external/dompurify/dist/purify.es.js +4 -2
- package/cjs/external/dompurify/dist/purify.es.js.map +1 -1
- package/cjs/file-upload/file-list/file-list.js +1 -1
- package/cjs/file-upload/file-list/file-list.js.map +1 -1
- package/cjs/file-upload/file-list/file-list.styles.js +1 -1
- package/cjs/file-upload/file-list/file-list.styles.js.map +1 -1
- package/cjs/file-upload/file-list/file-list.styles_1xbypnh.css +2 -0
- package/cjs/file-upload/file-list-item/file-item-actions.js +2 -0
- package/cjs/file-upload/file-list-item/file-item-actions.js.map +1 -0
- package/cjs/file-upload/file-list-item/file-item-actions.styles.js +2 -0
- package/cjs/file-upload/file-list-item/file-item-actions.styles.js.map +1 -0
- package/cjs/file-upload/file-list-item/file-item-actions.styles_1quulgy.css +8 -0
- package/cjs/file-upload/file-list-item/file-item-details.js +2 -0
- package/cjs/file-upload/file-list-item/file-item-details.js.map +1 -0
- package/cjs/file-upload/file-list-item/file-item-details.styles.js +2 -0
- package/cjs/file-upload/file-list-item/file-item-details.styles.js.map +1 -0
- package/cjs/file-upload/file-list-item/file-item-details.styles_1ce9akx.css +7 -0
- package/cjs/file-upload/file-list-item/file-list-item.js +1 -1
- package/cjs/file-upload/file-list-item/file-list-item.js.map +1 -1
- package/cjs/file-upload/file-list-item/file-list-item.styles.js +1 -1
- package/cjs/file-upload/file-list-item/file-list-item.styles.js.map +1 -1
- package/cjs/file-upload/file-list-item/file-list-item.styles_x3a500.css +10 -0
- package/cjs/file-upload/file-list-item/use-truncated-name.js +2 -0
- package/cjs/file-upload/file-list-item/use-truncated-name.js.map +1 -0
- package/cjs/local-nav/local-nav-dropdown/local-nav-dropdown.js +1 -1
- package/cjs/local-nav/local-nav-dropdown/local-nav-dropdown.js.map +1 -1
- package/cjs/local-nav/local-nav-dropdown/local-nav-dropdown.styles.js +1 -1
- package/cjs/local-nav/local-nav-dropdown/local-nav-dropdown.styles.js.map +1 -1
- package/{local-nav/local-nav-dropdown/local-nav-dropdown.styles_uhd4xl.css → cjs/local-nav/local-nav-dropdown/local-nav-dropdown.styles_kpel1m.css} +9 -6
- package/cjs/local-nav/local-nav-menu/local-nav-menu.js +1 -1
- package/cjs/local-nav/local-nav-menu/local-nav-menu.js.map +1 -1
- package/cjs/local-nav/local-nav-menu/local-nav-menu.styles.js +1 -1
- package/cjs/local-nav/local-nav-menu/local-nav-menu.styles.js.map +1 -1
- package/cjs/local-nav/local-nav-menu/local-nav-menu.styles_67fcyc.css +8 -0
- package/cjs/menu/menu-content.js +1 -1
- package/cjs/menu/menu-content.js.map +1 -1
- package/cjs/menu/menu-content.styles.js +1 -1
- package/cjs/menu/menu-content.styles.js.map +1 -1
- package/cjs/menu/menu-content.styles_1r8oxtk.css +5 -0
- package/cjs/menu/menu-item.styles.js +1 -1
- package/cjs/menu/menu-item.styles.js.map +1 -1
- package/cjs/menu/{menu-item.styles_liyed8.css → menu-item.styles_eut2j9.css} +1 -1
- package/cjs/menu/menu-link.styles.js +1 -1
- package/cjs/menu/menu-link.styles.js.map +1 -1
- package/cjs/menu/menu-link.styles_rng7n7.css +2 -0
- package/cjs/menu/menu-section.js +1 -1
- package/cjs/menu/menu-section.js.map +1 -1
- package/cjs/menu/menu-section.styles.js +1 -1
- package/cjs/menu/menu-section.styles.js.map +1 -1
- package/cjs/menu/menu-section.styles_1n0ppxl.css +5 -0
- package/cjs/modal-v2/slots/slot-styles.js +1 -1
- package/cjs/modal-v2/slots/slot-styles.js.map +1 -1
- package/cjs/modal-v2/slots/{slot-styles_ayb9il.css → slot-styles_ygu6zc.css} +1 -1
- package/cjs/navbar/navbar-items.js +1 -1
- package/cjs/navbar/navbar-items.js.map +1 -1
- package/cjs/notification-banner/notification-banner-hoc.js +1 -1
- package/cjs/notification-banner/notification-banner-hoc.js.map +1 -1
- package/cjs/pagination/pagination.js +1 -1
- package/cjs/pagination/pagination.js.map +1 -1
- package/cjs/shared/dropdown-list/dropdown-label.js +1 -1
- package/cjs/shared/dropdown-list/dropdown-label.js.map +1 -1
- package/cjs/shared/fade-wrapper/fade-wrapper.js +1 -1
- package/cjs/shared/fade-wrapper/fade-wrapper.js.map +1 -1
- package/cjs/theme/tokens/colour.js +1 -1
- package/cjs/theme/tokens/colour.js.map +1 -1
- package/cjs/theme/tokens/radius.js +1 -1
- package/cjs/theme/tokens/radius.js.map +1 -1
- package/codemods/run-codemod.js +8 -2
- package/codemods/run-codemod.js.map +1 -1
- package/codemods/run-codemod.ts +13 -4
- package/drawer/drawer.d.ts +1 -1
- package/drawer/drawer.js +1 -1
- package/drawer/drawer.js.map +1 -1
- package/drawer/drawer.styles.d.ts +3 -0
- package/drawer/drawer.styles.js +1 -1
- package/drawer/drawer.styles.js.map +1 -1
- package/{cjs/drawer/drawer.styles_94hx3y.css → drawer/drawer.styles_a4bwe0.css} +6 -3
- package/drawer/types.d.ts +7 -0
- package/external/dompurify/dist/purify.es.js +4 -2
- package/external/dompurify/dist/purify.es.js.map +1 -1
- package/file-upload/file-list/file-list.js +1 -1
- package/file-upload/file-list/file-list.js.map +1 -1
- package/file-upload/file-list/file-list.styles.d.ts +0 -1
- package/file-upload/file-list/file-list.styles.js +1 -1
- package/file-upload/file-list/file-list.styles.js.map +1 -1
- package/file-upload/file-list/file-list.styles_1xbypnh.css +2 -0
- package/file-upload/file-list-item/file-item-actions.d.ts +30 -0
- package/file-upload/file-list-item/file-item-actions.js +2 -0
- package/file-upload/file-list-item/file-item-actions.js.map +1 -0
- package/file-upload/file-list-item/file-item-actions.styles.d.ts +6 -0
- package/file-upload/file-list-item/file-item-actions.styles.js +2 -0
- package/file-upload/file-list-item/file-item-actions.styles.js.map +1 -0
- package/file-upload/file-list-item/file-item-actions.styles_1quulgy.css +8 -0
- package/file-upload/file-list-item/file-item-details.d.ts +15 -0
- package/file-upload/file-list-item/file-item-details.js +2 -0
- package/file-upload/file-list-item/file-item-details.js.map +1 -0
- package/file-upload/file-list-item/file-item-details.styles.d.ts +7 -0
- package/file-upload/file-list-item/file-item-details.styles.js +2 -0
- package/file-upload/file-list-item/file-item-details.styles.js.map +1 -0
- package/file-upload/file-list-item/file-item-details.styles_1ce9akx.css +7 -0
- package/file-upload/file-list-item/file-list-item.d.ts +1 -7
- package/file-upload/file-list-item/file-list-item.js +1 -1
- package/file-upload/file-list-item/file-list-item.js.map +1 -1
- package/file-upload/file-list-item/file-list-item.styles.d.ts +6 -13
- package/file-upload/file-list-item/file-list-item.styles.js +1 -1
- package/file-upload/file-list-item/file-list-item.styles.js.map +1 -1
- package/file-upload/file-list-item/file-list-item.styles_x3a500.css +10 -0
- package/file-upload/file-list-item/types.d.ts +10 -3
- package/file-upload/file-list-item/use-truncated-name.d.ts +1 -0
- package/file-upload/file-list-item/use-truncated-name.js +2 -0
- package/file-upload/file-list-item/use-truncated-name.js.map +1 -0
- package/input-group/types.d.ts +4 -1
- package/input-select/types.d.ts +1 -0
- package/local-nav/local-nav-dropdown/local-nav-dropdown.js +1 -1
- package/local-nav/local-nav-dropdown/local-nav-dropdown.js.map +1 -1
- package/local-nav/local-nav-dropdown/local-nav-dropdown.styles.d.ts +3 -0
- package/local-nav/local-nav-dropdown/local-nav-dropdown.styles.js +1 -1
- package/local-nav/local-nav-dropdown/local-nav-dropdown.styles.js.map +1 -1
- package/{cjs/local-nav/local-nav-dropdown/local-nav-dropdown.styles_uhd4xl.css → local-nav/local-nav-dropdown/local-nav-dropdown.styles_kpel1m.css} +9 -6
- package/local-nav/local-nav-menu/local-nav-menu.js +1 -1
- package/local-nav/local-nav-menu/local-nav-menu.js.map +1 -1
- package/local-nav/local-nav-menu/local-nav-menu.styles.d.ts +3 -0
- package/local-nav/local-nav-menu/local-nav-menu.styles.js +1 -1
- package/local-nav/local-nav-menu/local-nav-menu.styles.js.map +1 -1
- package/local-nav/local-nav-menu/local-nav-menu.styles_67fcyc.css +8 -0
- package/local-nav/types.d.ts +17 -0
- package/masked-input/types.d.ts +1 -2
- package/menu/menu-content.js +1 -1
- package/menu/menu-content.js.map +1 -1
- package/menu/menu-content.styles.d.ts +1 -0
- package/menu/menu-content.styles.js +1 -1
- package/menu/menu-content.styles.js.map +1 -1
- package/menu/menu-content.styles_1r8oxtk.css +5 -0
- package/menu/menu-item.styles.js +1 -1
- package/menu/menu-item.styles.js.map +1 -1
- package/menu/{menu-item.styles_liyed8.css → menu-item.styles_eut2j9.css} +1 -1
- package/menu/menu-link.styles.js +1 -1
- package/menu/menu-link.styles.js.map +1 -1
- package/menu/menu-link.styles_rng7n7.css +2 -0
- package/menu/menu-section.d.ts +1 -1
- package/menu/menu-section.js +1 -1
- package/menu/menu-section.js.map +1 -1
- package/menu/menu-section.styles.d.ts +7 -0
- package/menu/menu-section.styles.js +1 -1
- package/menu/menu-section.styles.js.map +1 -1
- package/menu/menu-section.styles_1n0ppxl.css +5 -0
- package/menu/menu.d.ts +1 -1
- package/menu/types.d.ts +10 -2
- package/modal-v2/slots/slot-styles.js +1 -1
- package/modal-v2/slots/slot-styles.js.map +1 -1
- package/modal-v2/slots/{slot-styles_ayb9il.css → slot-styles_ygu6zc.css} +1 -1
- package/navbar/navbar-items.js +1 -1
- package/navbar/navbar-items.js.map +1 -1
- package/navbar/types.d.ts +9 -0
- package/notification-banner/notification-banner-hoc.js +1 -1
- package/notification-banner/notification-banner-hoc.js.map +1 -1
- package/package.json +3 -4
- package/pagination/pagination.js +1 -1
- package/pagination/pagination.js.map +1 -1
- package/pagination/types.d.ts +8 -1
- package/scripts/cli.js +18 -0
- package/select-histogram/types.d.ts +1 -0
- package/shared/dropdown-list/dropdown-label.d.ts +2 -2
- package/shared/dropdown-list/dropdown-label.js +1 -1
- package/shared/dropdown-list/dropdown-label.js.map +1 -1
- package/shared/dropdown-list/types.d.ts +6 -2
- package/shared/fade-wrapper/fade-wrapper.js +1 -1
- package/shared/fade-wrapper/fade-wrapper.js.map +1 -1
- package/shared/fade-wrapper/types.d.ts +1 -0
- package/shared/styles/index.d.ts +5 -0
- package/skills/fds-build/SKILL.md +167 -0
- package/skills/fds-build/catalogue.md +181 -0
- package/skills/fds-build/evals/evals.json +519 -0
- package/skills/fds-build/resources/components/accordion.md +128 -0
- package/skills/fds-build/resources/components/alert.md +54 -0
- package/skills/fds-build/resources/components/animation.md +18 -0
- package/skills/fds-build/resources/components/avatar.md +10 -0
- package/skills/fds-build/resources/components/badge.md +18 -0
- package/skills/fds-build/resources/components/box-container.md +61 -0
- package/skills/fds-build/resources/components/breadcrumb.md +60 -0
- package/skills/fds-build/resources/components/button.md +74 -0
- package/skills/fds-build/resources/components/calendar.md +113 -0
- package/skills/fds-build/resources/components/card.md +43 -0
- package/skills/fds-build/resources/components/checkbox.md +53 -0
- package/skills/fds-build/resources/components/countdown-timer.md +20 -0
- package/skills/fds-build/resources/components/data-table.md +142 -0
- package/skills/fds-build/resources/components/date-navigator.md +25 -0
- package/skills/fds-build/resources/components/divider.md +23 -0
- package/skills/fds-build/resources/components/drawer.md +78 -0
- package/skills/fds-build/resources/components/error-display.md +137 -0
- package/skills/fds-build/resources/components/feedback-rating.md +61 -0
- package/skills/fds-build/resources/components/file-download.md +54 -0
- package/skills/fds-build/resources/components/file-upload.md +105 -0
- package/skills/fds-build/resources/components/filter.md +228 -0
- package/skills/fds-build/resources/components/footer.md +94 -0
- package/skills/fds-build/resources/components/form-date-input.md +85 -0
- package/skills/fds-build/resources/components/form-date-range-input.md +146 -0
- package/skills/fds-build/resources/components/form-e-signature.md +55 -0
- package/skills/fds-build/resources/components/form-input.md +65 -0
- package/skills/fds-build/resources/components/form-masked-input.md +69 -0
- package/skills/fds-build/resources/components/form-multi-select.md +100 -0
- package/skills/fds-build/resources/components/form-nested-multi-select.md +159 -0
- package/skills/fds-build/resources/components/form-nested-select.md +151 -0
- package/skills/fds-build/resources/components/form-otp-verification.md +175 -0
- package/skills/fds-build/resources/components/form-phone-number-input.md +87 -0
- package/skills/fds-build/resources/components/form-predictive-text-input.md +108 -0
- package/skills/fds-build/resources/components/form-select.md +103 -0
- package/skills/fds-build/resources/components/form-slider.md +116 -0
- package/skills/fds-build/resources/components/form-textarea.md +116 -0
- package/skills/fds-build/resources/components/form-time-range-picker.md +98 -0
- package/skills/fds-build/resources/components/form-timepicker.md +77 -0
- package/skills/fds-build/resources/components/form-unit-number-input.md +138 -0
- package/skills/fds-build/resources/components/fullscreen-image-carousel.md +159 -0
- package/skills/fds-build/resources/components/histogram-slider.md +41 -0
- package/skills/fds-build/resources/components/icon.md +167 -0
- package/skills/fds-build/resources/components/image-button.md +12 -0
- package/skills/fds-build/resources/components/input.md +51 -0
- package/skills/fds-build/resources/components/language-switcher.md +15 -0
- package/skills/fds-build/resources/components/layout.md +156 -0
- package/skills/fds-build/resources/components/link-list.md +120 -0
- package/skills/fds-build/resources/components/local-nav.md +119 -0
- package/skills/fds-build/resources/components/masthead.md +14 -0
- package/skills/fds-build/resources/components/menu.md +109 -0
- package/skills/fds-build/resources/components/modal.md +150 -0
- package/skills/fds-build/resources/components/navbar.md +270 -0
- package/skills/fds-build/resources/components/notification-banner.md +106 -0
- package/skills/fds-build/resources/components/pagination.md +104 -0
- package/skills/fds-build/resources/components/pill.md +55 -0
- package/skills/fds-build/resources/components/popover.md +80 -0
- package/skills/fds-build/resources/components/progress-indicator.md +47 -0
- package/skills/fds-build/resources/components/radio-button.md +66 -0
- package/skills/fds-build/resources/components/schedule.md +78 -0
- package/skills/fds-build/resources/components/sidenav.md +183 -0
- package/skills/fds-build/resources/components/singpass-button.md +14 -0
- package/skills/fds-build/resources/components/smart-app-banner.md +28 -0
- package/skills/fds-build/resources/components/tab.md +107 -0
- package/skills/fds-build/resources/components/table.md +65 -0
- package/skills/fds-build/resources/components/tag.md +68 -0
- package/skills/fds-build/resources/components/text-list.md +44 -0
- package/skills/fds-build/resources/components/time-slot-bar-week.md +66 -0
- package/skills/fds-build/resources/components/time-slot-bar.md +57 -0
- package/skills/fds-build/resources/components/time-slot-week-view.md +70 -0
- package/skills/fds-build/resources/components/timeline.md +69 -0
- package/skills/fds-build/resources/components/timetable.md +123 -0
- package/skills/fds-build/resources/components/toast.md +72 -0
- package/skills/fds-build/resources/components/toggle.md +119 -0
- package/skills/fds-build/resources/components/typography.md +86 -0
- package/skills/fds-build/resources/components/uneditable-section.md +84 -0
- package/skills/fds-build/resources/foundations/layout-composition-patterns.md +53 -0
- package/skills/fds-build/resources/foundations/tokens.md +547 -0
- package/skills/fds-build/resources/patterns/states.md +300 -0
- package/skills/fds-build/resources/setup/setup.md +202 -0
- package/skills/fds-build/resources/templates/form.md +427 -0
- package/skills/fds-build/resources/templates/listing.md +435 -0
- package/theme/styles/a11y-playground.css +52 -40
- package/theme/styles/bookingsg.css +52 -40
- package/theme/styles/careercompass.css +52 -40
- package/theme/styles/ccube.css +52 -40
- package/theme/styles/imda.css +52 -40
- package/theme/styles/lifesg.css +52 -40
- package/theme/styles/mylegacy.css +52 -40
- package/theme/styles/oneservice.css +52 -40
- package/theme/styles/pa.css +28 -22
- package/theme/styles/rbs.css +52 -40
- package/theme/styles/sgw-digital-lobby.css +52 -40
- package/theme/styles/smgs.css +52 -40
- package/theme/styles/spf.css +28 -27
- package/theme/styles/sportsg-orange.css +52 -40
- package/theme/styles/supportgowhere.css +52 -40
- package/theme/styles/tote-board.css +52 -40
- package/theme/styles/vica.css +52 -40
- package/theme/styles/websg.css +52 -40
- package/theme/styles/wise.css +52 -40
- package/theme/styles/wogaa.css +52 -40
- package/theme/tokens/colour.d.ts +6 -0
- package/theme/tokens/colour.js +1 -1
- package/theme/tokens/colour.js.map +1 -1
- package/theme/tokens/radius.d.ts +3 -0
- package/theme/tokens/radius.js +1 -1
- package/theme/tokens/radius.js.map +1 -1
- package/breadcrumb/breadcrumb.styles_1nl4aua.css +0 -18
- package/cjs/breadcrumb/breadcrumb.styles_1nl4aua.css +0 -18
- package/cjs/file-upload/file-item-edit.js +0 -2
- package/cjs/file-upload/file-item-edit.js.map +0 -1
- package/cjs/file-upload/file-item-edit.styles.js +0 -2
- package/cjs/file-upload/file-item-edit.styles.js.map +0 -1
- package/cjs/file-upload/file-item-edit.styles_19bvztn.css +0 -11
- package/cjs/file-upload/file-list/file-list.styles_1w7so98.css +0 -3
- package/cjs/file-upload/file-list-item/file-list-item.styles_kgtfke.css +0 -17
- package/cjs/local-nav/local-nav-menu/local-nav-menu.styles_pq19dh.css +0 -5
- package/cjs/menu/menu-content.styles_p7ijll.css +0 -2
- package/cjs/menu/menu-link.styles_hfxoez.css +0 -2
- package/cjs/menu/menu-section.styles_g7my4d.css +0 -3
- package/file-upload/file-item-edit.d.ts +0 -14
- package/file-upload/file-item-edit.js +0 -2
- package/file-upload/file-item-edit.js.map +0 -1
- package/file-upload/file-item-edit.styles.d.ts +0 -9
- package/file-upload/file-item-edit.styles.js +0 -2
- package/file-upload/file-item-edit.styles.js.map +0 -1
- package/file-upload/file-item-edit.styles_19bvztn.css +0 -11
- package/file-upload/file-list/file-list.styles_1w7so98.css +0 -3
- package/file-upload/file-list-item/file-list-item.styles_kgtfke.css +0 -17
- package/local-nav/local-nav-menu/local-nav-menu.styles_pq19dh.css +0 -5
- package/menu/menu-content.styles_p7ijll.css +0 -2
- package/menu/menu-link.styles_hfxoez.css +0 -2
- package/menu/menu-section.styles_g7my4d.css +0 -3
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
# DataTable
|
|
2
|
+
|
|
3
|
+
Import: `import { DataTable } from "@lifesg/react-design-system/data-table"`
|
|
4
|
+
|
|
5
|
+
## When to use
|
|
6
|
+
|
|
7
|
+
- Displaying tabular data with optional sorting, row selection, and custom cell rendering.
|
|
8
|
+
- Use `enableMultiSelect` + `enableSelectAll` when users need to act on multiple rows at once.
|
|
9
|
+
|
|
10
|
+
## Usage
|
|
11
|
+
|
|
12
|
+
### Column definitions, sorting, selection, and custom cell rendering
|
|
13
|
+
|
|
14
|
+
```tsx
|
|
15
|
+
import { useState, useMemo } from "react";
|
|
16
|
+
import {
|
|
17
|
+
DataTable,
|
|
18
|
+
SortIndicatorsProps,
|
|
19
|
+
} from "@lifesg/react-design-system/data-table";
|
|
20
|
+
import { Pill } from "@lifesg/react-design-system/pill";
|
|
21
|
+
|
|
22
|
+
const rows = [
|
|
23
|
+
{ id: "1", name: "Alice", status: "active", score: 90 },
|
|
24
|
+
{ id: "2", name: "Bob", status: "inactive", score: 72 },
|
|
25
|
+
{ id: "3", name: "Carol", status: "active", score: 85 },
|
|
26
|
+
];
|
|
27
|
+
|
|
28
|
+
const Example = () => {
|
|
29
|
+
const [selectedIds, setSelectedIds] = useState<string[]>([]);
|
|
30
|
+
const [sortState, setSortState] = useState<SortIndicatorsProps>({
|
|
31
|
+
score: "desc",
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
// onSelect: toggle a single row id
|
|
35
|
+
const handleSelect = (rowId: string, isSelected: boolean) => {
|
|
36
|
+
setSelectedIds((prev) =>
|
|
37
|
+
isSelected ? [...prev, rowId] : prev.filter((id) => id !== rowId)
|
|
38
|
+
);
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
// onSelectAll: isAllSelected=true means "clear all"; false means "select all"
|
|
42
|
+
const handleSelectAll = (isAllSelected: boolean) => {
|
|
43
|
+
setSelectedIds(isAllSelected ? [] : rows.map((r) => r.id));
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const handleHeaderClick = (fieldKey: string) => {
|
|
47
|
+
if (fieldKey === "score") {
|
|
48
|
+
setSortState({ score: sortState.score === "asc" ? "desc" : "asc" });
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
const sorted = useMemo(
|
|
53
|
+
() =>
|
|
54
|
+
[...rows].sort((a, b) =>
|
|
55
|
+
sortState.score === "asc"
|
|
56
|
+
? a.score - b.score
|
|
57
|
+
: b.score - a.score
|
|
58
|
+
),
|
|
59
|
+
[sortState]
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
return (
|
|
63
|
+
<DataTable
|
|
64
|
+
headers={[
|
|
65
|
+
{ fieldKey: "name", label: "Name", keyColumn: true },
|
|
66
|
+
{ fieldKey: "status", label: "Status" },
|
|
67
|
+
{ fieldKey: "score", label: "Score", clickable: true },
|
|
68
|
+
]}
|
|
69
|
+
rows={sorted.map((row) => ({
|
|
70
|
+
...row,
|
|
71
|
+
// custom cell: render status as a Pill
|
|
72
|
+
status: <Pill type="outline">{row.status}</Pill>,
|
|
73
|
+
}))}
|
|
74
|
+
selectedIds={selectedIds}
|
|
75
|
+
disabledIds={["2"]}
|
|
76
|
+
sortIndicators={sortState}
|
|
77
|
+
enableMultiSelect
|
|
78
|
+
enableSelectAll
|
|
79
|
+
onSelect={handleSelect}
|
|
80
|
+
onSelectAll={handleSelectAll}
|
|
81
|
+
onHeaderClick={handleHeaderClick}
|
|
82
|
+
/>
|
|
83
|
+
);
|
|
84
|
+
};
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## HeaderItemProps
|
|
88
|
+
|
|
89
|
+
| Prop | Type | Default | Description |
|
|
90
|
+
| ------------- | --------------------------- | ------- | ---------------------------------------------------------------------- |
|
|
91
|
+
| `fieldKey` \* | `string` | — | Key name in the row item object |
|
|
92
|
+
| `label` \* | `string \| React.ReactNode` | — | Display label for the column header |
|
|
93
|
+
| `clickable` | `boolean` | — | If true, `onHeaderClick` is called when the cell is clicked |
|
|
94
|
+
| `style` | `CSSProperties` | — | Custom styles for the column header cell |
|
|
95
|
+
| `keyColumn` | `boolean` | — | Marks this column as descriptive for screen reader row checkbox labels |
|
|
96
|
+
|
|
97
|
+
## Props — `DataTableProps`
|
|
98
|
+
|
|
99
|
+
| Prop | Type | Default | Description |
|
|
100
|
+
| --------------------------------- | ------------------------------------------------ | --------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
101
|
+
| `id` | `string` | — | — |
|
|
102
|
+
| `headers` \* | `HeaderProps[]` | — | Column definitions that determine the rendered headers and the `fieldKey` used to read values from each `RowProps` entry. |
|
|
103
|
+
| `rows` | `RowProps[]` | — | Row data to render. When omitted or empty the empty state is shown. |
|
|
104
|
+
| `className` | `string` | — | — |
|
|
105
|
+
| `selectedIds` | `string[]` | — | The ids of selected items. If undefined, the Select All checkbox remains enabled when rows are non-empty. |
|
|
106
|
+
| `disabledIds` | `string[]` | — | Row IDs whose checkboxes are rendered in a disabled state; the rows remain visible. |
|
|
107
|
+
| `enableMultiSelect` | `boolean` | — | Renders a checkbox column as the first column of each row to support row selection. |
|
|
108
|
+
| `enableSelectAll` | `boolean` | — | Renders a select-all checkbox in the header checkbox column. Requires `enableMultiSelect`. |
|
|
109
|
+
| `enableActionBar` | `boolean` | — | Shows the action bar whenever one or more rows are selected. |
|
|
110
|
+
| `enableActionBarWithoutSelection` | `boolean` | — | Shows the action bar even when no rows are selected. Requires `enableActionBar`. |
|
|
111
|
+
| `enableStickyHeader` | `boolean` | — | Keeps the header row visible as the user scrolls down through the table. |
|
|
112
|
+
| `actionBarContent` | `ReactNode` | — | Additional content rendered inside the action bar. |
|
|
113
|
+
| `loadState` | `LoadStateType` | "success" | Controls whether the table body renders data rows or a loading indicator. |
|
|
114
|
+
| `onSelect` | `((rowId: string, isSelected: boolean) => void)` | — | Called when a row's checkbox is toggled; receives the row ID and the new selected state. |
|
|
115
|
+
| `onSelectAll` | `((isAllSelected: boolean) => void)` | — | Called when the select-all checkbox is toggled. |
|
|
116
|
+
| `onHeaderClick` | `((fieldKey: string) => void)` | — | Called when a header cell is clicked; receives the `fieldKey` of the clicked column. |
|
|
117
|
+
| `onClearSelectionClick` | `(() => void)` | — | Called when the "Clear selection" button inside the action bar is clicked. |
|
|
118
|
+
| `sortIndicators` | `SortIndicatorsProps` | — | Maps each `fieldKey` to its current sort direction. A key present in this map causes the corresponding header to render a directional arrow and expose sort controls to assistive technology. |
|
|
119
|
+
| `alternatingRows` | `boolean` | — | Applies an alternate background colour to every odd-indexed row. |
|
|
120
|
+
| `emptyView` | `ErrorDisplayAttributes` | — | Overrides the title and description shown in the built-in empty state. Ignored when `renderCustomEmptyView` is provided. |
|
|
121
|
+
| `renderCustomEmptyView` | `(() => ReactNode)` | — | Renders a fully custom empty state in place of the default `ErrorDisplay`. |
|
|
122
|
+
|
|
123
|
+
## Props — `RowProps`
|
|
124
|
+
|
|
125
|
+
| Prop | Type | Default | Description |
|
|
126
|
+
| ------- | ------------------ | ------- | --------------------------------------------------------------------------------------------- |
|
|
127
|
+
| `id` \* | `string \| number` | — | Unique identifier for the row; used as the key and referenced by `selectedIds`/`disabledIds`. |
|
|
128
|
+
|
|
129
|
+
## Rules
|
|
130
|
+
|
|
131
|
+
- Each row object must have a unique `id: string` field.
|
|
132
|
+
- `selectedIds` and `disabledIds` are arrays of row `id` strings — manage them in external state.
|
|
133
|
+
- `onSelect(rowId, isSelected)` fires per row; toggle the id into/out of your `selectedIds` array.
|
|
134
|
+
- `onSelectAll(isAllSelected)` fires when the header checkbox is clicked; `isAllSelected` is `true` when the action should clear all selections (the parameter name is inverted — see example).
|
|
135
|
+
- For sortable columns, set `clickable: true` on the header and handle `onHeaderClick(fieldKey)`.
|
|
136
|
+
- Custom cell rendering: set a row field to a `ReactNode` or a render function `(row, renderProps) => ReactNode`.
|
|
137
|
+
|
|
138
|
+
## Anti-patterns
|
|
139
|
+
|
|
140
|
+
- Do not derive `selectedIds` from row data alone without external state — the table is uncontrolled for selection without it.
|
|
141
|
+
- Do not omit `id` on row objects — selection and disabled logic will break silently.
|
|
142
|
+
- Do not add `clickable: true` to a header without wiring `onHeaderClick` — clicks will silently do nothing.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# DateNavigator
|
|
2
|
+
|
|
3
|
+
Import: `import { DateNavigator } from "@lifesg/react-design-system/date-navigator"`
|
|
4
|
+
|
|
5
|
+
## Props
|
|
6
|
+
|
|
7
|
+
| Prop | Type | Default | Description |
|
|
8
|
+
| ------------------------ | --------------------------------- | ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
9
|
+
| `id` | `string` | — | — |
|
|
10
|
+
| `className` | `string` | — | — |
|
|
11
|
+
| `selectedDate` \* | `string` | — | The currently displayed date in `YYYY-MM-DD` format. |
|
|
12
|
+
| `minDate` | `string` | — | The earliest selectable date in `YYYY-MM-DD` format. The left arrow is disabled when `selectedDate` reaches this boundary. |
|
|
13
|
+
| `maxDate` | `string` | — | The latest selectable date in `YYYY-MM-DD` format. The right arrow is disabled when `selectedDate` reaches this boundary. |
|
|
14
|
+
| `loading` | `boolean` | — | When `true`, both navigation arrows and the calendar trigger are disabled. |
|
|
15
|
+
| `showDateAsShortForm` | `boolean` | — | When `true`, formats the displayed date using abbreviated month and day names (e.g. `"3 Jul 2025, Wed"` instead of `"3 July 2025, Wednesday"`). |
|
|
16
|
+
| `showCurrentDateAsToday` | `boolean` | — | When `true`, replaces the day-of-week label with `"Today"` if `selectedDate` matches the current calendar date. |
|
|
17
|
+
| `view` | `"day" \| "week"` | "day" | Controls whether navigation steps by a single day or by a full week. In `"week"` mode the label shows the Sunday–Saturday range that contains `selectedDate`. |
|
|
18
|
+
| `onLeftArrowClick` \* | `(currentDate: string) => void` | — | Called with the current `selectedDate` value when the left arrow is clicked. |
|
|
19
|
+
| `onRightArrowClick` \* | `(currentDate: string) => void` | — | Called with the current `selectedDate` value when the right arrow is clicked. |
|
|
20
|
+
| `onCalendarDateSelect` | `((currentDate: string) => void)` | — | Called with the chosen date string when the user selects a date from the calendar dropdown. When omitted the date label is non-interactive and the calendar dropdown is not shown. |
|
|
21
|
+
| `dropdownRootNode` | `RefObject<HTMLElement>` | document.body | The root element that contains the dropdown element. |
|
|
22
|
+
|
|
23
|
+
## Rules
|
|
24
|
+
|
|
25
|
+
- Only override `dropdownRootNode` if you need the dropdown to share a stacking context with a scroll container — may cause z-index issues.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Divider
|
|
2
|
+
|
|
3
|
+
Import: `import { Divider } from "@lifesg/react-design-system/divider"`
|
|
4
|
+
|
|
5
|
+
## Props — `DividerProps`
|
|
6
|
+
|
|
7
|
+
| Prop | Type | Default | Description |
|
|
8
|
+
| ------------ | ---------------------- | ---------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
9
|
+
| `thickness` | `number` | 1 | Thickness of the line in pixels. |
|
|
10
|
+
| `lineStyle` | `DividerLineStyleType` | "solid" | Visual style of the line. |
|
|
11
|
+
| `layoutType` | `DividerLayoutType` | "flex" | Controls how the divider is rendered relative to its parent layout. Use `"flex"` when the divider is a direct child of a flex container. Use `"grid"` to wrap the line in a `ColDiv`, enabling responsive column-span control via the `xxsCols`–`xxlCols` props. |
|
|
12
|
+
| `color` | `string` | Colour["border"] | Color of the line. Accepts a design-system colour token or any valid CSS color value. |
|
|
13
|
+
| `xxlCols` | `ColSpan` | — | Column span at the `xxl` breakpoint. |
|
|
14
|
+
| `xlCols` | `ColSpan` | — | Column span at the `xl` breakpoint. |
|
|
15
|
+
| `lgCols` | `ColSpan` | — | Column span at the `lg` breakpoint. |
|
|
16
|
+
| `mdCols` | `ColSpan` | — | Column span at the `md` breakpoint. |
|
|
17
|
+
| `smCols` | `ColSpan` | — | Column span at the `sm` breakpoint. |
|
|
18
|
+
| `xsCols` | `ColSpan` | — | Column span at the `xs` breakpoint. |
|
|
19
|
+
| `xxsCols` | `ColSpan` | — | Column span at the `xxs` (smallest) breakpoint. Acts as the base value. All larger breakpoints fall back to this when their own prop is not set. |
|
|
20
|
+
|
|
21
|
+
## Rules
|
|
22
|
+
|
|
23
|
+
- `mobileCols`, `tabletCols`, `desktopCols` follow the same semantics as `Layout.ColDiv` — see ColDiv docs for details.
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# Drawer
|
|
2
|
+
|
|
3
|
+
Import: `import { Drawer } from "@lifesg/react-design-system/drawer"`
|
|
4
|
+
|
|
5
|
+
## When to use
|
|
6
|
+
|
|
7
|
+
Use to show supplementary content or actions without navigating away from the current page — for example, filter panels or detail views.
|
|
8
|
+
|
|
9
|
+
Do not use for:
|
|
10
|
+
|
|
11
|
+
- Primary forms that require focused attention
|
|
12
|
+
- Flows that need the full viewport
|
|
13
|
+
|
|
14
|
+
## Usage
|
|
15
|
+
|
|
16
|
+
```tsx
|
|
17
|
+
import { useState } from "react";
|
|
18
|
+
import { Drawer } from "@lifesg/react-design-system/drawer";
|
|
19
|
+
import { Button } from "@lifesg/react-design-system/button";
|
|
20
|
+
import { Typography } from "@lifesg/react-design-system/typography";
|
|
21
|
+
|
|
22
|
+
const FilterDrawer = () => {
|
|
23
|
+
const [show, setShow] = useState(false);
|
|
24
|
+
|
|
25
|
+
const handleClose = () => setShow(false);
|
|
26
|
+
|
|
27
|
+
return (
|
|
28
|
+
<>
|
|
29
|
+
<Button onClick={() => setShow(true)}>Open filters</Button>
|
|
30
|
+
|
|
31
|
+
<Drawer
|
|
32
|
+
show={show}
|
|
33
|
+
heading="Filter options"
|
|
34
|
+
onClose={handleClose}
|
|
35
|
+
onOverlayClick={handleClose}
|
|
36
|
+
>
|
|
37
|
+
<div style={{ padding: "1.5rem" }}>
|
|
38
|
+
<Typography.HeadingMD style={{ marginBottom: "0.75rem" }}>
|
|
39
|
+
Category
|
|
40
|
+
</Typography.HeadingMD>
|
|
41
|
+
<Typography.BodyBL style={{ marginBottom: "2rem" }}>
|
|
42
|
+
Filter content goes here.
|
|
43
|
+
</Typography.BodyBL>
|
|
44
|
+
<Button styleType="secondary" onClick={handleClose}>
|
|
45
|
+
Close
|
|
46
|
+
</Button>
|
|
47
|
+
</div>
|
|
48
|
+
</Drawer>
|
|
49
|
+
</>
|
|
50
|
+
);
|
|
51
|
+
};
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Props
|
|
55
|
+
|
|
56
|
+
| Prop | Type | Default | Description |
|
|
57
|
+
| -------------------- | ----------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
58
|
+
| `children` | `React.ReactNode` | — | — |
|
|
59
|
+
| `className` | `string` | — | — |
|
|
60
|
+
| `id` | `string` | — | — |
|
|
61
|
+
| `heading` | `string` | — | Text rendered as the drawer title and used as the accessible label for the dialog. |
|
|
62
|
+
| `show` | `boolean` | — | Controls whether the drawer is visible. |
|
|
63
|
+
| `onClose` | `(() => void)` | — | Called when the user requests to close the drawer via the close button or the Escape key. |
|
|
64
|
+
| `onOverlayClick` | `(() => void)` | — | Called when the user clicks the background overlay. |
|
|
65
|
+
| `customCallToAction` | `React.ReactNode` | — | Optional element rendered in the header, e.g. a link or button. Sits beside the title on wider drawers, and wraps onto its own line below the title once the drawer is narrow. |
|
|
66
|
+
|
|
67
|
+
## Rules
|
|
68
|
+
|
|
69
|
+
- Always provide `onClose` so users can dismiss the panel via the close button.
|
|
70
|
+
- Provide `onOverlayClick` to allow dismissal by clicking outside the panel; set it to the same handler as `onClose` unless the overlay should not close the panel.
|
|
71
|
+
- Use `heading` to give the drawer a descriptive title for the user and for screen readers.
|
|
72
|
+
- The drawer slides in from the right edge of the viewport.
|
|
73
|
+
- Content scrolls independently within the panel when it exceeds the panel height.
|
|
74
|
+
|
|
75
|
+
## Anti-patterns
|
|
76
|
+
|
|
77
|
+
- Do not use the Drawer for full forms — use a dedicated page or ModalV2 instead.
|
|
78
|
+
- Do not omit `onClose` — users must have a way to dismiss the panel.
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# ErrorDisplay
|
|
2
|
+
|
|
3
|
+
Import: `import { ErrorDisplay } from "@lifesg/react-design-system/error-display"`
|
|
4
|
+
|
|
5
|
+
## When to use
|
|
6
|
+
|
|
7
|
+
Use for full-page or full-section states where the primary content cannot be shown — HTTP errors, empty results, session states, and system messages. It handles illustration, title, description, and action button as a unit.
|
|
8
|
+
|
|
9
|
+
Do not build custom error pages with raw Typography + Button — always use `ErrorDisplay` so illustrations and copy stay consistent across products.
|
|
10
|
+
|
|
11
|
+
## Variants
|
|
12
|
+
|
|
13
|
+
| `type` | When to use |
|
|
14
|
+
| ------------------------------- | ---------------------------------------------------------------- |
|
|
15
|
+
| `"no-item-found"` | Search or filter returned no results |
|
|
16
|
+
| `"404"` | Page not found |
|
|
17
|
+
| `"403"` | Access denied / permission error |
|
|
18
|
+
| `"500"` | Internal server error |
|
|
19
|
+
| `"400"` | Bad request |
|
|
20
|
+
| `"408"` | Request timeout |
|
|
21
|
+
| `"502"` | Bad gateway |
|
|
22
|
+
| `"503"` | Service unavailable |
|
|
23
|
+
| `"504"` | Gateway timeout |
|
|
24
|
+
| `"maintenance"` | Planned downtime — requires `additionalProps.dateString` |
|
|
25
|
+
| `"inactivity"` | Session timeout warning — requires `additionalProps.secondsLeft` |
|
|
26
|
+
| `"logout"` | User has been logged out |
|
|
27
|
+
| `"warning"` | General warning state |
|
|
28
|
+
| `"confirmation"` | Action confirmed (e.g. submission complete) |
|
|
29
|
+
| `"link-error"` | Broken or expired link |
|
|
30
|
+
| `"insufficient-credits"` | User lacks credits to proceed |
|
|
31
|
+
| `"payment-unsuccessful"` | Payment failed |
|
|
32
|
+
| `"transfer-unsuccessful"` | Transfer failed |
|
|
33
|
+
| `"unsupported-browser"` | Browser not supported |
|
|
34
|
+
| `"partially-supported-browser"` | Browser partially supported |
|
|
35
|
+
|
|
36
|
+
## Usage
|
|
37
|
+
|
|
38
|
+
```tsx
|
|
39
|
+
import { ErrorDisplay } from "@lifesg/react-design-system/error-display";
|
|
40
|
+
|
|
41
|
+
{
|
|
42
|
+
/* No search results */
|
|
43
|
+
}
|
|
44
|
+
<ErrorDisplay
|
|
45
|
+
type="no-item-found"
|
|
46
|
+
title="No results found"
|
|
47
|
+
description="Try adjusting your search or filters."
|
|
48
|
+
actionButton={{ children: "Clear filters", onClick: handleClear }}
|
|
49
|
+
/>;
|
|
50
|
+
|
|
51
|
+
{
|
|
52
|
+
/* Page not found */
|
|
53
|
+
}
|
|
54
|
+
<ErrorDisplay type="404" />;
|
|
55
|
+
|
|
56
|
+
{
|
|
57
|
+
/* Maintenance with scheduled date */
|
|
58
|
+
}
|
|
59
|
+
<ErrorDisplay
|
|
60
|
+
type="maintenance"
|
|
61
|
+
additionalProps={{ dateString: "1 Jan 2025, 8:00am to 10:00am" }}
|
|
62
|
+
/>;
|
|
63
|
+
|
|
64
|
+
{
|
|
65
|
+
/* Session inactivity warning */
|
|
66
|
+
}
|
|
67
|
+
<ErrorDisplay
|
|
68
|
+
type="inactivity"
|
|
69
|
+
additionalProps={{ secondsLeft: 60, reminderInterval: 30 }}
|
|
70
|
+
/>;
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## MaintenanceAdditionalAttributes
|
|
74
|
+
|
|
75
|
+
| Prop | Type | Default | Description |
|
|
76
|
+
| --------------- | -------- | ------- | -------------------------------------- |
|
|
77
|
+
| `dateString` \* | `string` | — | Date display for the maintenance error |
|
|
78
|
+
|
|
79
|
+
## InactivityAdditionalAttributes
|
|
80
|
+
|
|
81
|
+
| Prop | Type | Default | Description |
|
|
82
|
+
| ---------------- | -------- | ------- | ---------------------------------------------------- |
|
|
83
|
+
| `secondsLeft` \* | `number` | — | Time remaining in seconds for the inactivity display |
|
|
84
|
+
|
|
85
|
+
## Props — `MaintenanceAdditionalAttributes`
|
|
86
|
+
|
|
87
|
+
| Prop | Type | Default | Description |
|
|
88
|
+
| --------------- | -------- | ------- | ---------------------------------------------------------------- |
|
|
89
|
+
| `dateString` \* | `string` | — | Date string rendered inside the default maintenance description. |
|
|
90
|
+
|
|
91
|
+
## Props — `InactivityAdditionalAttributes`
|
|
92
|
+
|
|
93
|
+
| Prop | Type | Default | Description |
|
|
94
|
+
| ------------------ | -------- | ------- | --------------------------------------------------------------------------------- |
|
|
95
|
+
| `secondsLeft` \* | `number` | — | Remaining seconds before the session expires, used to render the countdown timer. |
|
|
96
|
+
| `reminderInterval` | `number` | — | Interval (in seconds) for announcing remaining time via screen readers. |
|
|
97
|
+
|
|
98
|
+
## Props — `ErrorDisplayAttributes`
|
|
99
|
+
|
|
100
|
+
| Prop | Type | Default | Description |
|
|
101
|
+
| -------------------- | ---------------------------------------------------------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
102
|
+
| `img` | `React.ImgHTMLAttributes<HTMLImageElement>` | — | Overrides the default illustration for the selected `type`. |
|
|
103
|
+
| `title` | `string \| JSX.Element` | — | Overrides the default title for the selected `type`. |
|
|
104
|
+
| `description` | `string \| JSX.Element` | — | Overrides the default description for the selected `type`. When `additionalProps` is also provided for `"maintenance"` or `"inactivity"` types, `additionalProps` takes precedence. |
|
|
105
|
+
| `actionButton` | `ButtonProps` | — | Action button rendered below the description. Defaults to a "Proceed" label when `children` is omitted. |
|
|
106
|
+
| `additionalProps` | `\| MaintenanceAdditionalAttributes \| InactivityAdditionalAttributes` | — | Type-specific attributes that inject dynamic content into the default description. |
|
|
107
|
+
| `imageOnly` | `boolean` | false | Renders only the illustration, hiding the title, description, and action button. |
|
|
108
|
+
| `illustrationScheme` | `ThemeType` | — | Selects the illustration resource scheme to use. |
|
|
109
|
+
|
|
110
|
+
## Props — `ErrorDisplayProps`
|
|
111
|
+
|
|
112
|
+
| Prop | Type | Default | Description |
|
|
113
|
+
| -------------------- | ---------------------------------------------------------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
114
|
+
| `type` \* | `ErrorDisplayType` | — | Determines the default illustration assets and copy to display. |
|
|
115
|
+
| `img` | `React.ImgHTMLAttributes<HTMLImageElement>` | — | Overrides the default illustration for the selected `type`. |
|
|
116
|
+
| `title` | `string \| JSX.Element` | — | Overrides the default title for the selected `type`. |
|
|
117
|
+
| `description` | `string \| JSX.Element` | — | Overrides the default description for the selected `type`. When `additionalProps` is also provided for `"maintenance"` or `"inactivity"` types, `additionalProps` takes precedence. |
|
|
118
|
+
| `actionButton` | `ButtonProps` | — | Action button rendered below the description. Defaults to a "Proceed" label when `children` is omitted. |
|
|
119
|
+
| `additionalProps` | `\| MaintenanceAdditionalAttributes \| InactivityAdditionalAttributes` | — | Type-specific attributes that inject dynamic content into the default description. |
|
|
120
|
+
| `imageOnly` | `boolean` | false | Renders only the illustration, hiding the title, description, and action button. |
|
|
121
|
+
| `illustrationScheme` | `ThemeType` | — | Selects the illustration resource scheme to use. |
|
|
122
|
+
|
|
123
|
+
## Rules
|
|
124
|
+
|
|
125
|
+
- Always use `ErrorDisplay` for error/empty states — never build custom error pages with raw components.
|
|
126
|
+
- `type` is required — it determines the default illustration, title, and description.
|
|
127
|
+
- Override `title` and `description` only when the defaults don't fit your context.
|
|
128
|
+
- `actionButton` accepts standard `ButtonProps` — label and `onClick` are the common fields.
|
|
129
|
+
- `"maintenance"` requires `additionalProps.dateString` to render the scheduled date in the description.
|
|
130
|
+
- `"inactivity"` requires `additionalProps.secondsLeft` for the countdown display.
|
|
131
|
+
- For listing pages use `type="no-item-found"` — it has the correct "empty results" illustration.
|
|
132
|
+
|
|
133
|
+
## Anti-patterns
|
|
134
|
+
|
|
135
|
+
- Do not use `imageOnly` unless rendering inside a constrained space where text would overflow.
|
|
136
|
+
- Do not hardcode error page titles/descriptions that duplicate what `ErrorDisplay` already provides by default.
|
|
137
|
+
- Do not use `type="warning"` as a generic placeholder — it implies a system-level warning, not a validation message (use `Alert` for that).
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# FeedbackRating
|
|
2
|
+
|
|
3
|
+
Import: `import { FeedbackRating } from "@lifesg/react-design-system/feedback-rating"`
|
|
4
|
+
|
|
5
|
+
## When to use
|
|
6
|
+
|
|
7
|
+
Use at the end of a flow or session to collect a star rating and an optional submission action from the user.
|
|
8
|
+
|
|
9
|
+
## Usage
|
|
10
|
+
|
|
11
|
+
### Complete controlled pattern
|
|
12
|
+
|
|
13
|
+
```tsx
|
|
14
|
+
import { useState } from "react";
|
|
15
|
+
import { FeedbackRating } from "@lifesg/react-design-system/feedback-rating";
|
|
16
|
+
|
|
17
|
+
const RatingWidget = () => {
|
|
18
|
+
// Track rating separately — onSubmit does NOT receive it
|
|
19
|
+
const [rating, setRating] = useState(0);
|
|
20
|
+
|
|
21
|
+
const handleSubmit = () => {
|
|
22
|
+
// Read from state, not from onSubmit arguments (there are none)
|
|
23
|
+
submitFeedback({ stars: rating });
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
return (
|
|
27
|
+
<FeedbackRating
|
|
28
|
+
rating={rating}
|
|
29
|
+
onRatingChange={(value) => setRating(value)}
|
|
30
|
+
onSubmit={handleSubmit}
|
|
31
|
+
description="How was your experience?"
|
|
32
|
+
buttonLabel="Send feedback"
|
|
33
|
+
/>
|
|
34
|
+
);
|
|
35
|
+
};
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
**Key gotcha:** `onSubmit` has the signature `() => void` — it carries no payload. The rating value is only available through the `rating` state you control via `onRatingChange`.
|
|
39
|
+
|
|
40
|
+
## Props
|
|
41
|
+
|
|
42
|
+
| Prop | Type | Default | Description |
|
|
43
|
+
| ------------------- | ------------------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
44
|
+
| `imgSrc` | `string` | — | URL of the banner image displayed above the star rating. Falls back to the default Life SG feedback banner when omitted. Hidden automatically if the image fails to load. |
|
|
45
|
+
| `description` | `string` | "Rate your experience" | Heading text displayed above the star rating. |
|
|
46
|
+
| `buttonLabel` | `string` | "Submit" | Label for the submit button. |
|
|
47
|
+
| `className` | `string` | — | — |
|
|
48
|
+
| `id` | `string` | — | — |
|
|
49
|
+
| `rating` \* | `number` | — | The currently selected star rating (1–5). |
|
|
50
|
+
| `onRatingChange` \* | `(value: number) => void` | — | Called when the user selects a star. |
|
|
51
|
+
| `onSubmit` \* | `() => void` | — | Called when the user clicks the submit button. |
|
|
52
|
+
|
|
53
|
+
## Rules
|
|
54
|
+
|
|
55
|
+
- All three props — `rating`, `onRatingChange`, `onSubmit` — are required.
|
|
56
|
+
- `onSubmit` does **not** receive the rating value. Track the rating separately via `onRatingChange` state and read it inside `onSubmit`.
|
|
57
|
+
- `rating` must be controlled state; the component does not manage selection internally.
|
|
58
|
+
|
|
59
|
+
## Anti-patterns
|
|
60
|
+
|
|
61
|
+
- Do not try to read the rating from inside `onSubmit`'s arguments — it receives none. Always use the state value set by `onRatingChange`.
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# FileDownload
|
|
2
|
+
|
|
3
|
+
Import: `import { FileDownload } from "@lifesg/react-design-system/file-download"`
|
|
4
|
+
|
|
5
|
+
## Sub-components
|
|
6
|
+
|
|
7
|
+
- `FileItemProps` — shape of each item in `fileItems`
|
|
8
|
+
|
|
9
|
+
## FileItemProps
|
|
10
|
+
|
|
11
|
+
| Prop | Type | Default | Description |
|
|
12
|
+
| ----------------------- | --------------------------- | ------- | --------------------------------------------- |
|
|
13
|
+
| `id` \* | `string` | — | The unique identifier of the file |
|
|
14
|
+
| `name` \* | `string` | — | The name of the file |
|
|
15
|
+
| `mimeType` \* | `string` | — | The MIME type of the file |
|
|
16
|
+
| `filePath` \* | `string` | — | The remote path of the file |
|
|
17
|
+
| `size` | `number` | — | The size of the file in bytes |
|
|
18
|
+
| `errorMessage` | `string \| React.ReactNode` | — | Custom error message when file download fails |
|
|
19
|
+
| `thumbnailImageDataUrl` | `string` | — | The thumbnail of the file |
|
|
20
|
+
| `truncateText` | `boolean` | `true` | Indicates if text should be truncated |
|
|
21
|
+
| `ready` | `boolean` | `true` | Indicates if the file is ready for download |
|
|
22
|
+
|
|
23
|
+
## Props — `FileItemDownloadProps`
|
|
24
|
+
|
|
25
|
+
| Prop | Type | Default | Description |
|
|
26
|
+
| ----------------------- | --------------------------- | ------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
|
|
27
|
+
| `id` \* | `string` | — | — |
|
|
28
|
+
| `name` \* | `string` | — | The display name of the file. |
|
|
29
|
+
| `mimeType` \* | `string` | — | The MIME type of the file (e.g. `"application/pdf"`). |
|
|
30
|
+
| `size` | `number` | — | The size of the file in bytes. Displayed as formatted text when provided. |
|
|
31
|
+
| `filePath` \* | `string` | — | The remote path or URL used to fetch the file for download. |
|
|
32
|
+
| `errorMessage` | `string \| React.ReactNode` | — | Error message shown on the file item to indicate a download failure. Accepts a plain string or a React node for richer error display. |
|
|
33
|
+
| `thumbnailImageDataUrl` | `string` | — | URL or data URL for a thumbnail image shown alongside the file entry. |
|
|
34
|
+
| `truncateText` | `boolean` | true | Truncates long file names with an ellipsis when `true`. |
|
|
35
|
+
| `ready` | `boolean` | true | Indicates the file is available and ready to be downloaded. |
|
|
36
|
+
| `clickLabel` | `string` | the file name | Name for the card, used when `FileDownload` is given an `onClick`. |
|
|
37
|
+
|
|
38
|
+
## Props — `FileDownloadProps`
|
|
39
|
+
|
|
40
|
+
| Prop | Type | Default | Description |
|
|
41
|
+
| --------------- | -------------------------------------------------------- | ---------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
42
|
+
| `title` | `string \| JSX.Element` | — | Optional heading rendered above the file list. Accepts a plain string or a JSX element for rich content. |
|
|
43
|
+
| `description` | `string \| JSX.Element` | — | Optional text rendered beneath the title. Accepts a plain string or a JSX element for rich content. |
|
|
44
|
+
| `fileItems` \* | `FileItemDownloadProps[]` | — | The list of file items to display. When empty, no file cards are rendered. |
|
|
45
|
+
| `styleType` | `FileDownloadStyle` | "bordered" | Controls whether the component is wrapped in a dashed border. |
|
|
46
|
+
| `className` | `string` | — | — |
|
|
47
|
+
| `id` | `string` | — | — |
|
|
48
|
+
| `onDownload` \* | `(file: FileItemDownloadProps) => void \| Promise<void>` | — | Called when the user triggers a download for an individual file item. May return a `Promise` to handle async download logic; the component awaits resolution. If the callback throws or the promise rejects, the item is marked as failed and the error UI is shown for that file card. |
|
|
49
|
+
| `onClick` | `((file: FileItemDownloadProps) => void)` | — | Called when a file card itself is activated, as opposed to its download button. When omitted, activating the card triggers `onDownload` instead. |
|
|
50
|
+
|
|
51
|
+
## Rules
|
|
52
|
+
|
|
53
|
+
- `fileItems` and `onDownload` are required.
|
|
54
|
+
- On `FileItemProps`: `id`, `name`, `mimeType`, and `filePath` are required.
|