@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":"histogram-slider.js","sources":["../../src/histogram-slider/histogram-slider.tsx"],"sourcesContent":["import { announce, clearAnnouncer } from \"@react-aria/live-announcer\";\nimport clsx from \"clsx\";\nimport { useEffect, useMemo, useRef, useState } from \"react\";\n\nimport { InputRangeSlider } from \"../input-range-slider\";\nimport { concatIds } from \"../shared/accessibility\";\nimport { useApplyStyle } from \"../theme\";\nimport { Typography } from \"../typography\";\nimport { useId } from \"../util\";\nimport * as styles from \"./histogram-slider.styles\";\nimport type { HistogramBinProps, HistogramSliderProps } from \"./types\";\n\nconst ANNOUNCEMENT_DEBOUNCE_MS = 500;\n\n/**\n * A histogram with an overlaid two-thumb range slider for numeric filtering.\n *\n * Use `HistogramSlider` to let users narrow a dataset by selecting a numeric\n * range while seeing how values are distributed across bins.\n */\nexport const HistogramSlider = ({\n bins = [],\n interval,\n disabled,\n readOnly,\n value,\n showRangeLabels,\n rangeLabelPrefix,\n rangeLabelSuffix,\n ariaLabels,\n \"aria-labelledby\": ariaLabelledBy,\n \"aria-describedby\": ariaDescribedBy,\n onChange,\n onChangeEnd,\n renderEmptyView,\n renderRangeLabel,\n className,\n ...otherProps\n}: HistogramSliderProps) => {\n // =========================================================================\n // CONST, STATE, REF\n // =========================================================================\n const counts = bins.map((item) => item.count);\n const maxCount = Math.max(...counts);\n\n const values = bins.map((item) => item.minValue);\n const maxValue = Math.max(...values);\n const minValue = Math.min(...values);\n\n const [selection, setSelection] = useState<[number, number]>(\n initSelection()\n );\n const internalId = useId();\n const announcementTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(\n null\n );\n const rangeLabelId = `${internalId}-range-label`;\n const sliderDescribedBy = concatIds(\n ariaDescribedBy,\n showRangeLabels ? rangeLabelId : undefined\n );\n\n const items = useMemo(() => {\n const sorted = [...bins].sort((a, b) => a.minValue - b.minValue);\n const numCols = (maxValue - minValue) / interval + 1;\n\n const items: typeof sorted = [];\n for (let i = 0; i < numCols; i++) {\n const bin = sorted.find(\n (b) => b.minValue === minValue + interval * i\n );\n if (bin) {\n items.push(bin);\n } else {\n items.push({ count: 0, minValue: minValue + interval * i });\n }\n }\n return items;\n }, [bins, interval]);\n\n // =========================================================================\n // EFFECTS\n // =========================================================================\n useEffect(() => {\n if (value !== selection) {\n setSelection(initSelection());\n }\n }, [value]);\n\n useEffect(() => {\n return () => {\n clearPendingAnnouncement();\n };\n }, []);\n\n // =========================================================================\n // EVENT HANDLERS\n // =========================================================================\n const handleChange = (values: number[]) => {\n const [val1, val2] = values;\n const newSelection: [number, number] = [val1, val2];\n setSelection(newSelection);\n scheduleRangePercentageAnnouncement(newSelection);\n onChange?.(newSelection);\n };\n\n const handleChangeEnd = (values: number[]) => {\n const [val1, val2] = values;\n const newSelection: [number, number] = [val1, val2];\n setSelection(newSelection);\n scheduleRangePercentageAnnouncement(newSelection);\n onChangeEnd?.(newSelection);\n };\n\n // =========================================================================\n // HELPER FUNCTIONS\n // =========================================================================\n function initSelection(): [number, number] {\n return value ?? [minValue, minValue + interval];\n }\n\n function clearPendingAnnouncement() {\n if (announcementTimeoutRef.current) {\n clearTimeout(announcementTimeoutRef.current);\n announcementTimeoutRef.current = null;\n }\n }\n\n function getRangePercentageDescription(currentSelection: [number, number]) {\n const totalCount = items.reduce((sum, item) => sum + item.count, 0);\n\n if (totalCount === 0) {\n return \"0% of results available in the range you specified.\";\n }\n\n const selectedCount = items.reduce((sum, item) => {\n const isSelected =\n item.minValue >= currentSelection[0] &&\n item.minValue < currentSelection[1];\n\n return isSelected ? sum + item.count : sum;\n }, 0);\n\n const percentage = Math.round((selectedCount / totalCount) * 100);\n\n return `${percentage}% of results available in the range you specified.`;\n }\n\n function scheduleRangePercentageAnnouncement(\n currentSelection: [number, number]\n ) {\n if (disabled || readOnly) {\n return;\n }\n\n const announcement = getRangePercentageDescription(currentSelection);\n\n clearPendingAnnouncement();\n\n announcementTimeoutRef.current = setTimeout(() => {\n clearAnnouncer(\"polite\");\n announce(announcement, \"polite\");\n }, ANNOUNCEMENT_DEBOUNCE_MS);\n }\n\n // =========================================================================\n // RENDER FUNCTIONS\n // =========================================================================\n const renderRangeItem = (value: number) => {\n if (renderRangeLabel) {\n return renderRangeLabel(value);\n }\n return (\n <Typography.BodyBL>\n {rangeLabelPrefix}\n {value}\n {rangeLabelSuffix}\n </Typography.BodyBL>\n );\n };\n\n const renderHistogramSlider = () => {\n const selectionDescription = getRangePercentageDescription(selection);\n\n return (\n <>\n <div className={styles.histogram}>\n {items.map((item, i) => (\n <HistogramBar\n key={i}\n item={item}\n maxCount={maxCount}\n isSelected={\n item.minValue >= selection[0] &&\n item.minValue < selection[1]\n }\n isDisabled={disabled || readOnly}\n />\n ))}\n </div>\n <InputRangeSlider\n min={minValue}\n max={maxValue + interval}\n step={interval}\n minRange={interval}\n numOfThumbs={2}\n value={selection}\n disabled={disabled}\n readOnly={readOnly}\n ariaLabels={ariaLabels}\n ariaDescriptions={[\n selectionDescription,\n selectionDescription,\n ]}\n aria-describedby={sliderDescribedBy}\n aria-labelledby={ariaLabelledBy}\n onChange={handleChange}\n onChangeEnd={handleChangeEnd}\n className={styles.slider}\n />\n </>\n );\n };\n\n return (\n <div role=\"group\" {...otherProps} className={className}>\n {showRangeLabels && (\n <div id={rangeLabelId} className={styles.label}>\n {renderRangeItem(selection[0])}\n <div className={styles.separator}>-</div>\n {renderRangeItem(selection[1])}\n </div>\n )}\n {items.every((item) => item.count === 0) && renderEmptyView\n ? renderEmptyView()\n : renderHistogramSlider()}\n </div>\n );\n};\n\n// =============================================================================\n// SUB COMPONENT\n// =============================================================================\ninterface HistogramBarProps {\n item: HistogramBinProps;\n maxCount: number;\n isSelected: boolean;\n isDisabled: boolean | undefined;\n}\n\nconst HistogramBar = ({\n item,\n maxCount,\n isSelected,\n isDisabled,\n}: HistogramBarProps) => {\n const ratio = item.count / maxCount;\n const barRef = useRef<HTMLDivElement>(null);\n\n useApplyStyle(barRef, {\n height: ratio ? `calc(calc(100% - 0.25rem) * ${ratio} + 0.25rem)` : \"0\",\n });\n\n return (\n <div\n data-testid=\"histogram-bar\"\n className={clsx(\n styles.bar,\n isDisabled && isSelected && styles.barSelectedDisabled,\n isDisabled && styles.barDisabled,\n isSelected && styles.barSelected\n )}\n ref={barRef}\n />\n );\n};\n"],"names":["HistogramSlider","_a","bins","interval","disabled","readOnly","value","showRangeLabels","rangeLabelPrefix","rangeLabelSuffix","ariaLabels","ariaLabelledBy","ariaDescribedBy","onChange","onChangeEnd","renderEmptyView","renderRangeLabel","className","otherProps","__rest","counts","map","item","count","maxCount","Math","max","values","minValue","maxValue","min","selection","setSelection","useState","initSelection","internalId","useId","announcementTimeoutRef","useRef","rangeLabelId","sliderDescribedBy","concatIds","undefined","items","useMemo","sorted","sort","a","b","numCols","i","bin","find","push","useEffect","clearPendingAnnouncement","handleChange","val1","val2","newSelection","scheduleRangePercentageAnnouncement","handleChangeEnd","current","clearTimeout","getRangePercentageDescription","currentSelection","totalCount","reduce","sum","selectedCount","round","announcement","setTimeout","clearAnnouncer","announce","renderRangeItem","_jsxs","Typography","BodyBL","children","Object","assign","role","id","styles.label","_jsx","styles.separator","every","selectionDescription","_Fragment","styles.histogram","HistogramBar","isSelected","isDisabled","InputRangeSlider","step","minRange","numOfThumbs","ariaDescriptions","styles.slider","renderHistogramSlider","ratio","barRef","useApplyStyle","height","clsx","styles.bar","styles.barSelectedDisabled","styles.barDisabled","styles.barSelected","ref"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"histogram-slider.js","sources":["../../src/histogram-slider/histogram-slider.tsx"],"sourcesContent":["import { announce, clearAnnouncer } from \"@react-aria/live-announcer\";\nimport clsx from \"clsx\";\nimport { useEffect, useMemo, useRef, useState } from \"react\";\n\nimport { InputRangeSlider } from \"../input-range-slider\";\nimport { concatIds } from \"../shared/accessibility\";\nimport { useApplyStyle } from \"../theme\";\nimport { Typography } from \"../typography\";\nimport { useId } from \"../util\";\nimport * as styles from \"./histogram-slider.styles\";\nimport type { HistogramBinProps, HistogramSliderProps } from \"./types\";\n\nconst ANNOUNCEMENT_DEBOUNCE_MS = 500;\n\n// @catalog\n/**\n * A histogram with an overlaid two-thumb range slider for numeric filtering.\n *\n * Use `HistogramSlider` to let users narrow a dataset by selecting a numeric\n * range while seeing how values are distributed across bins.\n */\nexport const HistogramSlider = ({\n bins = [],\n interval,\n disabled,\n readOnly,\n value,\n showRangeLabels,\n rangeLabelPrefix,\n rangeLabelSuffix,\n ariaLabels,\n \"aria-labelledby\": ariaLabelledBy,\n \"aria-describedby\": ariaDescribedBy,\n onChange,\n onChangeEnd,\n renderEmptyView,\n renderRangeLabel,\n className,\n ...otherProps\n}: HistogramSliderProps) => {\n // =========================================================================\n // CONST, STATE, REF\n // =========================================================================\n const counts = bins.map((item) => item.count);\n const maxCount = Math.max(...counts);\n\n const values = bins.map((item) => item.minValue);\n const maxValue = Math.max(...values);\n const minValue = Math.min(...values);\n\n const [selection, setSelection] = useState<[number, number]>(\n initSelection()\n );\n const internalId = useId();\n const announcementTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(\n null\n );\n const rangeLabelId = `${internalId}-range-label`;\n const sliderDescribedBy = concatIds(\n ariaDescribedBy,\n showRangeLabels ? rangeLabelId : undefined\n );\n\n const items = useMemo(() => {\n const sorted = [...bins].sort((a, b) => a.minValue - b.minValue);\n const numCols = (maxValue - minValue) / interval + 1;\n\n const items: typeof sorted = [];\n for (let i = 0; i < numCols; i++) {\n const bin = sorted.find(\n (b) => b.minValue === minValue + interval * i\n );\n if (bin) {\n items.push(bin);\n } else {\n items.push({ count: 0, minValue: minValue + interval * i });\n }\n }\n return items;\n }, [bins, interval]);\n\n // =========================================================================\n // EFFECTS\n // =========================================================================\n useEffect(() => {\n if (value !== selection) {\n setSelection(initSelection());\n }\n }, [value]);\n\n useEffect(() => {\n return () => {\n clearPendingAnnouncement();\n };\n }, []);\n\n // =========================================================================\n // EVENT HANDLERS\n // =========================================================================\n const handleChange = (values: number[]) => {\n const [val1, val2] = values;\n const newSelection: [number, number] = [val1, val2];\n setSelection(newSelection);\n scheduleRangePercentageAnnouncement(newSelection);\n onChange?.(newSelection);\n };\n\n const handleChangeEnd = (values: number[]) => {\n const [val1, val2] = values;\n const newSelection: [number, number] = [val1, val2];\n setSelection(newSelection);\n scheduleRangePercentageAnnouncement(newSelection);\n onChangeEnd?.(newSelection);\n };\n\n // =========================================================================\n // HELPER FUNCTIONS\n // =========================================================================\n function initSelection(): [number, number] {\n return value ?? [minValue, minValue + interval];\n }\n\n function clearPendingAnnouncement() {\n if (announcementTimeoutRef.current) {\n clearTimeout(announcementTimeoutRef.current);\n announcementTimeoutRef.current = null;\n }\n }\n\n function getRangePercentageDescription(currentSelection: [number, number]) {\n const totalCount = items.reduce((sum, item) => sum + item.count, 0);\n\n if (totalCount === 0) {\n return \"0% of results available in the range you specified.\";\n }\n\n const selectedCount = items.reduce((sum, item) => {\n const isSelected =\n item.minValue >= currentSelection[0] &&\n item.minValue < currentSelection[1];\n\n return isSelected ? sum + item.count : sum;\n }, 0);\n\n const percentage = Math.round((selectedCount / totalCount) * 100);\n\n return `${percentage}% of results available in the range you specified.`;\n }\n\n function scheduleRangePercentageAnnouncement(\n currentSelection: [number, number]\n ) {\n if (disabled || readOnly) {\n return;\n }\n\n const announcement = getRangePercentageDescription(currentSelection);\n\n clearPendingAnnouncement();\n\n announcementTimeoutRef.current = setTimeout(() => {\n clearAnnouncer(\"polite\");\n announce(announcement, \"polite\");\n }, ANNOUNCEMENT_DEBOUNCE_MS);\n }\n\n // =========================================================================\n // RENDER FUNCTIONS\n // =========================================================================\n const renderRangeItem = (value: number) => {\n if (renderRangeLabel) {\n return renderRangeLabel(value);\n }\n return (\n <Typography.BodyBL>\n {rangeLabelPrefix}\n {value}\n {rangeLabelSuffix}\n </Typography.BodyBL>\n );\n };\n\n const renderHistogramSlider = () => {\n const selectionDescription = getRangePercentageDescription(selection);\n\n return (\n <>\n <div className={styles.histogram}>\n {items.map((item, i) => (\n <HistogramBar\n key={i}\n item={item}\n maxCount={maxCount}\n isSelected={\n item.minValue >= selection[0] &&\n item.minValue < selection[1]\n }\n isDisabled={disabled || readOnly}\n />\n ))}\n </div>\n <InputRangeSlider\n min={minValue}\n max={maxValue + interval}\n step={interval}\n minRange={interval}\n numOfThumbs={2}\n value={selection}\n disabled={disabled}\n readOnly={readOnly}\n ariaLabels={ariaLabels}\n ariaDescriptions={[\n selectionDescription,\n selectionDescription,\n ]}\n aria-describedby={sliderDescribedBy}\n aria-labelledby={ariaLabelledBy}\n onChange={handleChange}\n onChangeEnd={handleChangeEnd}\n className={styles.slider}\n />\n </>\n );\n };\n\n return (\n <div role=\"group\" {...otherProps} className={className}>\n {showRangeLabels && (\n <div id={rangeLabelId} className={styles.label}>\n {renderRangeItem(selection[0])}\n <div className={styles.separator}>-</div>\n {renderRangeItem(selection[1])}\n </div>\n )}\n {items.every((item) => item.count === 0) && renderEmptyView\n ? renderEmptyView()\n : renderHistogramSlider()}\n </div>\n );\n};\n\n// =============================================================================\n// SUB COMPONENT\n// =============================================================================\ninterface HistogramBarProps {\n item: HistogramBinProps;\n maxCount: number;\n isSelected: boolean;\n isDisabled: boolean | undefined;\n}\n\nconst HistogramBar = ({\n item,\n maxCount,\n isSelected,\n isDisabled,\n}: HistogramBarProps) => {\n const ratio = item.count / maxCount;\n const barRef = useRef<HTMLDivElement>(null);\n\n useApplyStyle(barRef, {\n height: ratio ? `calc(calc(100% - 0.25rem) * ${ratio} + 0.25rem)` : \"0\",\n });\n\n return (\n <div\n data-testid=\"histogram-bar\"\n className={clsx(\n styles.bar,\n isDisabled && isSelected && styles.barSelectedDisabled,\n isDisabled && styles.barDisabled,\n isSelected && styles.barSelected\n )}\n ref={barRef}\n />\n );\n};\n"],"names":["HistogramSlider","_a","bins","interval","disabled","readOnly","value","showRangeLabels","rangeLabelPrefix","rangeLabelSuffix","ariaLabels","ariaLabelledBy","ariaDescribedBy","onChange","onChangeEnd","renderEmptyView","renderRangeLabel","className","otherProps","__rest","counts","map","item","count","maxCount","Math","max","values","minValue","maxValue","min","selection","setSelection","useState","initSelection","internalId","useId","announcementTimeoutRef","useRef","rangeLabelId","sliderDescribedBy","concatIds","undefined","items","useMemo","sorted","sort","a","b","numCols","i","bin","find","push","useEffect","clearPendingAnnouncement","handleChange","val1","val2","newSelection","scheduleRangePercentageAnnouncement","handleChangeEnd","current","clearTimeout","getRangePercentageDescription","currentSelection","totalCount","reduce","sum","selectedCount","round","announcement","setTimeout","clearAnnouncer","announce","renderRangeItem","_jsxs","Typography","BodyBL","children","Object","assign","role","id","styles.label","_jsx","styles.separator","every","selectionDescription","_Fragment","styles.histogram","HistogramBar","isSelected","isDisabled","InputRangeSlider","step","minRange","numOfThumbs","ariaDescriptions","styles.slider","renderHistogramSlider","ratio","barRef","useApplyStyle","height","clsx","styles.bar","styles.barSelectedDisabled","styles.barDisabled","styles.barSelected","ref"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"image-button.js","sources":["../../src/image-button/image-button.tsx"],"sourcesContent":["import clsx from \"clsx\";\nimport React from \"react\";\n\nimport type { ButtonRef } from \"../button/types\";\nimport { ImageWithFallback } from \"../shared/image-with-fallback/image-with-fallback\";\nimport * as styles from \"./image-button.styles\";\nimport type { ImageButtonProps } from \"./types\";\n\nconst Component = (\n {\n children,\n className,\n imgSrc,\n selected,\n error,\n type = \"button\",\n disabled = false,\n focusableWhenDisabled = false,\n onClick,\n ...otherProps\n }: ImageButtonProps,\n ref: ButtonRef\n) => {\n const isNativeDisabled = !!disabled && !focusableWhenDisabled;\n\n return (\n <button\n ref={ref}\n type={type}\n aria-disabled={disabled}\n disabled={isNativeDisabled}\n onClick={disabled ? undefined : onClick}\n className={clsx(\n styles.main,\n selected && styles.mainSelectedText,\n selected && styles.mainSelected,\n error && styles.mainError,\n disabled && styles.mainDisabled,\n className\n )}\n {...otherProps}\n >\n <ImageWithFallback src={imgSrc} />\n {children}\n </button>\n );\n};\n\n/**\n * A button that displays an image alongside optional label content.\n *\n * Use `ImageButton` for selectable image-based choices such as theme pickers or avatar\n * selectors, where each option is represented visually.\n */\nexport const ImageButton = React.forwardRef(Component);\n"],"names":["ImageButton","React","forwardRef","_a","ref","children","className","imgSrc","selected","error","type","disabled","focusableWhenDisabled","onClick","otherProps","__rest","isNativeDisabled","_jsxs","Object","assign","undefined","clsx","styles.main","styles.mainSelectedText","styles.mainSelected","styles.mainError","styles.mainDisabled","_jsx","ImageWithFallback","src"],"mappings":"4VAQA,
|
|
1
|
+
{"version":3,"file":"image-button.js","sources":["../../src/image-button/image-button.tsx"],"sourcesContent":["import clsx from \"clsx\";\nimport React from \"react\";\n\nimport type { ButtonRef } from \"../button/types\";\nimport { ImageWithFallback } from \"../shared/image-with-fallback/image-with-fallback\";\nimport * as styles from \"./image-button.styles\";\nimport type { ImageButtonProps } from \"./types\";\n\nconst Component = (\n {\n children,\n className,\n imgSrc,\n selected,\n error,\n type = \"button\",\n disabled = false,\n focusableWhenDisabled = false,\n onClick,\n ...otherProps\n }: ImageButtonProps,\n ref: ButtonRef\n) => {\n const isNativeDisabled = !!disabled && !focusableWhenDisabled;\n\n return (\n <button\n ref={ref}\n type={type}\n aria-disabled={disabled}\n disabled={isNativeDisabled}\n onClick={disabled ? undefined : onClick}\n className={clsx(\n styles.main,\n selected && styles.mainSelectedText,\n selected && styles.mainSelected,\n error && styles.mainError,\n disabled && styles.mainDisabled,\n className\n )}\n {...otherProps}\n >\n <ImageWithFallback src={imgSrc} />\n {children}\n </button>\n );\n};\n\n// @catalog\n/**\n * A button that displays an image alongside optional label content.\n *\n * Use `ImageButton` for selectable image-based choices such as theme pickers or avatar\n * selectors, where each option is represented visually.\n */\nexport const ImageButton = React.forwardRef(Component);\n"],"names":["ImageButton","React","forwardRef","_a","ref","children","className","imgSrc","selected","error","type","disabled","focusableWhenDisabled","onClick","otherProps","__rest","isNativeDisabled","_jsxs","Object","assign","undefined","clsx","styles.main","styles.mainSelectedText","styles.mainSelected","styles.mainError","styles.mainDisabled","_jsx","ImageWithFallback","src"],"mappings":"4VAQA,MA+CaA,EAAcC,EAAMC,YA/Cf,CACdC,EAYAC,KAZA,IAAAC,SACIA,EAAQC,UACRA,EAASC,OACTA,EAAMC,SACNA,EAAQC,MACRA,EAAKC,KACLA,EAAO,SAAQC,SACfA,GAAW,EAAKC,sBAChBA,GAAwB,EAAKC,QAC7BA,GAAOV,EACJW,EAAUC,EAAAZ,EAVjB,CAAA,WAAA,YAAA,SAAA,WAAA,QAAA,OAAA,WAAA,wBAAA,YAcA,MAAMa,IAAqBL,IAAaC,EAExC,OACIK,EAAA,SAAAC,OAAAC,OAAA,CACIf,IAAKA,EACLM,KAAMA,EAAI,gBACKC,EACfA,SAAUK,EACVH,QAASF,OAAWS,EAAYP,EAChCP,UAAWe,EACPC,EACAd,GAAYe,EACZf,GAAYgB,EACZf,GAASgB,EACTd,GAAYe,EACZpB,IAEAQ,EAAU,CAAAT,SAAA,CAEdsB,EAACC,EAAiB,CAACC,IAAKtB,IACvBF,KACI"}
|
package/input/input.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"input.js","sources":["../../src/input/input.tsx"],"sourcesContent":["import { CrossIcon } from \"@lifesg/react-icons/cross\";\nimport clsx from \"clsx\";\nimport React, { useImperativeHandle, useRef } from \"react\";\n\nimport { BasicButton, BasicInput, InputBox } from \"../shared/input-wrapper\";\nimport { StringHelper, useNextInputState } from \"../util\";\nimport * as styles from \"./input.styles\";\nimport type { InputProps, InputRef } from \"./types\";\n\nconst shouldAllowSpacing = (\n type: string | undefined,\n spacing: number | undefined\n): spacing is number => {\n return type === \"tel\" && !!spacing;\n};\n\nconst Component = (\n {\n value,\n spacing,\n type,\n error,\n disabled,\n readOnly,\n onChange,\n onClear,\n allowClear = false,\n className,\n styleType = \"bordered\",\n ...otherProps\n }: InputProps,\n ref: InputRef\n): JSX.Element => {\n // =============================================================================\n // CONST, STATE, REF\n // =============================================================================\n const allowSpacing = shouldAllowSpacing(type, spacing);\n const elementRef = useRef<HTMLInputElement>(null);\n useImperativeHandle(ref, () => elementRef.current!, []);\n\n const getNextInputState = useNextInputState({\n ref: elementRef,\n formatter: (value) => {\n return allowSpacing\n ? StringHelper.transformWithSpaces(value, spacing)\n : value;\n },\n });\n\n // =============================================================================\n // EVENT HANDLERS\n // =============================================================================\n const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {\n if (onChange) {\n if (allowSpacing) {\n handleSpacingAndCaretPosition(event);\n } else {\n onChange(event);\n }\n }\n };\n\n const handleClear = () => {\n if (onClear) onClear();\n\n if (elementRef && elementRef.current) {\n elementRef.current.focus();\n }\n };\n\n // =============================================================================\n // HELPER FUNCTIONS\n // =============================================================================\n const convertInputString = (value: string | number | readonly string[]) => {\n if (!value) return \"\";\n if (allowSpacing) {\n return StringHelper.transformWithSpaces(value, spacing);\n }\n return value;\n };\n\n const handleSpacingAndCaretPosition = (\n event: React.ChangeEvent<HTMLInputElement>\n ) => {\n const nextState = getNextInputState();\n if (!nextState) return;\n\n const { nextValue, updateCaretPosition } = nextState;\n\n // Send to handler unspaced value\n const valueWithoutSpace = nextValue.replace(/\\s/g, \"\");\n event.target.value = valueWithoutSpace;\n onChange?.(event);\n\n updateCaretPosition();\n };\n\n const shouldShowClear = () => {\n return allowClear && !disabled && !readOnly && !!value;\n };\n\n // =============================================================================\n // RENDER FUNCTIONS\n // =============================================================================\n /**\n * To clear controlled input value, you have to pass in value as empty string,\n * then set `updatedValue` to empty string.\n * `updatedValue` for uncontrolled components remains as undefined such that the\n * user is free to edit the field. (else the value of the InputElement will\n * be set to empty string)\n */\n const updatedValue = value ? convertInputString(value) : value;\n const showClear = shouldShowClear();\n\n const renderInputElement = () => {\n const inputClassName = clsx(styles.inputElement, {\n [styles.inputElementDisabled]: disabled,\n [styles.inputElementPaddingLeft]:\n styleType !== \"no-border\" && !readOnly,\n [styles.inputElementPaddingRight]:\n styleType !== \"no-border\" && !readOnly && !showClear,\n });\n\n const clearButtonClassName = clsx(\n styles.clearButton,\n styleType === \"no-border\" && styles.clearButtonNoBorder\n );\n\n return (\n <>\n <BasicInput\n data-testid=\"input\"\n ref={elementRef}\n aria-disabled={disabled}\n value={updatedValue}\n onChange={handleChange}\n type={type}\n readOnly={readOnly || disabled}\n className={inputClassName}\n {...otherProps}\n />\n {showClear && (\n <BasicButton\n onClick={handleClear}\n type=\"button\"\n aria-label=\"Clear input\"\n className={clearButtonClassName}\n >\n <CrossIcon className={styles.clearIcon} aria-hidden />\n </BasicButton>\n )}\n </>\n );\n };\n\n return (\n <>\n {styleType === \"no-border\" ? (\n <div className={clsx(styles.noBorderWrapper, className)}>\n {renderInputElement()}\n </div>\n ) : (\n <InputBox\n className={clsx(styles.defaultWrapper, className, {\n [styles.defaultWrapperDisabled]: disabled,\n [styles.defaultWrapperError]: error,\n [styles.defaultWrapperReadOnly]: readOnly,\n })}\n disabled={disabled}\n error={error}\n readOnly={readOnly}\n >\n {renderInputElement()}\n </InputBox>\n )}\n </>\n );\n};\n\n/**\n * A single-line text input field.\n *\n * Use `Input` for free-form text entry. It supports controlled and uncontrolled\n * usage.\n */\nexport const Input = React.forwardRef(Component);\n"],"names":["Input","React","forwardRef","_a","ref","value","spacing","type","error","disabled","readOnly","onChange","onClear","allowClear","className","styleType","otherProps","__rest","allowSpacing","shouldAllowSpacing","elementRef","useRef","useImperativeHandle","current","getNextInputState","useNextInputState","formatter","StringHelper","transformWithSpaces","handleChange","event","handleSpacingAndCaretPosition","handleClear","focus","nextState","nextValue","updateCaretPosition","valueWithoutSpace","replace","target","updatedValue","convertInputString","showClear","renderInputElement","inputClassName","clsx","styles.inputElement","inputElementDisabled","styles.inputElementDisabled","inputElementPaddingLeft","styles.inputElementPaddingLeft","inputElementPaddingRight","styles.inputElementPaddingRight","clearButtonClassName","styles.clearButton","styles.clearButtonNoBorder","_jsxs","_Fragment","children","_jsx","BasicInput","BasicButton","onClick","CrossIcon","styles.clearIcon","styles.noBorderWrapper","InputBox","styles.defaultWrapper","defaultWrapperDisabled","styles.defaultWrapperDisabled","defaultWrapperError","styles.defaultWrapperError","defaultWrapperReadOnly","styles.defaultWrapperReadOnly"],"mappings":"k6BASA,
|
|
1
|
+
{"version":3,"file":"input.js","sources":["../../src/input/input.tsx"],"sourcesContent":["import { CrossIcon } from \"@lifesg/react-icons/cross\";\nimport clsx from \"clsx\";\nimport React, { useImperativeHandle, useRef } from \"react\";\n\nimport { BasicButton, BasicInput, InputBox } from \"../shared/input-wrapper\";\nimport { StringHelper, useNextInputState } from \"../util\";\nimport * as styles from \"./input.styles\";\nimport type { InputProps, InputRef } from \"./types\";\n\nconst shouldAllowSpacing = (\n type: string | undefined,\n spacing: number | undefined\n): spacing is number => {\n return type === \"tel\" && !!spacing;\n};\n\nconst Component = (\n {\n value,\n spacing,\n type,\n error,\n disabled,\n readOnly,\n onChange,\n onClear,\n allowClear = false,\n className,\n styleType = \"bordered\",\n ...otherProps\n }: InputProps,\n ref: InputRef\n): JSX.Element => {\n // =============================================================================\n // CONST, STATE, REF\n // =============================================================================\n const allowSpacing = shouldAllowSpacing(type, spacing);\n const elementRef = useRef<HTMLInputElement>(null);\n useImperativeHandle(ref, () => elementRef.current!, []);\n\n const getNextInputState = useNextInputState({\n ref: elementRef,\n formatter: (value) => {\n return allowSpacing\n ? StringHelper.transformWithSpaces(value, spacing)\n : value;\n },\n });\n\n // =============================================================================\n // EVENT HANDLERS\n // =============================================================================\n const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {\n if (onChange) {\n if (allowSpacing) {\n handleSpacingAndCaretPosition(event);\n } else {\n onChange(event);\n }\n }\n };\n\n const handleClear = () => {\n if (onClear) onClear();\n\n if (elementRef && elementRef.current) {\n elementRef.current.focus();\n }\n };\n\n // =============================================================================\n // HELPER FUNCTIONS\n // =============================================================================\n const convertInputString = (value: string | number | readonly string[]) => {\n if (!value) return \"\";\n if (allowSpacing) {\n return StringHelper.transformWithSpaces(value, spacing);\n }\n return value;\n };\n\n const handleSpacingAndCaretPosition = (\n event: React.ChangeEvent<HTMLInputElement>\n ) => {\n const nextState = getNextInputState();\n if (!nextState) return;\n\n const { nextValue, updateCaretPosition } = nextState;\n\n // Send to handler unspaced value\n const valueWithoutSpace = nextValue.replace(/\\s/g, \"\");\n event.target.value = valueWithoutSpace;\n onChange?.(event);\n\n updateCaretPosition();\n };\n\n const shouldShowClear = () => {\n return allowClear && !disabled && !readOnly && !!value;\n };\n\n // =============================================================================\n // RENDER FUNCTIONS\n // =============================================================================\n /**\n * To clear controlled input value, you have to pass in value as empty string,\n * then set `updatedValue` to empty string.\n * `updatedValue` for uncontrolled components remains as undefined such that the\n * user is free to edit the field. (else the value of the InputElement will\n * be set to empty string)\n */\n const updatedValue = value ? convertInputString(value) : value;\n const showClear = shouldShowClear();\n\n const renderInputElement = () => {\n const inputClassName = clsx(styles.inputElement, {\n [styles.inputElementDisabled]: disabled,\n [styles.inputElementPaddingLeft]:\n styleType !== \"no-border\" && !readOnly,\n [styles.inputElementPaddingRight]:\n styleType !== \"no-border\" && !readOnly && !showClear,\n });\n\n const clearButtonClassName = clsx(\n styles.clearButton,\n styleType === \"no-border\" && styles.clearButtonNoBorder\n );\n\n return (\n <>\n <BasicInput\n data-testid=\"input\"\n ref={elementRef}\n aria-disabled={disabled}\n value={updatedValue}\n onChange={handleChange}\n type={type}\n readOnly={readOnly || disabled}\n className={inputClassName}\n {...otherProps}\n />\n {showClear && (\n <BasicButton\n onClick={handleClear}\n type=\"button\"\n aria-label=\"Clear input\"\n className={clearButtonClassName}\n >\n <CrossIcon className={styles.clearIcon} aria-hidden />\n </BasicButton>\n )}\n </>\n );\n };\n\n return (\n <>\n {styleType === \"no-border\" ? (\n <div className={clsx(styles.noBorderWrapper, className)}>\n {renderInputElement()}\n </div>\n ) : (\n <InputBox\n className={clsx(styles.defaultWrapper, className, {\n [styles.defaultWrapperDisabled]: disabled,\n [styles.defaultWrapperError]: error,\n [styles.defaultWrapperReadOnly]: readOnly,\n })}\n disabled={disabled}\n error={error}\n readOnly={readOnly}\n >\n {renderInputElement()}\n </InputBox>\n )}\n </>\n );\n};\n\n// @catalog\n/**\n * A single-line text input field.\n *\n * Use `Input` for free-form text entry. It supports controlled and uncontrolled\n * usage.\n */\nexport const Input = React.forwardRef(Component);\n"],"names":["Input","React","forwardRef","_a","ref","value","spacing","type","error","disabled","readOnly","onChange","onClear","allowClear","className","styleType","otherProps","__rest","allowSpacing","shouldAllowSpacing","elementRef","useRef","useImperativeHandle","current","getNextInputState","useNextInputState","formatter","StringHelper","transformWithSpaces","handleChange","event","handleSpacingAndCaretPosition","handleClear","focus","nextState","nextValue","updateCaretPosition","valueWithoutSpace","replace","target","updatedValue","convertInputString","showClear","renderInputElement","inputClassName","clsx","styles.inputElement","inputElementDisabled","styles.inputElementDisabled","inputElementPaddingLeft","styles.inputElementPaddingLeft","inputElementPaddingRight","styles.inputElementPaddingRight","clearButtonClassName","styles.clearButton","styles.clearButtonNoBorder","_jsxs","_Fragment","children","_jsx","BasicInput","BasicButton","onClick","CrossIcon","styles.clearIcon","styles.noBorderWrapper","InputBox","styles.defaultWrapper","defaultWrapperDisabled","styles.defaultWrapperDisabled","defaultWrapperError","styles.defaultWrapperError","defaultWrapperReadOnly","styles.defaultWrapperReadOnly"],"mappings":"k6BASA,MAiLaA,EAAQC,EAAMC,YA1KT,CACdC,EAcAC,KAdA,IAAAC,MACIA,EAAKC,QACLA,EAAOC,KACPA,EAAIC,MACJA,EAAKC,SACLA,EAAQC,SACRA,EAAQC,SACRA,EAAQC,QACRA,EAAOC,WACPA,GAAa,EAAKC,UAClBA,EAASC,UACTA,EAAY,YAAUZ,EACnBa,EAAUC,EAAAd,EAZjB,oHAmBA,MAAMe,EA3BiB,EACvBX,EACAD,IAEgB,QAATC,KAAoBD,EAuBNa,CAAmBZ,EAAMD,GACxCc,EAAaC,EAAyB,MAC5CC,EAAoBlB,GAAK,IAAMgB,EAAWG,SAAU,IAEpD,MAAMC,EAAoBC,EAAkB,CACxCrB,IAAKgB,EACLM,UAAYrB,GACDa,EACDS,EAAaC,oBAAoBvB,EAAOC,GACxCD,IAORwB,EAAgBC,IACdnB,IACIO,EACAa,EAA8BD,GAE9BnB,EAASmB,GAEjB,EAGEE,EAAc,KACZpB,GAASA,IAETQ,GAAcA,EAAWG,SACzBH,EAAWG,QAAQU,OACvB,EAcEF,EACFD,IAEA,MAAMI,EAAYV,IAClB,IAAKU,EAAW,OAEhB,MAAMC,UAAEA,EAASC,oBAAEA,GAAwBF,EAGrCG,EAAoBF,EAAUG,QAAQ,MAAO,IACnDR,EAAMS,OAAOlC,MAAQgC,EACrB1B,SAAAA,EAAWmB,GAEXM,GAAqB,EAiBnBI,EAAenC,EAtCM,CAACA,GACnBA,EACDa,EACOS,EAAaC,oBAAoBvB,EAAOC,GAE5CD,EAJY,GAqCMoC,CAAmBpC,GAASA,EACnDqC,EAdK7B,IAAeJ,IAAaC,KAAcL,EAgB/CsC,EAAqB,KACvB,MAAMC,EAAiBC,EAAKC,EAAqB,CAC7CC,CAACC,GAA8BvC,EAC/BwC,CAACC,GACiB,cAAdnC,IAA8BL,EAClCyC,CAACC,GACiB,cAAdrC,IAA8BL,IAAagC,IAG7CW,EAAuBR,EACzBS,EACc,cAAdvC,GAA6BwC,GAGjC,OACIC,EAAAC,EAAA,CAAAC,SAAA,CACIC,EAACC,+BACe,QACZxD,IAAKgB,EAAU,gBACAX,EACfJ,MAAOmC,EACP7B,SAAUkB,EACVtB,KAAMA,EACNG,SAAUA,GAAYD,EACtBK,UAAW8B,GACP5B,IAEP0B,GACGiB,EAACE,EAAW,CACRC,QAAS9B,EACTzB,KAAK,sBACM,cACXO,UAAWuC,EAAoBK,SAE/BC,EAACI,GAAUjD,UAAWkD,EAAgB,eAAA,QAG/C,EAIX,OACIL,EAAAF,EAAA,CAAAC,SACmB,cAAd3C,EACG4C,EAAA,MAAA,CAAK7C,UAAW+B,EAAKoB,EAAwBnD,GAAU4C,SAClDf,MAGLgB,EAACO,GACGpD,UAAW+B,EAAKsB,EAAuBrD,EAAW,CAC9CsD,CAACC,GAAgC5D,EACjC6D,CAACC,GAA6B/D,EAC9BgE,CAACC,GAAgC/D,IAErCD,SAAUA,EACVD,MAAOA,EACPE,SAAUA,WAETiC,OAGV"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"input-group.js","sources":["../../src/input-group/input-group.tsx"],"sourcesContent":["import clsx from \"clsx\";\nimport React from \"react\";\n\nimport { Input } from \"../input\";\nimport { concatIds, VisuallyHidden } from \"../shared/accessibility\";\nimport { InputBox } from \"../shared/input-wrapper\";\nimport { useId } from \"../util\";\nimport * as styles from \"./input-group.styles\";\nimport { InputGroupListAddon } from \"./input-group-list-addon\";\nimport type {\n CustomAddon,\n InputGroupProps,\n LabelAddon,\n ListAddon,\n} from \"./types\";\n\nconst Component = <T, V>(\n {\n addon,\n error,\n className,\n noBorder,\n \"aria-label\": ariaLabel,\n \"aria-labelledby\": ariaLabelledBy,\n ...otherProps\n }: InputGroupProps<T, V>,\n ref: React.Ref<HTMLInputElement>\n) => {\n // =============================================================================\n // CONST, STATE, REF\n // =============================================================================\n const internalId = useId();\n const addonId = `${internalId}-addon`;\n const ariaLabelId = `${internalId}-ariaLabelId`;\n\n // =============================================================================\n // RENDER FUNCTIONS\n // =============================================================================\n const renderNoAddons = () => (\n <InputBox\n disabled={otherProps.disabled}\n error={error}\n readOnly={otherProps.readOnly}\n noBorder={noBorder}\n data-testid={otherProps[\"data-testid\"]}\n className={clsx(styles.noAddonWrapper, className)}\n data-read-only={otherProps.readOnly}\n data-no-border={noBorder}\n >\n <VisuallyHidden aria-hidden id={ariaLabelId}>\n {ariaLabel}\n </VisuallyHidden>\n <Input\n ref={ref}\n {...otherProps}\n data-testid=\"input\"\n styleType=\"no-border\"\n aria-labelledby={concatIds(ariaLabelId, ariaLabelledBy)}\n />\n </InputBox>\n );\n\n const renderWithAddon = (\n addonContent: React.ReactNode,\n position: \"left\" | \"right\",\n allowClear?: boolean\n ) => (\n <InputBox\n disabled={otherProps.disabled}\n error={error}\n readOnly={otherProps.readOnly}\n noBorder={noBorder}\n data-testid={otherProps[\"data-testid\"]}\n className={clsx(styles.addonWrapper, className)}\n data-read-only={otherProps.readOnly}\n data-no-border={noBorder}\n data-position={position}\n >\n <div\n data-testid=\"addon\"\n id={addonId}\n className={styles.labelAddonContainer}\n data-disabled={otherProps.disabled}\n data-read-only={otherProps.readOnly}\n data-position={position}\n >\n {addonContent}\n </div>\n <VisuallyHidden aria-hidden id={ariaLabelId}>\n {ariaLabel}\n </VisuallyHidden>\n <Input\n ref={ref}\n {...otherProps}\n aria-labelledby={concatIds(\n ariaLabelId,\n ariaLabelledBy,\n addonId\n )}\n allowClear={allowClear && position !== \"right\"}\n error={error}\n data-testid=\"input\"\n styleType=\"no-border\"\n />\n </InputBox>\n );\n\n if (addon) {\n const { type = \"label\", position = \"left\" } = addon;\n const { allowClear } = otherProps;\n\n switch (type) {\n case \"list\": {\n const listAddon = addon.attributes as ListAddon<T, V>;\n if (listAddon.options && listAddon.options.length > 0) {\n return (\n <InputGroupListAddon\n ref={ref}\n addon={addon}\n error={error}\n className={className}\n noBorder={noBorder}\n aria-label={ariaLabel}\n aria-labelledby={ariaLabelledBy}\n {...otherProps}\n />\n );\n } else {\n return renderNoAddons();\n }\n }\n\n case \"custom\": {\n const customAddon = addon.attributes as CustomAddon;\n if (customAddon.children) {\n return renderWithAddon(\n customAddon.children,\n position,\n allowClear\n );\n } else {\n return renderNoAddons();\n }\n }\n default: {\n const labelAddon = addon.attributes as LabelAddon;\n if (labelAddon.value) {\n return renderWithAddon(\n labelAddon.value,\n position,\n allowClear\n );\n } else {\n return renderNoAddons();\n }\n }\n }\n } else {\n return renderNoAddons();\n }\n};\n\n/**\n * A single-line text input optionally paired with a static label, a custom element, or a\n * dropdown list selector.\n *\n * Use `InputGroup` when the input needs contextual decoration such as a unit label,\n * a country-code dropdown, or a fully custom slot.\n */\nexport const InputGroup = React.forwardRef(Component);\n"],"names":["InputGroup","React","forwardRef","_a","ref","addon","error","className","noBorder","ariaLabel","ariaLabelledBy","otherProps","__rest","internalId","useId","addonId","ariaLabelId","renderNoAddons","_jsxs","InputBox","disabled","readOnly","clsx","styles.noAddonWrapper","_jsx","VisuallyHidden","id","children","Input","Object","assign","styleType","concatIds","renderWithAddon","addonContent","position","allowClear","styles.addonWrapper","styles.labelAddonContainer","type","listAddon","attributes","options","length","InputGroupListAddon","customAddon","labelAddon","value"],"mappings":"orBAgBA,
|
|
1
|
+
{"version":3,"file":"input-group.js","sources":["../../src/input-group/input-group.tsx"],"sourcesContent":["import clsx from \"clsx\";\nimport React from \"react\";\n\nimport { Input } from \"../input\";\nimport { concatIds, VisuallyHidden } from \"../shared/accessibility\";\nimport { InputBox } from \"../shared/input-wrapper\";\nimport { useId } from \"../util\";\nimport * as styles from \"./input-group.styles\";\nimport { InputGroupListAddon } from \"./input-group-list-addon\";\nimport type {\n CustomAddon,\n InputGroupProps,\n LabelAddon,\n ListAddon,\n} from \"./types\";\n\nconst Component = <T, V>(\n {\n addon,\n error,\n className,\n noBorder,\n \"aria-label\": ariaLabel,\n \"aria-labelledby\": ariaLabelledBy,\n ...otherProps\n }: InputGroupProps<T, V>,\n ref: React.Ref<HTMLInputElement>\n) => {\n // =============================================================================\n // CONST, STATE, REF\n // =============================================================================\n const internalId = useId();\n const addonId = `${internalId}-addon`;\n const ariaLabelId = `${internalId}-ariaLabelId`;\n\n // =============================================================================\n // RENDER FUNCTIONS\n // =============================================================================\n const renderNoAddons = () => (\n <InputBox\n disabled={otherProps.disabled}\n error={error}\n readOnly={otherProps.readOnly}\n noBorder={noBorder}\n data-testid={otherProps[\"data-testid\"]}\n className={clsx(styles.noAddonWrapper, className)}\n data-read-only={otherProps.readOnly}\n data-no-border={noBorder}\n >\n <VisuallyHidden aria-hidden id={ariaLabelId}>\n {ariaLabel}\n </VisuallyHidden>\n <Input\n ref={ref}\n {...otherProps}\n data-testid=\"input\"\n styleType=\"no-border\"\n aria-labelledby={concatIds(ariaLabelId, ariaLabelledBy)}\n />\n </InputBox>\n );\n\n const renderWithAddon = (\n addonContent: React.ReactNode,\n position: \"left\" | \"right\",\n allowClear?: boolean\n ) => (\n <InputBox\n disabled={otherProps.disabled}\n error={error}\n readOnly={otherProps.readOnly}\n noBorder={noBorder}\n data-testid={otherProps[\"data-testid\"]}\n className={clsx(styles.addonWrapper, className)}\n data-read-only={otherProps.readOnly}\n data-no-border={noBorder}\n data-position={position}\n >\n <div\n data-testid=\"addon\"\n id={addonId}\n className={styles.labelAddonContainer}\n data-disabled={otherProps.disabled}\n data-read-only={otherProps.readOnly}\n data-position={position}\n >\n {addonContent}\n </div>\n <VisuallyHidden aria-hidden id={ariaLabelId}>\n {ariaLabel}\n </VisuallyHidden>\n <Input\n ref={ref}\n {...otherProps}\n aria-labelledby={concatIds(\n ariaLabelId,\n ariaLabelledBy,\n addonId\n )}\n allowClear={allowClear && position !== \"right\"}\n error={error}\n data-testid=\"input\"\n styleType=\"no-border\"\n />\n </InputBox>\n );\n\n if (addon) {\n const { type = \"label\", position = \"left\" } = addon;\n const { allowClear } = otherProps;\n\n switch (type) {\n case \"list\": {\n const listAddon = addon.attributes as ListAddon<T, V>;\n if (listAddon.options && listAddon.options.length > 0) {\n return (\n <InputGroupListAddon\n ref={ref}\n addon={addon}\n error={error}\n className={className}\n noBorder={noBorder}\n aria-label={ariaLabel}\n aria-labelledby={ariaLabelledBy}\n {...otherProps}\n />\n );\n } else {\n return renderNoAddons();\n }\n }\n\n case \"custom\": {\n const customAddon = addon.attributes as CustomAddon;\n if (customAddon.children) {\n return renderWithAddon(\n customAddon.children,\n position,\n allowClear\n );\n } else {\n return renderNoAddons();\n }\n }\n default: {\n const labelAddon = addon.attributes as LabelAddon;\n if (labelAddon.value) {\n return renderWithAddon(\n labelAddon.value,\n position,\n allowClear\n );\n } else {\n return renderNoAddons();\n }\n }\n }\n } else {\n return renderNoAddons();\n }\n};\n\n// @catalog\n/**\n * A single-line text input optionally paired with a static label, a custom element, or a\n * dropdown list selector.\n *\n * Use `InputGroup` when the input needs contextual decoration such as a unit label,\n * a country-code dropdown, or a fully custom slot.\n */\nexport const InputGroup = React.forwardRef(Component);\n"],"names":["InputGroup","React","forwardRef","_a","ref","addon","error","className","noBorder","ariaLabel","ariaLabelledBy","otherProps","__rest","internalId","useId","addonId","ariaLabelId","renderNoAddons","_jsxs","InputBox","disabled","readOnly","clsx","styles.noAddonWrapper","_jsx","VisuallyHidden","id","children","Input","Object","assign","styleType","concatIds","renderWithAddon","addonContent","position","allowClear","styles.addonWrapper","styles.labelAddonContainer","type","listAddon","attributes","options","length","InputGroupListAddon","customAddon","labelAddon","value"],"mappings":"orBAgBA,MA0JaA,EAAaC,EAAMC,YA1Jd,CACdC,EASAC,SATAC,MACIA,EAAKC,MACLA,EAAKC,UACLA,EAASC,SACTA,EACA,aAAcC,EACd,kBAAmBC,GAAcP,EAC9BQ,EAAUC,EAAAT,EAPjB,yEAcA,MAAMU,EAAaC,IACbC,EAAU,GAAGF,UACbG,EAAc,GAAGH,gBAKjBI,EAAiB,IACnBC,EAACC,EAAQ,CACLC,SAAUT,EAAWS,SACrBd,MAAOA,EACPe,SAAUV,EAAWU,SACrBb,SAAUA,gBACGG,EAAW,eACxBJ,UAAWe,EAAKC,EAAuBhB,oBACvBI,EAAWU,SAAQ,iBACnBb,YAEhBgB,EAACC,EAAc,CAAA,eAAA,EAAaC,GAAIV,EAAWW,SACtClB,IAELe,EAACI,EAAKC,OAAAC,OAAA,CACF1B,IAAKA,GACDO,iBACQ,QACZoB,UAAU,8BACOC,EAAUhB,EAAaN,SAK9CuB,EAAkB,CACpBC,EACAC,EACAC,IAEAlB,EAACC,EAAQ,CACLC,SAAUT,EAAWS,SACrBd,MAAOA,EACPe,SAAUV,EAAWU,SACrBb,SAAUA,EAAQ,cACLG,EAAW,eACxBJ,UAAWe,EAAKe,EAAqB9B,GAAU,iBAC/BI,EAAWU,SAAQ,iBACnBb,EAAQ,gBACT2B,EAAQR,SAAA,CAEvBH,EAAA,MAAA,CAAA,cACgB,QACZE,GAAIX,EACJR,UAAW+B,EAA0B,gBACtB3B,EAAWS,SAAQ,iBAClBT,EAAWU,SAAQ,gBACpBc,EAAQR,SAEtBO,IAELV,EAACC,EAAc,CAAA,eAAA,EAAaC,GAAIV,EAAWW,SACtClB,IAELe,EAACI,iBACGxB,IAAKA,GACDO,EAAU,CAAA,kBACGqB,EACbhB,EACAN,EACAK,GAEJqB,WAAYA,GAA2B,UAAbD,EAC1B7B,MAAOA,EAAK,cACA,QACZyB,UAAU,kBAKtB,IAAI1B,EAmDA,OAAOY,IAnDA,CACP,MAAMsB,KAAEA,EAAO,QAAOJ,SAAEA,EAAW,QAAW9B,GACxC+B,WAAEA,GAAezB,EAEvB,OAAQ4B,GACJ,IAAK,OAAQ,CACT,MAAMC,EAAYnC,EAAMoC,WACxB,OAAID,EAAUE,SAAWF,EAAUE,QAAQC,OAAS,EAE5CnB,EAACoB,EAAmBf,OAAAC,OAAA,CAChB1B,IAAKA,EACLC,MAAOA,EACPC,MAAOA,EACPC,UAAWA,EACXC,SAAUA,EAAQ,aACNC,EAAS,kBACJC,GACbC,IAILM,GAEf,CAEA,IAAK,SAAU,CACX,MAAM4B,EAAcxC,EAAMoC,WAC1B,OAAII,EAAYlB,SACLM,EACHY,EAAYlB,SACZQ,EACAC,GAGGnB,GAEf,CACA,QAAS,CACL,MAAM6B,EAAazC,EAAMoC,WACzB,OAAIK,EAAWC,MACJd,EACHa,EAAWC,MACXZ,EACAC,GAGGnB,GAEf,EAER,CAEA"}
|
package/input-group/types.d.ts
CHANGED
|
@@ -75,7 +75,7 @@ export interface ListAddon<T, V> extends DropdownDisplayProps<T, V>, DropdownSea
|
|
|
75
75
|
* Note: if a parent of the trigger has a higher `z-index` than the dropdown,
|
|
76
76
|
* the dropdown may be obscured.
|
|
77
77
|
*
|
|
78
|
-
* @default
|
|
78
|
+
* @default document.body
|
|
79
79
|
*/
|
|
80
80
|
dropdownRootNode?: RefObject<HTMLElement> | undefined;
|
|
81
81
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"input-multi-select.js","sources":["../../src/input-multi-select/input-multi-select.tsx"],"sourcesContent":["import type { OpenChangeReason } from \"@floating-ui/react\";\nimport findIndex from \"lodash/findIndex\";\nimport type React from \"react\";\nimport { useEffect, useRef, useState } from \"react\";\n\nimport {\n DropdownList,\n DropdownListState,\n ExpandableElement,\n} from \"../shared/dropdown-list\";\nimport { ElementWithDropdown } from \"../shared/dropdown-wrapper\";\nimport {\n LabelContainer,\n PlaceholderLabel,\n ValueLabel,\n} from \"../shared/dropdown-wrapper/dropdown-wrapper\";\nimport { InputBox } from \"../shared/input-wrapper/input-wrapper\";\nimport { useId } from \"../util\";\nimport type { InputMultiSelectProps } from \"./types\";\n\n/**\n * A dropdown field that lets users select multiple options from a list.\n *\n * Use `InputMultiSelect` when users need to pick one or more items from a\n * predefined list.\n */\nexport const InputMultiSelect = <T, V>({\n selectedOptions,\n placeholder = \"Select\",\n options,\n disabled,\n error,\n className,\n \"data-testid\": testId,\n id,\n \"aria-labelledby\": ariaLabelledBy,\n \"aria-describedby\": ariaDescribedBy,\n \"aria-invalid\": ariaInvalid,\n enableSearch = false,\n searchFunction,\n searchPlaceholder,\n valueExtractor,\n listExtractor,\n onSelectOptions,\n onShowOptions,\n onHideOptions,\n onRetry,\n optionsLoadState = \"success\",\n optionTruncationType = \"end\",\n renderListItem,\n hideNoResultsDisplay,\n noResultsDescription,\n customLabels,\n renderCustomCallToAction,\n onBlur,\n variant = \"default\",\n readOnly,\n alignment,\n dropdownZIndex,\n maxSelectable,\n dropdownRootNode,\n dropdownWidth,\n}: InputMultiSelectProps<T, V>): JSX.Element => {\n // =============================================================================\n // CONST, STATE\n // =============================================================================\n const { allSelectedLabel, multiSelectedLabel } = customLabels || {};\n const [selected, setSelected] = useState<T[]>(selectedOptions || []);\n const [showOptions, setShowOptions] = useState<boolean>(false);\n const [focused, setFocused] = useState<boolean>(false);\n const internalId = useId();\n\n const nodeRef = useRef<HTMLDivElement>(null);\n const selectorRef = useRef<HTMLButtonElement>(null);\n\n // =============================================================================\n // EFFECTS\n // =============================================================================\n useEffect(() => {\n setSelected(selectedOptions || []);\n }, [selectedOptions]);\n\n // =============================================================================\n // EVENT HANDLERS\n // =============================================================================\n const handleSelectAllClick = () => {\n if ((selected && selected.length > 0) || maxSelectable) {\n setSelected([]);\n performOnSelectOptions([]);\n } else {\n setSelected(options);\n performOnSelectOptions(options);\n }\n };\n\n const handleListItemClick = (item: T, extractedValue: T | V) => {\n const selectedCopy = [...selected];\n\n // Check if it is a selection or deselection\n const itemIndex = findIndex(selected, (item) => {\n const valueToCompare = valueExtractor ? valueExtractor(item) : item;\n return valueToCompare === extractedValue;\n });\n\n if (itemIndex > -1) {\n // Item exists in selected. This indicates a deselection\n selectedCopy.splice(itemIndex, 1);\n } else {\n // Item does not exist in selected. This indicates a selection\n selectedCopy.push(item);\n }\n\n setSelected(selectedCopy);\n performOnSelectOptions(selectedCopy);\n };\n\n const handleListDismiss = () => {\n if (showOptions) {\n setShowOptions(false);\n triggerOptionDisplayCallback(false);\n }\n };\n\n const handleNodeFocus = () => {\n if (!focused && !showOptions) {\n setFocused(true);\n }\n };\n\n const handleNodeBlur = (e: React.FocusEvent) => {\n if (\n focused &&\n !showOptions &&\n nodeRef.current &&\n !nodeRef.current.contains(e.relatedTarget as Node)\n ) {\n setFocused(false);\n onBlur?.();\n }\n };\n\n const handleOpen = () => {\n setShowOptions(true);\n triggerOptionDisplayCallback(true);\n setFocused(true);\n };\n\n const handleClose = (reason: OpenChangeReason | undefined) => {\n setShowOptions(false);\n triggerOptionDisplayCallback(false);\n\n // click to toggle should not blur the input\n if (reason !== \"click\") {\n setFocused(false);\n onBlur?.();\n }\n };\n\n const handleDismiss = () => {\n selectorRef.current?.focus();\n setShowOptions(false);\n triggerOptionDisplayCallback(false);\n };\n\n // =============================================================================\n // HELPER FUNCTION\n // =============================================================================\n const getDisplayValue = () => {\n if (options && selected.length === options.length) {\n return allSelectedLabel || \"All selected\";\n }\n\n return multiSelectedLabel || `${selected.length} selected`;\n };\n\n const triggerOptionDisplayCallback = (show: boolean) => {\n if (!show && onHideOptions) {\n onHideOptions();\n }\n\n if (show && onShowOptions) {\n onShowOptions();\n }\n };\n\n const performOnSelectOptions = (options: T[]) => {\n if (onSelectOptions) {\n onSelectOptions(options);\n }\n };\n\n // =============================================================================\n // RENDER FUNCTIONS\n // =============================================================================\n const renderLabel = () => {\n if (!selected || selected.length === 0) {\n return (\n <PlaceholderLabel\n variant={variant}\n truncateType={optionTruncationType}\n >\n {placeholder}\n </PlaceholderLabel>\n );\n } else {\n return (\n <ValueLabel\n variant={variant}\n truncateType={optionTruncationType}\n >\n {getDisplayValue()}\n </ValueLabel>\n );\n }\n };\n\n const renderSelectorContent = () => (\n <LabelContainer disabled={disabled}>{renderLabel()}</LabelContainer>\n );\n\n const renderElement = () => {\n return (\n <InputBox\n className={className}\n data-testid={testId}\n id={id}\n ref={nodeRef}\n tabIndex={-1}\n onFocus={handleNodeFocus}\n onBlur={handleNodeBlur}\n focused={focused}\n disabled={disabled}\n readOnly={readOnly}\n error={error}\n >\n <ExpandableElement\n ref={selectorRef}\n disabled={disabled}\n expanded={showOptions}\n listboxId={internalId}\n popupRole=\"listbox\"\n readOnly={readOnly}\n variant={variant}\n aria-labelledby={ariaLabelledBy}\n aria-describedby={ariaDescribedBy}\n aria-invalid={ariaInvalid}\n >\n {renderSelectorContent()}\n </ExpandableElement>\n </InputBox>\n );\n };\n\n const renderDropdown = () => {\n return (\n <DropdownList\n listboxId={internalId}\n listItems={options}\n onSelectItem={handleListItemClick}\n onDismiss={handleListDismiss}\n valueExtractor={valueExtractor}\n listExtractor={listExtractor}\n enableSearch={enableSearch}\n searchFunction={searchFunction}\n searchPlaceholder={searchPlaceholder}\n multiSelect\n maxSelectable={maxSelectable}\n selectedItems={selected}\n onSelectAll={handleSelectAllClick}\n onRetry={onRetry}\n itemsLoadState={optionsLoadState}\n itemTruncationType={optionTruncationType}\n renderListItem={renderListItem}\n hideNoResultsDisplay={hideNoResultsDisplay}\n noResultsDescription={noResultsDescription}\n customLabels={customLabels}\n renderCustomCallToAction={renderCustomCallToAction}\n variant={variant}\n width={dropdownWidth}\n matchElementWidth\n />\n );\n };\n\n return (\n <DropdownListState>\n <ElementWithDropdown\n enabled={!readOnly && !disabled}\n isOpen={showOptions}\n renderElement={renderElement}\n renderDropdown={renderDropdown}\n onOpen={handleOpen}\n onClose={handleClose}\n onDismiss={handleDismiss}\n clickToToggle\n offset={8}\n alignment={alignment}\n fitAvailableHeight\n customZIndex={dropdownZIndex}\n rootNode={dropdownRootNode}\n />\n </DropdownListState>\n );\n};\n"],"names":["InputMultiSelect","selectedOptions","placeholder","options","disabled","error","className","testId","id","ariaLabelledBy","ariaDescribedBy","ariaInvalid","enableSearch","searchFunction","searchPlaceholder","valueExtractor","listExtractor","onSelectOptions","onShowOptions","onHideOptions","onRetry","optionsLoadState","optionTruncationType","renderListItem","hideNoResultsDisplay","noResultsDescription","customLabels","renderCustomCallToAction","onBlur","variant","readOnly","alignment","dropdownZIndex","maxSelectable","dropdownRootNode","dropdownWidth","allSelectedLabel","multiSelectedLabel","selected","setSelected","useState","showOptions","setShowOptions","focused","setFocused","internalId","useId","nodeRef","useRef","selectorRef","useEffect","handleSelectAllClick","length","performOnSelectOptions","handleListItemClick","item","extractedValue","selectedCopy","itemIndex","findIndex","splice","push","handleListDismiss","triggerOptionDisplayCallback","handleNodeFocus","handleNodeBlur","e","current","contains","relatedTarget","show","_jsx","DropdownListState","children","ElementWithDropdown","enabled","isOpen","renderElement","InputBox","ref","tabIndex","onFocus","ExpandableElement","expanded","listboxId","popupRole","LabelContainer","ValueLabel","truncateType","PlaceholderLabel","renderDropdown","DropdownList","listItems","onSelectItem","onDismiss","multiSelect","selectedItems","onSelectAll","itemsLoadState","itemTruncationType","width","matchElementWidth","onOpen","onClose","reason","_a","focus","clickToToggle","offset","fitAvailableHeight","customZIndex","rootNode"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"input-multi-select.js","sources":["../../src/input-multi-select/input-multi-select.tsx"],"sourcesContent":["import type { OpenChangeReason } from \"@floating-ui/react\";\nimport findIndex from \"lodash/findIndex\";\nimport type React from \"react\";\nimport { useEffect, useRef, useState } from \"react\";\n\nimport {\n DropdownList,\n DropdownListState,\n ExpandableElement,\n} from \"../shared/dropdown-list\";\nimport { ElementWithDropdown } from \"../shared/dropdown-wrapper\";\nimport {\n LabelContainer,\n PlaceholderLabel,\n ValueLabel,\n} from \"../shared/dropdown-wrapper/dropdown-wrapper\";\nimport { InputBox } from \"../shared/input-wrapper/input-wrapper\";\nimport { useId } from \"../util\";\nimport type { InputMultiSelectProps } from \"./types\";\n\n// @catalog\n/**\n * A dropdown field that lets users select multiple options from a list.\n *\n * Use `InputMultiSelect` when users need to pick one or more items from a\n * predefined list.\n */\nexport const InputMultiSelect = <T, V>({\n selectedOptions,\n placeholder = \"Select\",\n options,\n disabled,\n error,\n className,\n \"data-testid\": testId,\n id,\n \"aria-labelledby\": ariaLabelledBy,\n \"aria-describedby\": ariaDescribedBy,\n \"aria-invalid\": ariaInvalid,\n enableSearch = false,\n searchFunction,\n searchPlaceholder,\n valueExtractor,\n listExtractor,\n onSelectOptions,\n onShowOptions,\n onHideOptions,\n onRetry,\n optionsLoadState = \"success\",\n optionTruncationType = \"end\",\n renderListItem,\n hideNoResultsDisplay,\n noResultsDescription,\n customLabels,\n renderCustomCallToAction,\n onBlur,\n variant = \"default\",\n readOnly,\n alignment,\n dropdownZIndex,\n maxSelectable,\n dropdownRootNode,\n dropdownWidth,\n}: InputMultiSelectProps<T, V>): JSX.Element => {\n // =============================================================================\n // CONST, STATE\n // =============================================================================\n const { allSelectedLabel, multiSelectedLabel } = customLabels || {};\n const [selected, setSelected] = useState<T[]>(selectedOptions || []);\n const [showOptions, setShowOptions] = useState<boolean>(false);\n const [focused, setFocused] = useState<boolean>(false);\n const internalId = useId();\n\n const nodeRef = useRef<HTMLDivElement>(null);\n const selectorRef = useRef<HTMLButtonElement>(null);\n\n // =============================================================================\n // EFFECTS\n // =============================================================================\n useEffect(() => {\n setSelected(selectedOptions || []);\n }, [selectedOptions]);\n\n // =============================================================================\n // EVENT HANDLERS\n // =============================================================================\n const handleSelectAllClick = () => {\n if ((selected && selected.length > 0) || maxSelectable) {\n setSelected([]);\n performOnSelectOptions([]);\n } else {\n setSelected(options);\n performOnSelectOptions(options);\n }\n };\n\n const handleListItemClick = (item: T, extractedValue: T | V) => {\n const selectedCopy = [...selected];\n\n // Check if it is a selection or deselection\n const itemIndex = findIndex(selected, (item) => {\n const valueToCompare = valueExtractor ? valueExtractor(item) : item;\n return valueToCompare === extractedValue;\n });\n\n if (itemIndex > -1) {\n // Item exists in selected. This indicates a deselection\n selectedCopy.splice(itemIndex, 1);\n } else {\n // Item does not exist in selected. This indicates a selection\n selectedCopy.push(item);\n }\n\n setSelected(selectedCopy);\n performOnSelectOptions(selectedCopy);\n };\n\n const handleListDismiss = () => {\n if (showOptions) {\n setShowOptions(false);\n triggerOptionDisplayCallback(false);\n }\n };\n\n const handleNodeFocus = () => {\n if (!focused && !showOptions) {\n setFocused(true);\n }\n };\n\n const handleNodeBlur = (e: React.FocusEvent) => {\n if (\n focused &&\n !showOptions &&\n nodeRef.current &&\n !nodeRef.current.contains(e.relatedTarget as Node)\n ) {\n setFocused(false);\n onBlur?.();\n }\n };\n\n const handleOpen = () => {\n setShowOptions(true);\n triggerOptionDisplayCallback(true);\n setFocused(true);\n };\n\n const handleClose = (reason: OpenChangeReason | undefined) => {\n setShowOptions(false);\n triggerOptionDisplayCallback(false);\n\n // click to toggle should not blur the input\n if (reason !== \"click\") {\n setFocused(false);\n onBlur?.();\n }\n };\n\n const handleDismiss = () => {\n selectorRef.current?.focus();\n setShowOptions(false);\n triggerOptionDisplayCallback(false);\n };\n\n // =============================================================================\n // HELPER FUNCTION\n // =============================================================================\n const getDisplayValue = () => {\n if (options && selected.length === options.length) {\n return allSelectedLabel || \"All selected\";\n }\n\n return multiSelectedLabel || `${selected.length} selected`;\n };\n\n const triggerOptionDisplayCallback = (show: boolean) => {\n if (!show && onHideOptions) {\n onHideOptions();\n }\n\n if (show && onShowOptions) {\n onShowOptions();\n }\n };\n\n const performOnSelectOptions = (options: T[]) => {\n if (onSelectOptions) {\n onSelectOptions(options);\n }\n };\n\n // =============================================================================\n // RENDER FUNCTIONS\n // =============================================================================\n const renderLabel = () => {\n if (!selected || selected.length === 0) {\n return (\n <PlaceholderLabel\n variant={variant}\n truncateType={optionTruncationType}\n >\n {placeholder}\n </PlaceholderLabel>\n );\n } else {\n return (\n <ValueLabel\n variant={variant}\n truncateType={optionTruncationType}\n >\n {getDisplayValue()}\n </ValueLabel>\n );\n }\n };\n\n const renderSelectorContent = () => (\n <LabelContainer disabled={disabled}>{renderLabel()}</LabelContainer>\n );\n\n const renderElement = () => {\n return (\n <InputBox\n className={className}\n data-testid={testId}\n id={id}\n ref={nodeRef}\n tabIndex={-1}\n onFocus={handleNodeFocus}\n onBlur={handleNodeBlur}\n focused={focused}\n disabled={disabled}\n readOnly={readOnly}\n error={error}\n >\n <ExpandableElement\n ref={selectorRef}\n disabled={disabled}\n expanded={showOptions}\n listboxId={internalId}\n popupRole=\"listbox\"\n readOnly={readOnly}\n variant={variant}\n aria-labelledby={ariaLabelledBy}\n aria-describedby={ariaDescribedBy}\n aria-invalid={ariaInvalid}\n >\n {renderSelectorContent()}\n </ExpandableElement>\n </InputBox>\n );\n };\n\n const renderDropdown = () => {\n return (\n <DropdownList\n listboxId={internalId}\n listItems={options}\n onSelectItem={handleListItemClick}\n onDismiss={handleListDismiss}\n valueExtractor={valueExtractor}\n listExtractor={listExtractor}\n enableSearch={enableSearch}\n searchFunction={searchFunction}\n searchPlaceholder={searchPlaceholder}\n multiSelect\n maxSelectable={maxSelectable}\n selectedItems={selected}\n onSelectAll={handleSelectAllClick}\n onRetry={onRetry}\n itemsLoadState={optionsLoadState}\n itemTruncationType={optionTruncationType}\n renderListItem={renderListItem}\n hideNoResultsDisplay={hideNoResultsDisplay}\n noResultsDescription={noResultsDescription}\n customLabels={customLabels}\n renderCustomCallToAction={renderCustomCallToAction}\n variant={variant}\n width={dropdownWidth}\n matchElementWidth\n />\n );\n };\n\n return (\n <DropdownListState>\n <ElementWithDropdown\n enabled={!readOnly && !disabled}\n isOpen={showOptions}\n renderElement={renderElement}\n renderDropdown={renderDropdown}\n onOpen={handleOpen}\n onClose={handleClose}\n onDismiss={handleDismiss}\n clickToToggle\n offset={8}\n alignment={alignment}\n fitAvailableHeight\n customZIndex={dropdownZIndex}\n rootNode={dropdownRootNode}\n />\n </DropdownListState>\n );\n};\n"],"names":["InputMultiSelect","selectedOptions","placeholder","options","disabled","error","className","testId","id","ariaLabelledBy","ariaDescribedBy","ariaInvalid","enableSearch","searchFunction","searchPlaceholder","valueExtractor","listExtractor","onSelectOptions","onShowOptions","onHideOptions","onRetry","optionsLoadState","optionTruncationType","renderListItem","hideNoResultsDisplay","noResultsDescription","customLabels","renderCustomCallToAction","onBlur","variant","readOnly","alignment","dropdownZIndex","maxSelectable","dropdownRootNode","dropdownWidth","allSelectedLabel","multiSelectedLabel","selected","setSelected","useState","showOptions","setShowOptions","focused","setFocused","internalId","useId","nodeRef","useRef","selectorRef","useEffect","handleSelectAllClick","length","performOnSelectOptions","handleListItemClick","item","extractedValue","selectedCopy","itemIndex","findIndex","splice","push","handleListDismiss","triggerOptionDisplayCallback","handleNodeFocus","handleNodeBlur","e","current","contains","relatedTarget","show","_jsx","DropdownListState","children","ElementWithDropdown","enabled","isOpen","renderElement","InputBox","ref","tabIndex","onFocus","ExpandableElement","expanded","listboxId","popupRole","LabelContainer","ValueLabel","truncateType","PlaceholderLabel","renderDropdown","DropdownList","listItems","onSelectItem","onDismiss","multiSelect","selectedItems","onSelectAll","itemsLoadState","itemTruncationType","width","matchElementWidth","onOpen","onClose","reason","_a","focus","clickToToggle","offset","fitAvailableHeight","customZIndex","rootNode"],"mappings":"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"}
|
|
@@ -56,7 +56,7 @@ export interface InputMultiSelectProps<T, V> extends React.HTMLAttributes<HTMLEl
|
|
|
56
56
|
* Note: if a parent of the trigger has a higher `z-index` than the dropdown,
|
|
57
57
|
* the dropdown may be obscured.
|
|
58
58
|
*
|
|
59
|
-
* @default
|
|
59
|
+
* @default document.body
|
|
60
60
|
*/
|
|
61
61
|
dropdownRootNode?: RefObject<HTMLElement> | undefined;
|
|
62
62
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"input-nested-multi-select.js","sources":["../../src/input-nested-multi-select/input-nested-multi-select.tsx"],"sourcesContent":["import type { OpenChangeReason } from \"@floating-ui/react\";\nimport isEmpty from \"lodash/isEmpty\";\nimport isEqual from \"lodash/isEqual\";\nimport type React from \"react\";\nimport { useEffect, useRef, useState } from \"react\";\n\nimport type {\n NestedDropdownListItemProps,\n NestedDropdownListLocalItem,\n} from \"../shared/dropdown-list\";\nimport {\n buildKeyPathToSet,\n ExpandableElement,\n NestedDropdownList,\n} from \"../shared/dropdown-list\";\nimport { ElementWithDropdown } from \"../shared/dropdown-wrapper\";\nimport {\n LabelContainer,\n PlaceholderLabel,\n ValueLabel,\n} from \"../shared/dropdown-wrapper/dropdown-wrapper\";\nimport { InputBox } from \"../shared/input-wrapper/input-wrapper\";\nimport { StringHelper, useId } from \"../util\";\nimport type { SelectedItem } from \"./helpers\";\nimport { getSelectedItems, getSelectedSubItems } from \"./helpers\";\nimport type {\n InputNestedMultiSelectProps,\n InputNestedMultiSelectValue,\n InputNestedMultiSelectValues,\n} from \"./types\";\n\n/**\n * A multi-select input that presents options in a nested hierarchy, up to three levels deep.\n *\n * Use `InputNestedMultiSelect` when users need to choose multiple values from a\n * hierarchical option tree. Selecting a parent item automatically selects all its\n * leaf descendants; deselecting a parent removes all its descendants from the\n * selection.\n */\nexport const InputNestedMultiSelect = <V1, V2, V3>({\n placeholder = \"Select\",\n options: _options,\n disabled,\n error,\n className,\n \"data-testid\": testId,\n id,\n \"aria-labelledby\": ariaLabelledBy,\n \"aria-describedby\": ariaDescribedBy,\n \"aria-invalid\": ariaInvalid,\n selectedKeyPaths: _selectedKeyPaths,\n mode,\n valueToStringFunction,\n enableSearch,\n searchPlaceholder,\n hideNoResultsDisplay,\n noResultsDescription,\n customLabels,\n readOnly,\n onSearch,\n onSelectOptions,\n onShowOptions,\n onHideOptions,\n onRetry,\n onBlur,\n optionsLoadState = \"success\",\n optionTruncationType = \"end\",\n variant = \"default\",\n alignment,\n dropdownZIndex,\n dropdownWidth,\n dropdownRootNode,\n}: InputNestedMultiSelectProps<V1, V2, V3>): JSX.Element => {\n // =========================================================================\n // CONST, STATE\n // =========================================================================\n type NestedValue = InputNestedMultiSelectValue<V1, V2, V3>;\n\n const { multiSelectedLabel } = customLabels || {};\n const options = _options as NestedDropdownListItemProps<NestedValue>[];\n const [selectedKeyPaths, setSelectedKeyPaths] = useState<Set<string>>(\n _selectedKeyPaths\n ? buildKeyPathToSet(_selectedKeyPaths)\n : new Set<string>()\n );\n const [selectedItems, setSelectedItems] = useState<\n SelectedItem<NestedValue>[]\n >([]);\n\n const [showOptions, setShowOptions] = useState<boolean>(false);\n const [focused, setFocused] = useState<boolean>(false);\n const internalId = useId();\n\n const nodeRef = useRef<HTMLDivElement>(null);\n const selectorRef = useRef<HTMLButtonElement>(null);\n const labelContainerRef = useRef<HTMLDivElement>(null);\n\n // =========================================================================\n // EFFECTS\n // =========================================================================\n useEffect(() => {\n const newKeyPath = _selectedKeyPaths || [];\n const selectedItems = getSelectedItems(options, newKeyPath);\n\n setSelectedKeyPaths(buildKeyPathToSet(newKeyPath));\n setSelectedItems(selectedItems);\n }, [_selectedKeyPaths, options]);\n\n // =========================================================================\n // EVENT HANDLERS\n // =========================================================================\n const handleSelectAll = (\n keyPaths: string[][],\n items: NestedDropdownListLocalItem<NestedValue>[]\n ) => {\n const selectedItems: SelectedItem<NestedValue>[] = items.map(\n (item) => ({\n keyPath: item.keyPath,\n label: item.item.label,\n value: item.item.value,\n })\n );\n setSelectedKeyPaths(buildKeyPathToSet(keyPaths));\n setSelectedItems(selectedItems);\n performOnSelectOptions(keyPaths, selectedItems);\n };\n\n const handleListItemClick = (\n listItem: NestedDropdownListLocalItem<NestedValue>\n ) => {\n const newSelectedItems: SelectedItem<NestedValue>[] =\n getNewSelection(listItem);\n const newKeyPaths = newSelectedItems.map((item) => item.keyPath);\n setSelectedItems(newSelectedItems);\n setSelectedKeyPaths(buildKeyPathToSet(newKeyPaths));\n performOnSelectOptions(newKeyPaths, newSelectedItems);\n };\n\n const handleNodeFocus = () => {\n if (!focused && !showOptions) {\n setFocused(true);\n }\n };\n\n const handleNodeBlur = (e: React.FocusEvent) => {\n if (\n focused &&\n !showOptions &&\n nodeRef.current &&\n !nodeRef.current.contains(e.relatedTarget as Node)\n ) {\n setFocused(false);\n onBlur?.();\n }\n };\n\n const handleOpen = () => {\n setShowOptions(true);\n triggerOptionDisplayCallback(true);\n setFocused(true);\n };\n\n const handleClose = (reason: OpenChangeReason | undefined) => {\n setShowOptions(false);\n triggerOptionDisplayCallback(false);\n\n // click to toggle should not blur the input\n if (reason !== \"click\") {\n setFocused(false);\n onBlur?.();\n }\n };\n\n const handleDismiss = () => {\n selectorRef.current?.focus();\n setShowOptions(false);\n triggerOptionDisplayCallback(false);\n };\n\n // =========================================================================\n // HELPER FUNCTION\n // =========================================================================\n const getDisplayValue = (): string => {\n if (selectedItems.length > 1) {\n return multiSelectedLabel || `${selectedItems.length} selected`;\n }\n\n const { label, value } = selectedItems[0];\n if (valueToStringFunction) {\n return valueToStringFunction(value);\n } else {\n return label;\n }\n };\n\n const truncateValue = (value: string) => {\n if (optionTruncationType === \"middle\") {\n let widthOfElement = 0;\n if (labelContainerRef && labelContainerRef.current) {\n widthOfElement =\n labelContainerRef.current.getBoundingClientRect().width;\n }\n return StringHelper.truncateOneLine(value, widthOfElement, 120, 6);\n }\n\n return value;\n };\n\n const triggerOptionDisplayCallback = (show: boolean) => {\n if (!show && onHideOptions) {\n onHideOptions();\n }\n\n if (show && onShowOptions) {\n onShowOptions();\n }\n };\n\n const performOnSelectOptions = (\n keyPaths: string[][],\n items: SelectedItem<NestedValue>[]\n ) => {\n if (onSelectOptions) {\n const returnValue: InputNestedMultiSelectValues<V1, V2, V3> =\n items.map((item) => item.value);\n onSelectOptions(keyPaths, returnValue);\n }\n };\n\n const getNewSelection = (\n item: NestedDropdownListLocalItem<NestedValue>\n ): SelectedItem<NestedValue>[] => {\n if (item.checked === true) {\n // remove item or subitems\n return selectedItems.filter((selectedItem) => {\n const ancestorKeyPath = selectedItem.keyPath.slice(\n 0,\n item.keyPath.length\n );\n return !isEqual(item.keyPath, ancestorKeyPath);\n });\n } else {\n // select item or all subitems\n const nextSelection = [...selectedItems];\n const newItemsToAdd = item.hasSubItems\n ? getSelectedSubItems(options, item.keyPath)\n : [\n {\n value: item.item.value,\n label: item.item.label,\n keyPath: item.keyPath,\n },\n ];\n newItemsToAdd.forEach((addedItem) => {\n if (\n !selectedItems.find((selectedItem) =>\n isEqual(selectedItem.keyPath, addedItem.keyPath)\n )\n ) {\n nextSelection.push(addedItem);\n }\n });\n return nextSelection;\n }\n };\n\n // =========================================================================\n // RENDER FUNCTION\n // =========================================================================\n const renderLabel = () => {\n if (isEmpty(selectedItems)) {\n return (\n <PlaceholderLabel truncateType={optionTruncationType}>\n {placeholder}\n </PlaceholderLabel>\n );\n } else {\n return (\n <ValueLabel truncateType={optionTruncationType}>\n {truncateValue(getDisplayValue())}\n </ValueLabel>\n );\n }\n };\n\n const renderSelectorContent = () => (\n <LabelContainer ref={labelContainerRef} disabled={disabled}>\n {renderLabel()}\n </LabelContainer>\n );\n\n const renderElement = () => {\n return (\n <InputBox\n className={className}\n data-testid={testId}\n id={id}\n ref={nodeRef}\n tabIndex={-1}\n onFocus={handleNodeFocus}\n onBlur={handleNodeBlur}\n focused={focused}\n disabled={disabled}\n readOnly={readOnly}\n error={error}\n >\n <ExpandableElement\n ref={selectorRef}\n disabled={disabled}\n expanded={showOptions}\n listboxId={internalId}\n popupRole=\"tree\"\n readOnly={readOnly}\n variant={variant}\n aria-labelledby={ariaLabelledBy}\n aria-describedby={ariaDescribedBy}\n aria-invalid={ariaInvalid}\n >\n {renderSelectorContent()}\n </ExpandableElement>\n </InputBox>\n );\n };\n\n const renderDropdown = () => {\n return (\n <NestedDropdownList\n listboxId={internalId}\n listItems={options}\n multiSelect\n selectedKeyPaths={selectedKeyPaths}\n itemsLoadState={optionsLoadState}\n itemTruncationType={optionTruncationType}\n enableSearch={enableSearch}\n searchPlaceholder={searchPlaceholder}\n hideNoResultsDisplay={hideNoResultsDisplay}\n noResultsDescription={noResultsDescription}\n customLabels={customLabels}\n onSelectItem={handleListItemClick}\n onSelectAll={handleSelectAll}\n onRetry={onRetry}\n onSearch={onSearch}\n variant={variant}\n mode={mode}\n width={dropdownWidth}\n matchElementWidth\n />\n );\n };\n\n return (\n <ElementWithDropdown\n enabled={!readOnly && !disabled}\n isOpen={showOptions}\n renderElement={renderElement}\n renderDropdown={renderDropdown}\n onOpen={handleOpen}\n onClose={handleClose}\n onDismiss={handleDismiss}\n clickToToggle\n offset={8}\n alignment={alignment}\n fitAvailableHeight\n customZIndex={dropdownZIndex}\n rootNode={dropdownRootNode}\n />\n );\n};\n"],"names":["InputNestedMultiSelect","placeholder","options","_options","disabled","error","className","testId","id","ariaLabelledBy","ariaDescribedBy","ariaInvalid","selectedKeyPaths","_selectedKeyPaths","mode","valueToStringFunction","enableSearch","searchPlaceholder","hideNoResultsDisplay","noResultsDescription","customLabels","readOnly","onSearch","onSelectOptions","onShowOptions","onHideOptions","onRetry","onBlur","optionsLoadState","optionTruncationType","variant","alignment","dropdownZIndex","dropdownWidth","dropdownRootNode","multiSelectedLabel","setSelectedKeyPaths","useState","buildKeyPathToSet","Set","selectedItems","setSelectedItems","showOptions","setShowOptions","focused","setFocused","internalId","useId","nodeRef","useRef","selectorRef","labelContainerRef","useEffect","newKeyPath","getSelectedItems","handleSelectAll","keyPaths","items","map","item","keyPath","label","value","performOnSelectOptions","handleListItemClick","listItem","newSelectedItems","getNewSelection","newKeyPaths","handleNodeFocus","handleNodeBlur","e","current","contains","relatedTarget","getDisplayValue","length","truncateValue","widthOfElement","getBoundingClientRect","width","StringHelper","truncateOneLine","triggerOptionDisplayCallback","show","returnValue","checked","filter","selectedItem","ancestorKeyPath","slice","isEqual","nextSelection","hasSubItems","getSelectedSubItems","forEach","addedItem","find","push","_jsx","ElementWithDropdown","enabled","isOpen","renderElement","InputBox","ref","tabIndex","onFocus","ExpandableElement","expanded","listboxId","popupRole","children","LabelContainer","isEmpty","PlaceholderLabel","truncateType","ValueLabel","renderDropdown","NestedDropdownList","listItems","multiSelect","itemsLoadState","itemTruncationType","onSelectItem","onSelectAll","matchElementWidth","onOpen","onClose","reason","onDismiss","_a","focus","clickToToggle","offset","fitAvailableHeight","customZIndex","rootNode"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"input-nested-multi-select.js","sources":["../../src/input-nested-multi-select/input-nested-multi-select.tsx"],"sourcesContent":["import type { OpenChangeReason } from \"@floating-ui/react\";\nimport isEmpty from \"lodash/isEmpty\";\nimport isEqual from \"lodash/isEqual\";\nimport type React from \"react\";\nimport { useEffect, useRef, useState } from \"react\";\n\nimport type {\n NestedDropdownListItemProps,\n NestedDropdownListLocalItem,\n} from \"../shared/dropdown-list\";\nimport {\n buildKeyPathToSet,\n ExpandableElement,\n NestedDropdownList,\n} from \"../shared/dropdown-list\";\nimport { ElementWithDropdown } from \"../shared/dropdown-wrapper\";\nimport {\n LabelContainer,\n PlaceholderLabel,\n ValueLabel,\n} from \"../shared/dropdown-wrapper/dropdown-wrapper\";\nimport { InputBox } from \"../shared/input-wrapper/input-wrapper\";\nimport { StringHelper, useId } from \"../util\";\nimport type { SelectedItem } from \"./helpers\";\nimport { getSelectedItems, getSelectedSubItems } from \"./helpers\";\nimport type {\n InputNestedMultiSelectProps,\n InputNestedMultiSelectValue,\n InputNestedMultiSelectValues,\n} from \"./types\";\n\n// @catalog\n/**\n * A multi-select input that presents options in a nested hierarchy, up to three levels deep.\n *\n * Use `InputNestedMultiSelect` when users need to choose multiple values from a\n * hierarchical option tree. Selecting a parent item automatically selects all its\n * leaf descendants; deselecting a parent removes all its descendants from the\n * selection.\n */\nexport const InputNestedMultiSelect = <V1, V2, V3>({\n placeholder = \"Select\",\n options: _options,\n disabled,\n error,\n className,\n \"data-testid\": testId,\n id,\n \"aria-labelledby\": ariaLabelledBy,\n \"aria-describedby\": ariaDescribedBy,\n \"aria-invalid\": ariaInvalid,\n selectedKeyPaths: _selectedKeyPaths,\n mode,\n valueToStringFunction,\n enableSearch,\n searchPlaceholder,\n hideNoResultsDisplay,\n noResultsDescription,\n customLabels,\n readOnly,\n onSearch,\n onSelectOptions,\n onShowOptions,\n onHideOptions,\n onRetry,\n onBlur,\n optionsLoadState = \"success\",\n optionTruncationType = \"end\",\n variant = \"default\",\n alignment,\n dropdownZIndex,\n dropdownWidth,\n dropdownRootNode,\n}: InputNestedMultiSelectProps<V1, V2, V3>): JSX.Element => {\n // =========================================================================\n // CONST, STATE\n // =========================================================================\n type NestedValue = InputNestedMultiSelectValue<V1, V2, V3>;\n\n const { multiSelectedLabel } = customLabels || {};\n const options = _options as NestedDropdownListItemProps<NestedValue>[];\n const [selectedKeyPaths, setSelectedKeyPaths] = useState<Set<string>>(\n _selectedKeyPaths\n ? buildKeyPathToSet(_selectedKeyPaths)\n : new Set<string>()\n );\n const [selectedItems, setSelectedItems] = useState<\n SelectedItem<NestedValue>[]\n >([]);\n\n const [showOptions, setShowOptions] = useState<boolean>(false);\n const [focused, setFocused] = useState<boolean>(false);\n const internalId = useId();\n\n const nodeRef = useRef<HTMLDivElement>(null);\n const selectorRef = useRef<HTMLButtonElement>(null);\n const labelContainerRef = useRef<HTMLDivElement>(null);\n\n // =========================================================================\n // EFFECTS\n // =========================================================================\n useEffect(() => {\n const newKeyPath = _selectedKeyPaths || [];\n const selectedItems = getSelectedItems(options, newKeyPath);\n\n setSelectedKeyPaths(buildKeyPathToSet(newKeyPath));\n setSelectedItems(selectedItems);\n }, [_selectedKeyPaths, options]);\n\n // =========================================================================\n // EVENT HANDLERS\n // =========================================================================\n const handleSelectAll = (\n keyPaths: string[][],\n items: NestedDropdownListLocalItem<NestedValue>[]\n ) => {\n const selectedItems: SelectedItem<NestedValue>[] = items.map(\n (item) => ({\n keyPath: item.keyPath,\n label: item.item.label,\n value: item.item.value,\n })\n );\n setSelectedKeyPaths(buildKeyPathToSet(keyPaths));\n setSelectedItems(selectedItems);\n performOnSelectOptions(keyPaths, selectedItems);\n };\n\n const handleListItemClick = (\n listItem: NestedDropdownListLocalItem<NestedValue>\n ) => {\n const newSelectedItems: SelectedItem<NestedValue>[] =\n getNewSelection(listItem);\n const newKeyPaths = newSelectedItems.map((item) => item.keyPath);\n setSelectedItems(newSelectedItems);\n setSelectedKeyPaths(buildKeyPathToSet(newKeyPaths));\n performOnSelectOptions(newKeyPaths, newSelectedItems);\n };\n\n const handleNodeFocus = () => {\n if (!focused && !showOptions) {\n setFocused(true);\n }\n };\n\n const handleNodeBlur = (e: React.FocusEvent) => {\n if (\n focused &&\n !showOptions &&\n nodeRef.current &&\n !nodeRef.current.contains(e.relatedTarget as Node)\n ) {\n setFocused(false);\n onBlur?.();\n }\n };\n\n const handleOpen = () => {\n setShowOptions(true);\n triggerOptionDisplayCallback(true);\n setFocused(true);\n };\n\n const handleClose = (reason: OpenChangeReason | undefined) => {\n setShowOptions(false);\n triggerOptionDisplayCallback(false);\n\n // click to toggle should not blur the input\n if (reason !== \"click\") {\n setFocused(false);\n onBlur?.();\n }\n };\n\n const handleDismiss = () => {\n selectorRef.current?.focus();\n setShowOptions(false);\n triggerOptionDisplayCallback(false);\n };\n\n // =========================================================================\n // HELPER FUNCTION\n // =========================================================================\n const getDisplayValue = (): string => {\n if (selectedItems.length > 1) {\n return multiSelectedLabel || `${selectedItems.length} selected`;\n }\n\n const { label, value } = selectedItems[0];\n if (valueToStringFunction) {\n return valueToStringFunction(value);\n } else {\n return label;\n }\n };\n\n const truncateValue = (value: string) => {\n if (optionTruncationType === \"middle\") {\n let widthOfElement = 0;\n if (labelContainerRef && labelContainerRef.current) {\n widthOfElement =\n labelContainerRef.current.getBoundingClientRect().width;\n }\n return StringHelper.truncateOneLine(value, widthOfElement, 120, 6);\n }\n\n return value;\n };\n\n const triggerOptionDisplayCallback = (show: boolean) => {\n if (!show && onHideOptions) {\n onHideOptions();\n }\n\n if (show && onShowOptions) {\n onShowOptions();\n }\n };\n\n const performOnSelectOptions = (\n keyPaths: string[][],\n items: SelectedItem<NestedValue>[]\n ) => {\n if (onSelectOptions) {\n const returnValue: InputNestedMultiSelectValues<V1, V2, V3> =\n items.map((item) => item.value);\n onSelectOptions(keyPaths, returnValue);\n }\n };\n\n const getNewSelection = (\n item: NestedDropdownListLocalItem<NestedValue>\n ): SelectedItem<NestedValue>[] => {\n if (item.checked === true) {\n // remove item or subitems\n return selectedItems.filter((selectedItem) => {\n const ancestorKeyPath = selectedItem.keyPath.slice(\n 0,\n item.keyPath.length\n );\n return !isEqual(item.keyPath, ancestorKeyPath);\n });\n } else {\n // select item or all subitems\n const nextSelection = [...selectedItems];\n const newItemsToAdd = item.hasSubItems\n ? getSelectedSubItems(options, item.keyPath)\n : [\n {\n value: item.item.value,\n label: item.item.label,\n keyPath: item.keyPath,\n },\n ];\n newItemsToAdd.forEach((addedItem) => {\n if (\n !selectedItems.find((selectedItem) =>\n isEqual(selectedItem.keyPath, addedItem.keyPath)\n )\n ) {\n nextSelection.push(addedItem);\n }\n });\n return nextSelection;\n }\n };\n\n // =========================================================================\n // RENDER FUNCTION\n // =========================================================================\n const renderLabel = () => {\n if (isEmpty(selectedItems)) {\n return (\n <PlaceholderLabel truncateType={optionTruncationType}>\n {placeholder}\n </PlaceholderLabel>\n );\n } else {\n return (\n <ValueLabel truncateType={optionTruncationType}>\n {truncateValue(getDisplayValue())}\n </ValueLabel>\n );\n }\n };\n\n const renderSelectorContent = () => (\n <LabelContainer ref={labelContainerRef} disabled={disabled}>\n {renderLabel()}\n </LabelContainer>\n );\n\n const renderElement = () => {\n return (\n <InputBox\n className={className}\n data-testid={testId}\n id={id}\n ref={nodeRef}\n tabIndex={-1}\n onFocus={handleNodeFocus}\n onBlur={handleNodeBlur}\n focused={focused}\n disabled={disabled}\n readOnly={readOnly}\n error={error}\n >\n <ExpandableElement\n ref={selectorRef}\n disabled={disabled}\n expanded={showOptions}\n listboxId={internalId}\n popupRole=\"tree\"\n readOnly={readOnly}\n variant={variant}\n aria-labelledby={ariaLabelledBy}\n aria-describedby={ariaDescribedBy}\n aria-invalid={ariaInvalid}\n >\n {renderSelectorContent()}\n </ExpandableElement>\n </InputBox>\n );\n };\n\n const renderDropdown = () => {\n return (\n <NestedDropdownList\n listboxId={internalId}\n listItems={options}\n multiSelect\n selectedKeyPaths={selectedKeyPaths}\n itemsLoadState={optionsLoadState}\n itemTruncationType={optionTruncationType}\n enableSearch={enableSearch}\n searchPlaceholder={searchPlaceholder}\n hideNoResultsDisplay={hideNoResultsDisplay}\n noResultsDescription={noResultsDescription}\n customLabels={customLabels}\n onSelectItem={handleListItemClick}\n onSelectAll={handleSelectAll}\n onRetry={onRetry}\n onSearch={onSearch}\n variant={variant}\n mode={mode}\n width={dropdownWidth}\n matchElementWidth\n />\n );\n };\n\n return (\n <ElementWithDropdown\n enabled={!readOnly && !disabled}\n isOpen={showOptions}\n renderElement={renderElement}\n renderDropdown={renderDropdown}\n onOpen={handleOpen}\n onClose={handleClose}\n onDismiss={handleDismiss}\n clickToToggle\n offset={8}\n alignment={alignment}\n fitAvailableHeight\n customZIndex={dropdownZIndex}\n rootNode={dropdownRootNode}\n />\n );\n};\n"],"names":["InputNestedMultiSelect","placeholder","options","_options","disabled","error","className","testId","id","ariaLabelledBy","ariaDescribedBy","ariaInvalid","selectedKeyPaths","_selectedKeyPaths","mode","valueToStringFunction","enableSearch","searchPlaceholder","hideNoResultsDisplay","noResultsDescription","customLabels","readOnly","onSearch","onSelectOptions","onShowOptions","onHideOptions","onRetry","onBlur","optionsLoadState","optionTruncationType","variant","alignment","dropdownZIndex","dropdownWidth","dropdownRootNode","multiSelectedLabel","setSelectedKeyPaths","useState","buildKeyPathToSet","Set","selectedItems","setSelectedItems","showOptions","setShowOptions","focused","setFocused","internalId","useId","nodeRef","useRef","selectorRef","labelContainerRef","useEffect","newKeyPath","getSelectedItems","handleSelectAll","keyPaths","items","map","item","keyPath","label","value","performOnSelectOptions","handleListItemClick","listItem","newSelectedItems","getNewSelection","newKeyPaths","handleNodeFocus","handleNodeBlur","e","current","contains","relatedTarget","getDisplayValue","length","truncateValue","widthOfElement","getBoundingClientRect","width","StringHelper","truncateOneLine","triggerOptionDisplayCallback","show","returnValue","checked","filter","selectedItem","ancestorKeyPath","slice","isEqual","nextSelection","hasSubItems","getSelectedSubItems","forEach","addedItem","find","push","_jsx","ElementWithDropdown","enabled","isOpen","renderElement","InputBox","ref","tabIndex","onFocus","ExpandableElement","expanded","listboxId","popupRole","children","LabelContainer","isEmpty","PlaceholderLabel","truncateType","ValueLabel","renderDropdown","NestedDropdownList","listItems","multiSelect","itemsLoadState","itemTruncationType","onSelectItem","onSelectAll","matchElementWidth","onOpen","onClose","reason","onDismiss","_a","focus","clickToToggle","offset","fitAvailableHeight","customZIndex","rootNode"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"input-nested-select.js","sources":["../../src/input-nested-select/input-nested-select.tsx"],"sourcesContent":["import type { OpenChangeReason } from \"@floating-ui/react\";\nimport isEmpty from \"lodash/isEmpty\";\nimport type React from \"react\";\nimport { useEffect, useRef, useState } from \"react\";\n\nimport type {\n NestedDropdownListItemProps,\n NestedDropdownListLocalItem,\n} from \"../shared/dropdown-list\";\nimport {\n buildKeyPathToSet,\n ExpandableElement,\n findItemByKeyPath,\n NestedDropdownList,\n} from \"../shared/dropdown-list\";\nimport { ElementWithDropdown } from \"../shared/dropdown-wrapper\";\nimport {\n LabelContainer,\n PlaceholderLabel,\n ValueLabel,\n} from \"../shared/dropdown-wrapper/dropdown-wrapper\";\nimport { InputBox } from \"../shared/input-wrapper/input-wrapper\";\nimport { StringHelper, useId } from \"../util\";\nimport type { InputNestedSelectProps } from \"./types\";\n\ninterface SelectedItemType<V1, V2, V3> {\n label: string;\n value: V1 | V2 | V3;\n}\n\n/**\n * A single-select input that presents options in a hierarchy, up to three levels deep.\n *\n * Use `InputNestedSelect` when users need to choose a value from a\n * hierarchical option tree. The dropdown renders as an expandable tree.\n * Parent nodes collapse or expand their children, and only one leaf or category\n * value can be selected at a time.\n */\nexport const InputNestedSelect = <V1, V2, V3>({\n placeholder = \"Select\",\n options: _options,\n disabled,\n error,\n className,\n \"data-testid\": testId,\n id,\n \"aria-labelledby\": ariaLabelledBy,\n \"aria-describedby\": ariaDescribedBy,\n \"aria-invalid\": ariaInvalid,\n selectedKeyPath: _selectedKeyPath,\n mode,\n valueToStringFunction,\n enableSearch,\n searchPlaceholder,\n selectableCategory,\n hideNoResultsDisplay,\n noResultsDescription,\n customLabels,\n readOnly,\n onBlur,\n onSearch,\n onSelectOption,\n onShowOptions,\n onHideOptions,\n onRetry,\n optionsLoadState = \"success\",\n optionTruncationType = \"end\",\n variant = \"default\",\n alignment,\n dropdownZIndex,\n dropdownWidth,\n dropdownRootNode,\n}: InputNestedSelectProps<V1, V2, V3>): JSX.Element => {\n // =========================================================================\n // CONST, STATE\n // =========================================================================\n const options = _options as NestedDropdownListItemProps<V1 | V2 | V3>[];\n const [selectedKeyPaths, setSelectedKeyPaths] = useState<Set<string>>(\n _selectedKeyPath\n ? buildKeyPathToSet([_selectedKeyPath])\n : new Set<string>()\n );\n const [selectedItem, setSelectedItem] =\n useState<SelectedItemType<V1, V2, V3>>();\n\n const [showOptions, setShowOptions] = useState<boolean>(false);\n const [focused, setFocused] = useState<boolean>(false);\n const internalId = useId();\n\n const nodeRef = useRef<HTMLDivElement>(null);\n const selectorRef = useRef<HTMLButtonElement>(null);\n const labelContainerRef = useRef<HTMLDivElement>(null);\n\n // =========================================================================\n // EFFECTS\n // =========================================================================\n useEffect(() => {\n setSelectedKeyPaths(\n _selectedKeyPath\n ? buildKeyPathToSet([_selectedKeyPath])\n : new Set<string>()\n );\n const selectedItem = findItemByKeyPath(options, _selectedKeyPath || []);\n setSelectedItem(selectedItem ?? undefined);\n }, [_selectedKeyPath, options]);\n\n // =========================================================================\n // EVENT HANDLERS\n // =========================================================================\n const handleListItemClick = (\n listItem: NestedDropdownListLocalItem<V1 | V2 | V3>\n ) => {\n const {\n keyPath,\n item: { label, value },\n } = listItem;\n setSelectedKeyPaths(buildKeyPathToSet([keyPath]));\n setSelectedItem({ label, value });\n setShowOptions(false);\n triggerOptionDisplayCallback(false);\n\n selectorRef.current?.focus();\n onSelectOption?.(keyPath, value);\n };\n\n const handleNodeFocus = () => {\n if (!focused && !showOptions) {\n setFocused(true);\n }\n };\n\n const handleNodeBlur = (e: React.FocusEvent) => {\n if (\n focused &&\n !showOptions &&\n nodeRef.current &&\n !nodeRef.current.contains(e.relatedTarget as Node)\n ) {\n setFocused(false);\n onBlur?.();\n }\n };\n\n const handleOpen = () => {\n setShowOptions(true);\n triggerOptionDisplayCallback(true);\n setFocused(true);\n };\n\n const handleClose = (reason: OpenChangeReason | undefined) => {\n setShowOptions(false);\n triggerOptionDisplayCallback(false);\n\n // click to toggle should not blur the input\n if (reason !== \"click\") {\n setFocused(false);\n onBlur?.();\n }\n };\n\n const handleDismiss = () => {\n selectorRef.current?.focus();\n setShowOptions(false);\n triggerOptionDisplayCallback(false);\n };\n\n // =========================================================================\n // HELPER FUNCTION\n // =========================================================================\n const getDisplayValue = (): string => {\n if (!selectedItem) return \"\";\n const { label, value } = selectedItem;\n\n if (valueToStringFunction) {\n return valueToStringFunction(value);\n } else {\n return label;\n }\n };\n\n const truncateValue = (value: string) => {\n if (optionTruncationType === \"middle\") {\n let widthOfElement = 0;\n if (labelContainerRef && labelContainerRef.current) {\n widthOfElement =\n labelContainerRef.current.getBoundingClientRect().width;\n }\n return StringHelper.truncateOneLine(value, widthOfElement, 120, 6);\n }\n\n return value;\n };\n\n const triggerOptionDisplayCallback = (show: boolean) => {\n if (!show && onHideOptions) {\n onHideOptions();\n }\n\n if (show && onShowOptions) {\n onShowOptions();\n }\n };\n\n // =========================================================================\n // RENDER FUNCTION\n // =========================================================================\n const renderLabel = () => {\n if (isEmpty(selectedItem)) {\n return (\n <PlaceholderLabel truncateType={optionTruncationType}>\n {placeholder}\n </PlaceholderLabel>\n );\n } else {\n return (\n <ValueLabel truncateType={optionTruncationType}>\n {truncateValue(getDisplayValue())}\n </ValueLabel>\n );\n }\n };\n\n const renderSelectorContent = () => (\n <LabelContainer ref={labelContainerRef} disabled={disabled}>\n {renderLabel()}\n </LabelContainer>\n );\n\n const renderElement = () => {\n return (\n <InputBox\n className={className}\n data-testid={testId}\n id={id}\n ref={nodeRef}\n tabIndex={-1}\n onFocus={handleNodeFocus}\n onBlur={handleNodeBlur}\n focused={focused}\n disabled={disabled}\n readOnly={readOnly}\n error={error}\n >\n <ExpandableElement\n ref={selectorRef}\n disabled={disabled}\n expanded={showOptions}\n listboxId={internalId}\n popupRole=\"tree\"\n readOnly={readOnly}\n variant={variant}\n aria-labelledby={ariaLabelledBy}\n aria-describedby={ariaDescribedBy}\n aria-invalid={ariaInvalid}\n >\n {renderSelectorContent()}\n </ExpandableElement>\n </InputBox>\n );\n };\n\n const renderDropdown = () => {\n return (\n <NestedDropdownList\n listboxId={internalId}\n listItems={options}\n selectedKeyPaths={selectedKeyPaths}\n selectableCategory={selectableCategory}\n itemsLoadState={optionsLoadState}\n itemTruncationType={optionTruncationType}\n enableSearch={enableSearch}\n searchPlaceholder={searchPlaceholder}\n hideNoResultsDisplay={hideNoResultsDisplay}\n noResultsDescription={noResultsDescription}\n customLabels={customLabels}\n onSelectItem={handleListItemClick}\n onRetry={onRetry}\n onSearch={onSearch}\n variant={variant}\n mode={mode}\n width={dropdownWidth}\n matchElementWidth\n />\n );\n };\n\n return (\n <ElementWithDropdown\n enabled={!readOnly && !disabled}\n isOpen={showOptions}\n renderElement={renderElement}\n renderDropdown={renderDropdown}\n onOpen={handleOpen}\n onClose={handleClose}\n onDismiss={handleDismiss}\n clickToToggle\n offset={8}\n alignment={alignment}\n fitAvailableHeight\n customZIndex={dropdownZIndex}\n rootNode={dropdownRootNode}\n />\n );\n};\n"],"names":["InputNestedSelect","placeholder","options","_options","disabled","error","className","testId","id","ariaLabelledBy","ariaDescribedBy","ariaInvalid","selectedKeyPath","_selectedKeyPath","mode","valueToStringFunction","enableSearch","searchPlaceholder","selectableCategory","hideNoResultsDisplay","noResultsDescription","customLabels","readOnly","onBlur","onSearch","onSelectOption","onShowOptions","onHideOptions","onRetry","optionsLoadState","optionTruncationType","variant","alignment","dropdownZIndex","dropdownWidth","dropdownRootNode","selectedKeyPaths","setSelectedKeyPaths","useState","buildKeyPathToSet","Set","selectedItem","setSelectedItem","showOptions","setShowOptions","focused","setFocused","internalId","useId","nodeRef","useRef","selectorRef","labelContainerRef","useEffect","findItemByKeyPath","undefined","handleListItemClick","listItem","keyPath","item","label","value","triggerOptionDisplayCallback","_a","current","focus","handleNodeFocus","handleNodeBlur","e","contains","relatedTarget","getDisplayValue","truncateValue","widthOfElement","getBoundingClientRect","width","StringHelper","truncateOneLine","show","_jsx","ElementWithDropdown","enabled","isOpen","renderElement","InputBox","ref","tabIndex","onFocus","ExpandableElement","expanded","listboxId","popupRole","children","LabelContainer","isEmpty","PlaceholderLabel","truncateType","ValueLabel","renderDropdown","NestedDropdownList","listItems","itemsLoadState","itemTruncationType","onSelectItem","matchElementWidth","onOpen","onClose","reason","onDismiss","clickToToggle","offset","fitAvailableHeight","customZIndex","rootNode"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"input-nested-select.js","sources":["../../src/input-nested-select/input-nested-select.tsx"],"sourcesContent":["import type { OpenChangeReason } from \"@floating-ui/react\";\nimport isEmpty from \"lodash/isEmpty\";\nimport type React from \"react\";\nimport { useEffect, useRef, useState } from \"react\";\n\nimport type {\n NestedDropdownListItemProps,\n NestedDropdownListLocalItem,\n} from \"../shared/dropdown-list\";\nimport {\n buildKeyPathToSet,\n ExpandableElement,\n findItemByKeyPath,\n NestedDropdownList,\n} from \"../shared/dropdown-list\";\nimport { ElementWithDropdown } from \"../shared/dropdown-wrapper\";\nimport {\n LabelContainer,\n PlaceholderLabel,\n ValueLabel,\n} from \"../shared/dropdown-wrapper/dropdown-wrapper\";\nimport { InputBox } from \"../shared/input-wrapper/input-wrapper\";\nimport { StringHelper, useId } from \"../util\";\nimport type { InputNestedSelectProps } from \"./types\";\n\ninterface SelectedItemType<V1, V2, V3> {\n label: string;\n value: V1 | V2 | V3;\n}\n\n// @catalog\n/**\n * A single-select input that presents options in a hierarchy, up to three levels deep.\n *\n * Use `InputNestedSelect` when users need to choose a value from a\n * hierarchical option tree. The dropdown renders as an expandable tree.\n * Parent nodes collapse or expand their children, and only one leaf or category\n * value can be selected at a time.\n */\nexport const InputNestedSelect = <V1, V2, V3>({\n placeholder = \"Select\",\n options: _options,\n disabled,\n error,\n className,\n \"data-testid\": testId,\n id,\n \"aria-labelledby\": ariaLabelledBy,\n \"aria-describedby\": ariaDescribedBy,\n \"aria-invalid\": ariaInvalid,\n selectedKeyPath: _selectedKeyPath,\n mode,\n valueToStringFunction,\n enableSearch,\n searchPlaceholder,\n selectableCategory,\n hideNoResultsDisplay,\n noResultsDescription,\n customLabels,\n readOnly,\n onBlur,\n onSearch,\n onSelectOption,\n onShowOptions,\n onHideOptions,\n onRetry,\n optionsLoadState = \"success\",\n optionTruncationType = \"end\",\n variant = \"default\",\n alignment,\n dropdownZIndex,\n dropdownWidth,\n dropdownRootNode,\n}: InputNestedSelectProps<V1, V2, V3>): JSX.Element => {\n // =========================================================================\n // CONST, STATE\n // =========================================================================\n const options = _options as NestedDropdownListItemProps<V1 | V2 | V3>[];\n const [selectedKeyPaths, setSelectedKeyPaths] = useState<Set<string>>(\n _selectedKeyPath\n ? buildKeyPathToSet([_selectedKeyPath])\n : new Set<string>()\n );\n const [selectedItem, setSelectedItem] =\n useState<SelectedItemType<V1, V2, V3>>();\n\n const [showOptions, setShowOptions] = useState<boolean>(false);\n const [focused, setFocused] = useState<boolean>(false);\n const internalId = useId();\n\n const nodeRef = useRef<HTMLDivElement>(null);\n const selectorRef = useRef<HTMLButtonElement>(null);\n const labelContainerRef = useRef<HTMLDivElement>(null);\n\n // =========================================================================\n // EFFECTS\n // =========================================================================\n useEffect(() => {\n setSelectedKeyPaths(\n _selectedKeyPath\n ? buildKeyPathToSet([_selectedKeyPath])\n : new Set<string>()\n );\n const selectedItem = findItemByKeyPath(options, _selectedKeyPath || []);\n setSelectedItem(selectedItem ?? undefined);\n }, [_selectedKeyPath, options]);\n\n // =========================================================================\n // EVENT HANDLERS\n // =========================================================================\n const handleListItemClick = (\n listItem: NestedDropdownListLocalItem<V1 | V2 | V3>\n ) => {\n const {\n keyPath,\n item: { label, value },\n } = listItem;\n setSelectedKeyPaths(buildKeyPathToSet([keyPath]));\n setSelectedItem({ label, value });\n setShowOptions(false);\n triggerOptionDisplayCallback(false);\n\n selectorRef.current?.focus();\n onSelectOption?.(keyPath, value);\n };\n\n const handleNodeFocus = () => {\n if (!focused && !showOptions) {\n setFocused(true);\n }\n };\n\n const handleNodeBlur = (e: React.FocusEvent) => {\n if (\n focused &&\n !showOptions &&\n nodeRef.current &&\n !nodeRef.current.contains(e.relatedTarget as Node)\n ) {\n setFocused(false);\n onBlur?.();\n }\n };\n\n const handleOpen = () => {\n setShowOptions(true);\n triggerOptionDisplayCallback(true);\n setFocused(true);\n };\n\n const handleClose = (reason: OpenChangeReason | undefined) => {\n setShowOptions(false);\n triggerOptionDisplayCallback(false);\n\n // click to toggle should not blur the input\n if (reason !== \"click\") {\n setFocused(false);\n onBlur?.();\n }\n };\n\n const handleDismiss = () => {\n selectorRef.current?.focus();\n setShowOptions(false);\n triggerOptionDisplayCallback(false);\n };\n\n // =========================================================================\n // HELPER FUNCTION\n // =========================================================================\n const getDisplayValue = (): string => {\n if (!selectedItem) return \"\";\n const { label, value } = selectedItem;\n\n if (valueToStringFunction) {\n return valueToStringFunction(value);\n } else {\n return label;\n }\n };\n\n const truncateValue = (value: string) => {\n if (optionTruncationType === \"middle\") {\n let widthOfElement = 0;\n if (labelContainerRef && labelContainerRef.current) {\n widthOfElement =\n labelContainerRef.current.getBoundingClientRect().width;\n }\n return StringHelper.truncateOneLine(value, widthOfElement, 120, 6);\n }\n\n return value;\n };\n\n const triggerOptionDisplayCallback = (show: boolean) => {\n if (!show && onHideOptions) {\n onHideOptions();\n }\n\n if (show && onShowOptions) {\n onShowOptions();\n }\n };\n\n // =========================================================================\n // RENDER FUNCTION\n // =========================================================================\n const renderLabel = () => {\n if (isEmpty(selectedItem)) {\n return (\n <PlaceholderLabel truncateType={optionTruncationType}>\n {placeholder}\n </PlaceholderLabel>\n );\n } else {\n return (\n <ValueLabel truncateType={optionTruncationType}>\n {truncateValue(getDisplayValue())}\n </ValueLabel>\n );\n }\n };\n\n const renderSelectorContent = () => (\n <LabelContainer ref={labelContainerRef} disabled={disabled}>\n {renderLabel()}\n </LabelContainer>\n );\n\n const renderElement = () => {\n return (\n <InputBox\n className={className}\n data-testid={testId}\n id={id}\n ref={nodeRef}\n tabIndex={-1}\n onFocus={handleNodeFocus}\n onBlur={handleNodeBlur}\n focused={focused}\n disabled={disabled}\n readOnly={readOnly}\n error={error}\n >\n <ExpandableElement\n ref={selectorRef}\n disabled={disabled}\n expanded={showOptions}\n listboxId={internalId}\n popupRole=\"tree\"\n readOnly={readOnly}\n variant={variant}\n aria-labelledby={ariaLabelledBy}\n aria-describedby={ariaDescribedBy}\n aria-invalid={ariaInvalid}\n >\n {renderSelectorContent()}\n </ExpandableElement>\n </InputBox>\n );\n };\n\n const renderDropdown = () => {\n return (\n <NestedDropdownList\n listboxId={internalId}\n listItems={options}\n selectedKeyPaths={selectedKeyPaths}\n selectableCategory={selectableCategory}\n itemsLoadState={optionsLoadState}\n itemTruncationType={optionTruncationType}\n enableSearch={enableSearch}\n searchPlaceholder={searchPlaceholder}\n hideNoResultsDisplay={hideNoResultsDisplay}\n noResultsDescription={noResultsDescription}\n customLabels={customLabels}\n onSelectItem={handleListItemClick}\n onRetry={onRetry}\n onSearch={onSearch}\n variant={variant}\n mode={mode}\n width={dropdownWidth}\n matchElementWidth\n />\n );\n };\n\n return (\n <ElementWithDropdown\n enabled={!readOnly && !disabled}\n isOpen={showOptions}\n renderElement={renderElement}\n renderDropdown={renderDropdown}\n onOpen={handleOpen}\n onClose={handleClose}\n onDismiss={handleDismiss}\n clickToToggle\n offset={8}\n alignment={alignment}\n fitAvailableHeight\n customZIndex={dropdownZIndex}\n rootNode={dropdownRootNode}\n />\n );\n};\n"],"names":["InputNestedSelect","placeholder","options","_options","disabled","error","className","testId","id","ariaLabelledBy","ariaDescribedBy","ariaInvalid","selectedKeyPath","_selectedKeyPath","mode","valueToStringFunction","enableSearch","searchPlaceholder","selectableCategory","hideNoResultsDisplay","noResultsDescription","customLabels","readOnly","onBlur","onSearch","onSelectOption","onShowOptions","onHideOptions","onRetry","optionsLoadState","optionTruncationType","variant","alignment","dropdownZIndex","dropdownWidth","dropdownRootNode","selectedKeyPaths","setSelectedKeyPaths","useState","buildKeyPathToSet","Set","selectedItem","setSelectedItem","showOptions","setShowOptions","focused","setFocused","internalId","useId","nodeRef","useRef","selectorRef","labelContainerRef","useEffect","findItemByKeyPath","undefined","handleListItemClick","listItem","keyPath","item","label","value","triggerOptionDisplayCallback","_a","current","focus","handleNodeFocus","handleNodeBlur","e","contains","relatedTarget","getDisplayValue","truncateValue","widthOfElement","getBoundingClientRect","width","StringHelper","truncateOneLine","show","_jsx","ElementWithDropdown","enabled","isOpen","renderElement","InputBox","ref","tabIndex","onFocus","ExpandableElement","expanded","listboxId","popupRole","children","LabelContainer","isEmpty","PlaceholderLabel","truncateType","ValueLabel","renderDropdown","NestedDropdownList","listItems","itemsLoadState","itemTruncationType","onSelectItem","matchElementWidth","onOpen","onClose","reason","onDismiss","clickToToggle","offset","fitAvailableHeight","customZIndex","rootNode"],"mappings":"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"}
|
|
@@ -37,7 +37,7 @@ export interface InputNestedSelectSharedProps<V1, V2, V3> extends Omit<InputSele
|
|
|
37
37
|
* Note: if a parent of the trigger has a higher `z-index` than the dropdown,
|
|
38
38
|
* the dropdown may be obscured.
|
|
39
39
|
*
|
|
40
|
-
* @default
|
|
40
|
+
* @default document.body
|
|
41
41
|
*/
|
|
42
42
|
dropdownRootNode?: RefObject<HTMLElement> | undefined;
|
|
43
43
|
/** Function to convert selected value into a string */
|