@lifesg/react-design-system 4.0.0-alpha.6 → 4.0.0-alpha.7
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/accordion/accordion.js.map +1 -1
- package/alert/alert.js.map +1 -1
- package/alert/types.d.ts +2 -0
- package/animations/loading-dots/loading-dots.d.ts +5 -2
- package/animations/loading-dots/loading-dots.js.map +1 -1
- package/animations/loading-dots-spinner/loading-dots-spinner.d.ts +3 -0
- package/animations/loading-dots-spinner/loading-dots-spinner.js.map +1 -1
- package/animations/loading-dots-spinner/lottie-animation.d.ts +2 -2
- package/animations/loading-dots-spinner/lottie-animation.js.map +1 -1
- package/animations/loading-spinner/loading-spinner.d.ts +5 -2
- package/animations/loading-spinner/loading-spinner.js.map +1 -1
- package/animations/themed-loading-spinner/themed-loading-spinner.d.ts +5 -2
- package/animations/themed-loading-spinner/themed-loading-spinner.js.map +1 -1
- package/animations/types.d.ts +13 -6
- package/avatar/avatar.js.map +1 -1
- package/badge/badge.js.map +1 -1
- package/badge/types.d.ts +13 -2
- package/box-container/box-container.js.map +1 -1
- package/box-container/types.d.ts +2 -0
- package/breadcrumb/breadcrumb.js.map +1 -1
- package/breadcrumb/types.d.ts +7 -2
- package/button/button.js.map +1 -1
- package/button/types.d.ts +5 -0
- package/calendar/calendar.js.map +1 -1
- package/calendar/types.d.ts +3 -3
- package/card/card.js.map +1 -1
- package/checkbox/checkbox.js.map +1 -1
- package/checkbox/types.d.ts +4 -0
- package/cjs/accordion/accordion.js.map +1 -1
- package/cjs/alert/alert.js.map +1 -1
- package/cjs/animations/loading-dots/loading-dots.js.map +1 -1
- package/cjs/animations/loading-dots-spinner/loading-dots-spinner.js.map +1 -1
- package/cjs/animations/loading-dots-spinner/lottie-animation.js.map +1 -1
- package/cjs/animations/loading-spinner/loading-spinner.js.map +1 -1
- package/cjs/animations/themed-loading-spinner/themed-loading-spinner.js.map +1 -1
- package/cjs/avatar/avatar.js.map +1 -1
- package/cjs/badge/badge.js.map +1 -1
- package/cjs/box-container/box-container.js.map +1 -1
- package/cjs/breadcrumb/breadcrumb.js.map +1 -1
- package/cjs/button/button.js.map +1 -1
- package/cjs/calendar/calendar.js.map +1 -1
- package/cjs/card/card.js.map +1 -1
- package/cjs/checkbox/checkbox.js.map +1 -1
- package/cjs/countdown-timer/countdown-timer.js.map +1 -1
- package/cjs/dashed-border/dashed-border.js.map +1 -1
- package/cjs/data-table/data-table.js.map +1 -1
- package/cjs/date-input/date-input.js.map +1 -1
- package/cjs/date-navigator/date-navigator.js.map +1 -1
- package/cjs/date-range-input/date-range-input.js.map +1 -1
- package/cjs/divider/divider.js.map +1 -1
- package/cjs/drawer/drawer.js.map +1 -1
- package/cjs/e-signature/e-signature.js.map +1 -1
- package/cjs/error-display/error-display.js.map +1 -1
- package/cjs/feedback-rating/feedback-rating.js.map +1 -1
- package/cjs/file-download/file-download.js.map +1 -1
- package/cjs/file-upload/file-item-edit.js.map +1 -1
- package/cjs/file-upload/file-list/file-list.js.map +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_o8000f.css → file-list-item.styles_kgtfke.css} +1 -1
- package/cjs/file-upload/file-upload.js.map +1 -1
- package/cjs/filter/addons/filter-item-checkbox-helpers.js.map +1 -1
- package/cjs/filter/addons/filter-item-checkbox.js.map +1 -1
- package/cjs/filter/filter-item.js +1 -1
- package/cjs/filter/filter-item.js.map +1 -1
- package/cjs/filter/filter.js.map +1 -1
- package/cjs/footer/footer.js.map +1 -1
- package/cjs/form/form-custom-field/form-custom-field.js +2 -0
- package/cjs/form/form-custom-field/form-custom-field.js.map +1 -0
- package/cjs/form/form-date-input/form-date-input.js +2 -0
- package/cjs/form/form-date-input/form-date-input.js.map +1 -0
- package/cjs/form/form-date-range-input/form-date-range-input.js +2 -0
- package/cjs/form/form-date-range-input/form-date-range-input.js.map +1 -0
- package/cjs/form/form-e-signature/form-e-signature.js +2 -0
- package/cjs/form/form-e-signature/form-e-signature.js.map +1 -0
- package/cjs/form/form-histogram-slider/form-histogram-slider.js +2 -0
- package/cjs/form/form-histogram-slider/form-histogram-slider.js.map +1 -0
- package/cjs/form/form-input/form-input.js +2 -0
- package/cjs/form/form-input/form-input.js.map +1 -0
- package/cjs/form/form-input-group/form-input-group.js +2 -0
- package/cjs/form/form-input-group/form-input-group.js.map +1 -0
- package/cjs/form/form-label/form-label-addon.js +2 -0
- package/cjs/form/form-label/form-label-addon.js.map +1 -0
- package/cjs/form/form-label/form-label-addon.styles.js +2 -0
- package/cjs/form/form-label/form-label-addon.styles.js.map +1 -0
- package/cjs/form/form-label/form-label-addon.styles_aztasj.css +1 -0
- package/cjs/form/form-label/form-label.js +2 -0
- package/cjs/form/form-label/form-label.js.map +1 -0
- package/cjs/form/form-label/form-label.styles.js +2 -0
- package/cjs/form/form-label/form-label.styles.js.map +1 -0
- package/cjs/form/form-label/form-label.styles_180zf7j.css +6 -0
- package/cjs/form/form-masked-input/form-masked-input.js +2 -0
- package/cjs/form/form-masked-input/form-masked-input.js.map +1 -0
- package/cjs/form/form-multi-select/form-multi-select.js +2 -0
- package/cjs/form/form-multi-select/form-multi-select.js.map +1 -0
- package/cjs/form/form-nested-multi-select/form-nested-multi-select.js +2 -0
- package/cjs/form/form-nested-multi-select/form-nested-multi-select.js.map +1 -0
- package/cjs/form/form-nested-select/form-nested-select.js +2 -0
- package/cjs/form/form-nested-select/form-nested-select.js.map +1 -0
- package/cjs/form/form-otp-verification/form-otp-verification.js +2 -0
- package/cjs/form/form-otp-verification/form-otp-verification.js.map +1 -0
- package/cjs/form/form-phone-number-input/form-phone-number-input.js +2 -0
- package/cjs/form/form-phone-number-input/form-phone-number-input.js.map +1 -0
- package/cjs/form/form-predictive-text-input/form-predictive-text-input.js +2 -0
- package/cjs/form/form-predictive-text-input/form-predictive-text-input.js.map +1 -0
- package/cjs/form/form-range-select/form-range-select.js +2 -0
- package/cjs/form/form-range-select/form-range-select.js.map +1 -0
- package/cjs/form/form-range-slider/form-range-slider.js +2 -0
- package/cjs/form/form-range-slider/form-range-slider.js.map +1 -0
- package/cjs/form/form-select/form-select.js +2 -0
- package/cjs/form/form-select/form-select.js.map +1 -0
- package/cjs/form/form-select-histogram/form-select-histogram.js +2 -0
- package/cjs/form/form-select-histogram/form-select-histogram.js.map +1 -0
- package/cjs/form/form-slider/form-slider.js +2 -0
- package/cjs/form/form-slider/form-slider.js.map +1 -0
- package/cjs/form/form-textarea/form-textarea.js +2 -0
- package/cjs/form/form-textarea/form-textarea.js.map +1 -0
- package/cjs/form/form-textarea/form-textarea.styles.js +2 -0
- package/cjs/form/form-textarea/form-textarea.styles.js.map +1 -0
- package/cjs/form/form-textarea/form-textarea.styles_1kneyif.css +3 -0
- package/cjs/form/form-time-range-picker/form-time-range-picker.js +2 -0
- package/cjs/form/form-time-range-picker/form-time-range-picker.js.map +1 -0
- package/cjs/form/form-timepicker/form-timepicker.js +2 -0
- package/cjs/form/form-timepicker/form-timepicker.js.map +1 -0
- package/cjs/form/form-unit-number-input/form-unit-number-input.js +2 -0
- package/cjs/form/form-unit-number-input/form-unit-number-input.js.map +1 -0
- package/cjs/form/form-wrapper.js +1 -1
- package/cjs/form/form-wrapper.js.map +1 -1
- package/cjs/form/index.js +1 -1
- package/cjs/form/index.js.map +1 -1
- package/cjs/fullscreen-image-carousel/fullscreen-image-carousel.js.map +1 -1
- package/cjs/histogram-slider/histogram-slider.js.map +1 -1
- package/cjs/image-button/image-button.js.map +1 -1
- package/cjs/input/input.js.map +1 -1
- package/cjs/input-group/input-group.js.map +1 -1
- package/cjs/input-multi-select/input-multi-select.js.map +1 -1
- package/cjs/input-nested-multi-select/input-nested-multi-select.js.map +1 -1
- package/cjs/input-nested-select/input-nested-select.js.map +1 -1
- package/cjs/input-range-select/input-range-select.js.map +1 -1
- package/cjs/input-range-slider/input-range-slider.js.map +1 -1
- package/cjs/input-select/input-select.js.map +1 -1
- package/cjs/input-slider/input-slider.js.map +1 -1
- package/cjs/input-textarea/textarea.js.map +1 -1
- package/cjs/input-textarea/textarea.styles.js +1 -1
- package/cjs/input-textarea/textarea.styles.js.map +1 -1
- package/cjs/input-textarea/{textarea.styles_22z4n3.css → textarea.styles_q77m5x.css} +1 -1
- package/cjs/language-switcher/language-switcher.js.map +1 -1
- package/cjs/layout/index.js.map +1 -1
- package/cjs/link-list/components/common.js.map +1 -1
- package/cjs/link-list/components/link-list-eager.js.map +1 -1
- package/cjs/link-list/components/link-list-lazy.js.map +1 -1
- package/cjs/link-list/link-list.js.map +1 -1
- package/cjs/local-nav/local-nav-dropdown/local-nav-dropdown.js.map +1 -1
- package/cjs/local-nav/local-nav-menu/local-nav-menu.js.map +1 -1
- package/cjs/markup/markup.js.map +1 -1
- package/cjs/masked-input/masked-input.js.map +1 -1
- package/cjs/masthead/masthead.js.map +1 -1
- package/cjs/menu/menu.js.map +1 -1
- package/cjs/modal/index.js.map +1 -1
- package/cjs/modal-v2/modal-v2.js.map +1 -1
- package/cjs/navbar/navbar.js.map +1 -1
- package/cjs/notification-banner/notification-banner.js.map +1 -1
- package/cjs/otp-input/otp-input.js +1 -1
- package/cjs/otp-input/otp-input.js.map +1 -1
- package/cjs/otp-verification/contact-input-section.js +1 -1
- package/cjs/otp-verification/contact-input-section.js.map +1 -1
- package/cjs/otp-verification/otp-verification.js.map +1 -1
- package/cjs/otp-verification/verification-section.js +1 -1
- package/cjs/otp-verification/verification-section.js.map +1 -1
- package/cjs/overlay/overlay.js.map +1 -1
- package/cjs/pagination/pagination.js.map +1 -1
- package/cjs/phone-number-input/phone-number-input.js.map +1 -1
- package/cjs/pill/pill.js.map +1 -1
- package/cjs/popover/popover-inline/popover-inline.js.map +1 -1
- package/cjs/popover/popover.js.map +1 -1
- package/cjs/predictive-text-input/predictive-text-input.js +1 -1
- package/cjs/predictive-text-input/predictive-text-input.js.map +1 -1
- package/cjs/progress-indicator/progress-indicator.js.map +1 -1
- package/cjs/radio-button/radio-button.js.map +1 -1
- package/cjs/schedule/schedule.js.map +1 -1
- package/cjs/select-histogram/select-histogram.js.map +1 -1
- package/cjs/shared/dropdown-list/dropdown-list.js +1 -1
- package/cjs/shared/dropdown-list/dropdown-list.js.map +1 -1
- package/cjs/shared/dropdown-wrapper/element-with-dropdown.js +1 -1
- package/cjs/shared/dropdown-wrapper/element-with-dropdown.js.map +1 -1
- package/cjs/sidenav/sidenav.js.map +1 -1
- package/cjs/singpass-button/singpass-button.js.map +1 -1
- package/cjs/smart-app-banner/smart-app-banner.js.map +1 -1
- package/cjs/tab/tab.js.map +1 -1
- package/cjs/table/table.js.map +1 -1
- package/cjs/tag/tag.js.map +1 -1
- package/cjs/text-list/index.js.map +1 -1
- package/cjs/theme/theme-provider/hooks.js.map +1 -1
- package/cjs/theme/theme-provider/index.js.map +1 -1
- package/cjs/theme/tokens/border.js.map +1 -1
- package/cjs/theme/tokens/breakpoint.js.map +1 -1
- package/cjs/theme/tokens/colour.js.map +1 -1
- package/cjs/theme/tokens/component.js.map +1 -1
- package/cjs/theme/tokens/font.js.map +1 -1
- package/cjs/theme/tokens/media-query.js.map +1 -1
- package/cjs/theme/tokens/motion.js.map +1 -1
- package/cjs/theme/tokens/radius.js.map +1 -1
- package/cjs/theme/tokens/shadow.js.map +1 -1
- package/cjs/theme/tokens/spacing.js.map +1 -1
- package/cjs/theme/utils/use-apply-styles.js.map +1 -1
- package/cjs/theme/utils/use-design-token.js.map +1 -1
- package/cjs/theme/utils/use-media-query.js.map +1 -1
- package/cjs/time-range-picker/combobox-picker/combobox-picker.js +1 -1
- package/cjs/time-range-picker/combobox-picker/combobox-picker.js.map +1 -1
- package/cjs/time-range-picker/time-range-picker.js.map +1 -1
- package/cjs/time-slot-bar/time-slot-bar.js.map +1 -1
- package/cjs/time-slot-bar-week/time-slot-bar-week.js.map +1 -1
- package/cjs/time-slot-week-view/time-slot-week-view.js.map +1 -1
- package/cjs/timeline/timeline.js.map +1 -1
- package/cjs/timepicker/timepicker.js.map +1 -1
- package/cjs/timetable/timetable.js.map +1 -1
- package/cjs/toast/toast.js.map +1 -1
- package/cjs/toggle/toggle.js.map +1 -1
- package/cjs/typography/index.js.map +1 -1
- package/cjs/uneditable-section/index.js.map +1 -1
- package/cjs/uneditable-section/section-item.js +1 -1
- package/cjs/uneditable-section/section-item.js.map +1 -1
- package/cjs/unit-number/unit-number-input.js.map +1 -1
- package/countdown-timer/countdown-timer.js.map +1 -1
- package/countdown-timer/types.d.ts +3 -3
- package/dashed-border/dashed-border.js.map +1 -1
- package/data-table/data-table.js.map +1 -1
- package/date-input/date-input.js.map +1 -1
- package/date-input/types.d.ts +1 -1
- package/date-navigator/date-navigator.js.map +1 -1
- package/date-navigator/types.d.ts +1 -1
- package/date-range-input/date-range-input.js.map +1 -1
- package/date-range-input/types.d.ts +1 -1
- package/divider/divider.js.map +1 -1
- package/divider/types.d.ts +1 -1
- package/docs/component-catalog.json +644 -0
- package/drawer/drawer.js.map +1 -1
- package/e-signature/e-signature.js.map +1 -1
- package/error-display/error-display.js.map +1 -1
- package/feedback-rating/feedback-rating.js.map +1 -1
- package/file-download/file-download.js.map +1 -1
- package/file-download/types.d.ts +6 -1
- package/file-upload/file-item-edit.d.ts +1 -1
- package/file-upload/file-item-edit.js.map +1 -1
- package/file-upload/file-list/file-list.d.ts +1 -1
- package/file-upload/file-list/file-list.js.map +1 -1
- package/file-upload/file-list-item/file-list-item.d.ts +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.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_o8000f.css → file-list-item.styles_kgtfke.css} +1 -1
- package/file-upload/file-upload.js.map +1 -1
- package/file-upload/types.d.ts +6 -2
- package/filter/addons/filter-item-checkbox-helpers.d.ts +2 -2
- package/filter/addons/filter-item-checkbox-helpers.js.map +1 -1
- package/filter/addons/filter-item-checkbox.d.ts +1 -1
- package/filter/addons/filter-item-checkbox.js.map +1 -1
- package/filter/addons/internal-types.d.ts +12 -0
- package/filter/addons/types.d.ts +60 -9
- package/filter/filter-item.js +1 -1
- package/filter/filter-item.js.map +1 -1
- package/filter/filter.d.ts +1 -1
- package/filter/filter.js.map +1 -1
- package/filter/index.d.ts +1 -0
- package/filter/types.d.ts +31 -63
- package/footer/footer.js.map +1 -1
- package/form/form-custom-field/form-custom-field.js +2 -0
- package/form/form-custom-field/form-custom-field.js.map +1 -0
- package/form/form-custom-field/index.d.ts +2 -0
- package/form/form-custom-field/types.d.ts +7 -0
- package/form/form-date-input/form-date-input.js +2 -0
- package/form/form-date-input/form-date-input.js.map +1 -0
- package/form/form-date-input/index.d.ts +2 -0
- package/form/form-date-input/types.d.ts +8 -0
- package/form/form-date-range-input/form-date-range-input.js +2 -0
- package/form/form-date-range-input/form-date-range-input.js.map +1 -0
- package/form/form-date-range-input/index.d.ts +2 -0
- package/form/form-date-range-input/types.d.ts +8 -0
- package/form/form-e-signature/form-e-signature.js +2 -0
- package/form/form-e-signature/form-e-signature.js.map +1 -0
- package/form/form-e-signature/index.d.ts +2 -0
- package/form/form-e-signature/types.d.ts +8 -0
- package/form/form-histogram-slider/form-histogram-slider.js +2 -0
- package/form/form-histogram-slider/form-histogram-slider.js.map +1 -0
- package/form/form-histogram-slider/index.d.ts +2 -0
- package/form/form-histogram-slider/types.d.ts +8 -0
- package/form/form-input/form-input.js +2 -0
- package/form/form-input/form-input.js.map +1 -0
- package/form/form-input/index.d.ts +2 -0
- package/form/form-input/types.d.ts +8 -0
- package/form/form-input-group/form-input-group.js +2 -0
- package/form/form-input-group/form-input-group.js.map +1 -0
- package/form/form-input-group/index.d.ts +2 -0
- package/form/form-input-group/types.d.ts +10 -0
- package/form/form-label/form-label-addon.js +2 -0
- package/form/form-label/form-label-addon.js.map +1 -0
- package/form/form-label/form-label-addon.styles.js +2 -0
- package/form/form-label/form-label-addon.styles.js.map +1 -0
- package/form/form-label/form-label-addon.styles_aztasj.css +1 -0
- package/form/form-label/form-label.js +2 -0
- package/form/form-label/form-label.js.map +1 -0
- package/form/form-label/form-label.styles.js +2 -0
- package/form/form-label/form-label.styles.js.map +1 -0
- package/form/form-label/form-label.styles_180zf7j.css +6 -0
- package/form/form-label/index.d.ts +2 -0
- package/form/form-label/types.d.ts +39 -0
- package/form/form-masked-input/form-masked-input.js +2 -0
- package/form/form-masked-input/form-masked-input.js.map +1 -0
- package/form/form-masked-input/index.d.ts +2 -0
- package/form/form-masked-input/types.d.ts +8 -0
- package/form/form-multi-select/form-multi-select.js +2 -0
- package/form/form-multi-select/form-multi-select.js.map +1 -0
- package/form/form-multi-select/index.d.ts +2 -0
- package/form/form-multi-select/types.d.ts +10 -0
- package/form/form-nested-multi-select/form-nested-multi-select.js +2 -0
- package/form/form-nested-multi-select/form-nested-multi-select.js.map +1 -0
- package/form/form-nested-multi-select/index.d.ts +2 -0
- package/form/form-nested-multi-select/types.d.ts +11 -0
- package/form/form-nested-select/form-nested-select.js +2 -0
- package/form/form-nested-select/form-nested-select.js.map +1 -0
- package/form/form-nested-select/index.d.ts +2 -0
- package/form/form-nested-select/types.d.ts +11 -0
- package/form/{form-otp-verification.d.ts → form-otp-verification/form-otp-verification.d.ts} +1 -1
- package/form/form-otp-verification/form-otp-verification.js +2 -0
- package/form/form-otp-verification/form-otp-verification.js.map +1 -0
- package/form/form-otp-verification/index.d.ts +2 -0
- package/form/form-otp-verification/types.d.ts +1 -0
- package/form/form-phone-number-input/form-phone-number-input.js +2 -0
- package/form/form-phone-number-input/form-phone-number-input.js.map +1 -0
- package/form/form-phone-number-input/index.d.ts +2 -0
- package/form/form-phone-number-input/types.d.ts +8 -0
- package/form/form-predictive-text-input/form-predictive-text-input.js +2 -0
- package/form/form-predictive-text-input/form-predictive-text-input.js.map +1 -0
- package/form/form-predictive-text-input/index.d.ts +2 -0
- package/form/form-predictive-text-input/types.d.ts +10 -0
- package/form/form-range-select/form-range-select.js +2 -0
- package/form/form-range-select/form-range-select.js.map +1 -0
- package/form/form-range-select/index.d.ts +2 -0
- package/form/form-range-select/types.d.ts +10 -0
- package/form/form-range-slider/form-range-slider.js +2 -0
- package/form/form-range-slider/form-range-slider.js.map +1 -0
- package/form/form-range-slider/index.d.ts +2 -0
- package/form/form-range-slider/types.d.ts +8 -0
- package/form/form-select/form-select.js +2 -0
- package/form/form-select/form-select.js.map +1 -0
- package/form/form-select/index.d.ts +2 -0
- package/form/form-select/types.d.ts +10 -0
- package/form/form-select-histogram/form-select-histogram.js +2 -0
- package/form/form-select-histogram/form-select-histogram.js.map +1 -0
- package/form/form-select-histogram/index.d.ts +2 -0
- package/form/form-select-histogram/types.d.ts +8 -0
- package/form/form-slider/form-slider.js +2 -0
- package/form/form-slider/form-slider.js.map +1 -0
- package/form/form-slider/index.d.ts +2 -0
- package/form/form-slider/types.d.ts +8 -0
- package/form/form-textarea/form-textarea.js +2 -0
- package/form/form-textarea/form-textarea.js.map +1 -0
- package/form/form-textarea/form-textarea.styles.js +2 -0
- package/form/form-textarea/form-textarea.styles.js.map +1 -0
- package/form/form-textarea/form-textarea.styles_1kneyif.css +3 -0
- package/form/form-textarea/index.d.ts +2 -0
- package/form/form-textarea/types.d.ts +8 -0
- package/form/form-time-range-picker/form-time-range-picker.js +2 -0
- package/form/form-time-range-picker/form-time-range-picker.js.map +1 -0
- package/form/form-time-range-picker/index.d.ts +2 -0
- package/form/form-time-range-picker/types.d.ts +8 -0
- package/form/form-timepicker/form-timepicker.js +2 -0
- package/form/form-timepicker/form-timepicker.js.map +1 -0
- package/form/form-timepicker/index.d.ts +2 -0
- package/form/form-timepicker/types.d.ts +8 -0
- package/form/form-unit-number-input/form-unit-number-input.js +2 -0
- package/form/form-unit-number-input/form-unit-number-input.js.map +1 -0
- package/form/form-unit-number-input/index.d.ts +2 -0
- package/form/form-unit-number-input/types.d.ts +8 -0
- package/form/form-wrapper.js +1 -1
- package/form/form-wrapper.js.map +1 -1
- package/form/index.d.ts +47 -24
- package/form/index.js +1 -1
- package/form/index.js.map +1 -1
- package/form/types.d.ts +1 -208
- package/fullscreen-image-carousel/fullscreen-image-carousel.js.map +1 -1
- package/histogram-slider/histogram-slider.js.map +1 -1
- package/image-button/image-button.js.map +1 -1
- package/input/input.js.map +1 -1
- package/input-group/input-group.js.map +1 -1
- package/input-group/types.d.ts +1 -1
- package/input-multi-select/input-multi-select.js.map +1 -1
- package/input-multi-select/types.d.ts +1 -1
- package/input-nested-multi-select/input-nested-multi-select.js.map +1 -1
- package/input-nested-select/input-nested-select.js.map +1 -1
- package/input-nested-select/types.d.ts +1 -1
- package/input-range-select/input-range-select.js.map +1 -1
- package/input-range-select/types.d.ts +1 -1
- package/input-range-slider/input-range-slider.js.map +1 -1
- package/input-select/input-select.js.map +1 -1
- package/input-select/types.d.ts +1 -1
- package/input-slider/input-slider.js.map +1 -1
- package/input-slider/types.d.ts +1 -1
- package/input-textarea/textarea.js.map +1 -1
- package/input-textarea/textarea.styles.js +1 -1
- package/input-textarea/textarea.styles.js.map +1 -1
- package/input-textarea/{textarea.styles_22z4n3.css → textarea.styles_q77m5x.css} +1 -1
- package/language-switcher/language-switcher.js.map +1 -1
- package/layout/index.js.map +1 -1
- package/link-list/components/common.d.ts +1 -1
- package/link-list/components/common.js.map +1 -1
- package/link-list/components/link-list-eager.d.ts +2 -2
- package/link-list/components/link-list-eager.js.map +1 -1
- package/link-list/components/link-list-lazy.d.ts +2 -2
- package/link-list/components/link-list-lazy.js.map +1 -1
- package/link-list/link-list.js.map +1 -1
- package/link-list/types.d.ts +89 -3
- package/local-nav/local-nav-dropdown/local-nav-dropdown.js.map +1 -1
- package/local-nav/local-nav-menu/local-nav-menu.js.map +1 -1
- package/markup/markup.js.map +1 -1
- package/masked-input/masked-input.js.map +1 -1
- package/masthead/masthead.js.map +1 -1
- package/menu/menu.js.map +1 -1
- package/menu/types.d.ts +17 -1
- package/modal/index.js.map +1 -1
- package/modal/types.d.ts +3 -1
- package/modal-v2/modal-v2.js.map +1 -1
- package/modal-v2/types.d.ts +17 -0
- package/navbar/navbar.js.map +1 -1
- package/navbar/types.d.ts +1 -0
- package/notification-banner/notification-banner.js.map +1 -1
- package/otp-input/otp-input.js +1 -1
- package/otp-input/otp-input.js.map +1 -1
- package/otp-input/types.d.ts +14 -9
- package/otp-verification/contact-input-section.js +1 -1
- package/otp-verification/contact-input-section.js.map +1 -1
- package/otp-verification/otp-verification.js.map +1 -1
- package/otp-verification/verification-section.js +1 -1
- package/otp-verification/verification-section.js.map +1 -1
- package/overlay/overlay.js.map +1 -1
- package/package.json +1 -1
- package/pagination/pagination.js.map +1 -1
- package/phone-number-input/phone-number-input.js.map +1 -1
- package/pill/pill.js.map +1 -1
- package/popover/popover-inline/index.d.ts +1 -0
- package/popover/popover-inline/popover-inline.d.ts +1 -1
- package/popover/popover-inline/popover-inline.js.map +1 -1
- package/popover/popover-inline/types.d.ts +36 -0
- package/popover/popover.js.map +1 -1
- package/popover/types.d.ts +2 -35
- package/predictive-text-input/predictive-text-input.js +1 -1
- package/predictive-text-input/predictive-text-input.js.map +1 -1
- package/predictive-text-input/types.d.ts +1 -1
- package/progress-indicator/progress-indicator.js.map +1 -1
- package/radio-button/radio-button.js.map +1 -1
- package/radio-button/types.d.ts +3 -0
- package/schedule/schedule.js.map +1 -1
- package/select-histogram/select-histogram.js.map +1 -1
- package/select-histogram/types.d.ts +1 -1
- package/shared/dropdown-list/dropdown-list.js +1 -1
- package/shared/dropdown-list/dropdown-list.js.map +1 -1
- package/shared/dropdown-wrapper/element-with-dropdown.d.ts +5 -4
- package/shared/dropdown-wrapper/element-with-dropdown.js +1 -1
- package/shared/dropdown-wrapper/element-with-dropdown.js.map +1 -1
- package/sidenav/sidenav.js.map +1 -1
- package/sidenav/types.d.ts +1 -0
- package/singpass-button/singpass-button.js.map +1 -1
- package/smart-app-banner/smart-app-banner.js.map +1 -1
- package/smart-app-banner/types.d.ts +2 -0
- package/tab/tab.js.map +1 -1
- package/table/table.d.ts +9 -8
- package/table/table.js.map +1 -1
- package/table/types.d.ts +35 -0
- package/tag/tag.js.map +1 -1
- package/text-list/index.js.map +1 -1
- package/theme/theme-provider/hooks.js.map +1 -1
- package/theme/theme-provider/index.js.map +1 -1
- package/theme/tokens/border.d.ts +9 -3
- package/theme/tokens/border.js.map +1 -1
- package/theme/tokens/breakpoint.js.map +1 -1
- package/theme/tokens/colour.d.ts +9 -3
- package/theme/tokens/colour.js.map +1 -1
- package/theme/tokens/component.d.ts +3 -1
- package/theme/tokens/component.js.map +1 -1
- package/theme/tokens/font.d.ts +6 -2
- package/theme/tokens/font.js.map +1 -1
- package/theme/tokens/media-query.d.ts +3 -1
- package/theme/tokens/media-query.js.map +1 -1
- package/theme/tokens/motion.d.ts +3 -1
- package/theme/tokens/motion.js.map +1 -1
- package/theme/tokens/radius.d.ts +3 -1
- package/theme/tokens/radius.js.map +1 -1
- package/theme/tokens/shadow.d.ts +3 -1
- package/theme/tokens/shadow.js.map +1 -1
- package/theme/tokens/spacing.d.ts +3 -1
- package/theme/tokens/spacing.js.map +1 -1
- package/theme/utils/use-apply-styles.js.map +1 -1
- package/theme/utils/use-design-token.js.map +1 -1
- package/theme/utils/use-media-query.js.map +1 -1
- package/time-range-picker/combobox-picker/combobox-picker.js +1 -1
- package/time-range-picker/combobox-picker/combobox-picker.js.map +1 -1
- package/time-range-picker/time-range-picker.js.map +1 -1
- package/time-range-picker/types.d.ts +1 -1
- package/time-slot-bar/time-slot-bar.js.map +1 -1
- package/time-slot-bar/types.d.ts +5 -1
- package/time-slot-bar-week/time-slot-bar-week.js.map +1 -1
- package/time-slot-bar-week/types.d.ts +6 -0
- package/time-slot-week-view/time-slot-week-view.js.map +1 -1
- package/time-slot-week-view/types.d.ts +2 -0
- package/timeline/timeline.js.map +1 -1
- package/timeline/types.d.ts +1 -1
- package/timepicker/timepicker.js.map +1 -1
- package/timepicker/types.d.ts +2 -2
- package/timetable/timetable.js.map +1 -1
- package/toast/toast.js.map +1 -1
- package/toast/types.d.ts +2 -0
- package/toggle/toggle.js.map +1 -1
- package/tools/shared/generated-file-formatter.d.ts +6 -0
- package/tools/shared/jsdoc-parser.d.ts +36 -0
- package/tools/shared/ts-morph-project-factory.d.ts +9 -0
- package/tools/shared/typescript-source-provider.d.ts +9 -0
- package/tools/storybook-argtypes/adapters/file-system-adapter.d.ts +69 -0
- package/tools/storybook-argtypes/arg-types-generator.d.ts +85 -0
- package/tools/storybook-argtypes/config/arg-types-config.d.ts +31 -0
- package/tools/storybook-argtypes/index.d.ts +11 -0
- package/tools/storybook-argtypes/services/arg-types-row-builder.d.ts +43 -0
- package/tools/storybook-argtypes/services/file-path-resolver.d.ts +118 -0
- package/tools/storybook-argtypes/services/index.d.ts +6 -0
- package/tools/storybook-argtypes/services/jsdoc-metadata-extractor.d.ts +33 -0
- package/tools/storybook-argtypes/services/story-registry-generator.d.ts +27 -0
- package/tools/storybook-argtypes/services/type-dependency-resolver.d.ts +46 -0
- package/tools/storybook-argtypes/services/type-formatting-service.d.ts +27 -0
- package/tools/storybook-argtypes/types.d.ts +102 -0
- package/typography/index.js.map +1 -1
- package/uneditable-section/index.js.map +1 -1
- package/uneditable-section/section-item.js +1 -1
- package/uneditable-section/section-item.js.map +1 -1
- package/uneditable-section/types.d.ts +2 -2
- package/unit-number/unit-number-input.js.map +1 -1
- package/cjs/form/form-custom-field.js +0 -2
- package/cjs/form/form-custom-field.js.map +0 -1
- package/cjs/form/form-date-input.js +0 -2
- package/cjs/form/form-date-input.js.map +0 -1
- package/cjs/form/form-date-range-input.js +0 -2
- package/cjs/form/form-date-range-input.js.map +0 -1
- package/cjs/form/form-e-signature.js +0 -2
- package/cjs/form/form-e-signature.js.map +0 -1
- package/cjs/form/form-histogram.js +0 -2
- package/cjs/form/form-histogram.js.map +0 -1
- package/cjs/form/form-input-group.js +0 -2
- package/cjs/form/form-input-group.js.map +0 -1
- package/cjs/form/form-input.js +0 -2
- package/cjs/form/form-input.js.map +0 -1
- package/cjs/form/form-label-addon.js +0 -2
- package/cjs/form/form-label-addon.js.map +0 -1
- package/cjs/form/form-label-addon.styles.js +0 -2
- package/cjs/form/form-label-addon.styles.js.map +0 -1
- package/cjs/form/form-label-addon.styles_b00z8p.css +0 -1
- package/cjs/form/form-label.js +0 -2
- package/cjs/form/form-label.js.map +0 -1
- package/cjs/form/form-label.styles.js +0 -2
- package/cjs/form/form-label.styles.js.map +0 -1
- package/cjs/form/form-label.styles_1nbe0bm.css +0 -6
- package/cjs/form/form-masked-input.js +0 -2
- package/cjs/form/form-masked-input.js.map +0 -1
- package/cjs/form/form-multi-select.js +0 -2
- package/cjs/form/form-multi-select.js.map +0 -1
- package/cjs/form/form-nested-multi-select.js +0 -2
- package/cjs/form/form-nested-multi-select.js.map +0 -1
- package/cjs/form/form-nested-select.js +0 -2
- package/cjs/form/form-nested-select.js.map +0 -1
- package/cjs/form/form-otp-verification.js +0 -2
- package/cjs/form/form-otp-verification.js.map +0 -1
- package/cjs/form/form-phone-number-input.js +0 -2
- package/cjs/form/form-phone-number-input.js.map +0 -1
- package/cjs/form/form-predictive-text-input.js +0 -2
- package/cjs/form/form-predictive-text-input.js.map +0 -1
- package/cjs/form/form-range-select.js +0 -2
- package/cjs/form/form-range-select.js.map +0 -1
- package/cjs/form/form-range-slider.js +0 -2
- package/cjs/form/form-range-slider.js.map +0 -1
- package/cjs/form/form-select-histogram.js +0 -2
- package/cjs/form/form-select-histogram.js.map +0 -1
- package/cjs/form/form-select.js +0 -2
- package/cjs/form/form-select.js.map +0 -1
- package/cjs/form/form-slider.js +0 -2
- package/cjs/form/form-slider.js.map +0 -1
- package/cjs/form/form-textarea.js +0 -2
- package/cjs/form/form-textarea.js.map +0 -1
- package/cjs/form/form-textarea.styles.js +0 -2
- package/cjs/form/form-textarea.styles.js.map +0 -1
- package/cjs/form/form-textarea.styles_3p9qoy.css +0 -3
- package/cjs/form/form-time-range-picker.js +0 -2
- package/cjs/form/form-time-range-picker.js.map +0 -1
- package/cjs/form/form-timepicker.js +0 -2
- package/cjs/form/form-timepicker.js.map +0 -1
- package/cjs/form/form-unit-number-input.js +0 -2
- package/cjs/form/form-unit-number-input.js.map +0 -1
- package/form/form-custom-field.js +0 -2
- package/form/form-custom-field.js.map +0 -1
- package/form/form-date-input.js +0 -2
- package/form/form-date-input.js.map +0 -1
- package/form/form-date-range-input.js +0 -2
- package/form/form-date-range-input.js.map +0 -1
- package/form/form-e-signature.js +0 -2
- package/form/form-e-signature.js.map +0 -1
- package/form/form-histogram.js +0 -2
- package/form/form-histogram.js.map +0 -1
- package/form/form-input-group.js +0 -2
- package/form/form-input-group.js.map +0 -1
- package/form/form-input.js +0 -2
- package/form/form-input.js.map +0 -1
- package/form/form-label-addon.js +0 -2
- package/form/form-label-addon.js.map +0 -1
- package/form/form-label-addon.styles.js +0 -2
- package/form/form-label-addon.styles.js.map +0 -1
- package/form/form-label-addon.styles_b00z8p.css +0 -1
- package/form/form-label.js +0 -2
- package/form/form-label.js.map +0 -1
- package/form/form-label.styles.js +0 -2
- package/form/form-label.styles.js.map +0 -1
- package/form/form-label.styles_1nbe0bm.css +0 -6
- package/form/form-masked-input.js +0 -2
- package/form/form-masked-input.js.map +0 -1
- package/form/form-multi-select.js +0 -2
- package/form/form-multi-select.js.map +0 -1
- package/form/form-nested-multi-select.js +0 -2
- package/form/form-nested-multi-select.js.map +0 -1
- package/form/form-nested-select.js +0 -2
- package/form/form-nested-select.js.map +0 -1
- package/form/form-otp-verification.js +0 -2
- package/form/form-otp-verification.js.map +0 -1
- package/form/form-phone-number-input.js +0 -2
- package/form/form-phone-number-input.js.map +0 -1
- package/form/form-predictive-text-input.js +0 -2
- package/form/form-predictive-text-input.js.map +0 -1
- package/form/form-range-select.js +0 -2
- package/form/form-range-select.js.map +0 -1
- package/form/form-range-slider.js +0 -2
- package/form/form-range-slider.js.map +0 -1
- package/form/form-select-histogram.js +0 -2
- package/form/form-select-histogram.js.map +0 -1
- package/form/form-select.js +0 -2
- package/form/form-select.js.map +0 -1
- package/form/form-slider.js +0 -2
- package/form/form-slider.js.map +0 -1
- package/form/form-textarea.js +0 -2
- package/form/form-textarea.js.map +0 -1
- package/form/form-textarea.styles.js +0 -2
- package/form/form-textarea.styles.js.map +0 -1
- package/form/form-textarea.styles_3p9qoy.css +0 -3
- package/form/form-time-range-picker.js +0 -2
- package/form/form-time-range-picker.js.map +0 -1
- package/form/form-timepicker.js +0 -2
- package/form/form-timepicker.js.map +0 -1
- package/form/form-unit-number-input.js +0 -2
- package/form/form-unit-number-input.js.map +0 -1
- package/link-list/internal-types.d.ts +0 -85
- /package/{codemod-utils.d.ts → codemods/codemod-utils.d.ts} +0 -0
- /package/{migrate-popover → codemods/migrate-popover}/index.d.ts +0 -0
- /package/{run-codemod.d.ts → codemods/run-codemod.d.ts} +0 -0
- /package/form/{form-custom-field.d.ts → form-custom-field/form-custom-field.d.ts} +0 -0
- /package/form/{form-date-input.d.ts → form-date-input/form-date-input.d.ts} +0 -0
- /package/form/{form-date-range-input.d.ts → form-date-range-input/form-date-range-input.d.ts} +0 -0
- /package/form/{form-e-signature.d.ts → form-e-signature/form-e-signature.d.ts} +0 -0
- /package/form/{form-histogram.d.ts → form-histogram-slider/form-histogram-slider.d.ts} +0 -0
- /package/form/{form-input.d.ts → form-input/form-input.d.ts} +0 -0
- /package/form/{form-input-group.d.ts → form-input-group/form-input-group.d.ts} +0 -0
- /package/form/{form-label-addon.d.ts → form-label/form-label-addon.d.ts} +0 -0
- /package/form/{form-label-addon.styles.d.ts → form-label/form-label-addon.styles.d.ts} +0 -0
- /package/form/{form-label.d.ts → form-label/form-label.d.ts} +0 -0
- /package/form/{form-label.styles.d.ts → form-label/form-label.styles.d.ts} +0 -0
- /package/form/{form-masked-input.d.ts → form-masked-input/form-masked-input.d.ts} +0 -0
- /package/form/{form-multi-select.d.ts → form-multi-select/form-multi-select.d.ts} +0 -0
- /package/form/{form-nested-multi-select.d.ts → form-nested-multi-select/form-nested-multi-select.d.ts} +0 -0
- /package/form/{form-nested-select.d.ts → form-nested-select/form-nested-select.d.ts} +0 -0
- /package/form/{form-phone-number-input.d.ts → form-phone-number-input/form-phone-number-input.d.ts} +0 -0
- /package/form/{form-predictive-text-input.d.ts → form-predictive-text-input/form-predictive-text-input.d.ts} +0 -0
- /package/form/{form-range-select.d.ts → form-range-select/form-range-select.d.ts} +0 -0
- /package/form/{form-range-slider.d.ts → form-range-slider/form-range-slider.d.ts} +0 -0
- /package/form/{form-select.d.ts → form-select/form-select.d.ts} +0 -0
- /package/form/{form-select-histogram.d.ts → form-select-histogram/form-select-histogram.d.ts} +0 -0
- /package/form/{form-slider.d.ts → form-slider/form-slider.d.ts} +0 -0
- /package/form/{form-textarea.d.ts → form-textarea/form-textarea.d.ts} +0 -0
- /package/form/{form-textarea.styles.d.ts → form-textarea/form-textarea.styles.d.ts} +0 -0
- /package/form/{form-time-range-picker.d.ts → form-time-range-picker/form-time-range-picker.d.ts} +0 -0
- /package/form/{form-timepicker.d.ts → form-timepicker/form-timepicker.d.ts} +0 -0
- /package/form/{form-unit-number-input.d.ts → form-unit-number-input/form-unit-number-input.d.ts} +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"timetable.js","sources":["../../src/timetable/timetable.tsx"],"sourcesContent":["import clsx from \"clsx\";\nimport dayjs from \"dayjs\";\nimport { isEmpty, throttle } from \"lodash\";\nimport {\n forwardRef,\n useEffect,\n useImperativeHandle,\n useRef,\n useState,\n} from \"react\";\nimport { useResizeDetector } from \"react-resize-detector\";\n\nimport { LoadingDotsSpinner } from \"../animations\";\nimport { ErrorDisplay } from \"../error-display\";\nimport type { PopoverTriggerProps } from \"../popover\";\nimport { PopoverTrigger } from \"../popover\";\nimport { VisuallyHidden } from \"../shared/accessibility\";\nimport { useApplyStyle } from \"../theme\";\nimport { Typography } from \"../typography\";\nimport { TimeHelper } from \"../util/time-helper\";\nimport {\n MIN_INTERVAL_WIDTH,\n ROW_BAR_COLOR_ALTERNATE_COLOR,\n ROW_BAR_COLOR_SEQUENCE,\n ROW_HEADER_WIDTH,\n ROW_INTERVAL,\n} from \"./const\";\nimport * as styles from \"./timetable.styles\";\nimport { TimeTableHeader } from \"./timetable-header/timetable-header\";\nimport { RowBar } from \"./timetable-row/row-bar\";\nimport type { TimeTableProps, TimeTableRef, TimeTableRowData } from \"./types\";\n\nconst Component = (props: TimeTableProps, ref: React.Ref<TimeTableRef>) => {\n // =============================================================================\n // CONST, STATE, REF\n // =============================================================================\n const {\n date,\n emptyContentMessage,\n rowData,\n loading,\n minTime = \"00:00\",\n maxTime = \"23:00\",\n initialScrollTime,\n minDate,\n maxDate,\n totalRecords,\n showCurrentDateAsToday,\n showDateAsShortForm,\n onPage,\n onRefresh,\n onNextDayClick,\n onPreviousDayClick,\n onCalendarDateSelect,\n roundInitialScrollTime = true,\n ...otherProps\n } = props;\n const testId = otherProps[\"data-testid\"] || \"timetable\";\n const timetableMinTime = TimeHelper.roundToNearestInterval(minTime, 60);\n const timetableMaxTime = TimeHelper.roundToNearestInterval(\n maxTime,\n 60,\n true\n );\n const hourlyIntervals = TimeHelper.generateHourlyIntervals(\n timetableMinTime,\n timetableMaxTime\n );\n const numberOfIntervals = Math.ceil(\n (hourlyIntervals.length * 60) / ROW_INTERVAL\n );\n const formattedDate = dayjs(date).format(\"D MMMM YYYY\");\n const timetableAriaLabel = `Timetable of resource availability, for ${formattedDate}, from ${dayjs(\n timetableMinTime,\n \"HH:mm\"\n ).format(\"ha\")} to ${dayjs(timetableMaxTime, \"HH:mm\").format(\"ha\")}`;\n const ariaRowCount = (totalRecords || rowData.length) + 1;\n const ariaColCount = numberOfIntervals + 1;\n\n const isEmptyContent = totalRecords === 0 || isEmpty(rowData);\n const allRecordsLoaded = isEmptyContent || rowData.length === totalRecords;\n const hasLazyLoad = !allRecordsLoaded && !!onPage;\n const tableContainerRef = useRef<HTMLDivElement>(null);\n const contentContainerRef = useRef<HTMLDivElement>(null);\n const columnHeaderRowRef = useRef<HTMLDivElement>(null);\n const loadingWrapperRef = useRef<HTMLDivElement>(null);\n const [isScrolledX, setIsScrolledX] = useState<boolean>(false);\n const [isScrolledY, setIsScrolledY] = useState<boolean>(false);\n const [intervalWidth, setIntervalWidth] = useState<number>(0);\n const [loadMore, setLoadMore] = useState<boolean>(false);\n\n // Expose imperative handle\n useImperativeHandle(ref, () => ({\n resetScroll,\n }));\n\n useApplyStyle(columnHeaderRowRef, {\n [styles.tokens.columnHeaderRow.columnWidth]: `${intervalWidth * 4}px`,\n });\n\n useApplyStyle(loadingWrapperRef, {\n [styles.tokens.loadingWrapper.cellWidth]: `${intervalWidth * 4}px`,\n });\n\n // =============================================================================\n // EFFECTS\n // =============================================================================\n useEffect(() => {\n const handleScroll = throttle(() => {\n if (tableContainerRef.current) {\n setIsScrolledX(tableContainerRef.current.scrollLeft > 0);\n setIsScrolledY(tableContainerRef.current.scrollTop > 0);\n }\n\n if (loadMore || !tableContainerRef.current) return;\n\n const { scrollTop, clientHeight, scrollHeight } =\n tableContainerRef.current;\n const scrollBottomTolerance = 1;\n const isEndReached =\n Math.ceil(scrollTop + clientHeight) >=\n scrollHeight - scrollBottomTolerance;\n const shouldLoadMore =\n isEndReached && !allRecordsLoaded && onPage && !loading;\n\n if (shouldLoadMore) {\n setLoadMore(true);\n onPage();\n }\n }, 100);\n\n const tableContainer = tableContainerRef.current;\n\n if (tableContainer) {\n tableContainer.addEventListener(\"scroll\", handleScroll);\n }\n\n return () => {\n if (tableContainer) {\n tableContainer.removeEventListener(\"scroll\", handleScroll);\n }\n };\n }, [allRecordsLoaded, loadMore, loading, onPage]);\n\n useEffect(() => {\n setLoadMore(false);\n }, [rowData]);\n\n // Initial scroll on mount and when dependencies change\n useEffect(() => {\n resetScroll();\n }, [initialScrollTime, intervalWidth, timetableMinTime, timetableMaxTime]);\n\n // =============================================================================\n // EVENT HANDLERS\n // =============================================================================\n /**\n * Handles when the TimeTable component is resized.\n *\n * @remarks\n * When the component is resized, we recalculate the width of each interval\n * in the Timetable. We do this by dividing the width of the container by\n * the number of intervals per row bar. We also make sure that the width\n * of each interval is at least 21px, otherwise it becomes too small.\n */\n const handleResize = () => {\n if (tableContainerRef.current) {\n const numberOfIntervalsPerRowBar = Math.ceil(\n (hourlyIntervals.length * 60) / ROW_INTERVAL\n );\n const tableContainerWidth =\n tableContainerRef.current.clientWidth - ROW_HEADER_WIDTH;\n const calcWidth = tableContainerWidth / numberOfIntervalsPerRowBar;\n const width =\n calcWidth > MIN_INTERVAL_WIDTH ? calcWidth : MIN_INTERVAL_WIDTH;\n setIntervalWidth(width);\n }\n };\n\n useResizeDetector({\n onResize: handleResize,\n targetRef: tableContainerRef,\n refreshMode: \"debounce\",\n refreshRate: 50,\n });\n\n const handleRowNameClick = (\n data: TimeTableRowData,\n event: React.MouseEvent\n ) => {\n if (data.onRowNameClick) {\n data.onRowNameClick(data, event);\n }\n };\n\n // ===========================================================================\n // HELPER FUNCTIONS\n // ===========================================================================\n /**\n * Using closures to more efficiently loop through and wrap the color sequencing instead of modding large numbers repeatedly\n * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures#closure\n */\n const getColorFromSequence = (() => {\n let colorIndex = 0;\n const colorSequenceLength = ROW_BAR_COLOR_SEQUENCE.length;\n\n return () => {\n const mainColor = ROW_BAR_COLOR_SEQUENCE[colorIndex];\n const alternateColor = ROW_BAR_COLOR_ALTERNATE_COLOR[colorIndex];\n colorIndex = (colorIndex + 1) % colorSequenceLength;\n return { mainColor, alternateColor };\n };\n })();\n\n const buildPopoverTrigger = (\n data: TimeTableRowData,\n child: JSX.Element\n ) => {\n if (!data.rowHeaderPopover) {\n return child;\n }\n\n const popoverTriggerProps: PopoverTriggerProps = {\n position: \"bottom-start\",\n customOffset: data.rowHeaderPopover.offset,\n children: child,\n trigger: data.rowHeaderPopover.trigger,\n delay: data.rowHeaderPopover.delay,\n popoverContent: data.rowHeaderPopover.content,\n };\n\n return (\n <PopoverTrigger\n {...popoverTriggerProps}\n className={styles.popoverTrigger}\n key={`${data.id}-popover-trigger`}\n zIndex={2}\n >\n {child}\n </PopoverTrigger>\n );\n };\n\n // Function to reset scroll to initialScrollTime\n const resetScroll = () => {\n if (\n initialScrollTime &&\n tableContainerRef.current &&\n intervalWidth > 0\n ) {\n const scrollPosition = TimeHelper.calculateScrollPosition({\n scrollTime: initialScrollTime,\n minTime: timetableMinTime,\n maxTime: timetableMaxTime,\n interval: ROW_INTERVAL,\n intervalWidth,\n options: {\n roundToInterval: roundInitialScrollTime,\n },\n });\n\n if (scrollPosition !== null) {\n tableContainerRef.current.scrollLeft = scrollPosition;\n }\n }\n };\n\n // =============================================================================\n // RENDER FUNCTIONS\n // =============================================================================\n const renderRowHeader = (data: TimeTableRowData) => {\n const rowHeaderContent = (\n <>\n <Typography.BodyMD\n className={clsx(\n styles.clickableRowHeaderTitle,\n !!data.onRowNameClick &&\n styles.clickableRowHeaderTitleClickable\n )}\n onClick={(event: React.MouseEvent) =>\n handleRowNameClick(data, event)\n }\n weight=\"semibold\"\n data-testid={`${data.id}-row-header-title`}\n >\n {data.name}\n </Typography.BodyMD>\n\n <Typography.BodyXS\n weight=\"bold\"\n className={clsx(\n styles.rowHeaderSubtitle,\n !data.subtitle && styles.rowHeaderSubtitleHidden\n )}\n data-testid={`${data.id}-row-header-subtitle`}\n >\n {data.subtitle}\n </Typography.BodyXS>\n </>\n );\n\n return (\n <div\n className={clsx(\n styles.rowHeader,\n isScrolledX && styles.rowHeaderScrolled\n )}\n key={`${data.id}-row-header`}\n role=\"rowheader\"\n aria-colindex={1}\n >\n {buildPopoverTrigger(data, rowHeaderContent)}\n </div>\n );\n };\n\n const renderColumnHeaders = () => {\n // Don't render first column if there are no rows\n\n return hourlyIntervals.map((columnHeader: string) => (\n <div\n className={styles.columnHeader}\n key={`${columnHeader}-column-key`}\n data-testid={`${columnHeader}-column`}\n >\n <Typography.BodySM\n className={styles.columnHeaderTitle}\n weight={\"semibold\"}\n >\n {columnHeader}\n </Typography.BodySM>\n </div>\n ));\n };\n\n const renderRows = () => {\n if (loading) {\n return (\n <LoadingDotsSpinner\n data-testid=\"timetable-loading-spinner\"\n className={clsx(\n styles.loadingSpinner,\n isEmptyContent\n ? styles.loadingSpinnerEmptyContent\n : styles.loadingSpinnerHasContent\n )}\n />\n );\n }\n\n return (\n <div\n className={styles.timeTableBody}\n data-testid=\"content-container-id\"\n ref={contentContainerRef}\n role=\"rowgroup\"\n >\n {rowData.map((data, index) => {\n return (\n <div\n className={styles.timeTableRow}\n key={`${index}-timetable-row`}\n role=\"row\"\n aria-rowindex={index + 2}\n aria-label={data.name}\n >\n {renderRowHeader(data)}\n <RowBar\n key={`${index}-row-bar`}\n timetableMinTime={timetableMinTime}\n timetableMaxTime={timetableMaxTime}\n rowBarColor={getColorFromSequence()}\n intervalWidth={intervalWidth}\n containerRef={contentContainerRef}\n {...data}\n />\n </div>\n );\n })}\n {renderLazyLoadRow()}\n </div>\n );\n };\n\n const renderLazyLoadRow = () => {\n if (loading || !loadMore) return;\n return (\n <div className={styles.timeTableRow}>\n <div\n className={clsx(\n styles.rowHeader,\n isScrolledX && styles.rowHeaderScrolled\n )}\n >\n <div className={styles.loadingBar} />\n </div>\n <div\n ref={loadingWrapperRef}\n className={styles.loadingWrapper}\n data-testid=\"lazy-loader\"\n role=\"presentation\"\n >\n {hourlyIntervals.map((_, index) => (\n <div\n className={styles.loadingCell}\n key={`lazy-load-cell-${index}`}\n >\n <div className={styles.loadingBar} />\n </div>\n ))}\n </div>\n </div>\n );\n };\n\n if (isEmptyContent) {\n return (\n <div {...otherProps} data-testid={testId}>\n <TimeTableHeader\n selectedDate={date}\n loading={loading || loadMore}\n tableContainerRef={tableContainerRef}\n minDate={minDate}\n maxDate={maxDate}\n totalRecords={totalRecords}\n showCurrentDateAsToday={showCurrentDateAsToday}\n showDateAsShortForm={showDateAsShortForm}\n onPreviousDayClick={onPreviousDayClick}\n onNextDayClick={onNextDayClick}\n onRefresh={onRefresh}\n onCalendarDateSelect={onCalendarDateSelect}\n />\n <div\n className={clsx(\n styles.emptyTableContainer,\n \"empty-container\"\n )}\n tabIndex={0}\n aria-live=\"polite\"\n aria-atomic\n aria-busy={loading}\n >\n {!loading ? (\n <ErrorDisplay\n className={styles.noResultsFound}\n type=\"no-item-found\"\n description={emptyContentMessage}\n />\n ) : (\n <>\n <VisuallyHidden>{`Loading ${timetableAriaLabel}`}</VisuallyHidden>\n <LoadingDotsSpinner\n data-testid=\"timetable-loading-spinner\"\n className={clsx(\n styles.loadingSpinner,\n isEmptyContent\n ? styles.loadingSpinnerEmptyContent\n : styles.loadingSpinnerHasContent\n )}\n />\n </>\n )}\n </div>\n </div>\n );\n }\n\n return (\n <div {...otherProps} data-testid={testId}>\n <TimeTableHeader\n data-id=\"timetable-date-navigator\"\n selectedDate={date}\n loading={loading || loadMore}\n tableContainerRef={tableContainerRef}\n minDate={minDate}\n maxDate={maxDate}\n totalRecords={totalRecords}\n showCurrentDateAsToday={showCurrentDateAsToday}\n showDateAsShortForm={showDateAsShortForm}\n onPreviousDayClick={onPreviousDayClick}\n onNextDayClick={onNextDayClick}\n onRefresh={onRefresh}\n onCalendarDateSelect={onCalendarDateSelect}\n />\n <div\n data-id=\"timetable-container\"\n data-testid=\"timetable-container\"\n ref={tableContainerRef}\n className={clsx(\n styles.timeTableContainer,\n hasLazyLoad && styles.timeTableContainerNotAllLoaded,\n loading && styles.timeTableContainerLoading\n )}\n role=\"grid\"\n aria-label={timetableAriaLabel}\n aria-rowcount={ariaRowCount}\n aria-colcount={ariaColCount}\n aria-busy={loadMore}\n tabIndex={0}\n >\n <div\n className={styles.timeTableHeaderRow}\n role=\"row\"\n aria-rowindex={1}\n data-testid={\"row-header-column-id\"}\n >\n <div\n className={clsx(\n styles.rowColumnHeader,\n (isScrolledX || isScrolledY) &&\n styles.rowColumnHeaderScrolled,\n isScrolledX && styles.rowColumnHeaderScrolledX,\n isScrolledY && styles.rowColumnHeaderScrolledY\n )}\n role=\"columnheader\"\n aria-colindex={1}\n >\n <VisuallyHidden>Resource</VisuallyHidden>\n </div>\n <div\n ref={columnHeaderRowRef}\n className={clsx(\n styles.columnHeaderRow,\n isScrolledY && styles.columnHeaderRowScrolled\n )}\n role=\"presentation\"\n >\n {renderColumnHeaders()}\n </div>\n </div>\n {renderRows()}\n </div>\n </div>\n );\n};\n\n/**\n * A scrollable grid that visualises time slot availability across a day.\n *\n * Use `TimeTable` to display one day's schedule for multiple resources side by\n * side.\n */\nexport const TimeTable = forwardRef<TimeTableRef, TimeTableProps>(Component);\n"],"names":["TimeTable","forwardRef","props","ref","date","emptyContentMessage","rowData","loading","minTime","maxTime","initialScrollTime","minDate","maxDate","totalRecords","showCurrentDateAsToday","showDateAsShortForm","onPage","onRefresh","onNextDayClick","onPreviousDayClick","onCalendarDateSelect","roundInitialScrollTime","otherProps","testId","timetableMinTime","TimeHelper","roundToNearestInterval","timetableMaxTime","hourlyIntervals","generateHourlyIntervals","numberOfIntervals","Math","ceil","length","ROW_INTERVAL","timetableAriaLabel","dayjs","format","ariaRowCount","ariaColCount","isEmptyContent","isEmpty","allRecordsLoaded","hasLazyLoad","tableContainerRef","useRef","contentContainerRef","columnHeaderRowRef","loadingWrapperRef","isScrolledX","setIsScrolledX","useState","isScrolledY","setIsScrolledY","intervalWidth","setIntervalWidth","loadMore","setLoadMore","useImperativeHandle","resetScroll","useApplyStyle","styles.tokens","columnHeaderRow","columnWidth","loadingWrapper","cellWidth","useEffect","handleScroll","throttle","current","scrollLeft","scrollTop","clientHeight","scrollHeight","tableContainer","addEventListener","removeEventListener","useResizeDetector","onResize","numberOfIntervalsPerRowBar","calcWidth","clientWidth","ROW_HEADER_WIDTH","MIN_INTERVAL_WIDTH","targetRef","refreshMode","refreshRate","getColorFromSequence","colorIndex","colorSequenceLength","ROW_BAR_COLOR_SEQUENCE","mainColor","alternateColor","ROW_BAR_COLOR_ALTERNATE_COLOR","buildPopoverTrigger","data","child","rowHeaderPopover","popoverTriggerProps","position","customOffset","offset","children","trigger","delay","popoverContent","content","_createElement","PopoverTrigger","Object","assign","className","styles.popoverTrigger","key","id","zIndex","scrollPosition","calculateScrollPosition","scrollTime","interval","options","roundToInterval","renderRowHeader","rowHeaderContent","_jsxs","_Fragment","_jsx","Typography","BodyMD","clsx","styles.clickableRowHeaderTitle","onRowNameClick","styles.clickableRowHeaderTitleClickable","onClick","event","handleRowNameClick","weight","name","BodyXS","styles.rowHeaderSubtitle","subtitle","styles.rowHeaderSubtitleHidden","styles.rowHeader","styles.rowHeaderScrolled","role","renderLazyLoadRow","styles.timeTableRow","styles.loadingBar","styles.loadingWrapper","map","_","index","styles.loadingCell","TimeTableHeader","selectedDate","styles.emptyTableContainer","tabIndex","VisuallyHidden","LoadingDotsSpinner","styles.loadingSpinner","styles.loadingSpinnerEmptyContent","styles.loadingSpinnerHasContent","ErrorDisplay","styles.noResultsFound","type","description","styles.timeTableContainer","styles.timeTableContainerNotAllLoaded","styles.timeTableContainerLoading","styles.timeTableHeaderRow","styles.rowColumnHeader","styles.rowColumnHeaderScrolled","styles.rowColumnHeaderScrolledX","styles.rowColumnHeaderScrolledY","styles.columnHeaderRow","styles.columnHeaderRowScrolled","columnHeader","styles.columnHeader","BodySM","styles.columnHeaderTitle","styles.timeTableBody","RowBar","rowBarColor","containerRef"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"timetable.js","sources":["../../src/timetable/timetable.tsx"],"sourcesContent":["import clsx from \"clsx\";\nimport dayjs from \"dayjs\";\nimport { isEmpty, throttle } from \"lodash\";\nimport {\n forwardRef,\n useEffect,\n useImperativeHandle,\n useRef,\n useState,\n} from \"react\";\nimport { useResizeDetector } from \"react-resize-detector\";\n\nimport { LoadingDotsSpinner } from \"../animations\";\nimport { ErrorDisplay } from \"../error-display\";\nimport type { PopoverTriggerProps } from \"../popover\";\nimport { PopoverTrigger } from \"../popover\";\nimport { VisuallyHidden } from \"../shared/accessibility\";\nimport { useApplyStyle } from \"../theme\";\nimport { Typography } from \"../typography\";\nimport { TimeHelper } from \"../util/time-helper\";\nimport {\n MIN_INTERVAL_WIDTH,\n ROW_BAR_COLOR_ALTERNATE_COLOR,\n ROW_BAR_COLOR_SEQUENCE,\n ROW_HEADER_WIDTH,\n ROW_INTERVAL,\n} from \"./const\";\nimport * as styles from \"./timetable.styles\";\nimport { TimeTableHeader } from \"./timetable-header/timetable-header\";\nimport { RowBar } from \"./timetable-row/row-bar\";\nimport type { TimeTableProps, TimeTableRef, TimeTableRowData } from \"./types\";\n\nconst Component = (props: TimeTableProps, ref: React.Ref<TimeTableRef>) => {\n // =============================================================================\n // CONST, STATE, REF\n // =============================================================================\n const {\n date,\n emptyContentMessage,\n rowData,\n loading,\n minTime = \"00:00\",\n maxTime = \"23:00\",\n initialScrollTime,\n minDate,\n maxDate,\n totalRecords,\n showCurrentDateAsToday,\n showDateAsShortForm,\n onPage,\n onRefresh,\n onNextDayClick,\n onPreviousDayClick,\n onCalendarDateSelect,\n roundInitialScrollTime = true,\n ...otherProps\n } = props;\n const testId = otherProps[\"data-testid\"] || \"timetable\";\n const timetableMinTime = TimeHelper.roundToNearestInterval(minTime, 60);\n const timetableMaxTime = TimeHelper.roundToNearestInterval(\n maxTime,\n 60,\n true\n );\n const hourlyIntervals = TimeHelper.generateHourlyIntervals(\n timetableMinTime,\n timetableMaxTime\n );\n const numberOfIntervals = Math.ceil(\n (hourlyIntervals.length * 60) / ROW_INTERVAL\n );\n const formattedDate = dayjs(date).format(\"D MMMM YYYY\");\n const timetableAriaLabel = `Timetable of resource availability, for ${formattedDate}, from ${dayjs(\n timetableMinTime,\n \"HH:mm\"\n ).format(\"ha\")} to ${dayjs(timetableMaxTime, \"HH:mm\").format(\"ha\")}`;\n const ariaRowCount = (totalRecords || rowData.length) + 1;\n const ariaColCount = numberOfIntervals + 1;\n\n const isEmptyContent = totalRecords === 0 || isEmpty(rowData);\n const allRecordsLoaded = isEmptyContent || rowData.length === totalRecords;\n const hasLazyLoad = !allRecordsLoaded && !!onPage;\n const tableContainerRef = useRef<HTMLDivElement>(null);\n const contentContainerRef = useRef<HTMLDivElement>(null);\n const columnHeaderRowRef = useRef<HTMLDivElement>(null);\n const loadingWrapperRef = useRef<HTMLDivElement>(null);\n const [isScrolledX, setIsScrolledX] = useState<boolean>(false);\n const [isScrolledY, setIsScrolledY] = useState<boolean>(false);\n const [intervalWidth, setIntervalWidth] = useState<number>(0);\n const [loadMore, setLoadMore] = useState<boolean>(false);\n\n // Expose imperative handle\n useImperativeHandle(ref, () => ({\n resetScroll,\n }));\n\n useApplyStyle(columnHeaderRowRef, {\n [styles.tokens.columnHeaderRow.columnWidth]: `${intervalWidth * 4}px`,\n });\n\n useApplyStyle(loadingWrapperRef, {\n [styles.tokens.loadingWrapper.cellWidth]: `${intervalWidth * 4}px`,\n });\n\n // =============================================================================\n // EFFECTS\n // =============================================================================\n useEffect(() => {\n const handleScroll = throttle(() => {\n if (tableContainerRef.current) {\n setIsScrolledX(tableContainerRef.current.scrollLeft > 0);\n setIsScrolledY(tableContainerRef.current.scrollTop > 0);\n }\n\n if (loadMore || !tableContainerRef.current) return;\n\n const { scrollTop, clientHeight, scrollHeight } =\n tableContainerRef.current;\n const scrollBottomTolerance = 1;\n const isEndReached =\n Math.ceil(scrollTop + clientHeight) >=\n scrollHeight - scrollBottomTolerance;\n const shouldLoadMore =\n isEndReached && !allRecordsLoaded && onPage && !loading;\n\n if (shouldLoadMore) {\n setLoadMore(true);\n onPage();\n }\n }, 100);\n\n const tableContainer = tableContainerRef.current;\n\n if (tableContainer) {\n tableContainer.addEventListener(\"scroll\", handleScroll);\n }\n\n return () => {\n if (tableContainer) {\n tableContainer.removeEventListener(\"scroll\", handleScroll);\n }\n };\n }, [allRecordsLoaded, loadMore, loading, onPage]);\n\n useEffect(() => {\n setLoadMore(false);\n }, [rowData]);\n\n // Initial scroll on mount and when dependencies change\n useEffect(() => {\n resetScroll();\n }, [initialScrollTime, intervalWidth, timetableMinTime, timetableMaxTime]);\n\n // =============================================================================\n // EVENT HANDLERS\n // =============================================================================\n /**\n * Handles when the TimeTable component is resized.\n *\n * @remarks\n * When the component is resized, we recalculate the width of each interval\n * in the Timetable. We do this by dividing the width of the container by\n * the number of intervals per row bar. We also make sure that the width\n * of each interval is at least 21px, otherwise it becomes too small.\n */\n const handleResize = () => {\n if (tableContainerRef.current) {\n const numberOfIntervalsPerRowBar = Math.ceil(\n (hourlyIntervals.length * 60) / ROW_INTERVAL\n );\n const tableContainerWidth =\n tableContainerRef.current.clientWidth - ROW_HEADER_WIDTH;\n const calcWidth = tableContainerWidth / numberOfIntervalsPerRowBar;\n const width =\n calcWidth > MIN_INTERVAL_WIDTH ? calcWidth : MIN_INTERVAL_WIDTH;\n setIntervalWidth(width);\n }\n };\n\n useResizeDetector({\n onResize: handleResize,\n targetRef: tableContainerRef,\n refreshMode: \"debounce\",\n refreshRate: 50,\n });\n\n const handleRowNameClick = (\n data: TimeTableRowData,\n event: React.MouseEvent\n ) => {\n if (data.onRowNameClick) {\n data.onRowNameClick(data, event);\n }\n };\n\n // ===========================================================================\n // HELPER FUNCTIONS\n // ===========================================================================\n /**\n * Using closures to more efficiently loop through and wrap the color sequencing instead of modding large numbers repeatedly\n * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures#closure\n */\n const getColorFromSequence = (() => {\n let colorIndex = 0;\n const colorSequenceLength = ROW_BAR_COLOR_SEQUENCE.length;\n\n return () => {\n const mainColor = ROW_BAR_COLOR_SEQUENCE[colorIndex];\n const alternateColor = ROW_BAR_COLOR_ALTERNATE_COLOR[colorIndex];\n colorIndex = (colorIndex + 1) % colorSequenceLength;\n return { mainColor, alternateColor };\n };\n })();\n\n const buildPopoverTrigger = (\n data: TimeTableRowData,\n child: JSX.Element\n ) => {\n if (!data.rowHeaderPopover) {\n return child;\n }\n\n const popoverTriggerProps: PopoverTriggerProps = {\n position: \"bottom-start\",\n customOffset: data.rowHeaderPopover.offset,\n children: child,\n trigger: data.rowHeaderPopover.trigger,\n delay: data.rowHeaderPopover.delay,\n popoverContent: data.rowHeaderPopover.content,\n };\n\n return (\n <PopoverTrigger\n {...popoverTriggerProps}\n className={styles.popoverTrigger}\n key={`${data.id}-popover-trigger`}\n zIndex={2}\n >\n {child}\n </PopoverTrigger>\n );\n };\n\n // Function to reset scroll to initialScrollTime\n const resetScroll = () => {\n if (\n initialScrollTime &&\n tableContainerRef.current &&\n intervalWidth > 0\n ) {\n const scrollPosition = TimeHelper.calculateScrollPosition({\n scrollTime: initialScrollTime,\n minTime: timetableMinTime,\n maxTime: timetableMaxTime,\n interval: ROW_INTERVAL,\n intervalWidth,\n options: {\n roundToInterval: roundInitialScrollTime,\n },\n });\n\n if (scrollPosition !== null) {\n tableContainerRef.current.scrollLeft = scrollPosition;\n }\n }\n };\n\n // =============================================================================\n // RENDER FUNCTIONS\n // =============================================================================\n const renderRowHeader = (data: TimeTableRowData) => {\n const rowHeaderContent = (\n <>\n <Typography.BodyMD\n className={clsx(\n styles.clickableRowHeaderTitle,\n !!data.onRowNameClick &&\n styles.clickableRowHeaderTitleClickable\n )}\n onClick={(event: React.MouseEvent) =>\n handleRowNameClick(data, event)\n }\n weight=\"semibold\"\n data-testid={`${data.id}-row-header-title`}\n >\n {data.name}\n </Typography.BodyMD>\n\n <Typography.BodyXS\n weight=\"bold\"\n className={clsx(\n styles.rowHeaderSubtitle,\n !data.subtitle && styles.rowHeaderSubtitleHidden\n )}\n data-testid={`${data.id}-row-header-subtitle`}\n >\n {data.subtitle}\n </Typography.BodyXS>\n </>\n );\n\n return (\n <div\n className={clsx(\n styles.rowHeader,\n isScrolledX && styles.rowHeaderScrolled\n )}\n key={`${data.id}-row-header`}\n role=\"rowheader\"\n aria-colindex={1}\n >\n {buildPopoverTrigger(data, rowHeaderContent)}\n </div>\n );\n };\n\n const renderColumnHeaders = () => {\n // Don't render first column if there are no rows\n\n return hourlyIntervals.map((columnHeader: string) => (\n <div\n className={styles.columnHeader}\n key={`${columnHeader}-column-key`}\n data-testid={`${columnHeader}-column`}\n >\n <Typography.BodySM\n className={styles.columnHeaderTitle}\n weight={\"semibold\"}\n >\n {columnHeader}\n </Typography.BodySM>\n </div>\n ));\n };\n\n const renderRows = () => {\n if (loading) {\n return (\n <LoadingDotsSpinner\n data-testid=\"timetable-loading-spinner\"\n className={clsx(\n styles.loadingSpinner,\n isEmptyContent\n ? styles.loadingSpinnerEmptyContent\n : styles.loadingSpinnerHasContent\n )}\n />\n );\n }\n\n return (\n <div\n className={styles.timeTableBody}\n data-testid=\"content-container-id\"\n ref={contentContainerRef}\n role=\"rowgroup\"\n >\n {rowData.map((data, index) => {\n return (\n <div\n className={styles.timeTableRow}\n key={`${index}-timetable-row`}\n role=\"row\"\n aria-rowindex={index + 2}\n aria-label={data.name}\n >\n {renderRowHeader(data)}\n <RowBar\n key={`${index}-row-bar`}\n timetableMinTime={timetableMinTime}\n timetableMaxTime={timetableMaxTime}\n rowBarColor={getColorFromSequence()}\n intervalWidth={intervalWidth}\n containerRef={contentContainerRef}\n {...data}\n />\n </div>\n );\n })}\n {renderLazyLoadRow()}\n </div>\n );\n };\n\n const renderLazyLoadRow = () => {\n if (loading || !loadMore) return;\n return (\n <div className={styles.timeTableRow}>\n <div\n className={clsx(\n styles.rowHeader,\n isScrolledX && styles.rowHeaderScrolled\n )}\n >\n <div className={styles.loadingBar} />\n </div>\n <div\n ref={loadingWrapperRef}\n className={styles.loadingWrapper}\n data-testid=\"lazy-loader\"\n role=\"presentation\"\n >\n {hourlyIntervals.map((_, index) => (\n <div\n className={styles.loadingCell}\n key={`lazy-load-cell-${index}`}\n >\n <div className={styles.loadingBar} />\n </div>\n ))}\n </div>\n </div>\n );\n };\n\n if (isEmptyContent) {\n return (\n <div {...otherProps} data-testid={testId}>\n <TimeTableHeader\n selectedDate={date}\n loading={loading || loadMore}\n tableContainerRef={tableContainerRef}\n minDate={minDate}\n maxDate={maxDate}\n totalRecords={totalRecords}\n showCurrentDateAsToday={showCurrentDateAsToday}\n showDateAsShortForm={showDateAsShortForm}\n onPreviousDayClick={onPreviousDayClick}\n onNextDayClick={onNextDayClick}\n onRefresh={onRefresh}\n onCalendarDateSelect={onCalendarDateSelect}\n />\n <div\n className={clsx(\n styles.emptyTableContainer,\n \"empty-container\"\n )}\n tabIndex={0}\n aria-live=\"polite\"\n aria-atomic\n aria-busy={loading}\n >\n {!loading ? (\n <ErrorDisplay\n className={styles.noResultsFound}\n type=\"no-item-found\"\n description={emptyContentMessage}\n />\n ) : (\n <>\n <VisuallyHidden>{`Loading ${timetableAriaLabel}`}</VisuallyHidden>\n <LoadingDotsSpinner\n data-testid=\"timetable-loading-spinner\"\n className={clsx(\n styles.loadingSpinner,\n isEmptyContent\n ? styles.loadingSpinnerEmptyContent\n : styles.loadingSpinnerHasContent\n )}\n />\n </>\n )}\n </div>\n </div>\n );\n }\n\n return (\n <div {...otherProps} data-testid={testId}>\n <TimeTableHeader\n data-id=\"timetable-date-navigator\"\n selectedDate={date}\n loading={loading || loadMore}\n tableContainerRef={tableContainerRef}\n minDate={minDate}\n maxDate={maxDate}\n totalRecords={totalRecords}\n showCurrentDateAsToday={showCurrentDateAsToday}\n showDateAsShortForm={showDateAsShortForm}\n onPreviousDayClick={onPreviousDayClick}\n onNextDayClick={onNextDayClick}\n onRefresh={onRefresh}\n onCalendarDateSelect={onCalendarDateSelect}\n />\n <div\n data-id=\"timetable-container\"\n data-testid=\"timetable-container\"\n ref={tableContainerRef}\n className={clsx(\n styles.timeTableContainer,\n hasLazyLoad && styles.timeTableContainerNotAllLoaded,\n loading && styles.timeTableContainerLoading\n )}\n role=\"grid\"\n aria-label={timetableAriaLabel}\n aria-rowcount={ariaRowCount}\n aria-colcount={ariaColCount}\n aria-busy={loadMore}\n tabIndex={0}\n >\n <div\n className={styles.timeTableHeaderRow}\n role=\"row\"\n aria-rowindex={1}\n data-testid={\"row-header-column-id\"}\n >\n <div\n className={clsx(\n styles.rowColumnHeader,\n (isScrolledX || isScrolledY) &&\n styles.rowColumnHeaderScrolled,\n isScrolledX && styles.rowColumnHeaderScrolledX,\n isScrolledY && styles.rowColumnHeaderScrolledY\n )}\n role=\"columnheader\"\n aria-colindex={1}\n >\n <VisuallyHidden>Resource</VisuallyHidden>\n </div>\n <div\n ref={columnHeaderRowRef}\n className={clsx(\n styles.columnHeaderRow,\n isScrolledY && styles.columnHeaderRowScrolled\n )}\n role=\"presentation\"\n >\n {renderColumnHeaders()}\n </div>\n </div>\n {renderRows()}\n </div>\n </div>\n );\n};\n\n// @catalog\n/**\n * A scrollable grid that visualises time slot availability across a day.\n *\n * Use `TimeTable` to display one day's schedule for multiple resources side by\n * side.\n */\nexport const TimeTable = forwardRef<TimeTableRef, TimeTableProps>(Component);\n"],"names":["TimeTable","forwardRef","props","ref","date","emptyContentMessage","rowData","loading","minTime","maxTime","initialScrollTime","minDate","maxDate","totalRecords","showCurrentDateAsToday","showDateAsShortForm","onPage","onRefresh","onNextDayClick","onPreviousDayClick","onCalendarDateSelect","roundInitialScrollTime","otherProps","testId","timetableMinTime","TimeHelper","roundToNearestInterval","timetableMaxTime","hourlyIntervals","generateHourlyIntervals","numberOfIntervals","Math","ceil","length","ROW_INTERVAL","timetableAriaLabel","dayjs","format","ariaRowCount","ariaColCount","isEmptyContent","isEmpty","allRecordsLoaded","hasLazyLoad","tableContainerRef","useRef","contentContainerRef","columnHeaderRowRef","loadingWrapperRef","isScrolledX","setIsScrolledX","useState","isScrolledY","setIsScrolledY","intervalWidth","setIntervalWidth","loadMore","setLoadMore","useImperativeHandle","resetScroll","useApplyStyle","styles.tokens","columnHeaderRow","columnWidth","loadingWrapper","cellWidth","useEffect","handleScroll","throttle","current","scrollLeft","scrollTop","clientHeight","scrollHeight","tableContainer","addEventListener","removeEventListener","useResizeDetector","onResize","numberOfIntervalsPerRowBar","calcWidth","clientWidth","ROW_HEADER_WIDTH","MIN_INTERVAL_WIDTH","targetRef","refreshMode","refreshRate","getColorFromSequence","colorIndex","colorSequenceLength","ROW_BAR_COLOR_SEQUENCE","mainColor","alternateColor","ROW_BAR_COLOR_ALTERNATE_COLOR","buildPopoverTrigger","data","child","rowHeaderPopover","popoverTriggerProps","position","customOffset","offset","children","trigger","delay","popoverContent","content","_createElement","PopoverTrigger","Object","assign","className","styles.popoverTrigger","key","id","zIndex","scrollPosition","calculateScrollPosition","scrollTime","interval","options","roundToInterval","renderRowHeader","rowHeaderContent","_jsxs","_Fragment","_jsx","Typography","BodyMD","clsx","styles.clickableRowHeaderTitle","onRowNameClick","styles.clickableRowHeaderTitleClickable","onClick","event","handleRowNameClick","weight","name","BodyXS","styles.rowHeaderSubtitle","subtitle","styles.rowHeaderSubtitleHidden","styles.rowHeader","styles.rowHeaderScrolled","role","renderLazyLoadRow","styles.timeTableRow","styles.loadingBar","styles.loadingWrapper","map","_","index","styles.loadingCell","TimeTableHeader","selectedDate","styles.emptyTableContainer","tabIndex","VisuallyHidden","LoadingDotsSpinner","styles.loadingSpinner","styles.loadingSpinnerEmptyContent","styles.loadingSpinnerHasContent","ErrorDisplay","styles.noResultsFound","type","description","styles.timeTableContainer","styles.timeTableContainerNotAllLoaded","styles.timeTableContainerLoading","styles.timeTableHeaderRow","styles.rowColumnHeader","styles.rowColumnHeaderScrolled","styles.rowColumnHeaderScrolledX","styles.rowColumnHeaderScrolledY","styles.columnHeaderRow","styles.columnHeaderRowScrolled","columnHeader","styles.columnHeader","BodySM","styles.columnHeaderTitle","styles.timeTableBody","RowBar","rowBarColor","containerRef"],"mappings":"ggFAgCA,MA+faA,GAAYC,GA/fP,CAACC,EAAuBC,MAItC,MAAMC,KACFA,GAAIC,oBACJA,GAAmBC,QACnBA,GAAOC,QACPA,GAAOC,QACPA,GAAU,QAAOC,QACjBA,GAAU,QAAOC,kBACjBA,GAAiBC,QACjBA,GAAOC,QACPA,GAAOC,aACPA,GAAYC,uBACZA,GAAsBC,oBACtBA,GAAmBC,OACnBA,GAAMC,UACNA,GAASC,eACTA,GAAcC,mBACdA,GAAkBC,qBAClBA,GAAoBC,uBACpBA,IAAyB,GAEzBnB,EADGoB,KACHpB,EApBE,CAAA,OAAA,sBAAA,UAAA,UAAA,UAAA,UAAA,oBAAA,UAAA,UAAA,eAAA,yBAAA,sBAAA,SAAA,YAAA,iBAAA,qBAAA,uBAAA,2BAqBAqB,GAASD,GAAW,gBAAkB,YACtCE,GAAmBC,EAAWC,uBAAuBlB,GAAS,IAC9DmB,GAAmBF,EAAWC,uBAChCjB,GACA,IACA,GAEEmB,GAAkBH,EAAWI,wBAC/BL,GACAG,IAEEG,GAAoBC,KAAKC,KACD,GAAzBJ,GAAgBK,OAAeC,GAG9BC,GAAqB,2CADLC,EAAMhC,IAAMiC,OAAO,wBACoDD,EACzFZ,GACA,SACFa,OAAO,YAAYD,EAAMT,GAAkB,SAASU,OAAO,QACvDC,IAAgBzB,IAAgBP,GAAQ2B,QAAU,EAClDM,GAAeT,GAAoB,EAEnCU,GAAkC,IAAjB3B,IAAsB4B,EAAAA,QAAQnC,IAC/CoC,GAAmBF,IAAkBlC,GAAQ2B,SAAWpB,GACxD8B,IAAeD,MAAsB1B,GACrC4B,GAAoBC,EAAuB,MAC3CC,GAAsBD,EAAuB,MAC7CE,GAAqBF,EAAuB,MAC5CG,GAAoBH,EAAuB,OAC1CI,GAAaC,IAAkBC,GAAkB,IACjDC,GAAaC,IAAkBF,GAAkB,IACjDG,GAAeC,IAAoBJ,EAAiB,IACpDK,GAAUC,IAAeN,GAAkB,GAGlDO,EAAoBvD,IAAK,KAAA,CACrBwD,mBAGJC,EAAcb,GAAoB,CAC9B,CAACc,EAAcC,gBAAgBC,aAAiC,EAAhBT,GAAH,OAGjDM,EAAcZ,GAAmB,CAC7B,CAACa,EAAcG,eAAeC,WAA+B,EAAhBX,GAAH,OAM9CY,GAAU,KACN,MAAMC,EAAeC,EAAAA,UAAS,KAM1B,GALIxB,GAAkByB,UAClBnB,GAAeN,GAAkByB,QAAQC,WAAa,GACtDjB,GAAeT,GAAkByB,QAAQE,UAAY,IAGrDf,KAAaZ,GAAkByB,QAAS,OAE5C,MAAME,UAAEA,EAASC,aAAEA,EAAYC,aAAEA,GAC7B7B,GAAkByB,QAGlBtC,KAAKC,KAAKuC,EAAYC,IACtBC,EAH0B,IAKT/B,IAAoB1B,KAAWT,KAGhDkD,IAAY,GACZzC,KACJ,GACD,KAEG0D,EAAiB9B,GAAkByB,QAMzC,OAJIK,GACAA,EAAeC,iBAAiB,SAAUR,GAGvC,KACCO,GACAA,EAAeE,oBAAoB,SAAUT,EACjD,CACH,GACF,CAACzB,GAAkBc,GAAUjD,GAASS,KAEzCkD,GAAU,KACNT,IAAY,EAAM,GACnB,CAACnD,KAGJ4D,GAAU,KACNP,IAAa,GACd,CAACjD,GAAmB4C,GAAe9B,GAAkBG,KA4BxDkD,EAAkB,CACdC,SAfiB,KACjB,GAAIlC,GAAkByB,QAAS,CAC3B,MAAMU,EAA6BhD,KAAKC,KACV,GAAzBJ,GAAgBK,OAAeC,GAI9B8C,GADFpC,GAAkByB,QAAQY,YAAcC,GACJH,EAGxCxB,GADIyB,EAAYG,EAAqBH,EAAYG,EAErD,GAKAC,UAAWxC,GACXyC,YAAa,WACbC,YAAa,KAGjB,MAgBMC,GAAuB,MACzB,IAAIC,EAAa,EACjB,MAAMC,EAAsBC,EAAuBzD,OAEnD,MAAO,KACH,MAAM0D,EAAYD,EAAuBF,GACnCI,EAAiBC,EAA8BL,GAErD,OADAA,GAAcA,EAAa,GAAKC,EACzB,CAAEE,YAAWC,iBAAgB,CAE3C,EAV4B,GAYvBE,GAAsB,CACxBC,EACAC,KAEA,IAAKD,EAAKE,iBACN,OAAOD,EAGX,MAAME,EAA2C,CAC7CC,SAAU,eACVC,aAAcL,EAAKE,iBAAiBI,OACpCC,SAAUN,EACVO,QAASR,EAAKE,iBAAiBM,QAC/BC,MAAOT,EAAKE,iBAAiBO,MAC7BC,eAAgBV,EAAKE,iBAAiBS,SAG1C,OACIC,EAACC,EAAcC,OAAAC,OAAA,CAAA,EACPZ,EAAmB,CACvBa,UAAWC,GACXC,IAAK,GAAGlB,EAAKmB,qBACbC,OAAQ,IAEPnB,EACY,EAKnBrC,GAAc,KAChB,GACIjD,IACAkC,GAAkByB,SAClBf,GAAgB,EAClB,CACE,MAAM8D,EAAiB3F,EAAW4F,wBAAwB,CACtDC,WAAY5G,GACZF,QAASgB,GACTf,QAASkB,GACT4F,SAAUrF,EACVoB,iBACAkE,QAAS,CACLC,gBAAiBpG,MAIF,OAAnB+F,IACAxE,GAAkByB,QAAQC,WAAa8C,EAE/C,GAMEM,GAAmB3B,IACrB,MAAM4B,EACFC,EAAAC,EAAA,CAAAvB,SAAA,CACIwB,EAACC,EAAWC,OAAM,CACdjB,UAAWkB,EACPC,IACEnC,EAAKoC,gBACHC,GAERC,QAAUC,GA7FC,EACvBvC,EACAuC,KAEIvC,EAAKoC,gBACLpC,EAAKoC,eAAepC,EAAMuC,EAC9B,EAwFgBC,CAAmBxC,EAAMuC,GAE7BE,OAAO,WAAU,cACJ,GAAGzC,EAAKmB,sBAAqBZ,SAEzCP,EAAK0C,OAGVX,EAACC,EAAWW,OAAM,CACdF,OAAO,OACPzB,UAAWkB,EACPU,GACC5C,EAAK6C,UAAYC,GACrB,cACY,GAAG9C,EAAKmB,yBAAwBZ,SAE5CP,EAAK6C,cAKlB,OACId,EAAA,MAAA,CACIf,UAAWkB,EACPa,EACA7F,IAAe8F,GAGnBC,KAAK,4BACU,EAAC1C,SAEfR,GAAoBC,EAAM4B,IAJtB,GAAG5B,EAAKmB,gBAKX,EAwER+B,GAAoB,KACtB,IAAI1I,IAAYiD,GAChB,OACIoE,EAAA,MAAA,CAAKb,UAAWmC,EAAmB5C,SAAA,CAC/BwB,EAAA,MAAA,CACIf,UAAWkB,EACPa,EACA7F,IAAe8F,GAClBzC,SAEDwB,EAAA,MAAA,CAAKf,UAAWoC,MAEpBrB,EAAA,MAAA,CACI3H,IAAK6C,GACL+D,UAAWqC,EAAqB,cACpB,cACZJ,KAAK,eAAc1C,SAElB1E,GAAgByH,KAAI,CAACC,EAAGC,IACrBzB,SACIf,UAAWyC,GAAkBlD,SAG7BwB,EAAA,MAAA,CAAKf,UAAWoC,KAFX,kBAAkBI,WAMjC,EAId,OAEQ3B,EAAA,MAFJpF,GAEIqE,OAAAC,OAAA,CAAA,EAASxF,GAAU,CAAA,cAAeC,GAAM+E,SAAA,CACpCwB,EAAC2B,GAAe,CACZC,aAActJ,GACdG,QAASA,IAAWiD,GACpBZ,kBAAmBA,GACnBjC,QAASA,GACTC,QAASA,GACTC,aAAcA,GACdC,uBAAwBA,GACxBC,oBAAqBA,GACrBI,mBAAoBA,GACpBD,eAAgBA,GAChBD,UAAWA,GACXG,qBAAsBA,KAE1B0G,EAAA,MAAA,CACIf,UAAWkB,EACP0B,EACA,mBAEJC,SAAU,EAAC,YACD,SAAQ,eAAA,EAAA,YAEPrJ,GAAO+F,SAEhB/F,GAOEqH,EAAAC,EAAA,CAAAvB,SAAA,CACIwB,EAAC+B,EAAc,CAAAvD,SAAE,WAAWnE,OAC5B2F,EAACgC,EAAkB,CAAA,cACH,4BACZ/C,UAAWkB,EACP8B,EACAvH,GACMwH,EACAC,QAdlBnC,EAACoC,EAAY,CACTnD,UAAWoD,EACXC,KAAK,gBACLC,YAAahK,UAsBjCwG,OAAAC,OAAA,CAAA,EAASxF,GAAU,CAAA,cAAeC,GAAM+E,SAAA,CACpCwB,EAAC2B,GAAe,CAAA,UACJ,2BACRC,aAActJ,GACdG,QAASA,IAAWiD,GACpBZ,kBAAmBA,GACnBjC,QAASA,GACTC,QAASA,GACTC,aAAcA,GACdC,uBAAwBA,GACxBC,oBAAqBA,GACrBI,mBAAoBA,GACpBD,eAAgBA,GAChBD,UAAWA,GACXG,qBAAsBA,KAE1BwG,EAAA,MAAA,CAAA,UACY,sBAAqB,cACjB,sBACZzH,IAAKyC,GACLmE,UAAWkB,EACPqC,EACA3H,IAAe4H,EACfhK,IAAWiK,GAEfxB,KAAK,OAAM,aACC7G,GAAkB,gBACfG,GAAY,gBACZC,GAAY,YAChBiB,GACXoG,SAAU,EAACtD,SAAA,CAEXsB,EAAA,MAAA,CACIb,UAAW0D,EACXzB,KAAK,MAAK,gBACK,EAAC,cACH,uBAAsB1C,SAAA,CAEnCwB,EAAA,MAAA,CACIf,UAAWkB,EACPyC,GACCzH,IAAeG,KACZuH,EACJ1H,IAAe2H,EACfxH,IAAeyH,GAEnB7B,KAAK,eAAc,gBACJ,EAAC1C,SAEhBwB,EAAC+B,EAAc,CAAAvD,SAAA,eAEnBwB,EAAA,MAAA,CACI3H,IAAK4C,GACLgE,UAAWkB,EACP6C,EACA1H,IAAe2H,GAEnB/B,KAAK,eAAc1C,SA9M5B1E,GAAgByH,KAAK2B,GACxBlD,SACIf,UAAWkE,gBAEE,GAAGD,WAAqB1E,SAErCwB,EAACC,EAAWmD,QACRnE,UAAWoE,EACX3C,OAAQ,WAAUlC,SAEjB0E,KAPA,GAAGA,uBAcZzK,GAEIuH,EAACgC,EAAkB,CAAA,cACH,4BACZ/C,UAAWkB,EACP8B,EACAvH,GACMwH,EACAC,KAOlBrC,EAAA,MAAA,CACIb,UAAWqE,EAAoB,cACnB,uBACZjL,IAAK2C,GACLkG,KAAK,WAAU1C,SAAA,CAEdhG,GAAQ+I,KAAI,CAACtD,EAAMwD,IAEZ3B,EAAA,MAAA,CACIb,UAAWmC,EAEXF,KAAK,MAAK,gBACKO,EAAQ,EAAC,aACZxD,EAAK0C,KAAInC,SAAA,CAEpBoB,GAAgB3B,GACjB+B,EAACuD,GAAMxE,OAAAC,OAAA,CAEHtF,iBAAkBA,GAClBG,iBAAkBA,GAClB2J,YAAa/F,KACbjC,cAAeA,GACfiI,aAAczI,IACViD,GANC,GAAGwD,eAPP,GAAGA,qBAkBnBN,cAyJH"}
|
package/toast/toast.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"toast.js","sources":["../../src/toast/toast.tsx"],"sourcesContent":["import {\n CrossIcon,\n ExclamationCircleFillIcon,\n ExclamationTriangleFillIcon,\n ICircleFillIcon,\n TickCircleFillIcon,\n} from \"@lifesg/react-icons\";\nimport { animated, easings, useSpring } from \"@react-spring/web\";\nimport clsx from \"clsx\";\nimport React, { useEffect, useRef, useState } from \"react\";\n\nimport { Button } from \"../button\";\nimport { inertValue, VisuallyHidden } from \"../shared/accessibility\";\nimport { ClickableIcon } from \"../shared/clickable-icon\";\nimport { useMaxWidthMediaQuery } from \"../theme\";\nimport { Typography } from \"../typography\";\nimport * as styles from \"./toast.styles\";\nimport type { ToastProps } from \"./types\";\n\nconst DEFAULT_AUTO_DISMISS_TIME = 4000;\nconst EASING_DURATION = 1000;\n\nconst TOAST_ICON_MAP = {\n success: TickCircleFillIcon,\n warning: ExclamationTriangleFillIcon,\n error: ExclamationCircleFillIcon,\n info: ICircleFillIcon,\n};\n\n/**\n * A brief notification that appears on screen to provide feedback about an\n * operation or event.\n *\n * Use `Toast` to surface status messages without interrupting the user's workflow.\n */\nexport const Toast = ({\n type = \"success\",\n title,\n label,\n className,\n autoDismiss,\n autoDismissTime = DEFAULT_AUTO_DISMISS_TIME,\n onDismiss,\n fixed = true,\n actionButton,\n ...otherProps\n}: ToastProps) => {\n // =============================================================================\n // CONST, STATE\n // =============================================================================\n const toastRef = useRef<HTMLDivElement>(null);\n const [isVisible, setVisible] = useState<boolean>(false);\n\n const isMobile = useMaxWidthMediaQuery(\"lg\");\n\n // =============================================================================\n // EFFECTS\n // =============================================================================\n useEffect(() => {\n setVisible(true);\n }, []);\n\n useEffect(() => {\n if (!autoDismiss) return;\n\n const timeout = setTimeout(() => {\n setVisible(false);\n }, autoDismissTime);\n\n return () => clearTimeout(timeout);\n }, [autoDismiss, autoDismissTime]);\n\n useEffect(() => {\n const handleKeyDown = (event: KeyboardEvent) => {\n if (\n event.key === \"Escape\" &&\n toastRef.current?.contains(document.activeElement)\n ) {\n handleDismiss();\n }\n };\n\n document.addEventListener(\"keydown\", handleKeyDown);\n return () => {\n document.removeEventListener(\"keydown\", handleKeyDown);\n };\n }, []);\n\n // =============================================================================\n // EVENT HANDLERS\n // =============================================================================\n const handleDismiss = () => {\n setVisible(false);\n };\n\n // =============================================================================\n // HELPER FUNCTIONS\n // =============================================================================\n const transitions = useSpring({\n opacity: isVisible ? 1 : 0,\n transform: isVisible\n ? isMobile\n ? `translateY(0%)`\n : `translateX(0%)`\n : isMobile\n ? `translateY(-1500%)`\n : `translateX(150%)`,\n config: {\n easing: easings.easeInOutQuart,\n duration: EASING_DURATION,\n },\n onRest: () => {\n if (!isVisible) onDismiss?.();\n },\n });\n\n // =============================================================================\n // RENDER FUNCTIONS\n // =============================================================================\n const renderIcon = () => {\n const Icon = TOAST_ICON_MAP[type];\n return Icon && <Icon aria-hidden />;\n };\n\n const renderTitle = () => {\n if (React.isValidElement(title)) {\n return title;\n } else {\n return (\n <h2 className={styles.title} role=\"presentation\">\n {title}\n </h2>\n );\n }\n };\n\n const renderDesc = () => {\n if (React.isValidElement(label)) {\n return label;\n } else if (title) {\n return (\n <Typography.BodyMD className={styles.description}>\n {label}\n </Typography.BodyMD>\n );\n } else {\n return (\n <Typography.BodyBL className={styles.description}>\n {label}\n </Typography.BodyBL>\n );\n }\n };\n\n return (\n <animated.div\n ref={toastRef}\n style={transitions}\n className={clsx(styles.wrapper, className)}\n data-type={type}\n data-fixed={fixed}\n role=\"alert\"\n inert={inertValue(!isVisible)}\n {...otherProps}\n >\n <VisuallyHidden>{type}</VisuallyHidden>\n <div className={styles.contentWrapper}>\n <div className={styles.textIconWrapper} data-type={type}>\n {renderIcon()}\n <div className={styles.textContainer}>\n {title && renderTitle()}\n {label && renderDesc()}\n </div>\n </div>\n\n {actionButton && (\n <Button\n className={styles.actionButton}\n styleType=\"light\"\n onClick={actionButton.onClick}\n sizeType=\"small\"\n >\n {actionButton.label}\n </Button>\n )}\n </div>\n <ClickableIcon\n className={styles.dismissButton}\n onClick={handleDismiss}\n >\n <VisuallyHidden role=\"presentation\">\n Close notification\n </VisuallyHidden>\n <CrossIcon aria-hidden />\n </ClickableIcon>\n </animated.div>\n );\n};\n"],"names":["DEFAULT_AUTO_DISMISS_TIME","TOAST_ICON_MAP","success","TickCircleFillIcon","warning","ExclamationTriangleFillIcon","error","ExclamationCircleFillIcon","info","ICircleFillIcon","Toast","_a","type","title","label","className","autoDismiss","autoDismissTime","onDismiss","fixed","actionButton","otherProps","__rest","toastRef","useRef","isVisible","setVisible","useState","isMobile","useMaxWidthMediaQuery","useEffect","timeout","setTimeout","clearTimeout","handleKeyDown","event","key","current","contains","document","activeElement","handleDismiss","addEventListener","removeEventListener","transitions","useSpring","opacity","transform","config","easing","easings","easeInOutQuart","duration","onRest","_jsxs","animated","div","Object","assign","ref","style","clsx","styles.wrapper","role","inert","inertValue","children","_jsx","VisuallyHidden","styles.contentWrapper","styles.textIconWrapper","Icon","renderIcon","styles.textContainer","React","isValidElement","styles.title","Typography","BodyMD","BodyBL","styles.description","Button","styles.actionButton","styleType","onClick","sizeType","ClickableIcon","styles.dismissButton","CrossIcon"],"mappings":"+xCAmBA,MAAMA,EAA4B,IAG5BC,EAAiB,CACnBC,QAASC,EACTC,QAASC,EACTC,MAAOC,EACPC,KAAMC,
|
|
1
|
+
{"version":3,"file":"toast.js","sources":["../../src/toast/toast.tsx"],"sourcesContent":["import {\n CrossIcon,\n ExclamationCircleFillIcon,\n ExclamationTriangleFillIcon,\n ICircleFillIcon,\n TickCircleFillIcon,\n} from \"@lifesg/react-icons\";\nimport { animated, easings, useSpring } from \"@react-spring/web\";\nimport clsx from \"clsx\";\nimport React, { useEffect, useRef, useState } from \"react\";\n\nimport { Button } from \"../button\";\nimport { inertValue, VisuallyHidden } from \"../shared/accessibility\";\nimport { ClickableIcon } from \"../shared/clickable-icon\";\nimport { useMaxWidthMediaQuery } from \"../theme\";\nimport { Typography } from \"../typography\";\nimport * as styles from \"./toast.styles\";\nimport type { ToastProps } from \"./types\";\n\nconst DEFAULT_AUTO_DISMISS_TIME = 4000;\nconst EASING_DURATION = 1000;\n\nconst TOAST_ICON_MAP = {\n success: TickCircleFillIcon,\n warning: ExclamationTriangleFillIcon,\n error: ExclamationCircleFillIcon,\n info: ICircleFillIcon,\n};\n\n// @catalog\n/**\n * A brief notification that appears on screen to provide feedback about an\n * operation or event.\n *\n * Use `Toast` to surface status messages without interrupting the user's workflow.\n */\nexport const Toast = ({\n type = \"success\",\n title,\n label,\n className,\n autoDismiss,\n autoDismissTime = DEFAULT_AUTO_DISMISS_TIME,\n onDismiss,\n fixed = true,\n actionButton,\n ...otherProps\n}: ToastProps) => {\n // =============================================================================\n // CONST, STATE\n // =============================================================================\n const toastRef = useRef<HTMLDivElement>(null);\n const [isVisible, setVisible] = useState<boolean>(false);\n\n const isMobile = useMaxWidthMediaQuery(\"lg\");\n\n // =============================================================================\n // EFFECTS\n // =============================================================================\n useEffect(() => {\n setVisible(true);\n }, []);\n\n useEffect(() => {\n if (!autoDismiss) return;\n\n const timeout = setTimeout(() => {\n setVisible(false);\n }, autoDismissTime);\n\n return () => clearTimeout(timeout);\n }, [autoDismiss, autoDismissTime]);\n\n useEffect(() => {\n const handleKeyDown = (event: KeyboardEvent) => {\n if (\n event.key === \"Escape\" &&\n toastRef.current?.contains(document.activeElement)\n ) {\n handleDismiss();\n }\n };\n\n document.addEventListener(\"keydown\", handleKeyDown);\n return () => {\n document.removeEventListener(\"keydown\", handleKeyDown);\n };\n }, []);\n\n // =============================================================================\n // EVENT HANDLERS\n // =============================================================================\n const handleDismiss = () => {\n setVisible(false);\n };\n\n // =============================================================================\n // HELPER FUNCTIONS\n // =============================================================================\n const transitions = useSpring({\n opacity: isVisible ? 1 : 0,\n transform: isVisible\n ? isMobile\n ? `translateY(0%)`\n : `translateX(0%)`\n : isMobile\n ? `translateY(-1500%)`\n : `translateX(150%)`,\n config: {\n easing: easings.easeInOutQuart,\n duration: EASING_DURATION,\n },\n onRest: () => {\n if (!isVisible) onDismiss?.();\n },\n });\n\n // =============================================================================\n // RENDER FUNCTIONS\n // =============================================================================\n const renderIcon = () => {\n const Icon = TOAST_ICON_MAP[type];\n return Icon && <Icon aria-hidden />;\n };\n\n const renderTitle = () => {\n if (React.isValidElement(title)) {\n return title;\n } else {\n return (\n <h2 className={styles.title} role=\"presentation\">\n {title}\n </h2>\n );\n }\n };\n\n const renderDesc = () => {\n if (React.isValidElement(label)) {\n return label;\n } else if (title) {\n return (\n <Typography.BodyMD className={styles.description}>\n {label}\n </Typography.BodyMD>\n );\n } else {\n return (\n <Typography.BodyBL className={styles.description}>\n {label}\n </Typography.BodyBL>\n );\n }\n };\n\n return (\n <animated.div\n ref={toastRef}\n style={transitions}\n className={clsx(styles.wrapper, className)}\n data-type={type}\n data-fixed={fixed}\n role=\"alert\"\n inert={inertValue(!isVisible)}\n {...otherProps}\n >\n <VisuallyHidden>{type}</VisuallyHidden>\n <div className={styles.contentWrapper}>\n <div className={styles.textIconWrapper} data-type={type}>\n {renderIcon()}\n <div className={styles.textContainer}>\n {title && renderTitle()}\n {label && renderDesc()}\n </div>\n </div>\n\n {actionButton && (\n <Button\n className={styles.actionButton}\n styleType=\"light\"\n onClick={actionButton.onClick}\n sizeType=\"small\"\n >\n {actionButton.label}\n </Button>\n )}\n </div>\n <ClickableIcon\n className={styles.dismissButton}\n onClick={handleDismiss}\n >\n <VisuallyHidden role=\"presentation\">\n Close notification\n </VisuallyHidden>\n <CrossIcon aria-hidden />\n </ClickableIcon>\n </animated.div>\n );\n};\n"],"names":["DEFAULT_AUTO_DISMISS_TIME","TOAST_ICON_MAP","success","TickCircleFillIcon","warning","ExclamationTriangleFillIcon","error","ExclamationCircleFillIcon","info","ICircleFillIcon","Toast","_a","type","title","label","className","autoDismiss","autoDismissTime","onDismiss","fixed","actionButton","otherProps","__rest","toastRef","useRef","isVisible","setVisible","useState","isMobile","useMaxWidthMediaQuery","useEffect","timeout","setTimeout","clearTimeout","handleKeyDown","event","key","current","contains","document","activeElement","handleDismiss","addEventListener","removeEventListener","transitions","useSpring","opacity","transform","config","easing","easings","easeInOutQuart","duration","onRest","_jsxs","animated","div","Object","assign","ref","style","clsx","styles.wrapper","role","inert","inertValue","children","_jsx","VisuallyHidden","styles.contentWrapper","styles.textIconWrapper","Icon","renderIcon","styles.textContainer","React","isValidElement","styles.title","Typography","BodyMD","BodyBL","styles.description","Button","styles.actionButton","styleType","onClick","sizeType","ClickableIcon","styles.dismissButton","CrossIcon"],"mappings":"+xCAmBA,MAAMA,EAA4B,IAG5BC,EAAiB,CACnBC,QAASC,EACTC,QAASC,EACTC,MAAOC,EACPC,KAAMC,GAUGC,EAASC,IAAA,IAAAC,KAClBA,EAAO,gBACPC,EAAKC,MACLA,EAAKC,UACLA,EAASC,YACTA,EAAWC,gBACXA,EAAkBjB,EAAyBkB,UAC3CA,EAASC,MACTA,GAAQ,EAAIC,aACZA,GAAYT,EACTU,EAAUC,EAAAX,EAVK,CAAA,OAAA,QAAA,QAAA,YAAA,cAAA,kBAAA,YAAA,QAAA,iBAelB,MAAMY,EAAWC,EAAuB,OACjCC,EAAWC,GAAcC,GAAkB,GAE5CC,EAAWC,EAAsB,MAKvCC,GAAU,KACNJ,GAAW,EAAK,GACjB,IAEHI,GAAU,KACN,IAAKd,EAAa,OAElB,MAAMe,EAAUC,YAAW,KACvBN,GAAW,EAAM,GAClBT,GAEH,MAAO,IAAMgB,aAAaF,EAAQ,GACnC,CAACf,EAAaC,IAEjBa,GAAU,KACN,MAAMI,EAAiBC,UAED,WAAdA,EAAMC,MACU,QAAhBzB,EAAAY,EAASc,eAAO,IAAA1B,OAAA,EAAAA,EAAE2B,SAASC,SAASC,iBAEpCC,GACJ,EAIJ,OADAF,SAASG,iBAAiB,UAAWR,GAC9B,KACHK,SAASI,oBAAoB,UAAWT,EAAc,CACzD,GACF,IAKH,MAAMO,EAAgB,KAClBf,GAAW,EAAM,EAMfkB,EAAcC,EAAU,CAC1BC,QAASrB,EAAY,EAAI,EACzBsB,UAAWtB,EACLG,EACI,iBACA,iBACJA,EACA,qBACA,mBACNoB,OAAQ,CACJC,OAAQC,EAAQC,eAChBC,SA1FY,KA4FhBC,OAAQ,KACC5B,GAAWP,SAAAA,GAAa,IA0CrC,OACIoC,EAACC,EAASC,IAAGC,OAAAC,OAAA,CACTC,IAAKpC,EACLqC,MAAOhB,EACP7B,UAAW8C,EAAKC,EAAgB/C,GAAU,YAC/BH,EAAI,aACHO,EACZ4C,KAAK,QACLC,MAAOC,GAAYxC,IACfJ,EAAU,CAAA6C,SAAA,CAEdC,EAACC,EAAc,CAAAF,SAAEtD,IACjB0C,EAAA,MAAA,CAAKvC,UAAWsD,EAAqBH,SAAA,CACjCZ,EAAA,MAAA,CAAKvC,UAAWuD,EAAsB,YAAa1D,EAAIsD,SAAA,CAhDhD,MACf,MAAMK,EAAOtE,EAAeW,GAC5B,OAAO2D,GAAQJ,EAACI,qBAAmB,EA+CtBC,GACDlB,EAAA,MAAA,CAAKvC,UAAW0D,EAAoBP,SAAA,CAC/BrD,IA7Cb6D,EAAMC,eAAe9D,GACdA,EAGHsD,EAAA,KAAA,CAAIpD,UAAW6D,EAAcb,KAAK,eAAcG,SAC3CrD,KAyCIC,IAlCb4D,EAAMC,eAAe7D,GACdA,EAGHqD,EAFGtD,EAEFgE,EAAWC,OAMXD,EAAWE,OANM,CAAChE,UAAWiE,EAAkBd,SAC3CpD,WAiCJM,GACG+C,EAACc,EAAM,CACHlE,UAAWmE,EACXC,UAAU,QACVC,QAAShE,EAAagE,QACtBC,SAAS,QAAOnB,SAEf9C,EAAaN,WAI1BwC,EAACgC,GACGvE,UAAWwE,EACXH,QAAS3C,EAAayB,SAAA,CAEtBC,EAACC,EAAc,CAACL,KAAK,eAAcG,SAAA,uBAGnCC,EAACqB,EAAS,CAAA,eAAA,UAEH"}
|
package/toast/types.d.ts
CHANGED
|
@@ -8,7 +8,9 @@ export type ToastType = "success" | "warning" | "error" | "info";
|
|
|
8
8
|
* Configuration for the optional action button rendered inside a `Toast`.
|
|
9
9
|
*/
|
|
10
10
|
export interface ToastActionButtonProps {
|
|
11
|
+
/** The label of the action button */
|
|
11
12
|
label: string;
|
|
13
|
+
/** Called when the action button is clicked */
|
|
12
14
|
onClick: () => void;
|
|
13
15
|
}
|
|
14
16
|
/**
|
package/toggle/toggle.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"toggle.js","sources":["../../src/toggle/toggle.tsx"],"sourcesContent":["import { ChevronDownIcon } from \"@lifesg/react-icons/chevron-down\";\nimport { ChevronUpIcon } from \"@lifesg/react-icons/chevron-up\";\nimport clsx from \"clsx\";\nimport { useEffect, useMemo, useRef, useState } from \"react\";\n\nimport { Alert } from \"../alert\";\nimport { Markup } from \"../markup\";\nimport { TextList } from \"../text-list\";\nimport { useApplyStyle } from \"../theme\";\nimport { Typography } from \"../typography\";\nimport { useId } from \"../util\";\nimport * as styles from \"./toggle.styles\";\nimport type { ToggleIconType } from \"./toggle-icon\";\nimport { ToggleIcon } from \"./toggle-icon\";\nimport type { ToggleProps } from \"./types\";\n\n/**\n * A selectable control for checkbox and radio interaction patterns.\n *\n * Use `Toggle` to present a labeled option that the user can select or\n * deselect.\n */\nexport const Toggle = ({\n type = \"checkbox\",\n indicator,\n checked,\n styleType = \"default\",\n children,\n childrenMaxLines,\n subLabel,\n disabled,\n error,\n name,\n id,\n className,\n compositeSection,\n removable,\n focusableWhenDisabled,\n useContentWidth,\n onRemove,\n onChange,\n \"data-testid\": testId,\n \"aria-describedby\": ariaDescribedBy,\n ...otherProps\n}: ToggleProps) => {\n // =============================================================================\n // CONST, STATE, REF\n // =============================================================================\n const {\n collapsible = true,\n errors,\n children: compositeSectionChildren,\n initialExpanded,\n } = compositeSection || {};\n const [selected, setSelected] = useState<boolean | undefined>(checked);\n const [expanded, setExpanded] = useState<boolean>(!!initialExpanded);\n const hasCompositeSectionError = useMemo(() => {\n const hasErrorList = Array.isArray(errors) && errors?.length > 0;\n const hasErrorElement = !Array.isArray(errors) && !!errors;\n return hasErrorList || hasErrorElement;\n }, [errors]);\n const uniqueId = useId();\n const generatedId = id ? `${id}` : `tg-${uniqueId}`;\n\n const inputRef = useRef<HTMLInputElement>(null);\n const labelRef = useRef<HTMLLabelElement>(null);\n\n useApplyStyle(labelRef, {\n [styles.tokens.label.desktopLineClamp]:\n childrenMaxLines?.desktop == null\n ? null\n : `${childrenMaxLines.desktop}`,\n [styles.tokens.label.tabletLineClamp]:\n childrenMaxLines?.tablet == null\n ? null\n : `${childrenMaxLines.tablet}`,\n [styles.tokens.label.mobileLineClamp]:\n childrenMaxLines?.mobile == null\n ? null\n : `${childrenMaxLines.mobile}`,\n });\n\n const isFocusableWhenDisabled = !!disabled && !!focusableWhenDisabled;\n const isNativeDisabled = !!disabled && !focusableWhenDisabled;\n const isInteractionBlocked = !!disabled;\n\n // =============================================================================\n // EFFECTS\n // =============================================================================\n useEffect(() => {\n setSelected(checked);\n }, [checked]);\n\n useEffect(() => {\n if (selected) {\n setExpanded(initialExpanded ?? true);\n }\n }, [selected]);\n\n // =============================================================================\n // EVENT HANDLERS\n // =============================================================================\n const handleOnChange = (event: React.ChangeEvent<HTMLInputElement>) => {\n if (isInteractionBlocked) {\n event.preventDefault();\n return;\n }\n\n if (onChange) {\n onChange(event);\n return;\n }\n\n switch (type) {\n case \"checkbox\":\n setSelected((prevSelected) => {\n return !prevSelected;\n });\n break;\n case \"radio\":\n case \"yes\":\n case \"no\":\n if (!selected) {\n setSelected(true);\n }\n break;\n }\n };\n\n const handleExpandCollapseClick = () => {\n if (!disabled) {\n setExpanded(!expanded);\n }\n };\n\n const handleOnRemove = () => {\n if (!disabled) {\n if (onRemove) {\n onRemove();\n return;\n }\n }\n };\n\n const handleContainerClick = () => {\n inputRef?.current?.click();\n };\n\n const handleInputClick = (e: React.MouseEvent<HTMLInputElement>) => {\n e.stopPropagation();\n };\n\n // =============================================================================\n // HELPER FUNCTIONS\n // =============================================================================\n\n const getContainerStateClass = () => {\n if (styleType === \"no-border\") {\n if (error) {\n return clsx(\n styles.colorBorderError,\n !disabled && styles.toggleContainerError\n );\n }\n\n if (disabled) {\n return selected\n ? styles.toggleContainerNoBorderDisabledSelected\n : styles.toggleContainerNoBorderDisabled;\n }\n\n if (selected) {\n return styles.toggleContainerNoBorderSelected;\n }\n\n return styles.toggleContainerNoBorder;\n }\n\n if (error) {\n return disabled\n ? styles.colorBorderError\n : styles.toggleContainerError;\n }\n\n if (disabled) {\n return selected\n ? styles.toggleContainerDisabledSelected\n : styles.toggleContainerDisabled;\n }\n\n if (selected) {\n return styles.toggleContainerSelected;\n }\n\n return styles.toggleContainer;\n };\n\n const getContainerHoverClass = () => {\n if (disabled) {\n return undefined;\n }\n\n if (!error && selected) {\n return styles.toggleContainerHoverSelected;\n }\n\n return styles.toggleContainerHoverDefault;\n };\n\n const getTextContainerStateClass = () => {\n if (disabled) {\n return selected\n ? styles.toggleTextContainerDisabledSelected\n : styles.colorTextDisabled;\n }\n\n if (selected) {\n return styles.toggleTextContainerSelected;\n }\n };\n\n // =============================================================================\n // RENDER FUNCTIONS\n // =============================================================================\n const renderIndicator = () => {\n let toggleIconType: ToggleIconType;\n\n switch (type) {\n case \"yes\":\n toggleIconType = \"tick\";\n break;\n case \"no\":\n toggleIconType = \"cross\";\n break;\n case \"checkbox\":\n case \"radio\":\n toggleIconType = type;\n break;\n }\n\n return (\n <ToggleIcon\n type={toggleIconType}\n active={selected}\n disabled={disabled}\n />\n );\n };\n\n const renderSubLabel = () => {\n if (!subLabel) {\n return null;\n }\n\n let component: string | JSX.Element;\n\n if (typeof subLabel === \"function\") {\n component = subLabel();\n } else {\n component = subLabel;\n }\n\n // Hide sublabel from screen readers as the main input already has aria-describedby that points to the sublabel\n return (\n <div\n data-id=\"toggle-sublabel\"\n id={`${generatedId}-sublabel`}\n aria-hidden\n className={styles.subLabel}\n >\n {component}\n </div>\n );\n };\n\n const renderCompositeChildren = () => {\n return (\n (!collapsible || expanded) && (\n <div\n data-id=\"toggle-composite-children\"\n className={clsx(\n styles.children,\n !collapsible && styles.childrenIsFinalItem,\n disabled && styles.colorTextDisabled\n )}\n >\n <Markup baseTextSize=\"body-md\">\n {compositeSectionChildren}\n </Markup>\n </div>\n )\n );\n };\n\n const renderExpandButton = () => {\n const collapsedWithoutErrors = !expanded && !hasCompositeSectionError;\n\n return (\n collapsible && (\n <button\n className={clsx(\n styles.expandButton,\n disabled && styles.disabledColorCursor,\n collapsedWithoutErrors &&\n styles.expandButtonPaddingTopRequired\n )}\n disabled={disabled}\n onClick={handleExpandCollapseClick}\n data-testid={expanded ? \"collapse-button\" : \"expand-button\"}\n >\n {expanded ? \"Show less\" : \"Show more\"}\n {expanded ? (\n <ChevronUpIcon aria-hidden />\n ) : (\n <ChevronDownIcon aria-hidden />\n )}\n </button>\n )\n );\n };\n\n const renderToggleWithRemoveButton = () => {\n const ariaDescriptions =\n [\n typeof subLabel === \"string\" ? `${generatedId}-sublabel` : null,\n ariaDescribedBy,\n ]\n .filter(Boolean)\n .join(\" \") || undefined;\n\n return (\n <div\n id={`${generatedId}-header-container`}\n className={styles.headerContainer}\n >\n <div\n className={clsx(\n styles.indicatorLabelContainer,\n removable && styles.indicatorLabelContainerAddPadding\n )}\n >\n <div\n id={`${generatedId}-input-container`}\n onClick={handleContainerClick}\n className={styles.inputContainer}\n >\n <input\n ref={inputRef}\n name={name}\n id={`${generatedId}-input`}\n type={type === \"checkbox\" ? \"checkbox\" : \"radio\"}\n data-testid=\"toggle-input\"\n className={clsx(\n styles.input,\n disabled && styles.toggleInputDisabled\n )}\n disabled={isNativeDisabled}\n aria-disabled={isFocusableWhenDisabled}\n onChange={handleOnChange}\n onClick={handleInputClick}\n checked={selected}\n tabIndex={isFocusableWhenDisabled ? 0 : undefined}\n aria-describedby={ariaDescriptions}\n {...otherProps}\n />\n {indicator && renderIndicator()}\n <div\n className={clsx(\n styles.textContainer,\n getTextContainerStateClass()\n )}\n >\n <label\n ref={labelRef}\n htmlFor={`${generatedId}-input`}\n data-testid={`toggle-label`}\n id={`${generatedId}-label`}\n className={clsx(\n styles.label,\n selected\n ? styles.toggleLabelSelected\n : styles.toggleLabelDefault\n )}\n >\n {children}\n </label>\n {subLabel && renderSubLabel()}\n </div>\n </div>\n </div>\n {removable && (\n <button\n type=\"button\"\n className={clsx(\n styles.removeButton,\n disabled && styles.disabledColorCursor\n )}\n onClick={handleOnRemove}\n id={`${generatedId}-remove-button`}\n >\n Remove\n </button>\n )}\n </div>\n );\n };\n\n const renderErrorList = (errors: string[]) => {\n return (\n <>\n <Typography.BodyMD\n weight=\"semibold\"\n className={clsx(\n styles.colorTextError,\n disabled && styles.colorTextDisabled\n )}\n >\n Error\n </Typography.BodyMD>\n <TextList.Ul\n className={clsx(\n styles.colorTextError,\n disabled && styles.colorTextDisabled\n )}\n >\n {errors?.map((item, index) => {\n return (\n <li\n key={index}\n id={`${generatedId}-error-list-item-${index}`}\n >\n <Typography.BodyMD\n weight=\"semibold\"\n className={clsx(\n styles.colorTextError,\n disabled && styles.colorTextDisabled\n )}\n >\n {item}\n </Typography.BodyMD>\n </li>\n );\n })}\n </TextList.Ul>\n </>\n );\n };\n\n const renderError = () => {\n return (\n collapsible &&\n !expanded &&\n hasCompositeSectionError && (\n <div\n className={clsx(\n styles.errorContainer,\n disabled && styles.disabledColorCursor\n )}\n onClick={handleExpandCollapseClick}\n id={`${generatedId}-error-alert`}\n >\n <Alert\n type={disabled ? \"description\" : \"error\"}\n className={styles.alertContainer}\n showIcon\n >\n {Array.isArray(errors)\n ? renderErrorList(errors)\n : errors}\n </Alert>\n </div>\n )\n );\n };\n\n const renderCompositeSection = () => {\n return (\n compositeSectionChildren && (\n <div>\n {renderCompositeChildren()}\n {renderError()}\n {renderExpandButton()}\n </div>\n )\n );\n };\n\n return (\n <div\n className={clsx(\n styles.container,\n getContainerStateClass(),\n getContainerHoverClass(),\n !indicator && styles.noIndicatorContainer,\n useContentWidth && styles.useContentWidthContainer,\n className\n )}\n id={id}\n data-testid={testId}\n >\n {renderToggleWithRemoveButton()}\n {renderCompositeSection()}\n </div>\n );\n};\n"],"names":["Toggle","_a","type","indicator","checked","styleType","children","childrenMaxLines","subLabel","disabled","error","name","id","className","compositeSection","removable","focusableWhenDisabled","useContentWidth","onRemove","onChange","testId","ariaDescribedBy","otherProps","__rest","collapsible","errors","compositeSectionChildren","initialExpanded","selected","setSelected","useState","expanded","setExpanded","hasCompositeSectionError","useMemo","hasErrorList","Array","isArray","length","hasErrorElement","uniqueId","useId","generatedId","inputRef","useRef","labelRef","useApplyStyle","styles.tokens","label","desktopLineClamp","desktop","tabletLineClamp","tablet","mobileLineClamp","mobile","isFocusableWhenDisabled","isNativeDisabled","isInteractionBlocked","useEffect","handleOnChange","event","preventDefault","prevSelected","handleExpandCollapseClick","handleOnRemove","handleContainerClick","current","click","handleInputClick","e","stopPropagation","renderIndicator","toggleIconType","_jsx","ToggleIcon","active","renderSubLabel","component","styles.subLabel","renderErrorList","_jsxs","_Fragment","Typography","BodyMD","weight","clsx","styles.colorTextError","styles.colorTextDisabled","TextList","Ul","map","item","index","styles.container","styles.colorBorderError","styles.toggleContainerError","styles.toggleContainerNoBorderDisabledSelected","styles.toggleContainerNoBorderDisabled","styles.toggleContainerNoBorderSelected","styles.toggleContainerNoBorder","styles.toggleContainerDisabledSelected","styles.toggleContainerDisabled","styles.toggleContainerSelected","styles.toggleContainer","styles.toggleContainerHoverSelected","styles.toggleContainerHoverDefault","getContainerHoverClass","styles.noIndicatorContainer","styles.useContentWidthContainer","ariaDescriptions","filter","Boolean","join","undefined","styles.headerContainer","styles.indicatorLabelContainer","styles.indicatorLabelContainerAddPadding","onClick","styles.inputContainer","ref","styles.input","styles.toggleInputDisabled","tabIndex","styles.textContainer","styles.toggleTextContainerDisabledSelected","styles.toggleTextContainerSelected","htmlFor","styles.label","styles.toggleLabelSelected","styles.toggleLabelDefault","styles.removeButton","styles.disabledColorCursor","renderToggleWithRemoveButton","styles.children","styles.childrenIsFinalItem","Markup","baseTextSize","styles.errorContainer","Alert","styles.alertContainer","showIcon","styles.expandButton","styles.expandButtonPaddingTopRequired","ChevronUpIcon","ChevronDownIcon"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"toggle.js","sources":["../../src/toggle/toggle.tsx"],"sourcesContent":["import { ChevronDownIcon } from \"@lifesg/react-icons/chevron-down\";\nimport { ChevronUpIcon } from \"@lifesg/react-icons/chevron-up\";\nimport clsx from \"clsx\";\nimport { useEffect, useMemo, useRef, useState } from \"react\";\n\nimport { Alert } from \"../alert\";\nimport { Markup } from \"../markup\";\nimport { TextList } from \"../text-list\";\nimport { useApplyStyle } from \"../theme\";\nimport { Typography } from \"../typography\";\nimport { useId } from \"../util\";\nimport * as styles from \"./toggle.styles\";\nimport type { ToggleIconType } from \"./toggle-icon\";\nimport { ToggleIcon } from \"./toggle-icon\";\nimport type { ToggleProps } from \"./types\";\n\n// @catalog\n/**\n * A selectable control for checkbox and radio interaction patterns.\n *\n * Use `Toggle` to present a labeled option that the user can select or\n * deselect.\n */\nexport const Toggle = ({\n type = \"checkbox\",\n indicator,\n checked,\n styleType = \"default\",\n children,\n childrenMaxLines,\n subLabel,\n disabled,\n error,\n name,\n id,\n className,\n compositeSection,\n removable,\n focusableWhenDisabled,\n useContentWidth,\n onRemove,\n onChange,\n \"data-testid\": testId,\n \"aria-describedby\": ariaDescribedBy,\n ...otherProps\n}: ToggleProps) => {\n // =============================================================================\n // CONST, STATE, REF\n // =============================================================================\n const {\n collapsible = true,\n errors,\n children: compositeSectionChildren,\n initialExpanded,\n } = compositeSection || {};\n const [selected, setSelected] = useState<boolean | undefined>(checked);\n const [expanded, setExpanded] = useState<boolean>(!!initialExpanded);\n const hasCompositeSectionError = useMemo(() => {\n const hasErrorList = Array.isArray(errors) && errors?.length > 0;\n const hasErrorElement = !Array.isArray(errors) && !!errors;\n return hasErrorList || hasErrorElement;\n }, [errors]);\n const uniqueId = useId();\n const generatedId = id ? `${id}` : `tg-${uniqueId}`;\n\n const inputRef = useRef<HTMLInputElement>(null);\n const labelRef = useRef<HTMLLabelElement>(null);\n\n useApplyStyle(labelRef, {\n [styles.tokens.label.desktopLineClamp]:\n childrenMaxLines?.desktop == null\n ? null\n : `${childrenMaxLines.desktop}`,\n [styles.tokens.label.tabletLineClamp]:\n childrenMaxLines?.tablet == null\n ? null\n : `${childrenMaxLines.tablet}`,\n [styles.tokens.label.mobileLineClamp]:\n childrenMaxLines?.mobile == null\n ? null\n : `${childrenMaxLines.mobile}`,\n });\n\n const isFocusableWhenDisabled = !!disabled && !!focusableWhenDisabled;\n const isNativeDisabled = !!disabled && !focusableWhenDisabled;\n const isInteractionBlocked = !!disabled;\n\n // =============================================================================\n // EFFECTS\n // =============================================================================\n useEffect(() => {\n setSelected(checked);\n }, [checked]);\n\n useEffect(() => {\n if (selected) {\n setExpanded(initialExpanded ?? true);\n }\n }, [selected]);\n\n // =============================================================================\n // EVENT HANDLERS\n // =============================================================================\n const handleOnChange = (event: React.ChangeEvent<HTMLInputElement>) => {\n if (isInteractionBlocked) {\n event.preventDefault();\n return;\n }\n\n if (onChange) {\n onChange(event);\n return;\n }\n\n switch (type) {\n case \"checkbox\":\n setSelected((prevSelected) => {\n return !prevSelected;\n });\n break;\n case \"radio\":\n case \"yes\":\n case \"no\":\n if (!selected) {\n setSelected(true);\n }\n break;\n }\n };\n\n const handleExpandCollapseClick = () => {\n if (!disabled) {\n setExpanded(!expanded);\n }\n };\n\n const handleOnRemove = () => {\n if (!disabled) {\n if (onRemove) {\n onRemove();\n return;\n }\n }\n };\n\n const handleContainerClick = () => {\n inputRef?.current?.click();\n };\n\n const handleInputClick = (e: React.MouseEvent<HTMLInputElement>) => {\n e.stopPropagation();\n };\n\n // =============================================================================\n // HELPER FUNCTIONS\n // =============================================================================\n\n const getContainerStateClass = () => {\n if (styleType === \"no-border\") {\n if (error) {\n return clsx(\n styles.colorBorderError,\n !disabled && styles.toggleContainerError\n );\n }\n\n if (disabled) {\n return selected\n ? styles.toggleContainerNoBorderDisabledSelected\n : styles.toggleContainerNoBorderDisabled;\n }\n\n if (selected) {\n return styles.toggleContainerNoBorderSelected;\n }\n\n return styles.toggleContainerNoBorder;\n }\n\n if (error) {\n return disabled\n ? styles.colorBorderError\n : styles.toggleContainerError;\n }\n\n if (disabled) {\n return selected\n ? styles.toggleContainerDisabledSelected\n : styles.toggleContainerDisabled;\n }\n\n if (selected) {\n return styles.toggleContainerSelected;\n }\n\n return styles.toggleContainer;\n };\n\n const getContainerHoverClass = () => {\n if (disabled) {\n return undefined;\n }\n\n if (!error && selected) {\n return styles.toggleContainerHoverSelected;\n }\n\n return styles.toggleContainerHoverDefault;\n };\n\n const getTextContainerStateClass = () => {\n if (disabled) {\n return selected\n ? styles.toggleTextContainerDisabledSelected\n : styles.colorTextDisabled;\n }\n\n if (selected) {\n return styles.toggleTextContainerSelected;\n }\n };\n\n // =============================================================================\n // RENDER FUNCTIONS\n // =============================================================================\n const renderIndicator = () => {\n let toggleIconType: ToggleIconType;\n\n switch (type) {\n case \"yes\":\n toggleIconType = \"tick\";\n break;\n case \"no\":\n toggleIconType = \"cross\";\n break;\n case \"checkbox\":\n case \"radio\":\n toggleIconType = type;\n break;\n }\n\n return (\n <ToggleIcon\n type={toggleIconType}\n active={selected}\n disabled={disabled}\n />\n );\n };\n\n const renderSubLabel = () => {\n if (!subLabel) {\n return null;\n }\n\n let component: string | JSX.Element;\n\n if (typeof subLabel === \"function\") {\n component = subLabel();\n } else {\n component = subLabel;\n }\n\n // Hide sublabel from screen readers as the main input already has aria-describedby that points to the sublabel\n return (\n <div\n data-id=\"toggle-sublabel\"\n id={`${generatedId}-sublabel`}\n aria-hidden\n className={styles.subLabel}\n >\n {component}\n </div>\n );\n };\n\n const renderCompositeChildren = () => {\n return (\n (!collapsible || expanded) && (\n <div\n data-id=\"toggle-composite-children\"\n className={clsx(\n styles.children,\n !collapsible && styles.childrenIsFinalItem,\n disabled && styles.colorTextDisabled\n )}\n >\n <Markup baseTextSize=\"body-md\">\n {compositeSectionChildren}\n </Markup>\n </div>\n )\n );\n };\n\n const renderExpandButton = () => {\n const collapsedWithoutErrors = !expanded && !hasCompositeSectionError;\n\n return (\n collapsible && (\n <button\n className={clsx(\n styles.expandButton,\n disabled && styles.disabledColorCursor,\n collapsedWithoutErrors &&\n styles.expandButtonPaddingTopRequired\n )}\n disabled={disabled}\n onClick={handleExpandCollapseClick}\n data-testid={expanded ? \"collapse-button\" : \"expand-button\"}\n >\n {expanded ? \"Show less\" : \"Show more\"}\n {expanded ? (\n <ChevronUpIcon aria-hidden />\n ) : (\n <ChevronDownIcon aria-hidden />\n )}\n </button>\n )\n );\n };\n\n const renderToggleWithRemoveButton = () => {\n const ariaDescriptions =\n [\n typeof subLabel === \"string\" ? `${generatedId}-sublabel` : null,\n ariaDescribedBy,\n ]\n .filter(Boolean)\n .join(\" \") || undefined;\n\n return (\n <div\n id={`${generatedId}-header-container`}\n className={styles.headerContainer}\n >\n <div\n className={clsx(\n styles.indicatorLabelContainer,\n removable && styles.indicatorLabelContainerAddPadding\n )}\n >\n <div\n id={`${generatedId}-input-container`}\n onClick={handleContainerClick}\n className={styles.inputContainer}\n >\n <input\n ref={inputRef}\n name={name}\n id={`${generatedId}-input`}\n type={type === \"checkbox\" ? \"checkbox\" : \"radio\"}\n data-testid=\"toggle-input\"\n className={clsx(\n styles.input,\n disabled && styles.toggleInputDisabled\n )}\n disabled={isNativeDisabled}\n aria-disabled={isFocusableWhenDisabled}\n onChange={handleOnChange}\n onClick={handleInputClick}\n checked={selected}\n tabIndex={isFocusableWhenDisabled ? 0 : undefined}\n aria-describedby={ariaDescriptions}\n {...otherProps}\n />\n {indicator && renderIndicator()}\n <div\n className={clsx(\n styles.textContainer,\n getTextContainerStateClass()\n )}\n >\n <label\n ref={labelRef}\n htmlFor={`${generatedId}-input`}\n data-testid={`toggle-label`}\n id={`${generatedId}-label`}\n className={clsx(\n styles.label,\n selected\n ? styles.toggleLabelSelected\n : styles.toggleLabelDefault\n )}\n >\n {children}\n </label>\n {subLabel && renderSubLabel()}\n </div>\n </div>\n </div>\n {removable && (\n <button\n type=\"button\"\n className={clsx(\n styles.removeButton,\n disabled && styles.disabledColorCursor\n )}\n onClick={handleOnRemove}\n id={`${generatedId}-remove-button`}\n >\n Remove\n </button>\n )}\n </div>\n );\n };\n\n const renderErrorList = (errors: string[]) => {\n return (\n <>\n <Typography.BodyMD\n weight=\"semibold\"\n className={clsx(\n styles.colorTextError,\n disabled && styles.colorTextDisabled\n )}\n >\n Error\n </Typography.BodyMD>\n <TextList.Ul\n className={clsx(\n styles.colorTextError,\n disabled && styles.colorTextDisabled\n )}\n >\n {errors?.map((item, index) => {\n return (\n <li\n key={index}\n id={`${generatedId}-error-list-item-${index}`}\n >\n <Typography.BodyMD\n weight=\"semibold\"\n className={clsx(\n styles.colorTextError,\n disabled && styles.colorTextDisabled\n )}\n >\n {item}\n </Typography.BodyMD>\n </li>\n );\n })}\n </TextList.Ul>\n </>\n );\n };\n\n const renderError = () => {\n return (\n collapsible &&\n !expanded &&\n hasCompositeSectionError && (\n <div\n className={clsx(\n styles.errorContainer,\n disabled && styles.disabledColorCursor\n )}\n onClick={handleExpandCollapseClick}\n id={`${generatedId}-error-alert`}\n >\n <Alert\n type={disabled ? \"description\" : \"error\"}\n className={styles.alertContainer}\n showIcon\n >\n {Array.isArray(errors)\n ? renderErrorList(errors)\n : errors}\n </Alert>\n </div>\n )\n );\n };\n\n const renderCompositeSection = () => {\n return (\n compositeSectionChildren && (\n <div>\n {renderCompositeChildren()}\n {renderError()}\n {renderExpandButton()}\n </div>\n )\n );\n };\n\n return (\n <div\n className={clsx(\n styles.container,\n getContainerStateClass(),\n getContainerHoverClass(),\n !indicator && styles.noIndicatorContainer,\n useContentWidth && styles.useContentWidthContainer,\n className\n )}\n id={id}\n data-testid={testId}\n >\n {renderToggleWithRemoveButton()}\n {renderCompositeSection()}\n </div>\n );\n};\n"],"names":["Toggle","_a","type","indicator","checked","styleType","children","childrenMaxLines","subLabel","disabled","error","name","id","className","compositeSection","removable","focusableWhenDisabled","useContentWidth","onRemove","onChange","testId","ariaDescribedBy","otherProps","__rest","collapsible","errors","compositeSectionChildren","initialExpanded","selected","setSelected","useState","expanded","setExpanded","hasCompositeSectionError","useMemo","hasErrorList","Array","isArray","length","hasErrorElement","uniqueId","useId","generatedId","inputRef","useRef","labelRef","useApplyStyle","styles.tokens","label","desktopLineClamp","desktop","tabletLineClamp","tablet","mobileLineClamp","mobile","isFocusableWhenDisabled","isNativeDisabled","isInteractionBlocked","useEffect","handleOnChange","event","preventDefault","prevSelected","handleExpandCollapseClick","handleOnRemove","handleContainerClick","current","click","handleInputClick","e","stopPropagation","renderIndicator","toggleIconType","_jsx","ToggleIcon","active","renderSubLabel","component","styles.subLabel","renderErrorList","_jsxs","_Fragment","Typography","BodyMD","weight","clsx","styles.colorTextError","styles.colorTextDisabled","TextList","Ul","map","item","index","styles.container","styles.colorBorderError","styles.toggleContainerError","styles.toggleContainerNoBorderDisabledSelected","styles.toggleContainerNoBorderDisabled","styles.toggleContainerNoBorderSelected","styles.toggleContainerNoBorder","styles.toggleContainerDisabledSelected","styles.toggleContainerDisabled","styles.toggleContainerSelected","styles.toggleContainer","styles.toggleContainerHoverSelected","styles.toggleContainerHoverDefault","getContainerHoverClass","styles.noIndicatorContainer","styles.useContentWidthContainer","ariaDescriptions","filter","Boolean","join","undefined","styles.headerContainer","styles.indicatorLabelContainer","styles.indicatorLabelContainerAddPadding","onClick","styles.inputContainer","ref","styles.input","styles.toggleInputDisabled","tabIndex","styles.textContainer","styles.toggleTextContainerDisabledSelected","styles.toggleTextContainerSelected","htmlFor","styles.label","styles.toggleLabelSelected","styles.toggleLabelDefault","styles.removeButton","styles.disabledColorCursor","renderToggleWithRemoveButton","styles.children","styles.childrenIsFinalItem","Markup","baseTextSize","styles.errorContainer","Alert","styles.alertContainer","showIcon","styles.expandButton","styles.expandButtonPaddingTopRequired","ChevronUpIcon","ChevronDownIcon"],"mappings":"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"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
type JsDocTagLike = {
|
|
2
|
+
getCommentText: () => string | undefined;
|
|
3
|
+
getTagName: () => string;
|
|
4
|
+
};
|
|
5
|
+
type JsDocBlockLike = {
|
|
6
|
+
getCommentText: () => string | undefined;
|
|
7
|
+
getTags: () => JsDocTagLike[];
|
|
8
|
+
};
|
|
9
|
+
type JsDocNodeLike = {
|
|
10
|
+
getJsDocs: () => JsDocBlockLike[];
|
|
11
|
+
};
|
|
12
|
+
type LeadingCommentNodeLike = {
|
|
13
|
+
getLeadingCommentRanges: () => Array<{
|
|
14
|
+
getText: () => string;
|
|
15
|
+
}>;
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* Shared parser for JSDoc tags and leading comments.
|
|
19
|
+
*/
|
|
20
|
+
export declare class JsDocParser {
|
|
21
|
+
getTagCommentText(tag: {
|
|
22
|
+
getCommentText: () => string | undefined;
|
|
23
|
+
}): string | undefined;
|
|
24
|
+
getDescriptionFromNode(node: JsDocNodeLike, options?: {
|
|
25
|
+
joinWith?: string;
|
|
26
|
+
normalizeNewlinesToSpaces?: boolean;
|
|
27
|
+
}): string | undefined;
|
|
28
|
+
getTags(node: JsDocNodeLike): JsDocTagLike[];
|
|
29
|
+
getLeadingNonJsDocComments(node: LeadingCommentNodeLike): string[];
|
|
30
|
+
getMarkerValuesFromLeadingComments(node: LeadingCommentNodeLike, marker: string): string[];
|
|
31
|
+
splitCommaSeparatedValues(rawValue: string | undefined): string[];
|
|
32
|
+
normalizeCommentText(text: string | undefined, options?: {
|
|
33
|
+
normalizeNewlinesToSpaces?: boolean;
|
|
34
|
+
}): string | undefined;
|
|
35
|
+
}
|
|
36
|
+
export {};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type Project, type SourceFile } from "ts-morph";
|
|
2
|
+
/**
|
|
3
|
+
* Shared source provider for ts-morph project and source-file operations.
|
|
4
|
+
*/
|
|
5
|
+
export declare class TypeScriptSourceProvider {
|
|
6
|
+
getProject(): Project;
|
|
7
|
+
getSourceFile(filePath: string): SourceFile;
|
|
8
|
+
getSourceFilesByGlobs(globs: readonly string[]): SourceFile[];
|
|
9
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FileSystemAdapter - Minimal abstraction for filesystem operations.
|
|
3
|
+
*
|
|
4
|
+
* This adapter abstracts path resolution and file existence checks,
|
|
5
|
+
* making file operations testable via mocking without filesystem access.
|
|
6
|
+
*/
|
|
7
|
+
import type { FileStat } from "../types";
|
|
8
|
+
/**
|
|
9
|
+
* Interface for filesystem operations used by path resolution services.
|
|
10
|
+
* Allows mocking during tests without real filesystem access.
|
|
11
|
+
*/
|
|
12
|
+
export interface IFileSystemAdapter {
|
|
13
|
+
/**
|
|
14
|
+
* Check if a path exists (file or directory).
|
|
15
|
+
* @param path The path to check
|
|
16
|
+
* @returns true if path exists, false otherwise
|
|
17
|
+
*/
|
|
18
|
+
existsSync(path: string): boolean;
|
|
19
|
+
/**
|
|
20
|
+
* Get file statistics for a path.
|
|
21
|
+
* @param path The path to stat
|
|
22
|
+
* @returns File stat object with isFile() and isDirectory() methods
|
|
23
|
+
* @throws If path doesn't exist
|
|
24
|
+
*/
|
|
25
|
+
statSync(path: string): FileStat;
|
|
26
|
+
/**
|
|
27
|
+
* Resolve one or more path segments relative to working directory.
|
|
28
|
+
* @param segments Path segments to resolve
|
|
29
|
+
* @returns Absolute resolved path
|
|
30
|
+
*/
|
|
31
|
+
resolvePath(...segments: string[]): string;
|
|
32
|
+
/**
|
|
33
|
+
* Remove a file or directory.
|
|
34
|
+
* @param path The path to remove
|
|
35
|
+
* @param options.force If true, suppress errors if path doesn't exist
|
|
36
|
+
*/
|
|
37
|
+
rm(path: string, options?: {
|
|
38
|
+
force?: boolean;
|
|
39
|
+
}): Promise<void>;
|
|
40
|
+
/**
|
|
41
|
+
* Create a directory.
|
|
42
|
+
* @param path The directory path
|
|
43
|
+
* @param options.recursive If true, create parent directories as needed
|
|
44
|
+
*/
|
|
45
|
+
mkdir(path: string, options?: {
|
|
46
|
+
recursive?: boolean;
|
|
47
|
+
}): Promise<void>;
|
|
48
|
+
/**
|
|
49
|
+
* Write text content to a file.
|
|
50
|
+
* @param path The file path
|
|
51
|
+
* @param data The content to write
|
|
52
|
+
*/
|
|
53
|
+
writeFile(path: string, data: string): Promise<void>;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Default FileSystemAdapter implementation using Node.js fs module.
|
|
57
|
+
*/
|
|
58
|
+
export declare class FileSystemAdapter implements IFileSystemAdapter {
|
|
59
|
+
existsSync(path: string): boolean;
|
|
60
|
+
statSync(path: string): FileStat;
|
|
61
|
+
resolvePath(...segments: string[]): string;
|
|
62
|
+
rm(path: string, options?: {
|
|
63
|
+
force?: boolean;
|
|
64
|
+
}): Promise<void>;
|
|
65
|
+
mkdir(path: string, options?: {
|
|
66
|
+
recursive?: boolean;
|
|
67
|
+
}): Promise<void>;
|
|
68
|
+
writeFile(path: string, data: string): Promise<void>;
|
|
69
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ArgTypesGenerator - Orchestrator for Storybook argTypes generation.
|
|
3
|
+
*
|
|
4
|
+
* Composes all services to generate argTypes files from TypeScript sources
|
|
5
|
+
* and the registry mapping story titles to their argTypes.
|
|
6
|
+
*
|
|
7
|
+
* This class mirrors the logic in the original procedural script but with
|
|
8
|
+
* clear method boundaries and injectable dependencies.
|
|
9
|
+
*/
|
|
10
|
+
import type { IFileSystemAdapter } from "./adapters/file-system-adapter";
|
|
11
|
+
/**
|
|
12
|
+
* Orchestrates the full Storybook argTypes generation pipeline.
|
|
13
|
+
* Coordinates all services: source analysis, type formatting, row building, and registry generation.
|
|
14
|
+
*
|
|
15
|
+
* Usage:
|
|
16
|
+
* ```typescript
|
|
17
|
+
* const generator = new ArgTypesGenerator();
|
|
18
|
+
* await generator.generateAll();
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
export declare class ArgTypesGenerator {
|
|
22
|
+
private readonly sourceProvider;
|
|
23
|
+
private readonly jsDocExtractor;
|
|
24
|
+
private readonly typeDependencyResolver;
|
|
25
|
+
private readonly typeFormatter;
|
|
26
|
+
private readonly rowBuilder;
|
|
27
|
+
private readonly resolver;
|
|
28
|
+
private readonly storyRegistryGenerator;
|
|
29
|
+
private readonly generatedFileFormatter;
|
|
30
|
+
private readonly fsAdapter;
|
|
31
|
+
/**
|
|
32
|
+
* Create a new ArgTypesGenerator.
|
|
33
|
+
*
|
|
34
|
+
* @param fsAdapter Optional filesystem adapter for testability
|
|
35
|
+
*/
|
|
36
|
+
constructor(fsAdapter?: IFileSystemAdapter);
|
|
37
|
+
/**
|
|
38
|
+
* Generate all component argTypes files and the registry.
|
|
39
|
+
* This is the main entry point for full generation.
|
|
40
|
+
*/
|
|
41
|
+
generateAll(): Promise<void>;
|
|
42
|
+
/**
|
|
43
|
+
* Generate argTypes for a single component types.ts file.
|
|
44
|
+
*
|
|
45
|
+
* @param sourceFilePath Path to the source types.ts file
|
|
46
|
+
*/
|
|
47
|
+
generateForSourceFile(sourceFilePath: string): Promise<void>;
|
|
48
|
+
/**
|
|
49
|
+
* Generate the global registry mapping story titles to their argTypes imports.
|
|
50
|
+
* Scans all story files to discover which component types.ts each story uses.
|
|
51
|
+
*/
|
|
52
|
+
generateStorybookArgTypesRegistry(): Promise<void>;
|
|
53
|
+
/**
|
|
54
|
+
* Format all generated files using prettier.
|
|
55
|
+
*/
|
|
56
|
+
formatGenerated(): void;
|
|
57
|
+
/**
|
|
58
|
+
* Get the output file path for generated argTypes.
|
|
59
|
+
*/
|
|
60
|
+
getOutputFile(sourceFilePath: string): string;
|
|
61
|
+
/**
|
|
62
|
+
* Delete the generated argTypes output file for a given source file path.
|
|
63
|
+
* Used when the source file is removed during watch mode.
|
|
64
|
+
*/
|
|
65
|
+
deleteOutputFile(sourceFilePath: string): Promise<void>;
|
|
66
|
+
/**
|
|
67
|
+
* Get the export name for the component's argTypes object.
|
|
68
|
+
* e.g. "form-custom-field" → "formCustomFieldExtraArgTypes"
|
|
69
|
+
*/
|
|
70
|
+
getExportName(sourceFilePath: string): string;
|
|
71
|
+
/**
|
|
72
|
+
* Get the relative import path for a generated argTypes file.
|
|
73
|
+
*/
|
|
74
|
+
getArgTypesImportPath(outputFile: string): string;
|
|
75
|
+
private getPropertyName;
|
|
76
|
+
private getCategoryName;
|
|
77
|
+
private findReferencedTypeNames;
|
|
78
|
+
private getWrappedTypeNames;
|
|
79
|
+
private getInheritedHtmlAttributesRow;
|
|
80
|
+
private getInheritedInterfacesDescription;
|
|
81
|
+
private getInterfaceArgTypes;
|
|
82
|
+
private getTypeAliasArgTypes;
|
|
83
|
+
private generateImportedTypeRows;
|
|
84
|
+
private shouldSkipImportedTypeRows;
|
|
85
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration constants for Storybook argTypes generation.
|
|
3
|
+
* Centralizes all configuration to improve testability and maintainability.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Glob patterns for source files containing type definitions.
|
|
7
|
+
* Used to discover which component types.ts files to generate argTypes from.
|
|
8
|
+
*/
|
|
9
|
+
export declare const SOURCE_FILE_GLOBS: readonly ["src/*/types.ts", "src/filter/addons/types.ts", "src/form/form-*/types.ts", "src/popover/popover-inline/types.ts"];
|
|
10
|
+
/**
|
|
11
|
+
* Root directories to watch for file changes (when in watch mode).
|
|
12
|
+
*/
|
|
13
|
+
export declare const WATCH_ROOTS: string[];
|
|
14
|
+
/**
|
|
15
|
+
* Glob pattern for story files to scan for component references.
|
|
16
|
+
*/
|
|
17
|
+
export declare const STORY_FILE_GLOB = "stories/**/*.stories.@(ts|tsx)";
|
|
18
|
+
/**
|
|
19
|
+
* Output file path for the generated registry mapping stories to argTypes imports.
|
|
20
|
+
*/
|
|
21
|
+
export declare const STORYBOOK_ARGTYPES_FILE: string;
|
|
22
|
+
/**
|
|
23
|
+
* TypeScript type formatting flags for consistent text representation.
|
|
24
|
+
* NoTruncation: Show full type text without truncation
|
|
25
|
+
* UseSingleQuotesForStringLiteralType: Prefer 'string' over "string"
|
|
26
|
+
*/
|
|
27
|
+
export declare const TYPE_FORMAT_FLAGS: number;
|
|
28
|
+
/**
|
|
29
|
+
* Header comment for all generated files.
|
|
30
|
+
*/
|
|
31
|
+
export declare const GENERATED_FILE_HEADER: "// This file is generated. Do not edit manually.\n// Run: npm run storybook:argtypes\n";
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Storybook ArgTypes Generation Tool - Public API
|
|
3
|
+
*
|
|
4
|
+
* Main entry point for the storybook-argtypes utility.
|
|
5
|
+
* Exports all public interfaces, classes, and utilities.
|
|
6
|
+
*/
|
|
7
|
+
export { ArgTypesGenerator } from "./arg-types-generator";
|
|
8
|
+
export { GENERATED_FILE_HEADER, SOURCE_FILE_GLOBS, STORY_FILE_GLOB, STORYBOOK_ARGTYPES_FILE, TYPE_FORMAT_FLAGS, WATCH_ROOTS, } from "./config/arg-types-config";
|
|
9
|
+
export type * as StorybookArgtypesTypes from "./types";
|
|
10
|
+
export { FileSystemAdapter, type IFileSystemAdapter, } from "./adapters/file-system-adapter";
|
|
11
|
+
export * from "./services";
|