@lifesg/react-design-system 4.0.0-alpha.7 → 4.0.0-alpha.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/accordion/accordion-item.js.map +1 -1
- package/accordion/accordion.js.map +1 -1
- package/alert/alert.js.map +1 -1
- package/button/button.js +1 -1
- package/button/button.js.map +1 -1
- package/button/button.styles.d.ts +1 -0
- package/button/button.styles.js +1 -1
- package/button/button.styles.js.map +1 -1
- package/button/button.styles_19i4dfq.css +21 -0
- package/cjs/accordion/accordion-item.js.map +1 -1
- package/cjs/accordion/accordion.js.map +1 -1
- package/cjs/alert/alert.js.map +1 -1
- package/cjs/button/button.js +1 -1
- package/cjs/button/button.js.map +1 -1
- package/cjs/button/button.styles.js +1 -1
- package/cjs/button/button.styles.js.map +1 -1
- package/cjs/button/button.styles_19i4dfq.css +21 -0
- package/cjs/countdown-timer/countdown-timer.js.map +1 -1
- package/cjs/data-table/data-table.js +1 -1
- package/cjs/data-table/data-table.js.map +1 -1
- package/cjs/data-table/data-table.styles.js +1 -1
- package/cjs/data-table/data-table.styles.js.map +1 -1
- package/{data-table/data-table.styles_rxganh.css → cjs/data-table/data-table.styles_1tnlmhe.css} +7 -6
- package/cjs/date-range-input/date-range-input.js.map +1 -1
- package/cjs/e-signature/e-signature-canvas.js.map +1 -1
- package/cjs/error-display/error-display-data.js +1 -1
- package/cjs/error-display/error-display-data.js.map +1 -1
- package/cjs/error-display/inactivity-timer.js.map +1 -1
- package/cjs/external/dompurify/dist/purify.es.js +2 -2
- package/cjs/external/dompurify/dist/purify.es.js.map +1 -1
- package/cjs/file-download/file-list-card/file-list-card.js.map +1 -1
- package/cjs/file-upload/custom-sensors.js.map +1 -1
- package/cjs/file-upload/file-list/file-list.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/addons/filter-item-checkbox.styles.js +1 -1
- package/cjs/filter/addons/filter-item-checkbox.styles.js.map +1 -1
- package/{filter/addons/filter-item-checkbox.styles_7degw7.css → cjs/filter/addons/filter-item-checkbox.styles_6nbpdl.css} +1 -1
- package/cjs/filter/filter-item.js.map +1 -1
- package/cjs/filter/filter-item.styles.js +1 -1
- package/cjs/filter/filter-item.styles.js.map +1 -1
- package/cjs/filter/{filter-item.styles_cphjnj.css → filter-item.styles_1yixp8h.css} +1 -1
- package/cjs/filter/filter-modal.styles.js +1 -1
- package/cjs/filter/filter-modal.styles.js.map +1 -1
- package/{filter/filter-modal.styles_qw3xlg.css → cjs/filter/filter-modal.styles_kuth21.css} +1 -1
- package/cjs/filter/filter-sidebar.styles.js +1 -1
- package/cjs/filter/filter-sidebar.styles.js.map +1 -1
- package/cjs/filter/{filter-sidebar.styles_1otwpjl.css → filter-sidebar.styles_rbfq4f.css} +1 -1
- package/cjs/filter/filter.js.map +1 -1
- package/cjs/form/form-textarea/form-textarea.js +1 -1
- package/cjs/form/form-textarea/form-textarea.js.map +1 -1
- package/cjs/fullscreen-image-carousel/stateful-image.js.map +1 -1
- package/cjs/histogram-slider/histogram-slider.js.map +1 -1
- package/cjs/input-range-slider/input-range-slider.js.map +1 -1
- package/cjs/input-slider/input-slider.js.map +1 -1
- package/cjs/input-textarea/textarea-counter.js.map +1 -1
- package/cjs/input-textarea/textarea.js +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_q77m5x.css → textarea.styles_6we7bs.css} +3 -1
- package/cjs/modal/index.js.map +1 -1
- package/cjs/modal-v2/modal-v2.js +1 -1
- package/cjs/modal-v2/modal-v2.js.map +1 -1
- package/cjs/modal-v2/slots/card.js +1 -1
- package/cjs/modal-v2/slots/card.js.map +1 -1
- package/cjs/modal-v2/slots/header.js +2 -0
- package/cjs/modal-v2/slots/header.js.map +1 -0
- package/cjs/modal-v2/slots/slot-styles.js +1 -1
- package/cjs/modal-v2/slots/slot-styles.js.map +1 -1
- package/cjs/modal-v2/slots/{slot-styles_13sd376.css → slot-styles_10ut1v7.css} +5 -1
- package/cjs/navbar/navbar-items.js +1 -1
- package/cjs/navbar/navbar-items.js.map +1 -1
- package/cjs/navbar/navbar-items.styles.js +1 -1
- package/cjs/navbar/navbar-items.styles.js.map +1 -1
- package/cjs/navbar/{navbar-items.styles_1i3ltot.css → navbar-items.styles_1b1zx.css} +9 -8
- package/cjs/navbar/navbar-logo-data.js +1 -1
- package/cjs/navbar/navbar-logo-data.js.map +1 -1
- package/cjs/navbar/navbar.js.map +1 -1
- package/cjs/otp-input/otp-input.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/predictive-text-input/predictive-text-input.js.map +1 -1
- package/cjs/shared/dropdown-list/dropdown-list.js.map +1 -1
- package/cjs/shared/internal-calendar/calendar-manager.js.map +1 -1
- package/cjs/shared/standalone-date-input/standalone-date-input.js.map +1 -1
- package/cjs/singpass-button/singpass-button.styles.js +1 -1
- package/cjs/singpass-button/singpass-button.styles.js.map +1 -1
- package/cjs/singpass-button/{singpass-button.styles_1miyex3.css → singpass-button.styles_1fj2lru.css} +1 -1
- package/cjs/smart-app-banner/smart-app-banner.styles.js +1 -1
- package/cjs/smart-app-banner/smart-app-banner.styles.js.map +1 -1
- package/cjs/smart-app-banner/{smart-app-banner.styles_15u6yv4.css → smart-app-banner.styles_r6yjq9.css} +1 -1
- package/cjs/theme/types.js +1 -1
- package/cjs/theme/types.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-days.js.map +1 -1
- package/cjs/timetable/timetable.js.map +1 -1
- package/cjs/toast/toast.styles.js +1 -1
- package/cjs/toast/toast.styles.js.map +1 -1
- package/{toast/toast.styles_1e0l60w.css → cjs/toast/toast.styles_57j3lf.css} +1 -1
- package/cjs/toggle/toggle-icon.js +1 -1
- package/cjs/toggle/toggle-icon.js.map +1 -1
- package/cjs/toggle/toggle-icon.styles.js +1 -1
- package/cjs/toggle/toggle-icon.styles.js.map +1 -1
- package/cjs/toggle/{toggle-icon.styles_ba71y.css → toggle-icon.styles_o6dxr3.css} +3 -2
- package/cjs/toggle/toggle.js +1 -1
- package/cjs/toggle/toggle.js.map +1 -1
- package/cjs/toggle/toggle.styles.js +1 -1
- package/cjs/toggle/toggle.styles.js.map +1 -1
- package/cjs/toggle/toggle.styles_11tmfsr.css +41 -0
- package/cjs/unit-number/unit-number-input.js.map +1 -1
- package/cjs/util/is-styled-components.js.map +1 -1
- package/cjs/util/string-helper.js +1 -1
- package/cjs/util/string-helper.js.map +1 -1
- package/cjs/util/use-event-listener.js.map +1 -1
- package/cjs/util/use-state-actions.js.map +1 -1
- package/countdown-timer/countdown-timer.js.map +1 -1
- package/data-table/data-table.d.ts +1 -1
- package/data-table/data-table.js +1 -1
- package/data-table/data-table.js.map +1 -1
- package/data-table/data-table.styles.d.ts +1 -0
- package/data-table/data-table.styles.js +1 -1
- package/data-table/data-table.styles.js.map +1 -1
- package/{cjs/data-table/data-table.styles_rxganh.css → data-table/data-table.styles_1tnlmhe.css} +7 -6
- package/data-table/types.d.ts +4 -2
- package/date-range-input/date-range-input.js.map +1 -1
- package/docs/component-catalog.json +1 -1
- package/e-signature/e-signature-canvas.js.map +1 -1
- package/error-display/error-display-data.js +1 -1
- package/error-display/error-display-data.js.map +1 -1
- package/error-display/inactivity-timer.js.map +1 -1
- package/external/dompurify/dist/purify.es.js +2 -2
- package/external/dompurify/dist/purify.es.js.map +1 -1
- package/file-download/file-list-card/file-list-card.js.map +1 -1
- package/file-upload/custom-sensors.d.ts +2 -2
- package/file-upload/custom-sensors.js.map +1 -1
- package/file-upload/file-list/file-list.js.map +1 -1
- package/filter/addons/filter-item-checkbox-helpers.js.map +1 -1
- package/filter/addons/filter-item-checkbox.js.map +1 -1
- package/filter/addons/filter-item-checkbox.styles.js +1 -1
- package/filter/addons/filter-item-checkbox.styles.js.map +1 -1
- package/{cjs/filter/addons/filter-item-checkbox.styles_7degw7.css → filter/addons/filter-item-checkbox.styles_6nbpdl.css} +1 -1
- package/filter/filter-item.js.map +1 -1
- package/filter/filter-item.styles.js +1 -1
- package/filter/filter-item.styles.js.map +1 -1
- package/filter/{filter-item.styles_cphjnj.css → filter-item.styles_1yixp8h.css} +1 -1
- package/filter/filter-modal.styles.js +1 -1
- package/filter/filter-modal.styles.js.map +1 -1
- package/{cjs/filter/filter-modal.styles_qw3xlg.css → filter/filter-modal.styles_kuth21.css} +1 -1
- package/filter/filter-sidebar.styles.js +1 -1
- package/filter/filter-sidebar.styles.js.map +1 -1
- package/filter/{filter-sidebar.styles_1otwpjl.css → filter-sidebar.styles_rbfq4f.css} +1 -1
- package/filter/filter.js.map +1 -1
- package/form/form-textarea/form-textarea.js +1 -1
- package/form/form-textarea/form-textarea.js.map +1 -1
- package/fullscreen-image-carousel/stateful-image.js.map +1 -1
- package/fullscreen-image-carousel/types.d.ts +2 -2
- package/histogram-slider/histogram-slider.js.map +1 -1
- package/input-range-slider/input-range-slider.js.map +1 -1
- package/input-slider/input-slider.js.map +1 -1
- package/input-textarea/textarea-counter.js.map +1 -1
- package/input-textarea/textarea.js +1 -1
- package/input-textarea/textarea.js.map +1 -1
- package/input-textarea/textarea.styles.d.ts +2 -0
- package/input-textarea/textarea.styles.js +1 -1
- package/input-textarea/textarea.styles.js.map +1 -1
- package/input-textarea/{textarea.styles_q77m5x.css → textarea.styles_6we7bs.css} +3 -1
- package/input-textarea/types.d.ts +7 -0
- package/modal/index.d.ts +4 -0
- package/modal/index.js.map +1 -1
- package/modal/types.d.ts +2 -0
- package/modal-v2/modal-v2.d.ts +6 -0
- package/modal-v2/modal-v2.js +1 -1
- package/modal-v2/modal-v2.js.map +1 -1
- package/modal-v2/slots/card.js +1 -1
- package/modal-v2/slots/card.js.map +1 -1
- package/modal-v2/slots/header.d.ts +5 -0
- package/modal-v2/slots/header.js +2 -0
- package/modal-v2/slots/header.js.map +1 -0
- package/modal-v2/slots/index.d.ts +1 -0
- package/modal-v2/slots/slot-styles.d.ts +4 -0
- package/modal-v2/slots/slot-styles.js +1 -1
- package/modal-v2/slots/slot-styles.js.map +1 -1
- package/modal-v2/slots/{slot-styles_13sd376.css → slot-styles_10ut1v7.css} +5 -1
- package/modal-v2/types.d.ts +21 -0
- package/navbar/navbar-items.js +1 -1
- package/navbar/navbar-items.js.map +1 -1
- package/navbar/navbar-items.styles.d.ts +2 -1
- package/navbar/navbar-items.styles.js +1 -1
- package/navbar/navbar-items.styles.js.map +1 -1
- package/navbar/{navbar-items.styles_1i3ltot.css → navbar-items.styles_1b1zx.css} +9 -8
- package/navbar/navbar-logo-data.js +1 -1
- package/navbar/navbar-logo-data.js.map +1 -1
- package/navbar/navbar.js.map +1 -1
- package/otp-input/otp-input.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/predictive-text-input/predictive-text-input.js.map +1 -1
- package/shared/dropdown-list/dropdown-list.js.map +1 -1
- package/shared/internal-calendar/calendar-manager.js.map +1 -1
- package/shared/standalone-date-input/standalone-date-input.js.map +1 -1
- package/singpass-button/singpass-button.styles.js +1 -1
- package/singpass-button/singpass-button.styles.js.map +1 -1
- package/singpass-button/{singpass-button.styles_1miyex3.css → singpass-button.styles_1fj2lru.css} +1 -1
- package/smart-app-banner/smart-app-banner.styles.js +1 -1
- package/smart-app-banner/smart-app-banner.styles.js.map +1 -1
- package/smart-app-banner/{smart-app-banner.styles_15u6yv4.css → smart-app-banner.styles_r6yjq9.css} +1 -1
- package/theme/styles/a11y-playground.css +358 -87
- package/theme/styles/bookingsg.css +391 -85
- package/theme/styles/careercompass.css +396 -90
- package/theme/styles/ccube.css +402 -45
- package/theme/styles/imda.css +348 -85
- package/theme/styles/lifesg.css +377 -87
- package/theme/styles/mylegacy.css +382 -85
- package/theme/styles/oneservice.css +349 -86
- package/theme/styles/pa.css +172 -104
- package/theme/styles/rbs.css +403 -46
- package/theme/styles/sgw-digital-lobby.css +352 -87
- package/theme/styles/smgs.css +401 -95
- package/theme/styles/spf.css +208 -99
- package/theme/styles/supportgowhere.css +387 -90
- package/theme/styles/tote-board.css +816 -0
- package/theme/types.d.ts +1 -1
- package/theme/types.js +1 -1
- package/theme/types.js.map +1 -1
- package/time-slot-bar/time-slot-bar.js.map +1 -1
- package/time-slot-bar-week/time-slot-bar-week-days.js.map +1 -1
- package/timetable/timetable.js.map +1 -1
- package/toast/toast.styles.js +1 -1
- package/toast/toast.styles.js.map +1 -1
- package/{cjs/toast/toast.styles_1e0l60w.css → toast/toast.styles_57j3lf.css} +1 -1
- package/toggle/toggle-icon.d.ts +2 -1
- package/toggle/toggle-icon.js +1 -1
- package/toggle/toggle-icon.js.map +1 -1
- package/toggle/toggle-icon.styles.d.ts +1 -0
- package/toggle/toggle-icon.styles.js +1 -1
- package/toggle/toggle-icon.styles.js.map +1 -1
- package/toggle/{toggle-icon.styles_ba71y.css → toggle-icon.styles_o6dxr3.css} +3 -2
- package/toggle/toggle.js +1 -1
- package/toggle/toggle.js.map +1 -1
- package/toggle/toggle.styles.d.ts +18 -15
- package/toggle/toggle.styles.js +1 -1
- package/toggle/toggle.styles.js.map +1 -1
- package/toggle/toggle.styles_11tmfsr.css +41 -0
- package/tools/storybook-argtypes/services/arg-types-row-builder.d.ts +6 -0
- package/tools/storybook-argtypes/types.d.ts +13 -1
- package/unit-number/unit-number-input.js.map +1 -1
- package/util/is-styled-components.js.map +1 -1
- package/util/string-helper.d.ts +2 -2
- package/util/string-helper.js +1 -1
- package/util/string-helper.js.map +1 -1
- package/util/use-event-listener.js.map +1 -1
- package/util/use-state-actions.js.map +1 -1
- package/button/button.styles_1pxy0co.css +0 -20
- package/cjs/button/button.styles_1pxy0co.css +0 -20
- package/cjs/form/form-textarea/form-textarea.styles.js +0 -2
- package/cjs/form/form-textarea/form-textarea.styles.js.map +0 -1
- package/cjs/form/form-textarea/form-textarea.styles_1kneyif.css +0 -3
- package/cjs/toggle/toggle.styles_1t5qrye.css +0 -38
- package/form/form-textarea/form-textarea.styles.d.ts +0 -3
- package/form/form-textarea/form-textarea.styles.js +0 -2
- package/form/form-textarea/form-textarea.styles.js.map +0 -1
- package/form/form-textarea/form-textarea.styles_1kneyif.css +0 -3
- package/theme/styles/default.css +0 -158
- package/toggle/toggle.styles_1t5qrye.css +0 -38
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dropdown-list.js","sources":["../../../src/shared/dropdown-list/dropdown-list.tsx"],"sourcesContent":["import { ExclamationCircleFillIcon } from \"@lifesg/react-icons/exclamation-circle-fill\";\nimport { SquareIcon } from \"@lifesg/react-icons/square\";\nimport { SquareFillIcon } from \"@lifesg/react-icons/square-fill\";\nimport { SquareTickFillIcon } from \"@lifesg/react-icons/square-tick-fill\";\nimport { TickIcon } from \"@lifesg/react-icons/tick\";\nimport clsx from \"clsx\";\nimport find from \"lodash/find\";\nimport isEqual from \"lodash/isEqual\";\nimport type React from \"react\";\nimport {\n forwardRef,\n useCallback,\n useContext,\n useEffect,\n useImperativeHandle,\n useRef,\n useState,\n} from \"react\";\nimport type { VirtuosoHandle } from \"react-virtuoso\";\nimport { Virtuoso } from \"react-virtuoso\";\n\nimport { Markup } from \"../../markup\";\nimport { useApplyStyle } from \"../../theme\";\nimport {\n mergeRefs,\n useCompare,\n useEvent,\n useEventListener,\n useIsMounted,\n} from \"../../util\";\nimport { VisuallyHidden } from \"../accessibility\";\nimport { ComponentLoadingSpinner } from \"../component-loading-spinner\";\nimport { useDropdownRender } from \"../dropdown-wrapper\";\nimport { BasicButton } from \"../input-wrapper\";\nimport { DropdownLabel } from \"./dropdown-label\";\nimport type { ContainerWidthType } from \"./dropdown-list.styles\";\nimport * as styles from \"./dropdown-list.styles\";\nimport { DropdownListStateContext } from \"./dropdown-list-state\";\nimport { DropdownSearch } from \"./dropdown-search\";\nimport type {\n DropdownListApi,\n DropdownListProps,\n ListItemDisplayProps,\n} from \"./types\";\nimport { VirtuosoItem, VirtuosoList } from \"./virtuoso-components\";\n\n/**\n * NOTE: This component is not directly exportable but forms part of a component\n */\nconst DropdownListInner = <T, V>(\n {\n listItems,\n multiSelect,\n maxSelectable,\n selectedItems,\n disableItemFocus,\n itemsLoadState = \"success\",\n itemTruncationType = \"end\",\n itemMaxLines = 2,\n labelDisplayType = \"inline\",\n variant = \"default\",\n listboxId,\n ariaLabel,\n matchElementWidth = false,\n width,\n topScrollItem,\n onSelectItem,\n onSelectAll,\n onDismiss,\n onRetry,\n /* DropdownDisplayProps */\n valueExtractor,\n listExtractor,\n renderListItem,\n renderCustomCallToAction,\n /* DropdownSearchProps */\n enableSearch,\n hideNoResultsDisplay,\n noResultsDescription: _noResultsDescription,\n customLabels,\n searchPlaceholder: _searchPlaceholder,\n searchFunction,\n onSearch,\n }: DropdownListProps<T, V>,\n ref: React.ForwardedRef<DropdownListApi>\n): JSX.Element => {\n // =========================================================================\n // CONST, REF, STATE\n // =========================================================================\n const {\n noResultsLabel = \"No results found.\",\n selectAllButtonLabel = \"Select all\",\n clearAllButtonLabel = \"Clear all\",\n } = customLabels || {};\n const searchPlaceholder =\n customLabels?.searchPlaceholder || _searchPlaceholder || \"Search\";\n const noResultsDescription =\n customLabels?.noResultsDescription || _noResultsDescription;\n const { focusedIndex, setFocusedIndex } = useContext(\n DropdownListStateContext\n );\n const {\n elementWidth,\n setFloatingRef,\n getFloatingProps,\n styles: floatingStyles,\n } = useDropdownRender();\n const [searchValue, setSearchValue] = useState<string>(\"\");\n const [displayListItems, setDisplayListItems] = useState(listItems ?? []);\n const itemsLoadStateChanged = useCompare(itemsLoadState);\n const mounted = useIsMounted();\n\n const nodeRef = useRef<HTMLDivElement | null>(null);\n const listItemRefs = useRef<(HTMLElement | null)[]>([]);\n const searchInputRef = useRef<HTMLInputElement>(null);\n const virtuosoRef = useRef<VirtuosoHandle>(null);\n\n const hasSelectedMax =\n !!maxSelectable &&\n !!selectedItems &&\n selectedItems?.length === maxSelectable;\n\n // =========================================================================\n // APPLY STYLES\n // =========================================================================\n let containerWidthType: ContainerWidthType = \"default\";\n let containerWidth: string | undefined = undefined;\n if (width) {\n containerWidth = width;\n containerWidthType = \"custom\";\n } else if (matchElementWidth && elementWidth) {\n containerWidth = `${elementWidth}px`;\n containerWidthType = \"match\";\n }\n\n useApplyStyle(nodeRef, {\n [styles.tokens.containerWidth]: containerWidth,\n });\n\n // =========================================================================\n // HELPER FUNCTIONS\n // =========================================================================\n const getValue = (item: T): V => {\n return valueExtractor ? valueExtractor(item) : (item as unknown as V);\n };\n\n const getItemKey = (item: T, index: number) => {\n const formattedValue = valueExtractor ? valueExtractor(item) : item;\n return `item_${index}__${formattedValue}`;\n };\n\n const getOptionLabel = (item: T): ListItemDisplayProps => {\n const value = listExtractor ? listExtractor(item) : item?.toString();\n\n if (typeof value === \"object\") {\n return { title: value.title, secondaryLabel: value.secondaryLabel };\n }\n\n return { title: value ?? \"\" };\n };\n\n const checkListItemSelected = useCallback(\n (item: T): boolean => {\n return !!find(selectedItems, (arrItem) => {\n return isEqual(arrItem, item);\n });\n },\n [selectedItems]\n );\n\n const filterItemsByCustomSearch = useEvent(() => {\n return searchFunction?.(searchValue);\n });\n\n const filterItemsByLabel = useEvent(() => {\n return listItems?.filter((item) => {\n const { title, secondaryLabel } = getOptionLabel(item);\n const updatedSearchValue = searchValue.trim().toLowerCase();\n return (\n title.toLowerCase().includes(updatedSearchValue) ||\n (secondaryLabel &&\n secondaryLabel.toLowerCase().includes(updatedSearchValue))\n );\n });\n });\n\n const refocus = useCallback(\n (opts?: { index?: number; preferSelected?: boolean }) => {\n if (disableItemFocus) return;\n\n if (searchInputRef.current) {\n setFocusedIndex(-1);\n setTimeout(() => searchInputRef.current?.focus(), 0);\n return;\n }\n\n const items = displayListItems ?? [];\n if (items.length === 0) return;\n\n if (opts?.index !== undefined) {\n const forced = Math.max(\n 0,\n Math.min(opts.index, items.length - 1)\n );\n virtuosoRef.current?.scrollToIndex({\n index: forced,\n align: \"center\",\n });\n setFocusedIndex(forced);\n setTimeout(() => listItemRefs.current[forced]?.focus(), 0);\n\n return;\n }\n\n const selectedIndex = opts?.preferSelected\n ? items.findIndex((item) => checkListItemSelected(item))\n : -1;\n\n const nextIndex =\n selectedIndex !== -1\n ? selectedIndex\n : focusedIndex >= 0 && focusedIndex < items.length\n ? focusedIndex\n : 0;\n\n virtuosoRef.current?.scrollToIndex({\n index: nextIndex,\n align: \"center\",\n });\n setFocusedIndex(nextIndex);\n setTimeout(() => listItemRefs.current[nextIndex]?.focus(), 0);\n },\n [\n checkListItemSelected,\n disableItemFocus,\n displayListItems,\n focusedIndex,\n setFocusedIndex,\n ]\n );\n\n // =========================================================================\n // EVENT HANDLERS\n // =========================================================================\n const handleKeyboardPress = (event: KeyboardEvent) => {\n switch (event.code) {\n case \"ArrowDown\":\n event.preventDefault();\n if (focusedIndex < displayListItems.length - 1) {\n const upcomingIndex = focusedIndex + 1;\n listItemRefs.current[upcomingIndex]?.focus();\n setFocusedIndex(upcomingIndex);\n }\n break;\n case \"ArrowUp\":\n event.preventDefault();\n if (focusedIndex > 0) {\n const upcomingIndex = focusedIndex - 1;\n listItemRefs.current[upcomingIndex]?.focus();\n setFocusedIndex(upcomingIndex);\n } else if (focusedIndex === 0 && searchInputRef.current) {\n searchInputRef.current.focus();\n setFocusedIndex(-1);\n }\n break;\n case \"Space\":\n case \"Enter\":\n if (\n focusedIndex >= 0 &&\n (document.activeElement ===\n listItemRefs.current[focusedIndex] ||\n document.activeElement === searchInputRef.current)\n ) {\n event.preventDefault();\n if (displayListItems[focusedIndex]) {\n handleListItemClick(\n displayListItems[focusedIndex],\n focusedIndex\n );\n }\n }\n break;\n default:\n break;\n }\n };\n\n const handleListItemClick = (item: T, upcomingIndex: number) => {\n if (hasSelectedMax && !checkListItemSelected(item)) return;\n setFocusedIndex(upcomingIndex);\n onSelectItem?.(item, getValue(item));\n };\n\n const handleListItemHover = (index: number) => setFocusedIndex(index);\n\n const handleSearchInputChange = (\n event: React.ChangeEvent<HTMLInputElement>\n ) => {\n const value = event.target.value;\n setSearchValue(value);\n onSearch?.();\n };\n\n const handleOnClear = () => {\n setSearchValue(\"\");\n searchInputRef.current?.focus();\n onSearch?.();\n };\n\n const handleTryAgain = () => onRetry?.();\n\n // =========================================================================\n // EFFECTS\n // =========================================================================\n useEventListener(\"keydown\", handleKeyboardPress);\n useImperativeHandle(ref, () => ({ refocus }), [refocus]);\n\n useEffect(() => {\n if (!topScrollItem) {\n virtuosoRef.current?.scrollTo({ top: 0 });\n return;\n }\n const timer = setTimeout(() => {\n if (!listItems) return;\n\n const index = listItems.indexOf(topScrollItem);\n if (virtuosoRef.current && index !== -1) {\n virtuosoRef.current.scrollToIndex({ index });\n setFocusedIndex(index);\n }\n }, 0);\n\n return () => clearTimeout(timer);\n }, [listItemRefs, listItems, setFocusedIndex, topScrollItem]);\n\n useEffect(() => {\n if (disableItemFocus) return;\n if (!mounted || !itemsLoadStateChanged) return;\n\n if (itemsLoadState === \"success\") {\n if (searchInputRef.current) {\n setFocusedIndex(-1);\n searchInputRef.current.focus();\n }\n }\n }, [\n mounted,\n itemsLoadStateChanged,\n itemsLoadState,\n setFocusedIndex,\n disableItemFocus,\n ]);\n\n useEffect(() => {\n const filterItems = () => {\n if (searchValue === \"\") {\n return listItems;\n } else if (searchFunction) {\n return filterItemsByCustomSearch();\n } else {\n return filterItemsByLabel();\n }\n };\n\n setDisplayListItems(filterItems() ?? []);\n }, [\n filterItemsByCustomSearch,\n filterItemsByLabel,\n listItems,\n searchFunction,\n searchValue,\n ]);\n\n useEffect(() => {\n if (mounted) {\n return;\n }\n\n if (disableItemFocus || !listItems) return;\n\n const index = listItems.findIndex((item) =>\n checkListItemSelected(item)\n );\n\n if (searchInputRef.current) {\n setFocusedIndex(-1);\n setTimeout(() => searchInputRef.current?.focus(), 200);\n } else if (focusedIndex > 0) {\n virtuosoRef.current?.scrollToIndex({\n index: focusedIndex,\n align: \"center\",\n });\n setTimeout(() => listItemRefs.current[focusedIndex]?.focus(), 200);\n } else if (index !== -1) {\n virtuosoRef.current?.scrollToIndex({ index, align: \"center\" });\n setFocusedIndex(index);\n setTimeout(() => listItemRefs.current[index]?.focus(), 200);\n } else {\n virtuosoRef.current?.scrollToIndex({ index: 0 });\n setFocusedIndex(0);\n setTimeout(() => listItemRefs.current[0]?.focus(), 200);\n }\n }, [\n checkListItemSelected,\n disableItemFocus,\n focusedIndex,\n listItems,\n mounted,\n setFocusedIndex,\n ]);\n\n // =========================================================================\n // RENDER FUNCTIONS\n // =========================================================================\n const renderListItemIcon = (selected: boolean) => {\n if (multiSelect) {\n if (hasSelectedMax && !selected) {\n return (\n <SquareFillIcon\n aria-hidden\n className={clsx(\n styles.baseCheckboxIndicatorStyle,\n styles.checkboxDisabledIndicator\n )}\n />\n );\n }\n\n return selected ? (\n <SquareTickFillIcon\n aria-hidden\n className={clsx(\n styles.baseCheckboxIndicatorStyle,\n styles.checkboxSelectedIndicator\n )}\n />\n ) : (\n <SquareIcon\n aria-hidden\n className={clsx(\n styles.baseCheckboxIndicatorStyle,\n styles.checkboxUnselectedIndicator\n )}\n />\n );\n }\n\n return selected ? (\n <TickIcon\n aria-hidden\n className={clsx(\n styles.baseIndicatorStyle,\n styles.selectedIndicator\n )}\n />\n ) : (\n <div className={styles.baseIndicatorStyle} />\n );\n };\n\n const renderDropdownLabel = (item: T, selected: boolean) => {\n const { title, secondaryLabel } = getOptionLabel(item);\n\n return (\n <DropdownLabel\n displayType={labelDisplayType}\n label={title}\n maxLines={itemMaxLines}\n selected={selected}\n disabled={!selected && hasSelectedMax}\n sublabel={secondaryLabel}\n truncationType={itemTruncationType}\n variant={variant}\n />\n );\n };\n\n const renderItem = (item: T, index: number) => {\n if (!onRetry || itemsLoadState === \"success\") {\n const selected = checkListItemSelected(item);\n const active = index === focusedIndex;\n const disabled = !selected && hasSelectedMax;\n return (\n <li\n aria-selected={selected}\n aria-multiselectable={multiSelect}\n aria-disabled={disabled}\n aria-posinset={index + 1}\n aria-setsize={displayListItems?.length}\n data-testid=\"list-item\"\n key={getItemKey(item, index)}\n onClick={() => handleListItemClick(item, index)}\n onMouseEnter={() => handleListItemHover(index)}\n ref={(element) => {\n listItemRefs.current[index] = element;\n }}\n role=\"option\"\n tabIndex={active ? 0 : -1}\n className={clsx(\n styles.listItem,\n (disabled && styles.listItemDisabled) ||\n (active &&\n selected &&\n styles.listItemActiveSelected) ||\n (active && styles.listItemActive)\n )}\n >\n {renderListItem ? (\n renderListItem(item, { selected })\n ) : (\n <>\n {renderListItemIcon(selected)}\n {renderDropdownLabel(item, selected)}\n </>\n )}\n </li>\n );\n }\n };\n\n const renderSearchInput = () => {\n if ((enableSearch || searchFunction) && itemsLoadState === \"success\") {\n return (\n <DropdownSearch\n ref={searchInputRef}\n onChange={handleSearchInputChange}\n value={searchValue}\n placeholder={searchPlaceholder}\n data-testid=\"search-input\"\n aria-label=\"Enter text to search\"\n onClear={handleOnClear}\n variant={variant}\n />\n );\n }\n };\n\n const renderSelectAll = () => {\n if (\n selectedItems &&\n multiSelect &&\n displayListItems.length > 0 &&\n !searchValue &&\n itemsLoadState === \"success\"\n ) {\n return (\n <div className={styles.selectAllContainer}>\n <BasicButton\n onClick={onSelectAll}\n type=\"button\"\n className={clsx(\n styles.baseButton,\n styles.selectAllButton\n )}\n >\n {maxSelectable || selectedItems.length !== 0\n ? clearAllButtonLabel\n : selectAllButtonLabel}\n </BasicButton>\n </div>\n );\n }\n };\n\n const renderNoResults = () => {\n if (\n !hideNoResultsDisplay &&\n (searchValue || !enableSearch) &&\n displayListItems.length === 0 &&\n itemsLoadState === \"success\"\n ) {\n return (\n <>\n <div\n data-testid=\"list-no-results\"\n className={styles.resultStateContainer}\n >\n <ExclamationCircleFillIcon\n data-testid=\"no-result-icon\"\n className={styles.labelIcon}\n />\n {noResultsLabel}\n </div>\n {noResultsDescription && (\n <Markup\n data-testid=\"no-result-desc\"\n className={styles.noResultDescContainer}\n >\n {noResultsDescription}\n </Markup>\n )}\n </>\n );\n }\n };\n\n const renderLoading = () => {\n if (onRetry && itemsLoadState === \"loading\") {\n return (\n <div\n data-testid=\"list-loading\"\n className={styles.resultStateContainer}\n >\n <ComponentLoadingSpinner className={styles.spinner} />\n Loading...\n </div>\n );\n }\n };\n\n const renderTryAgain = () => {\n if (onRetry && itemsLoadState === \"fail\") {\n return (\n <div\n data-testid=\"list-fail\"\n className={styles.resultStateContainer}\n >\n <ExclamationCircleFillIcon\n data-testid=\"load-error-icon\"\n className={styles.labelIcon}\n />\n Failed to load. \n <BasicButton\n onClick={handleTryAgain}\n type=\"button\"\n className={clsx(\n styles.baseButton,\n styles.tryAgainButton\n )}\n >\n Try again.\n </BasicButton>\n </div>\n );\n }\n };\n\n const renderVirtualisedList = () => {\n const isTestEnv = process.env.NODE_ENV === \"test\";\n\n return (\n <Virtuoso\n ref={virtuosoRef}\n style={{ height: \"100%\" }}\n data={displayListItems}\n customScrollParent={nodeRef.current ?? undefined}\n itemContent={(index, item) => renderItem(item, index)}\n components={{\n List: VirtuosoList,\n Item: VirtuosoItem,\n }}\n context={{\n listProps: {\n id: listboxId,\n role: \"listbox\",\n \"aria-multiselectable\": multiSelect,\n },\n listItemProps: {\n role: \"none\",\n },\n }}\n // disable virtualisation in tests\n // https://github.com/petyosi/react-virtuoso/issues/26#issuecomment-1040316576\n // explicitly set the `key` prop to avoid React warning\n key={isTestEnv ? displayListItems.length : undefined}\n // omit the `initialItemCount` prop to resolve NaN error\n {...(isTestEnv\n ? {\n initialItemCount: displayListItems.length,\n }\n : {})}\n />\n );\n };\n\n const renderList = () => {\n return (\n <div\n data-testid=\"dropdown-list\"\n role=\"group\"\n aria-label={ariaLabel}\n className={styles.list}\n >\n {renderSearchInput()}\n {renderSelectAll()}\n {renderNoResults()}\n {renderLoading()}\n {renderTryAgain()}\n {renderVirtualisedList()}\n </div>\n );\n };\n\n const renderBottomCta = () => {\n if (!renderCustomCallToAction) {\n return;\n }\n\n return (\n <div data-testid=\"custom-cta\">\n {renderCustomCallToAction(onDismiss as any, displayListItems)}\n </div>\n );\n };\n\n return (\n <div\n data-testid=\"dropdown-container\"\n ref={mergeRefs(nodeRef, setFloatingRef)}\n {...getFloatingProps()}\n data-width-type={containerWidthType}\n className={clsx(\n styles.container,\n variant === \"small\" && styles.containerVariantSmall\n )}\n style={floatingStyles}\n >\n <VisuallyHidden role=\"status\">{ariaLabel}</VisuallyHidden>\n {renderList()}\n {renderBottomCta()}\n </div>\n );\n};\n\nexport const DropdownList = forwardRef(DropdownListInner);\n"],"names":["DropdownList","forwardRef","listItems","multiSelect","maxSelectable","selectedItems","disableItemFocus","itemsLoadState","itemTruncationType","itemMaxLines","labelDisplayType","variant","listboxId","ariaLabel","matchElementWidth","width","topScrollItem","onSelectItem","onSelectAll","onDismiss","onRetry","valueExtractor","listExtractor","renderListItem","renderCustomCallToAction","enableSearch","hideNoResultsDisplay","noResultsDescription","_noResultsDescription","customLabels","searchPlaceholder","_searchPlaceholder","searchFunction","onSearch","ref","noResultsLabel","selectAllButtonLabel","clearAllButtonLabel","focusedIndex","setFocusedIndex","useContext","DropdownListStateContext","elementWidth","setFloatingRef","getFloatingProps","styles","floatingStyles","useDropdownRender","searchValue","setSearchValue","useState","displayListItems","setDisplayListItems","itemsLoadStateChanged","useCompare","mounted","useIsMounted","nodeRef","useRef","listItemRefs","searchInputRef","virtuosoRef","hasSelectedMax","length","containerWidth","containerWidthType","useApplyStyle","styles.tokens","getOptionLabel","item","value","toString","title","secondaryLabel","checkListItemSelected","useCallback","find","arrItem","isEqual","filterItemsByCustomSearch","useEvent","filterItemsByLabel","filter","updatedSearchValue","trim","toLowerCase","includes","refocus","opts","current","setTimeout","_a","focus","items","undefined","index","forced","Math","max","min","scrollToIndex","align","selectedIndex","preferSelected","findIndex","nextIndex","_b","handleListItemClick","upcomingIndex","getValue","handleSearchInputChange","event","target","handleOnClear","handleTryAgain","useEventListener","code","preventDefault","document","activeElement","useImperativeHandle","useEffect","scrollTo","top","timer","indexOf","clearTimeout","_c","renderListItemIcon","selected","_jsx","SquareFillIcon","className","clsx","styles.baseCheckboxIndicatorStyle","styles.checkboxDisabledIndicator","SquareTickFillIcon","styles.checkboxSelectedIndicator","SquareIcon","styles.checkboxUnselectedIndicator","TickIcon","styles.baseIndicatorStyle","styles.selectedIndicator","renderDropdownLabel","DropdownLabel","displayType","label","maxLines","disabled","sublabel","truncationType","renderItem","active","onClick","onMouseEnter","handleListItemHover","element","role","tabIndex","styles.listItem","styles.listItemDisabled","styles.listItemActiveSelected","styles.listItemActive","children","_jsxs","_Fragment","getItemKey","renderSearchInput","DropdownSearch","onChange","placeholder","onClear","renderSelectAll","styles.selectAllContainer","BasicButton","type","styles.baseButton","styles.selectAllButton","renderNoResults","styles.resultStateContainer","ExclamationCircleFillIcon","styles.labelIcon","Markup","styles.noResultDescContainer","renderLoading","ComponentLoadingSpinner","styles.spinner","renderTryAgain","styles.tryAgainButton","renderVirtualisedList","isTestEnv","process","env","NODE_ENV","Virtuoso","Object","assign","style","height","data","customScrollParent","itemContent","components","List","VirtuosoList","Item","VirtuosoItem","context","listProps","id","listItemProps","initialItemCount","mergeRefs","styles.container","styles.containerVariantSmall","VisuallyHidden","styles.list","renderBottomCta"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"dropdown-list.js","sources":["../../../src/shared/dropdown-list/dropdown-list.tsx"],"sourcesContent":["import { ExclamationCircleFillIcon } from \"@lifesg/react-icons/exclamation-circle-fill\";\nimport { SquareIcon } from \"@lifesg/react-icons/square\";\nimport { SquareFillIcon } from \"@lifesg/react-icons/square-fill\";\nimport { SquareTickFillIcon } from \"@lifesg/react-icons/square-tick-fill\";\nimport { TickIcon } from \"@lifesg/react-icons/tick\";\nimport clsx from \"clsx\";\nimport find from \"lodash/find\";\nimport isEqual from \"lodash/isEqual\";\nimport type React from \"react\";\nimport {\n forwardRef,\n useCallback,\n useContext,\n useEffect,\n useImperativeHandle,\n useRef,\n useState,\n} from \"react\";\nimport type { VirtuosoHandle } from \"react-virtuoso\";\nimport { Virtuoso } from \"react-virtuoso\";\n\nimport { Markup } from \"../../markup\";\nimport { useApplyStyle } from \"../../theme\";\nimport {\n mergeRefs,\n useCompare,\n useEvent,\n useEventListener,\n useIsMounted,\n} from \"../../util\";\nimport { VisuallyHidden } from \"../accessibility\";\nimport { ComponentLoadingSpinner } from \"../component-loading-spinner\";\nimport { useDropdownRender } from \"../dropdown-wrapper\";\nimport { BasicButton } from \"../input-wrapper\";\nimport { DropdownLabel } from \"./dropdown-label\";\nimport type { ContainerWidthType } from \"./dropdown-list.styles\";\nimport * as styles from \"./dropdown-list.styles\";\nimport { DropdownListStateContext } from \"./dropdown-list-state\";\nimport { DropdownSearch } from \"./dropdown-search\";\nimport type {\n DropdownListApi,\n DropdownListProps,\n ListItemDisplayProps,\n} from \"./types\";\nimport { VirtuosoItem, VirtuosoList } from \"./virtuoso-components\";\n\n/**\n * NOTE: This component is not directly exportable but forms part of a component\n */\nconst DropdownListInner = <T, V>(\n {\n listItems,\n multiSelect,\n maxSelectable,\n selectedItems,\n disableItemFocus,\n itemsLoadState = \"success\",\n itemTruncationType = \"end\",\n itemMaxLines = 2,\n labelDisplayType = \"inline\",\n variant = \"default\",\n listboxId,\n ariaLabel,\n matchElementWidth = false,\n width,\n topScrollItem,\n onSelectItem,\n onSelectAll,\n onDismiss,\n onRetry,\n /* DropdownDisplayProps */\n valueExtractor,\n listExtractor,\n renderListItem,\n renderCustomCallToAction,\n /* DropdownSearchProps */\n enableSearch,\n hideNoResultsDisplay,\n noResultsDescription: _noResultsDescription,\n customLabels,\n searchPlaceholder: _searchPlaceholder,\n searchFunction,\n onSearch,\n }: DropdownListProps<T, V>,\n ref: React.ForwardedRef<DropdownListApi>\n): JSX.Element => {\n // =========================================================================\n // CONST, REF, STATE\n // =========================================================================\n const {\n noResultsLabel = \"No results found.\",\n selectAllButtonLabel = \"Select all\",\n clearAllButtonLabel = \"Clear all\",\n } = customLabels || {};\n const searchPlaceholder =\n customLabels?.searchPlaceholder || _searchPlaceholder || \"Search\";\n const noResultsDescription =\n customLabels?.noResultsDescription || _noResultsDescription;\n const { focusedIndex, setFocusedIndex } = useContext(\n DropdownListStateContext\n );\n const {\n elementWidth,\n setFloatingRef,\n getFloatingProps,\n styles: floatingStyles,\n } = useDropdownRender();\n const [searchValue, setSearchValue] = useState<string>(\"\");\n const [displayListItems, setDisplayListItems] = useState(listItems ?? []);\n const itemsLoadStateChanged = useCompare(itemsLoadState);\n const mounted = useIsMounted();\n\n const nodeRef = useRef<HTMLDivElement | null>(null);\n const listItemRefs = useRef<(HTMLElement | null)[]>([]);\n const searchInputRef = useRef<HTMLInputElement>(null);\n const virtuosoRef = useRef<VirtuosoHandle>(null);\n\n const hasSelectedMax =\n !!maxSelectable &&\n !!selectedItems &&\n selectedItems?.length === maxSelectable;\n\n // =========================================================================\n // APPLY STYLES\n // =========================================================================\n let containerWidthType: ContainerWidthType = \"default\";\n let containerWidth: string | undefined = undefined;\n if (width) {\n containerWidth = width;\n containerWidthType = \"custom\";\n } else if (matchElementWidth && elementWidth) {\n containerWidth = `${elementWidth}px`;\n containerWidthType = \"match\";\n }\n\n useApplyStyle(nodeRef, {\n [styles.tokens.containerWidth]: containerWidth,\n });\n\n // =========================================================================\n // HELPER FUNCTIONS\n // =========================================================================\n const getValue = (item: T): V => {\n return valueExtractor ? valueExtractor(item) : (item as unknown as V);\n };\n\n const getItemKey = (item: T, index: number) => {\n const formattedValue = valueExtractor ? valueExtractor(item) : item;\n return `item_${index}__${formattedValue}`;\n };\n\n const getOptionLabel = (item: T): ListItemDisplayProps => {\n const value = listExtractor ? listExtractor(item) : item?.toString();\n\n if (typeof value === \"object\") {\n return { title: value.title, secondaryLabel: value.secondaryLabel };\n }\n\n return { title: value ?? \"\" };\n };\n\n const checkListItemSelected = useCallback(\n (item: T): boolean => {\n return !!find(selectedItems, (arrItem) => {\n return isEqual(arrItem, item);\n });\n },\n [selectedItems]\n );\n\n const filterItemsByCustomSearch = useEvent(() => {\n return searchFunction?.(searchValue);\n });\n\n const filterItemsByLabel = useEvent(() => {\n return listItems?.filter((item) => {\n const { title, secondaryLabel } = getOptionLabel(item);\n const updatedSearchValue = searchValue.trim().toLowerCase();\n return (\n title.toLowerCase().includes(updatedSearchValue) ||\n (secondaryLabel &&\n secondaryLabel.toLowerCase().includes(updatedSearchValue))\n );\n });\n });\n\n const refocus = useCallback(\n (opts?: { index?: number; preferSelected?: boolean }) => {\n if (disableItemFocus) return;\n\n if (searchInputRef.current) {\n setFocusedIndex(-1);\n setTimeout(() => searchInputRef.current?.focus(), 0);\n return;\n }\n\n const items = displayListItems ?? [];\n if (items.length === 0) return;\n\n if (opts?.index !== undefined) {\n const forced = Math.max(\n 0,\n Math.min(opts.index, items.length - 1)\n );\n virtuosoRef.current?.scrollToIndex({\n index: forced,\n align: \"center\",\n });\n setFocusedIndex(forced);\n setTimeout(() => listItemRefs.current[forced]?.focus(), 0);\n\n return;\n }\n\n const selectedIndex = opts?.preferSelected\n ? items.findIndex((item) => checkListItemSelected(item))\n : -1;\n\n const nextIndex =\n selectedIndex !== -1\n ? selectedIndex\n : focusedIndex >= 0 && focusedIndex < items.length\n ? focusedIndex\n : 0;\n\n virtuosoRef.current?.scrollToIndex({\n index: nextIndex,\n align: \"center\",\n });\n setFocusedIndex(nextIndex);\n setTimeout(() => listItemRefs.current[nextIndex]?.focus(), 0);\n },\n [\n checkListItemSelected,\n disableItemFocus,\n displayListItems,\n focusedIndex,\n setFocusedIndex,\n ]\n );\n\n // =========================================================================\n // EVENT HANDLERS\n // =========================================================================\n const handleKeyboardPress = (event: KeyboardEvent) => {\n switch (event.code) {\n case \"ArrowDown\":\n event.preventDefault();\n if (focusedIndex < displayListItems.length - 1) {\n const upcomingIndex = focusedIndex + 1;\n listItemRefs.current[upcomingIndex]?.focus();\n setFocusedIndex(upcomingIndex);\n }\n break;\n case \"ArrowUp\":\n event.preventDefault();\n if (focusedIndex > 0) {\n const upcomingIndex = focusedIndex - 1;\n listItemRefs.current[upcomingIndex]?.focus();\n setFocusedIndex(upcomingIndex);\n } else if (focusedIndex === 0 && searchInputRef.current) {\n searchInputRef.current.focus();\n setFocusedIndex(-1);\n }\n break;\n case \"Space\":\n case \"Enter\":\n if (\n focusedIndex >= 0 &&\n (document.activeElement ===\n listItemRefs.current[focusedIndex] ||\n document.activeElement === searchInputRef.current)\n ) {\n event.preventDefault();\n if (displayListItems[focusedIndex]) {\n handleListItemClick(\n displayListItems[focusedIndex],\n focusedIndex\n );\n }\n }\n break;\n default:\n break;\n }\n };\n\n const handleListItemClick = (item: T, upcomingIndex: number) => {\n if (hasSelectedMax && !checkListItemSelected(item)) return;\n setFocusedIndex(upcomingIndex);\n onSelectItem?.(item, getValue(item));\n };\n\n const handleListItemHover = (index: number) => setFocusedIndex(index);\n\n const handleSearchInputChange = (\n event: React.ChangeEvent<HTMLInputElement>\n ) => {\n const value = event.target.value;\n setSearchValue(value);\n onSearch?.();\n };\n\n const handleOnClear = () => {\n setSearchValue(\"\");\n searchInputRef.current?.focus();\n onSearch?.();\n };\n\n const handleTryAgain = () => onRetry?.();\n\n // =========================================================================\n // EFFECTS\n // =========================================================================\n useEventListener(\"keydown\", handleKeyboardPress);\n useImperativeHandle(ref, () => ({ refocus }), [refocus]);\n\n useEffect(() => {\n if (!topScrollItem) {\n virtuosoRef.current?.scrollTo({ top: 0 });\n return;\n }\n const timer = setTimeout(() => {\n if (!listItems) return;\n\n const index = listItems.indexOf(topScrollItem);\n if (virtuosoRef.current && index !== -1) {\n virtuosoRef.current.scrollToIndex({ index });\n setFocusedIndex(index);\n }\n }, 0);\n\n return () => clearTimeout(timer);\n }, [listItemRefs, listItems, setFocusedIndex, topScrollItem]);\n\n useEffect(() => {\n if (disableItemFocus) return;\n if (!mounted || !itemsLoadStateChanged) return;\n\n if (itemsLoadState === \"success\") {\n if (searchInputRef.current) {\n setFocusedIndex(-1);\n searchInputRef.current.focus();\n }\n }\n }, [\n mounted,\n itemsLoadStateChanged,\n itemsLoadState,\n setFocusedIndex,\n disableItemFocus,\n ]);\n\n useEffect(() => {\n const filterItems = () => {\n if (searchValue === \"\") {\n return listItems;\n } else if (searchFunction) {\n return filterItemsByCustomSearch();\n } else {\n return filterItemsByLabel();\n }\n };\n\n setDisplayListItems(filterItems() ?? []);\n }, [\n filterItemsByCustomSearch,\n filterItemsByLabel,\n listItems,\n searchFunction,\n searchValue,\n ]);\n\n useEffect(() => {\n if (mounted) {\n return;\n }\n\n if (disableItemFocus || !listItems) return;\n\n const index = listItems.findIndex((item) =>\n checkListItemSelected(item)\n );\n\n if (searchInputRef.current) {\n setFocusedIndex(-1);\n setTimeout(() => searchInputRef.current?.focus(), 200);\n } else if (focusedIndex > 0) {\n virtuosoRef.current?.scrollToIndex({\n index: focusedIndex,\n align: \"center\",\n });\n setTimeout(() => listItemRefs.current[focusedIndex]?.focus(), 200);\n } else if (index !== -1) {\n virtuosoRef.current?.scrollToIndex({ index, align: \"center\" });\n setFocusedIndex(index);\n setTimeout(() => listItemRefs.current[index]?.focus(), 200);\n } else {\n virtuosoRef.current?.scrollToIndex({ index: 0 });\n setFocusedIndex(0);\n setTimeout(() => listItemRefs.current[0]?.focus(), 200);\n }\n }, [\n checkListItemSelected,\n disableItemFocus,\n focusedIndex,\n listItems,\n mounted,\n setFocusedIndex,\n ]);\n\n // =========================================================================\n // RENDER FUNCTIONS\n // =========================================================================\n const renderListItemIcon = (selected: boolean) => {\n if (multiSelect) {\n if (hasSelectedMax && !selected) {\n return (\n <SquareFillIcon\n aria-hidden\n className={clsx(\n styles.baseCheckboxIndicatorStyle,\n styles.checkboxDisabledIndicator\n )}\n />\n );\n }\n\n return selected ? (\n <SquareTickFillIcon\n aria-hidden\n className={clsx(\n styles.baseCheckboxIndicatorStyle,\n styles.checkboxSelectedIndicator\n )}\n />\n ) : (\n <SquareIcon\n aria-hidden\n className={clsx(\n styles.baseCheckboxIndicatorStyle,\n styles.checkboxUnselectedIndicator\n )}\n />\n );\n }\n\n return selected ? (\n <TickIcon\n aria-hidden\n className={clsx(\n styles.baseIndicatorStyle,\n styles.selectedIndicator\n )}\n />\n ) : (\n <div className={styles.baseIndicatorStyle} />\n );\n };\n\n const renderDropdownLabel = (item: T, selected: boolean) => {\n const { title, secondaryLabel } = getOptionLabel(item);\n\n return (\n <DropdownLabel\n displayType={labelDisplayType}\n label={title}\n maxLines={itemMaxLines}\n selected={selected}\n disabled={!selected && hasSelectedMax}\n sublabel={secondaryLabel}\n truncationType={itemTruncationType}\n variant={variant}\n />\n );\n };\n\n const renderItem = (item: T, index: number) => {\n if (!onRetry || itemsLoadState === \"success\") {\n const selected = checkListItemSelected(item);\n const active = index === focusedIndex;\n const disabled = !selected && hasSelectedMax;\n return (\n <li\n aria-selected={selected}\n aria-multiselectable={multiSelect}\n aria-disabled={disabled}\n aria-posinset={index + 1}\n aria-setsize={displayListItems?.length}\n data-testid=\"list-item\"\n key={getItemKey(item, index)}\n onClick={() => handleListItemClick(item, index)}\n onMouseEnter={() => handleListItemHover(index)}\n ref={(element) => {\n listItemRefs.current[index] = element;\n }}\n role=\"option\"\n tabIndex={active ? 0 : -1}\n className={clsx(\n styles.listItem,\n (disabled && styles.listItemDisabled) ||\n (active &&\n selected &&\n styles.listItemActiveSelected) ||\n (active && styles.listItemActive)\n )}\n >\n {renderListItem ? (\n renderListItem(item, { selected })\n ) : (\n <>\n {renderListItemIcon(selected)}\n {renderDropdownLabel(item, selected)}\n </>\n )}\n </li>\n );\n }\n };\n\n const renderSearchInput = () => {\n if ((enableSearch || searchFunction) && itemsLoadState === \"success\") {\n return (\n <DropdownSearch\n ref={searchInputRef}\n onChange={handleSearchInputChange}\n value={searchValue}\n placeholder={searchPlaceholder}\n data-testid=\"search-input\"\n aria-label=\"Enter text to search\"\n onClear={handleOnClear}\n variant={variant}\n />\n );\n }\n };\n\n const renderSelectAll = () => {\n if (\n selectedItems &&\n multiSelect &&\n displayListItems.length > 0 &&\n !searchValue &&\n itemsLoadState === \"success\"\n ) {\n return (\n <div className={styles.selectAllContainer}>\n <BasicButton\n onClick={onSelectAll}\n type=\"button\"\n className={clsx(\n styles.baseButton,\n styles.selectAllButton\n )}\n >\n {maxSelectable || selectedItems.length !== 0\n ? clearAllButtonLabel\n : selectAllButtonLabel}\n </BasicButton>\n </div>\n );\n }\n };\n\n const renderNoResults = () => {\n if (\n !hideNoResultsDisplay &&\n (searchValue || !enableSearch) &&\n displayListItems.length === 0 &&\n itemsLoadState === \"success\"\n ) {\n return (\n <>\n <div\n data-testid=\"list-no-results\"\n className={styles.resultStateContainer}\n >\n <ExclamationCircleFillIcon\n data-testid=\"no-result-icon\"\n className={styles.labelIcon}\n />\n {noResultsLabel}\n </div>\n {noResultsDescription && (\n <Markup\n data-testid=\"no-result-desc\"\n className={styles.noResultDescContainer}\n >\n {noResultsDescription}\n </Markup>\n )}\n </>\n );\n }\n };\n\n const renderLoading = () => {\n if (onRetry && itemsLoadState === \"loading\") {\n return (\n <div\n data-testid=\"list-loading\"\n className={styles.resultStateContainer}\n >\n <ComponentLoadingSpinner className={styles.spinner} />\n Loading...\n </div>\n );\n }\n };\n\n const renderTryAgain = () => {\n if (onRetry && itemsLoadState === \"fail\") {\n return (\n <div\n data-testid=\"list-fail\"\n className={styles.resultStateContainer}\n >\n <ExclamationCircleFillIcon\n data-testid=\"load-error-icon\"\n className={styles.labelIcon}\n />\n Failed to load. \n <BasicButton\n onClick={handleTryAgain}\n type=\"button\"\n className={clsx(\n styles.baseButton,\n styles.tryAgainButton\n )}\n >\n Try again.\n </BasicButton>\n </div>\n );\n }\n };\n\n const renderVirtualisedList = () => {\n const isTestEnv = process.env.NODE_ENV === \"test\";\n\n return (\n <Virtuoso\n ref={virtuosoRef}\n style={{ height: \"100%\" }}\n data={displayListItems}\n customScrollParent={nodeRef.current ?? undefined}\n itemContent={(index, item) => renderItem(item, index)}\n components={{\n List: VirtuosoList,\n Item: VirtuosoItem,\n }}\n context={{\n listProps: {\n id: listboxId,\n role: \"listbox\",\n \"aria-multiselectable\": multiSelect,\n },\n listItemProps: {\n role: \"none\",\n },\n }}\n // disable virtualisation in tests\n // https://github.com/petyosi/react-virtuoso/issues/26#issuecomment-1040316576\n // explicitly set the `key` prop to avoid React warning\n key={isTestEnv ? displayListItems.length : undefined}\n // omit the `initialItemCount` prop to resolve NaN error\n {...(isTestEnv\n ? {\n initialItemCount: displayListItems.length,\n }\n : {})}\n />\n );\n };\n\n const renderList = () => {\n return (\n <div\n data-testid=\"dropdown-list\"\n role=\"group\"\n aria-label={ariaLabel}\n className={styles.list}\n >\n {renderSearchInput()}\n {renderSelectAll()}\n {renderNoResults()}\n {renderLoading()}\n {renderTryAgain()}\n {renderVirtualisedList()}\n </div>\n );\n };\n\n const renderBottomCta = () => {\n if (!renderCustomCallToAction) {\n return;\n }\n\n return (\n <div data-testid=\"custom-cta\">\n {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n renderCustomCallToAction(onDismiss as any, displayListItems)\n }\n </div>\n );\n };\n\n return (\n <div\n data-testid=\"dropdown-container\"\n ref={mergeRefs(nodeRef, setFloatingRef)}\n {...getFloatingProps()}\n data-width-type={containerWidthType}\n className={clsx(\n styles.container,\n variant === \"small\" && styles.containerVariantSmall\n )}\n style={floatingStyles}\n >\n <VisuallyHidden role=\"status\">{ariaLabel}</VisuallyHidden>\n {renderList()}\n {renderBottomCta()}\n </div>\n );\n};\n\nexport const DropdownList = forwardRef(DropdownListInner);\n"],"names":["DropdownList","forwardRef","listItems","multiSelect","maxSelectable","selectedItems","disableItemFocus","itemsLoadState","itemTruncationType","itemMaxLines","labelDisplayType","variant","listboxId","ariaLabel","matchElementWidth","width","topScrollItem","onSelectItem","onSelectAll","onDismiss","onRetry","valueExtractor","listExtractor","renderListItem","renderCustomCallToAction","enableSearch","hideNoResultsDisplay","noResultsDescription","_noResultsDescription","customLabels","searchPlaceholder","_searchPlaceholder","searchFunction","onSearch","ref","noResultsLabel","selectAllButtonLabel","clearAllButtonLabel","focusedIndex","setFocusedIndex","useContext","DropdownListStateContext","elementWidth","setFloatingRef","getFloatingProps","styles","floatingStyles","useDropdownRender","searchValue","setSearchValue","useState","displayListItems","setDisplayListItems","itemsLoadStateChanged","useCompare","mounted","useIsMounted","nodeRef","useRef","listItemRefs","searchInputRef","virtuosoRef","hasSelectedMax","length","containerWidth","containerWidthType","useApplyStyle","styles.tokens","getOptionLabel","item","value","toString","title","secondaryLabel","checkListItemSelected","useCallback","find","arrItem","isEqual","filterItemsByCustomSearch","useEvent","filterItemsByLabel","filter","updatedSearchValue","trim","toLowerCase","includes","refocus","opts","current","setTimeout","_a","focus","items","undefined","index","forced","Math","max","min","scrollToIndex","align","selectedIndex","preferSelected","findIndex","nextIndex","_b","handleListItemClick","upcomingIndex","getValue","handleSearchInputChange","event","target","handleOnClear","handleTryAgain","useEventListener","code","preventDefault","document","activeElement","useImperativeHandle","useEffect","scrollTo","top","timer","indexOf","clearTimeout","_c","renderListItemIcon","selected","_jsx","SquareFillIcon","className","clsx","styles.baseCheckboxIndicatorStyle","styles.checkboxDisabledIndicator","SquareTickFillIcon","styles.checkboxSelectedIndicator","SquareIcon","styles.checkboxUnselectedIndicator","TickIcon","styles.baseIndicatorStyle","styles.selectedIndicator","renderDropdownLabel","DropdownLabel","displayType","label","maxLines","disabled","sublabel","truncationType","renderItem","active","onClick","onMouseEnter","handleListItemHover","element","role","tabIndex","styles.listItem","styles.listItemDisabled","styles.listItemActiveSelected","styles.listItemActive","children","_jsxs","_Fragment","getItemKey","renderSearchInput","DropdownSearch","onChange","placeholder","onClear","renderSelectAll","styles.selectAllContainer","BasicButton","type","styles.baseButton","styles.selectAllButton","renderNoResults","styles.resultStateContainer","ExclamationCircleFillIcon","styles.labelIcon","Markup","styles.noResultDescContainer","renderLoading","ComponentLoadingSpinner","styles.spinner","renderTryAgain","styles.tryAgainButton","renderVirtualisedList","isTestEnv","process","env","NODE_ENV","Virtuoso","Object","assign","style","height","data","customScrollParent","itemContent","components","List","VirtuosoList","Item","VirtuosoItem","context","listProps","id","listItemProps","initialItemCount","mergeRefs","styles.container","styles.containerVariantSmall","VisuallyHidden","styles.list","renderBottomCta"],"mappings":"slFAiDA,MAsqBaA,GAAeC,GAtqBF,EAElBC,YACAC,eACAC,iBACAC,iBACAC,oBACAC,kBAAiB,UACjBC,sBAAqB,MACrBC,gBAAe,EACfC,oBAAmB,SACnBC,WAAU,UACVC,aACAC,aACAC,sBAAoB,EACpBC,SACAC,iBACAC,gBACAC,eACAC,aACAC,WAEAC,kBACAC,iBACAC,kBACAC,4BAEAC,gBACAC,wBACAC,qBAAsBC,GACtBC,gBACAC,kBAAmBC,GACnBC,kBACAC,aAEJC,MAKA,MAAMC,eACFA,GAAiB,oBAAmBC,qBACpCA,GAAuB,aAAYC,oBACnCA,GAAsB,aACtBR,IAAgB,CAAA,EACdC,IACFD,cAAY,EAAZA,GAAcC,oBAAqBC,IAAsB,SACvDJ,IACFE,cAAY,EAAZA,GAAcF,uBAAwBC,IACpCU,aAAEA,GAAYC,gBAAEA,IAAoBC,EACtCC,IAEEC,aACFA,GAAYC,eACZA,GAAcC,iBACdA,GACAC,OAAQC,IACRC,KACGC,GAAaC,IAAkBC,EAAiB,KAChDC,GAAkBC,IAAuBF,EAAShD,QAAAA,EAAa,IAChEmD,GAAwBC,EAAW/C,IACnCgD,GAAUC,IAEVC,GAAUC,EAA8B,MACxCC,GAAeD,EAA+B,IAC9CE,GAAiBF,EAAyB,MAC1CG,GAAcH,EAAuB,MAErCI,KACA1D,MACAC,KACFA,cAAa,EAAbA,GAAe0D,UAAW3D,GAK9B,IACI4D,GADAC,GAAyC,UAEzClD,IACAiD,GAAiBjD,GACjBkD,GAAqB,UACdnD,IAAqB4B,KAC5BsB,GAAiB,GAAGtB,OACpBuB,GAAqB,SAGzBC,EAAcT,GAAS,CACnB,CAACU,EAAcH,gBAAiBA,KAMpC,MASMI,GAAkBC,IACpB,MAAMC,EAAQhD,GAAgBA,GAAc+C,GAAQA,eAAAA,EAAME,WAE1D,MAAqB,iBAAVD,EACA,CAAEE,MAAOF,EAAME,MAAOC,eAAgBH,EAAMG,gBAGhD,CAAED,MAAOF,QAAAA,EAAS,GAAI,EAG3BI,GAAwBC,GACzBN,KACYO,EAAKvE,IAAgBwE,GACnBC,EAAQD,EAASR,MAGhC,CAAChE,KAGC0E,GAA4BC,GAAS,IAChChD,cAAc,EAAdA,GAAiBgB,MAGtBiC,GAAqBD,GAAS,IACzB9E,aAAS,EAATA,EAAWgF,QAAQb,IACtB,MAAMG,MAAEA,EAAKC,eAAEA,GAAmBL,GAAeC,GAC3Cc,EAAqBnC,GAAYoC,OAAOC,cAC9C,OACIb,EAAMa,cAAcC,SAASH,IAC5BV,GACGA,EAAeY,cAAcC,SAASH,EAAoB,MAKpEI,GAAUZ,GACXa,YACG,GAAIlF,GAAkB,OAEtB,GAAIsD,GAAe6B,QAGf,OAFAlD,IAAgB,QAChBmD,YAAW,KAAK,IAAAC,EAAC,OAAsB,UAAtB/B,GAAe6B,eAAO,IAAAE,OAAA,EAAAA,EAAEC,OAAO,GAAE,GAItD,MAAMC,EAAQ1C,SAAAA,GAAoB,GAClC,GAAqB,IAAjB0C,EAAM9B,OAAc,OAExB,QAAoB+B,KAAhBN,aAAI,EAAJA,EAAMO,OAAqB,CAC3B,MAAMC,EAASC,KAAKC,IAChB,EACAD,KAAKE,IAAIX,EAAKO,MAAOF,EAAM9B,OAAS,IASxC,OAPmB,QAAnB4B,EAAA9B,GAAY4B,eAAO,IAAAE,GAAAA,EAAES,cAAc,CAC/BL,MAAOC,EACPK,MAAO,WAEX9D,GAAgByD,QAChBN,YAAW,KAAK,IAAAC,EAAC,OAA4B,QAA5BA,EAAAhC,GAAa8B,QAAQO,UAAO,IAAAL,OAAA,EAAAA,EAAEC,OAAO,GAAE,EAG5D,CAEA,MAAMU,GAAgBd,aAAI,EAAJA,EAAMe,gBACtBV,EAAMW,WAAWnC,GAASK,GAAsBL,MAChD,EAEAoC,GACgB,IAAlBH,EACMA,EACAhE,IAAgB,GAAKA,GAAeuD,EAAM9B,OAC1CzB,GACA,EAES,QAAnBoE,EAAA7C,GAAY4B,eAAO,IAAAiB,GAAAA,EAAEN,cAAc,CAC/BL,MAAOU,EACPJ,MAAO,WAEX9D,GAAgBkE,GAChBf,YAAW,KAAK,IAAAC,EAAC,OAA+B,QAA/BA,EAAAhC,GAAa8B,QAAQgB,UAAU,IAAAd,OAAA,EAAAA,EAAEC,OAAO,GAAE,EAAE,GAEjE,CACIlB,GACApE,GACA6C,GACAb,GACAC,KAkDFoE,GAAsB,CAACtC,EAASuC,KAC9B9C,KAAmBY,GAAsBL,KAC7C9B,GAAgBqE,GAChB3F,UAAAA,GAAeoD,EApJF,CAACA,GACPhD,GAAiBA,GAAegD,GAASA,EAmJ3BwC,CAASxC,IAAM,EAKlCyC,GACFC,IAEA,MAAMzC,EAAQyC,EAAMC,OAAO1C,MAC3BrB,GAAeqB,GACfrC,UAAAA,IAAY,EAGVgF,GAAgB,WAClBhE,GAAe,IACO,QAAtB0C,EAAA/B,GAAe6B,eAAO,IAAAE,GAAAA,EAAEC,QACxB3D,UAAAA,IAAY,EAGViF,GAAiB,IAAM9F,cAAO,EAAPA,KAK7B+F,EAAiB,WAtEYJ,YACzB,OAAQA,EAAMK,MACV,IAAK,YAED,GADAL,EAAMM,iBACF/E,GAAea,GAAiBY,OAAS,EAAG,CAC5C,MAAM6C,EAAgBtE,GAAe,EACF,QAAnCqD,EAAAhC,GAAa8B,QAAQmB,UAAc,IAAAjB,GAAAA,EAAEC,QACrCrD,GAAgBqE,EACpB,CACA,MACJ,IAAK,UAED,GADAG,EAAMM,iBACF/E,GAAe,EAAG,CAClB,MAAMsE,EAAgBtE,GAAe,EACF,QAAnCoE,EAAA/C,GAAa8B,QAAQmB,UAAc,IAAAF,GAAAA,EAAEd,QACrCrD,GAAgBqE,EACpB,MAA4B,IAAjBtE,IAAsBsB,GAAe6B,UAC5C7B,GAAe6B,QAAQG,QACvBrD,IAAgB,IAEpB,MACJ,IAAK,QACL,IAAK,QAEGD,IAAgB,IACfgF,SAASC,gBACN5D,GAAa8B,QAAQnD,KACrBgF,SAASC,gBAAkB3D,GAAe6B,WAE9CsB,EAAMM,iBACFlE,GAAiBb,KACjBqE,GACIxD,GAAiBb,IACjBA,SAsCxBkF,EAAoBtF,IAAK,KAAA,CAASqD,cAAY,CAACA,KAE/CkC,GAAU,WACN,IAAKzG,GAED,YADmB,QAAnB2E,EAAA9B,GAAY4B,eAAO,IAAAE,GAAAA,EAAE+B,SAAS,CAAEC,IAAK,KAGzC,MAAMC,EAAQlC,YAAW,KACrB,IAAKxF,EAAW,OAEhB,MAAM6F,EAAQ7F,EAAU2H,QAAQ7G,IAC5B6C,GAAY4B,cAAWM,IACvBlC,GAAY4B,QAAQW,cAAc,CAAEL,UACpCxD,GAAgBwD,GACpB,GACD,GAEH,MAAO,IAAM+B,aAAaF,EAAM,GACjC,CAACjE,GAAczD,EAAWqC,GAAiBvB,KAE9CyG,GAAU,KACFnH,IACCiD,IAAYF,IAEM,YAAnB9C,IACIqD,GAAe6B,UACflD,IAAgB,GAChBqB,GAAe6B,QAAQG,QAE/B,GACD,CACCrC,GACAF,GACA9C,GACAgC,GACAjC,KAGJmH,GAAU,WAWNrE,GAAiC,QAAbuC,EATI,KAAhB3C,GACO9C,EACA8B,GACA+C,KAEAE,YAIkB,IAAAU,EAAAA,EAAI,GAAG,GACzC,CACCZ,GACAE,GACA/E,EACA8B,GACAgB,KAGJyE,GAAU,eACN,GAAIlE,GACA,OAGJ,GAAIjD,KAAqBJ,EAAW,OAEpC,MAAM6F,EAAQ7F,EAAUsG,WAAWnC,GAC/BK,GAAsBL,KAGtBT,GAAe6B,SACflD,IAAgB,GAChBmD,YAAW,KAAK,IAAAC,EAAC,OAAsB,UAAtB/B,GAAe6B,eAAO,IAAAE,OAAA,EAAAA,EAAEC,OAAO,GAAE,MAC3CtD,GAAe,GACH,QAAnBqD,EAAA9B,GAAY4B,eAAO,IAAAE,GAAAA,EAAES,cAAc,CAC/BL,MAAOzD,GACP+D,MAAO,WAEXX,YAAW,KAAK,IAAAC,EAAC,OAAkC,QAAlCA,EAAAhC,GAAa8B,QAAQnD,WAAa,IAAAqD,OAAA,EAAAA,EAAEC,OAAO,GAAE,OAC7C,IAAVG,GACY,QAAnBW,EAAA7C,GAAY4B,eAAO,IAAAiB,GAAAA,EAAEN,cAAc,CAAEL,QAAOM,MAAO,WACnD9D,GAAgBwD,GAChBL,YAAW,KAAK,IAAAC,EAAC,OAA2B,QAA3BA,EAAAhC,GAAa8B,QAAQM,UAAM,IAAAJ,OAAA,EAAAA,EAAEC,OAAO,GAAE,OAEpC,QAAnBmC,EAAAlE,GAAY4B,eAAO,IAAAsC,GAAAA,EAAE3B,cAAc,CAAEL,MAAO,IAC5CxD,GAAgB,GAChBmD,YAAW,KAAK,IAAAC,EAAC,OAAuB,QAAvBA,EAAAhC,GAAa8B,QAAQ,UAAE,IAAAE,OAAA,EAAAA,EAAEC,OAAO,GAAE,KACvD,GACD,CACClB,GACApE,GACAgC,GACApC,EACAqD,GACAhB,KAMJ,MAAMyF,GAAsBC,GACpB9H,GACI2D,KAAmBmE,EAEfC,EAACC,oBAEGC,UAAWC,EACPC,EACAC,KAMTN,EACHC,EAACM,EAAkB,CAAA,eAAA,EAEfJ,UAAWC,EACPC,EACAG,KAIRP,EAACQ,EAAU,CAAA,eAAA,EAEPN,UAAWC,EACPC,EACAK,KAMTV,EACHC,EAACU,EAAQ,CAAA,eAAA,EAELR,UAAWC,EACPQ,EACAC,KAIRZ,EAAA,MAAA,CAAKE,UAAWS,IAIlBE,GAAsB,CAAC1E,EAAS4D,KAClC,MAAMzD,MAAEA,EAAKC,eAAEA,GAAmBL,GAAeC,GAEjD,OACI6D,EAACc,GACGC,YAAavI,GACbwI,MAAO1E,EACP2E,SAAU1I,GACVwH,SAAUA,EACVmB,UAAWnB,GAAYnE,GACvBuF,SAAU5E,EACV6E,eAAgB9I,GAChBG,QAASA,IACX,EAIJ4I,GAAa,CAAClF,EAAS0B,KACzB,IAAK3E,IAA8B,YAAnBb,GAA8B,CAC1C,MAAM0H,EAAWvD,GAAsBL,GACjCmF,EAASzD,IAAUzD,GACnB8G,GAAYnB,GAAYnE,GAC9B,OACIoE,wBACmBD,EAAQ,uBACD9H,GAAW,gBAClBiJ,EAAQ,gBACRrD,EAAQ,iBACT5C,cAAgB,EAAhBA,GAAkBY,OAAM,cAC1B,YAEZ0F,QAAS,IAAM9C,GAAoBtC,EAAM0B,GACzC2D,aAAc,IAvMF,CAAC3D,GAAkBxD,GAAgBwD,GAuM3B4D,CAAoB5D,GACxC7D,IAAM0H,IACFjG,GAAa8B,QAAQM,GAAS6D,CAAO,EAEzCC,KAAK,SACLC,SAAUN,EAAS,GAAI,EACvBpB,UAAWC,EACP0B,EACCX,GAAYY,GACRR,GACGvB,GACAgC,GACHT,GAAUU,GAClBC,SAEA5I,GACGA,GAAe8C,EAAM,CAAE4D,aAEvBmC,EAAAC,EAAA,CAAAF,SAAA,CACKnC,GAAmBC,GACnBc,GAAoB1E,EAAM4D,OA9WhC,EAAC5D,EAAS0B,IAElB,QAAQA,MADQ1E,GAAiBA,GAAegD,GAAQA,IAuV9CiG,CAAWjG,EAAM0B,GA2BlC,GAGEwE,GAAoB,KACtB,IAAK9I,IAAgBO,KAAsC,YAAnBzB,GACpC,OACI2H,EAACsC,GAAc,CACXtI,IAAK0B,GACL6G,SAAU3D,GACVxC,MAAOtB,GACP0H,YAAa5I,GAAiB,cAClB,eAAc,aACf,uBACX6I,QAAS1D,GACTtG,QAASA,IAGrB,EAGEiK,GAAkB,KACpB,GACIvK,IACAF,IACAgD,GAAiBY,OAAS,IACzBf,IACkB,YAAnBzC,GAEA,OACI2H,EAAA,MAAA,CAAKE,UAAWyC,EAAyBV,SACrCjC,EAAC4C,GACGrB,QAASvI,GACT6J,KAAK,SACL3C,UAAWC,EACP2C,EACAC,YAGH7K,IAA0C,IAAzBC,GAAc0D,OAC1B1B,GACAD,MAItB,EAGE8I,GAAkB,KACpB,IACKxJ,KACAsB,KAAgBvB,KACW,IAA5B0B,GAAiBY,QACE,YAAnBxD,GAEA,OACI6J,eACIA,EAAA,MAAA,CAAA,cACgB,kBACZhC,UAAW+C,YAEXjD,EAACkD,iBACe,iBACZhD,UAAWiD,IAEdlJ,MAEJR,IACGuG,EAACoD,iBACe,iBACZlD,UAAWmD,EAA4BpB,SAEtCxI,OAKrB,EAGE6J,GAAgB,KAClB,GAAIpK,IAA8B,YAAnBb,GACX,OACI6J,uBACgB,eACZhC,UAAW+C,EAA2BhB,SAAA,CAEtCjC,EAACuD,EAAuB,CAACrD,UAAWsD,IAAkB,eAIlE,EAGEC,GAAiB,KACnB,GAAIvK,IAA8B,SAAnBb,GACX,OACI6J,uBACgB,YACZhC,UAAW+C,EAA2BhB,SAAA,CAEtCjC,EAACkD,EAAyB,CAAA,cACV,kBACZhD,UAAWiD,IACb,mBAEFnD,EAAC4C,GACGrB,QAASvC,GACT6D,KAAK,SACL3C,UAAWC,EACP2C,EACAY,GACHzB,SAAA,iBAMjB,EAGE0B,GAAwB,WAC1B,MAAMC,EAAqC,SAAzBC,QAAQC,IAAIC,SAE9B,OACI/D,EAACgE,EAAQC,OAAAC,OAAA,CACLlK,IAAK2B,GACLwI,MAAO,CAAEC,OAAQ,QACjBC,KAAMpJ,GACNqJ,2BAAoB7G,EAAAlC,GAAQgC,4BAAWK,EACvC2G,YAAa,CAAC1G,EAAO1B,IAASkF,GAAWlF,EAAM0B,GAC/C2G,WAAY,CACRC,KAAMC,GACNC,KAAMC,IAEVC,QAAS,CACLC,UAAW,CACPC,GAAIrM,GACJiJ,KAAM,UACN,uBAAwB1J,IAE5B+M,cAAe,CACXrD,KAAM,UAQTiC,EACC,CACIqB,iBAAkBhK,GAAiBY,QAEvC,CAAA,GAND+H,EAAY3I,GAAiBY,YAAS+B,EAO7C,EAqCV,OACIsE,EAAA,MAAA+B,OAAAC,OAAA,CAAA,cACgB,qBACZlK,IAAKkL,EAAU3J,GAASd,KACpBC,KAAkB,CAAA,kBACLqB,GACjBmE,UAAWC,EACPgF,EACY,UAAZ1M,IAAuB2M,GAE3BjB,MAAOvJ,GAAcqH,SAAA,CAErBjC,EAACqF,EAAc,CAAC1D,KAAK,SAAQM,SAAEtJ,KA3C/BuJ,EAAA,MAAA,CAAA,cACgB,gBACZP,KAAK,QAAO,aACAhJ,GACZuH,UAAWoF,EAAWrD,SAAA,CAErBI,KACAK,KACAM,KACAM,KACAG,KACAE,QAKW,MACpB,GAAKrK,GAIL,OACI0G,uBAAiB,aAAYiC,SAGrB3I,GAAyBL,GAAkBgC,KAE7C,EAkBLsK,MACC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"calendar-manager.js","sources":["../../../src/shared/internal-calendar/calendar-manager.tsx"],"sourcesContent":["import { ChevronDownIcon } from \"@lifesg/react-icons/chevron-down\";\nimport { ChevronLeftIcon } from \"@lifesg/react-icons/chevron-left\";\nimport { ChevronRightIcon } from \"@lifesg/react-icons/chevron-right\";\nimport clsx from \"clsx\";\nimport type { Dayjs } from \"dayjs\";\nimport dayjs from \"dayjs\";\nimport React, { useEffect, useImperativeHandle, useRef, useState } from \"react\";\n\nimport { Button } from \"../../button\";\nimport { DateHelper } from \"../../util\";\nimport { CalendarHelper } from \"../../util/calendar-helper\";\nimport { inertValue } from \"../accessibility\";\nimport { ClickableIcon } from \"../clickable-icon\";\nimport * as styles from \"./calendar-manager.styles\";\nimport { InternalCalendarMonth } from \"./internal-calendar-month\";\nimport { InternalCalendarYear } from \"./internal-calendar-year\";\nimport type {\n CalendarAction,\n CalendarManagerProps,\n CalendarManagerRef,\n View,\n} from \"./types\";\n\nconst Component = (\n {\n children,\n initialCalendarDate,\n minDate,\n maxDate,\n currentFocus,\n selectedStartDate,\n selectedEndDate,\n selectWithinRange,\n dynamicHeight = false,\n allowDisabledSelection,\n onCalendarDateChange,\n /* action button props */\n withButton,\n doneButtonDisabled,\n onDismiss,\n /* header props */\n showNavigationHeader = true,\n getLeftArrowDate,\n getRightArrowDate,\n isLeftArrowDisabled: _isLeftArrowDisabled,\n isRightArrowDisabled: _isRightArrowDisabled,\n getMonthHeaderLabel,\n getYearHeaderLabel,\n isFocusable = false,\n ...otherProps\n }: CalendarManagerProps,\n ref: React.ForwardedRef<CalendarManagerRef>\n) => {\n // =============================================================================\n // CONST, STATE, REF\n // =============================================================================\n // the current visible date in month/year views and header\n const [calendarDate, setCalendarDate] = useState<Dayjs>(\n DateHelper.toDayjs(initialCalendarDate)\n );\n // the selected date in month/year views and the current visible date in day view\n const [viewCalendarDate, setViewCalendarDate] = useState<Dayjs>(\n DateHelper.toDayjs(initialCalendarDate)\n );\n const [currentView, setCurrentView] = useState<View>(\"default\");\n\n const doneButtonRef = useRef<HTMLButtonElement>(null);\n const cancelButtonRef = useRef<HTMLButtonElement>(null);\n const containerRef = useRef<HTMLDivElement>(null);\n const yearDropdownRef = useRef<HTMLButtonElement>(null);\n\n // =============================================================================\n // EFFECTS\n // =============================================================================\n useImperativeHandle(ref, () => {\n return {\n defaultView() {\n setCurrentView(\"default\");\n },\n resetView() {\n const date = DateHelper.toDayjs(initialCalendarDate);\n setCalendarDate(date);\n setViewCalendarDate(date);\n\n setCurrentView(\"default\");\n },\n setCalendarDate(value?: string) {\n const date = DateHelper.toDayjs(value);\n setCalendarDate(date);\n setViewCalendarDate(date);\n },\n };\n });\n\n useEffect(() => {\n const date = DateHelper.toDayjs(initialCalendarDate);\n setCalendarDate(date);\n setViewCalendarDate(date);\n }, [initialCalendarDate]);\n\n useEffect(() => {\n performOnCalendarDateChange(viewCalendarDate);\n // more accurate than calendarDate since it accounts for selection state\n // in month/year views\n }, [viewCalendarDate]);\n\n // =============================================================================\n // EVENT HANDLERS\n // =============================================================================\n const handleMonthDropdownClick = () => {\n if (currentView !== \"month-options\") {\n setCurrentView(\"month-options\");\n\n // Maintain focus when selecting month dropdown\n containerRef.current?.focus();\n } else {\n setCurrentView(\"default\");\n setCalendarDate(viewCalendarDate);\n }\n };\n\n const handleMonthDropdownKeydown = (\n event: React.KeyboardEvent<HTMLButtonElement>\n ) => {\n if (event.key === \"Enter\" || event.key === \" \") {\n event.preventDefault();\n handleMonthDropdownClick();\n yearDropdownRef.current?.focus(); // Focus on year dropdown after month selection\n }\n\n // Up and Down arrow keys will change the month\n if (event.key === \"ArrowUp\" || event.key === \"ArrowDown\") {\n event.preventDefault();\n const nextDate =\n event.key === \"ArrowUp\"\n ? calendarDate.subtract(1, \"month\")\n : calendarDate.add(1, \"month\");\n\n if (\n !CalendarHelper.isWithinRange(\n nextDate,\n minDate ? dayjs(minDate) : undefined,\n maxDate ? dayjs(maxDate) : undefined,\n \"month\"\n )\n )\n return;\n setCalendarDate(nextDate);\n\n if (currentView === \"default\") {\n setViewCalendarDate(nextDate);\n }\n }\n };\n\n const handleYearDropdownClick = () => {\n /**\n * If the view is in the month options view,\n * then clicking will send the view back to\n * default\n */\n if (currentView !== \"default\") {\n setCurrentView(\"default\");\n setCalendarDate(viewCalendarDate);\n } else {\n setCurrentView(\"year-options\");\n }\n };\n\n const handleYearDropdownKeydown = (\n event: React.KeyboardEvent<HTMLButtonElement>\n ) => {\n if (event.key === \"Enter\" || event.key === \" \") {\n event.preventDefault();\n handleYearDropdownClick();\n }\n\n // Up and Down arrow keys will change the year\n if (event.key === \"ArrowUp\" || event.key === \"ArrowDown\") {\n event.preventDefault();\n const isYearView = currentView === \"year-options\";\n let nextDate: Dayjs;\n\n if (isYearView) {\n // In year options view, change decade\n nextDate =\n event.key === \"ArrowUp\"\n ? calendarDate.subtract(10, \"year\")\n : calendarDate.add(10, \"year\");\n } else {\n // In default view, change year\n nextDate =\n event.key === \"ArrowUp\"\n ? calendarDate.subtract(1, \"year\")\n : calendarDate.add(1, \"year\");\n }\n\n if (\n !CalendarHelper.isWithinRange(\n nextDate,\n minDate ? dayjs(minDate) : undefined,\n maxDate ? dayjs(maxDate) : undefined,\n \"year\"\n )\n )\n return;\n\n setCalendarDate(nextDate);\n\n if (currentView === \"default\") {\n setViewCalendarDate(nextDate);\n }\n }\n };\n\n const handleLeftArrowClick = () => {\n // Maintain focus as button could become disabled\n containerRef.current?.focus();\n\n const nextDate = getLeftArrowDate\n ? getLeftArrowDate(calendarDate)\n : calendarDate.subtract(1, \"month\");\n\n switch (currentView) {\n case \"default\":\n setViewCalendarDate(nextDate);\n setCalendarDate(nextDate);\n break;\n case \"month-options\":\n setCalendarDate((date) => date.subtract(1, \"year\"));\n break;\n case \"year-options\":\n setCalendarDate((date) => date.subtract(10, \"year\"));\n break;\n }\n };\n\n const handleRightArrowClick = () => {\n // Maintain focus as button could become disabled\n containerRef.current?.focus();\n\n const nextDate = getRightArrowDate\n ? getRightArrowDate(calendarDate)\n : calendarDate.add(1, \"month\");\n\n switch (currentView) {\n case \"default\":\n setViewCalendarDate(nextDate);\n setCalendarDate(nextDate);\n break;\n case \"month-options\":\n setCalendarDate((date) => date.add(1, \"year\"));\n break;\n case \"year-options\":\n setCalendarDate((date) => date.add(10, \"year\"));\n break;\n }\n };\n\n const handleMonthYearSelect = (value: Dayjs) => {\n setCalendarDate(value);\n setViewCalendarDate(value);\n\n if (!withButton) {\n setCurrentView(\"default\");\n }\n };\n\n const handleCancelButton = () => {\n const initialValue = DateHelper.toDayjs(initialCalendarDate);\n setCalendarDate(initialValue);\n setViewCalendarDate(initialValue);\n\n if (currentView === \"default\") {\n performOnDismissHandler(\"reset\");\n } else {\n setCurrentView(\"default\");\n }\n };\n\n const handleDoneButton = (isDisabled: boolean | undefined) => {\n if (isDisabled) return;\n\n setCalendarDate(viewCalendarDate);\n\n if (currentView === \"default\") {\n performOnDismissHandler(\"confirmed\");\n } else {\n setCurrentView(\"default\");\n }\n };\n\n // =============================================================================\n // HELPER FUNCTIONS\n // =============================================================================\n const performOnCalendarDateChange = (date: Dayjs) => {\n if (onCalendarDateChange) {\n onCalendarDateChange(date);\n }\n };\n\n const performOnDismissHandler = (action: CalendarAction) => {\n if (onDismiss) {\n onDismiss(action);\n }\n };\n\n const isLeftArrowDisabled = () => {\n if (!minDate || allowDisabledSelection) {\n return false;\n }\n\n const min = dayjs(minDate);\n if (currentView === \"month-options\") {\n return !CalendarHelper.isPreviousYearWithinRange(calendarDate, min);\n } else if (currentView === \"year-options\") {\n return !CalendarHelper.isPreviousDecadeWithinRange(\n calendarDate,\n min\n );\n } else {\n if (_isLeftArrowDisabled) {\n return _isLeftArrowDisabled(calendarDate);\n }\n return !CalendarHelper.isPreviousMonthWithinRange(\n calendarDate,\n min\n );\n }\n };\n\n const isRightArrowDisabled = () => {\n if (!maxDate || allowDisabledSelection) {\n return false;\n }\n\n const max = dayjs(maxDate);\n if (currentView === \"month-options\") {\n return !CalendarHelper.isNextYearWithinRange(calendarDate, max);\n } else if (currentView === \"year-options\") {\n return !CalendarHelper.isNextDecadeWithinRange(calendarDate, max);\n } else {\n if (_isRightArrowDisabled) {\n return _isRightArrowDisabled(calendarDate);\n }\n return !CalendarHelper.isNextMonthWithinRange(calendarDate, max);\n }\n };\n\n // =============================================================================\n // RENDER FUNCTIONS\n // =============================================================================\n\n const getYearHeaderText = (): string => {\n if (currentView === \"year-options\") {\n const { beginDecade, endDecade } =\n CalendarHelper.getStartEndDecade(calendarDate);\n\n return `${beginDecade} to ${endDecade}`;\n } else {\n return getYearHeaderLabel\n ? getYearHeaderLabel(calendarDate)\n : calendarDate.format(\"YYYY\");\n }\n };\n\n const renderDropdownButtons = () => {\n const monthLabel = getMonthHeaderLabel\n ? getMonthHeaderLabel(calendarDate)\n : calendarDate.format(\"MMM\");\n\n const fullMonthLabel = dayjs(monthLabel, \"MMM\").format(\"MMMM\");\n\n const yearLabel = getYearHeaderText();\n const viewToYearLabel: Record<View, string> = {\n \"month-options\": `${yearLabel}, Close month selection`,\n \"year-options\": `${yearLabel}, Close year selection`,\n default: `${yearLabel}, Select year`,\n };\n\n return (\n <>\n <button\n className={clsx(\n styles.dropdownButton,\n currentView !== \"default\" && styles.hidden\n )}\n aria-label={`${fullMonthLabel}, Select month`}\n type=\"button\"\n id=\"month-dropdown\"\n onClick={handleMonthDropdownClick}\n onKeyDown={handleMonthDropdownKeydown}\n tabIndex={isFocusable ? 0 : -1}\n >\n <span className={styles.dropdownText}>{monthLabel}</span>\n <ChevronDownIcon\n className={clsx(\n styles.icon,\n styles.iconChevronDown,\n currentView === \"month-options\" &&\n styles.iconChevronDownExpanded\n )}\n />\n </button>\n <button\n ref={yearDropdownRef}\n className={styles.dropdownButton}\n aria-label={viewToYearLabel[currentView]}\n type=\"button\"\n id=\"year-dropdown\"\n onClick={handleYearDropdownClick}\n onKeyDown={handleYearDropdownKeydown}\n tabIndex={isFocusable ? 0 : -1}\n >\n <span className={styles.dropdownText}>{yearLabel}</span>\n <ChevronDownIcon\n className={clsx(\n styles.icon,\n styles.iconChevronDown,\n currentView !== \"default\" &&\n styles.iconChevronDownExpanded\n )}\n />\n </button>\n </>\n );\n };\n\n const renderOptionsOverlay = () => {\n switch (currentView) {\n case \"month-options\":\n return (\n <InternalCalendarMonth\n calendarDate={calendarDate}\n currentFocus={currentFocus}\n minDate={minDate}\n maxDate={maxDate}\n selectedStartDate={selectedStartDate}\n selectedEndDate={selectedEndDate}\n viewCalendarDate={viewCalendarDate}\n isNewSelection={!!selectWithinRange}\n onMonthSelect={handleMonthYearSelect}\n allowDisabledSelection={allowDisabledSelection}\n />\n );\n case \"year-options\":\n return (\n <InternalCalendarYear\n setCalendarDate={setCalendarDate}\n calendarDate={calendarDate}\n currentFocus={currentFocus}\n minDate={minDate}\n maxDate={maxDate}\n selectedStartDate={selectedStartDate}\n selectedEndDate={selectedEndDate}\n viewCalendarDate={viewCalendarDate}\n isNewSelection={!!selectWithinRange}\n onYearSelect={handleMonthYearSelect}\n allowDisabledSelection={allowDisabledSelection}\n />\n );\n default:\n return null;\n }\n };\n\n const renderHeader = () => {\n const viewToSelection: Record<View, string> = {\n \"month-options\": \"year\",\n \"year-options\": \"decade\",\n default: \"month\",\n };\n\n const selection = viewToSelection[currentView];\n\n return (\n <div\n className={styles.header}\n data-id=\"calendar-header\"\n data-testid=\"calendar-header\"\n >\n <div className={styles.headerInputDropdown}>\n {renderDropdownButtons()}\n </div>\n <div className={styles.headerArrows}>\n <ClickableIcon\n className={styles.headerArrowButton}\n aria-label={`Previous ${selection}`}\n data-testid=\"left-arrow-btn\"\n disabled={isLeftArrowDisabled()}\n focusHighlight={false}\n focusOutline=\"browser\"\n onClick={handleLeftArrowClick}\n tabIndex={isFocusable ? 0 : -1}\n >\n <ChevronLeftIcon className={styles.icon} />\n </ClickableIcon>\n <ClickableIcon\n className={styles.headerArrowButton}\n aria-label={`Next ${selection}`}\n data-testid=\"right-arrow-btn\"\n disabled={isRightArrowDisabled()}\n focusHighlight={false}\n focusOutline=\"browser\"\n onClick={handleRightArrowClick}\n tabIndex={isFocusable ? 0 : -1}\n >\n <ChevronRightIcon className={styles.icon} />\n </ClickableIcon>\n </div>\n </div>\n );\n };\n\n const renderActionButtons = () => {\n if (!withButton) return;\n\n const isDayView = currentView === \"default\";\n\n const disabled = !isDayView ? false : doneButtonDisabled;\n\n return (\n <div className={styles.actionButtonSection}>\n <Button\n className={styles.actionButton}\n ref={cancelButtonRef}\n data-testid=\"cancel-button\"\n styleType=\"light\"\n type=\"button\"\n onClick={handleCancelButton}\n sizeType=\"small\"\n >\n Cancel\n </Button>\n <Button\n className={styles.actionButton}\n data-testid=\"done-button\"\n ref={doneButtonRef}\n type=\"button\"\n onClick={() => handleDoneButton(disabled)}\n disabled={disabled}\n sizeType=\"small\"\n >\n Done\n </Button>\n </div>\n );\n };\n\n const renderViews = () => {\n const defaultView =\n typeof children === \"function\"\n ? children({ calendarDate: viewCalendarDate, currentView })\n : children;\n\n if (dynamicHeight) {\n return (\n <>\n {currentView === \"default\" && defaultView}\n {renderOptionsOverlay()}\n </>\n );\n } else {\n const isDefaultView = currentView === \"default\";\n return (\n // Prevent interaction with the default view when options are open\n <>\n <div\n className={styles.defaultView}\n inert={inertValue(!isDefaultView)}\n >\n {defaultView}\n </div>\n <div\n className={clsx(\n styles.optionsOverlay,\n isDefaultView && styles.hidden\n )}\n >\n {renderOptionsOverlay()}\n </div>\n </>\n );\n }\n };\n\n return (\n <div\n className={styles.container}\n ref={containerRef}\n data-id=\"calendar-container\"\n data-testid=\"calendar-container\"\n aria-label={viewCalendarDate.format(\"MMMM, YYYY\")}\n role=\"group\"\n {...otherProps}\n >\n {showNavigationHeader && renderHeader()}\n <div className={styles.toggleZone} data-testid=\"toggle-zone\">\n {renderViews()}\n </div>\n {renderActionButtons()}\n </div>\n );\n};\n\nexport const CalendarManager = React.forwardRef(Component);\n"],"names":["CalendarManager","React","forwardRef","_a","ref","children","initialCalendarDate","minDate","maxDate","currentFocus","selectedStartDate","selectedEndDate","selectWithinRange","dynamicHeight","allowDisabledSelection","onCalendarDateChange","withButton","doneButtonDisabled","onDismiss","showNavigationHeader","getLeftArrowDate","getRightArrowDate","isLeftArrowDisabled","_isLeftArrowDisabled","isRightArrowDisabled","_isRightArrowDisabled","getMonthHeaderLabel","getYearHeaderLabel","isFocusable","otherProps","__rest","calendarDate","setCalendarDate","useState","DateHelper","toDayjs","viewCalendarDate","setViewCalendarDate","currentView","setCurrentView","doneButtonRef","useRef","cancelButtonRef","containerRef","yearDropdownRef","useImperativeHandle","defaultView","resetView","date","value","useEffect","performOnCalendarDateChange","handleMonthDropdownClick","current","focus","handleMonthDropdownKeydown","event","key","preventDefault","nextDate","subtract","add","CalendarHelper","isWithinRange","dayjs","undefined","handleYearDropdownClick","handleYearDropdownKeydown","handleLeftArrowClick","handleRightArrowClick","handleMonthYearSelect","handleCancelButton","initialValue","performOnDismissHandler","action","min","isPreviousYearWithinRange","isPreviousDecadeWithinRange","isPreviousMonthWithinRange","max","isNextYearWithinRange","isNextDecadeWithinRange","isNextMonthWithinRange","renderDropdownButtons","monthLabel","format","fullMonthLabel","yearLabel","beginDecade","endDecade","getStartEndDecade","getYearHeaderText","viewToYearLabel","default","_jsxs","_Fragment","className","clsx","styles.dropdownButton","styles.hidden","type","id","onClick","onKeyDown","tabIndex","_jsx","styles.dropdownText","ChevronDownIcon","styles.icon","styles.iconChevronDown","styles.iconChevronDownExpanded","renderOptionsOverlay","InternalCalendarMonth","isNewSelection","onMonthSelect","InternalCalendarYear","onYearSelect","styles.container","role","selection","styles.header","styles.headerInputDropdown","styles.headerArrows","ClickableIcon","styles.headerArrowButton","disabled","focusHighlight","focusOutline","ChevronLeftIcon","ChevronRightIcon","renderHeader","styles.toggleZone","isDefaultView","styles.defaultView","inert","inertValue","styles.optionsOverlay","renderViews","styles.actionButtonSection","Button","styles.actionButton","styleType","sizeType","renderActionButtons"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"calendar-manager.js","sources":["../../../src/shared/internal-calendar/calendar-manager.tsx"],"sourcesContent":["import { ChevronDownIcon } from \"@lifesg/react-icons/chevron-down\";\nimport { ChevronLeftIcon } from \"@lifesg/react-icons/chevron-left\";\nimport { ChevronRightIcon } from \"@lifesg/react-icons/chevron-right\";\nimport clsx from \"clsx\";\nimport type { Dayjs } from \"dayjs\";\nimport dayjs from \"dayjs\";\nimport React, { useEffect, useImperativeHandle, useRef, useState } from \"react\";\n\nimport { Button } from \"../../button\";\nimport { DateHelper } from \"../../util\";\nimport { CalendarHelper } from \"../../util/calendar-helper\";\nimport { inertValue } from \"../accessibility\";\nimport { ClickableIcon } from \"../clickable-icon\";\nimport * as styles from \"./calendar-manager.styles\";\nimport { InternalCalendarMonth } from \"./internal-calendar-month\";\nimport { InternalCalendarYear } from \"./internal-calendar-year\";\nimport type {\n CalendarAction,\n CalendarManagerProps,\n CalendarManagerRef,\n View,\n} from \"./types\";\n\nconst Component = (\n {\n children,\n initialCalendarDate,\n minDate,\n maxDate,\n currentFocus,\n selectedStartDate,\n selectedEndDate,\n selectWithinRange,\n dynamicHeight = false,\n allowDisabledSelection,\n onCalendarDateChange,\n /* action button props */\n withButton,\n doneButtonDisabled,\n onDismiss,\n /* header props */\n showNavigationHeader = true,\n getLeftArrowDate,\n getRightArrowDate,\n isLeftArrowDisabled: _isLeftArrowDisabled,\n isRightArrowDisabled: _isRightArrowDisabled,\n getMonthHeaderLabel,\n getYearHeaderLabel,\n isFocusable = false,\n ...otherProps\n }: CalendarManagerProps,\n ref: React.ForwardedRef<CalendarManagerRef>\n) => {\n // =============================================================================\n // CONST, STATE, REF\n // =============================================================================\n // the current visible date in month/year views and header\n const [calendarDate, setCalendarDate] = useState<Dayjs>(\n DateHelper.toDayjs(initialCalendarDate)\n );\n // the selected date in month/year views and the current visible date in day view\n const [viewCalendarDate, setViewCalendarDate] = useState<Dayjs>(\n DateHelper.toDayjs(initialCalendarDate)\n );\n const [currentView, setCurrentView] = useState<View>(\"default\");\n\n const doneButtonRef = useRef<HTMLButtonElement>(null);\n const cancelButtonRef = useRef<HTMLButtonElement>(null);\n const containerRef = useRef<HTMLDivElement>(null);\n const yearDropdownRef = useRef<HTMLButtonElement>(null);\n\n // =============================================================================\n // EFFECTS\n // =============================================================================\n useImperativeHandle(ref, () => {\n return {\n defaultView() {\n setCurrentView(\"default\");\n },\n resetView() {\n const date = DateHelper.toDayjs(initialCalendarDate);\n setCalendarDate(date);\n setViewCalendarDate(date);\n\n setCurrentView(\"default\");\n },\n setCalendarDate(value?: string) {\n const date = DateHelper.toDayjs(value);\n setCalendarDate(date);\n setViewCalendarDate(date);\n },\n };\n });\n\n useEffect(() => {\n const date = DateHelper.toDayjs(initialCalendarDate);\n setCalendarDate(date);\n setViewCalendarDate(date);\n }, [initialCalendarDate]);\n\n useEffect(() => {\n performOnCalendarDateChange(viewCalendarDate);\n // more accurate than calendarDate since it accounts for selection state\n // in month/year views\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [viewCalendarDate]);\n\n // =============================================================================\n // EVENT HANDLERS\n // =============================================================================\n const handleMonthDropdownClick = () => {\n if (currentView !== \"month-options\") {\n setCurrentView(\"month-options\");\n\n // Maintain focus when selecting month dropdown\n containerRef.current?.focus();\n } else {\n setCurrentView(\"default\");\n setCalendarDate(viewCalendarDate);\n }\n };\n\n const handleMonthDropdownKeydown = (\n event: React.KeyboardEvent<HTMLButtonElement>\n ) => {\n if (event.key === \"Enter\" || event.key === \" \") {\n event.preventDefault();\n handleMonthDropdownClick();\n yearDropdownRef.current?.focus(); // Focus on year dropdown after month selection\n }\n\n // Up and Down arrow keys will change the month\n if (event.key === \"ArrowUp\" || event.key === \"ArrowDown\") {\n event.preventDefault();\n const nextDate =\n event.key === \"ArrowUp\"\n ? calendarDate.subtract(1, \"month\")\n : calendarDate.add(1, \"month\");\n\n if (\n !CalendarHelper.isWithinRange(\n nextDate,\n minDate ? dayjs(minDate) : undefined,\n maxDate ? dayjs(maxDate) : undefined,\n \"month\"\n )\n )\n return;\n setCalendarDate(nextDate);\n\n if (currentView === \"default\") {\n setViewCalendarDate(nextDate);\n }\n }\n };\n\n const handleYearDropdownClick = () => {\n /**\n * If the view is in the month options view,\n * then clicking will send the view back to\n * default\n */\n if (currentView !== \"default\") {\n setCurrentView(\"default\");\n setCalendarDate(viewCalendarDate);\n } else {\n setCurrentView(\"year-options\");\n }\n };\n\n const handleYearDropdownKeydown = (\n event: React.KeyboardEvent<HTMLButtonElement>\n ) => {\n if (event.key === \"Enter\" || event.key === \" \") {\n event.preventDefault();\n handleYearDropdownClick();\n }\n\n // Up and Down arrow keys will change the year\n if (event.key === \"ArrowUp\" || event.key === \"ArrowDown\") {\n event.preventDefault();\n const isYearView = currentView === \"year-options\";\n let nextDate: Dayjs;\n\n if (isYearView) {\n // In year options view, change decade\n nextDate =\n event.key === \"ArrowUp\"\n ? calendarDate.subtract(10, \"year\")\n : calendarDate.add(10, \"year\");\n } else {\n // In default view, change year\n nextDate =\n event.key === \"ArrowUp\"\n ? calendarDate.subtract(1, \"year\")\n : calendarDate.add(1, \"year\");\n }\n\n if (\n !CalendarHelper.isWithinRange(\n nextDate,\n minDate ? dayjs(minDate) : undefined,\n maxDate ? dayjs(maxDate) : undefined,\n \"year\"\n )\n )\n return;\n\n setCalendarDate(nextDate);\n\n if (currentView === \"default\") {\n setViewCalendarDate(nextDate);\n }\n }\n };\n\n const handleLeftArrowClick = () => {\n // Maintain focus as button could become disabled\n containerRef.current?.focus();\n\n const nextDate = getLeftArrowDate\n ? getLeftArrowDate(calendarDate)\n : calendarDate.subtract(1, \"month\");\n\n switch (currentView) {\n case \"default\":\n setViewCalendarDate(nextDate);\n setCalendarDate(nextDate);\n break;\n case \"month-options\":\n setCalendarDate((date) => date.subtract(1, \"year\"));\n break;\n case \"year-options\":\n setCalendarDate((date) => date.subtract(10, \"year\"));\n break;\n }\n };\n\n const handleRightArrowClick = () => {\n // Maintain focus as button could become disabled\n containerRef.current?.focus();\n\n const nextDate = getRightArrowDate\n ? getRightArrowDate(calendarDate)\n : calendarDate.add(1, \"month\");\n\n switch (currentView) {\n case \"default\":\n setViewCalendarDate(nextDate);\n setCalendarDate(nextDate);\n break;\n case \"month-options\":\n setCalendarDate((date) => date.add(1, \"year\"));\n break;\n case \"year-options\":\n setCalendarDate((date) => date.add(10, \"year\"));\n break;\n }\n };\n\n const handleMonthYearSelect = (value: Dayjs) => {\n setCalendarDate(value);\n setViewCalendarDate(value);\n\n if (!withButton) {\n setCurrentView(\"default\");\n }\n };\n\n const handleCancelButton = () => {\n const initialValue = DateHelper.toDayjs(initialCalendarDate);\n setCalendarDate(initialValue);\n setViewCalendarDate(initialValue);\n\n if (currentView === \"default\") {\n performOnDismissHandler(\"reset\");\n } else {\n setCurrentView(\"default\");\n }\n };\n\n const handleDoneButton = (isDisabled: boolean | undefined) => {\n if (isDisabled) return;\n\n setCalendarDate(viewCalendarDate);\n\n if (currentView === \"default\") {\n performOnDismissHandler(\"confirmed\");\n } else {\n setCurrentView(\"default\");\n }\n };\n\n // =============================================================================\n // HELPER FUNCTIONS\n // =============================================================================\n const performOnCalendarDateChange = (date: Dayjs) => {\n if (onCalendarDateChange) {\n onCalendarDateChange(date);\n }\n };\n\n const performOnDismissHandler = (action: CalendarAction) => {\n if (onDismiss) {\n onDismiss(action);\n }\n };\n\n const isLeftArrowDisabled = () => {\n if (!minDate || allowDisabledSelection) {\n return false;\n }\n\n const min = dayjs(minDate);\n if (currentView === \"month-options\") {\n return !CalendarHelper.isPreviousYearWithinRange(calendarDate, min);\n } else if (currentView === \"year-options\") {\n return !CalendarHelper.isPreviousDecadeWithinRange(\n calendarDate,\n min\n );\n } else {\n if (_isLeftArrowDisabled) {\n return _isLeftArrowDisabled(calendarDate);\n }\n return !CalendarHelper.isPreviousMonthWithinRange(\n calendarDate,\n min\n );\n }\n };\n\n const isRightArrowDisabled = () => {\n if (!maxDate || allowDisabledSelection) {\n return false;\n }\n\n const max = dayjs(maxDate);\n if (currentView === \"month-options\") {\n return !CalendarHelper.isNextYearWithinRange(calendarDate, max);\n } else if (currentView === \"year-options\") {\n return !CalendarHelper.isNextDecadeWithinRange(calendarDate, max);\n } else {\n if (_isRightArrowDisabled) {\n return _isRightArrowDisabled(calendarDate);\n }\n return !CalendarHelper.isNextMonthWithinRange(calendarDate, max);\n }\n };\n\n // =============================================================================\n // RENDER FUNCTIONS\n // =============================================================================\n\n const getYearHeaderText = (): string => {\n if (currentView === \"year-options\") {\n const { beginDecade, endDecade } =\n CalendarHelper.getStartEndDecade(calendarDate);\n\n return `${beginDecade} to ${endDecade}`;\n } else {\n return getYearHeaderLabel\n ? getYearHeaderLabel(calendarDate)\n : calendarDate.format(\"YYYY\");\n }\n };\n\n const renderDropdownButtons = () => {\n const monthLabel = getMonthHeaderLabel\n ? getMonthHeaderLabel(calendarDate)\n : calendarDate.format(\"MMM\");\n\n const fullMonthLabel = dayjs(monthLabel, \"MMM\").format(\"MMMM\");\n\n const yearLabel = getYearHeaderText();\n const viewToYearLabel: Record<View, string> = {\n \"month-options\": `${yearLabel}, Close month selection`,\n \"year-options\": `${yearLabel}, Close year selection`,\n default: `${yearLabel}, Select year`,\n };\n\n return (\n <>\n <button\n className={clsx(\n styles.dropdownButton,\n currentView !== \"default\" && styles.hidden\n )}\n aria-label={`${fullMonthLabel}, Select month`}\n type=\"button\"\n id=\"month-dropdown\"\n onClick={handleMonthDropdownClick}\n onKeyDown={handleMonthDropdownKeydown}\n tabIndex={isFocusable ? 0 : -1}\n >\n <span className={styles.dropdownText}>{monthLabel}</span>\n <ChevronDownIcon\n className={clsx(\n styles.icon,\n styles.iconChevronDown,\n currentView === \"month-options\" &&\n styles.iconChevronDownExpanded\n )}\n />\n </button>\n <button\n ref={yearDropdownRef}\n className={styles.dropdownButton}\n aria-label={viewToYearLabel[currentView]}\n type=\"button\"\n id=\"year-dropdown\"\n onClick={handleYearDropdownClick}\n onKeyDown={handleYearDropdownKeydown}\n tabIndex={isFocusable ? 0 : -1}\n >\n <span className={styles.dropdownText}>{yearLabel}</span>\n <ChevronDownIcon\n className={clsx(\n styles.icon,\n styles.iconChevronDown,\n currentView !== \"default\" &&\n styles.iconChevronDownExpanded\n )}\n />\n </button>\n </>\n );\n };\n\n const renderOptionsOverlay = () => {\n switch (currentView) {\n case \"month-options\":\n return (\n <InternalCalendarMonth\n calendarDate={calendarDate}\n currentFocus={currentFocus}\n minDate={minDate}\n maxDate={maxDate}\n selectedStartDate={selectedStartDate}\n selectedEndDate={selectedEndDate}\n viewCalendarDate={viewCalendarDate}\n isNewSelection={!!selectWithinRange}\n onMonthSelect={handleMonthYearSelect}\n allowDisabledSelection={allowDisabledSelection}\n />\n );\n case \"year-options\":\n return (\n <InternalCalendarYear\n setCalendarDate={setCalendarDate}\n calendarDate={calendarDate}\n currentFocus={currentFocus}\n minDate={minDate}\n maxDate={maxDate}\n selectedStartDate={selectedStartDate}\n selectedEndDate={selectedEndDate}\n viewCalendarDate={viewCalendarDate}\n isNewSelection={!!selectWithinRange}\n onYearSelect={handleMonthYearSelect}\n allowDisabledSelection={allowDisabledSelection}\n />\n );\n default:\n return null;\n }\n };\n\n const renderHeader = () => {\n const viewToSelection: Record<View, string> = {\n \"month-options\": \"year\",\n \"year-options\": \"decade\",\n default: \"month\",\n };\n\n const selection = viewToSelection[currentView];\n\n return (\n <div\n className={styles.header}\n data-id=\"calendar-header\"\n data-testid=\"calendar-header\"\n >\n <div className={styles.headerInputDropdown}>\n {renderDropdownButtons()}\n </div>\n <div className={styles.headerArrows}>\n <ClickableIcon\n className={styles.headerArrowButton}\n aria-label={`Previous ${selection}`}\n data-testid=\"left-arrow-btn\"\n disabled={isLeftArrowDisabled()}\n focusHighlight={false}\n focusOutline=\"browser\"\n onClick={handleLeftArrowClick}\n tabIndex={isFocusable ? 0 : -1}\n >\n <ChevronLeftIcon className={styles.icon} />\n </ClickableIcon>\n <ClickableIcon\n className={styles.headerArrowButton}\n aria-label={`Next ${selection}`}\n data-testid=\"right-arrow-btn\"\n disabled={isRightArrowDisabled()}\n focusHighlight={false}\n focusOutline=\"browser\"\n onClick={handleRightArrowClick}\n tabIndex={isFocusable ? 0 : -1}\n >\n <ChevronRightIcon className={styles.icon} />\n </ClickableIcon>\n </div>\n </div>\n );\n };\n\n const renderActionButtons = () => {\n if (!withButton) return;\n\n const isDayView = currentView === \"default\";\n\n const disabled = !isDayView ? false : doneButtonDisabled;\n\n return (\n <div className={styles.actionButtonSection}>\n <Button\n className={styles.actionButton}\n ref={cancelButtonRef}\n data-testid=\"cancel-button\"\n styleType=\"light\"\n type=\"button\"\n onClick={handleCancelButton}\n sizeType=\"small\"\n >\n Cancel\n </Button>\n <Button\n className={styles.actionButton}\n data-testid=\"done-button\"\n ref={doneButtonRef}\n type=\"button\"\n onClick={() => handleDoneButton(disabled)}\n disabled={disabled}\n sizeType=\"small\"\n >\n Done\n </Button>\n </div>\n );\n };\n\n const renderViews = () => {\n const defaultView =\n typeof children === \"function\"\n ? children({ calendarDate: viewCalendarDate, currentView })\n : children;\n\n if (dynamicHeight) {\n return (\n <>\n {currentView === \"default\" && defaultView}\n {renderOptionsOverlay()}\n </>\n );\n } else {\n const isDefaultView = currentView === \"default\";\n return (\n // Prevent interaction with the default view when options are open\n <>\n <div\n className={styles.defaultView}\n inert={inertValue(!isDefaultView)}\n >\n {defaultView}\n </div>\n <div\n className={clsx(\n styles.optionsOverlay,\n isDefaultView && styles.hidden\n )}\n >\n {renderOptionsOverlay()}\n </div>\n </>\n );\n }\n };\n\n return (\n <div\n className={styles.container}\n ref={containerRef}\n data-id=\"calendar-container\"\n data-testid=\"calendar-container\"\n aria-label={viewCalendarDate.format(\"MMMM, YYYY\")}\n role=\"group\"\n {...otherProps}\n >\n {showNavigationHeader && renderHeader()}\n <div className={styles.toggleZone} data-testid=\"toggle-zone\">\n {renderViews()}\n </div>\n {renderActionButtons()}\n </div>\n );\n};\n\nexport const CalendarManager = React.forwardRef(Component);\n"],"names":["CalendarManager","React","forwardRef","_a","ref","children","initialCalendarDate","minDate","maxDate","currentFocus","selectedStartDate","selectedEndDate","selectWithinRange","dynamicHeight","allowDisabledSelection","onCalendarDateChange","withButton","doneButtonDisabled","onDismiss","showNavigationHeader","getLeftArrowDate","getRightArrowDate","isLeftArrowDisabled","_isLeftArrowDisabled","isRightArrowDisabled","_isRightArrowDisabled","getMonthHeaderLabel","getYearHeaderLabel","isFocusable","otherProps","__rest","calendarDate","setCalendarDate","useState","DateHelper","toDayjs","viewCalendarDate","setViewCalendarDate","currentView","setCurrentView","doneButtonRef","useRef","cancelButtonRef","containerRef","yearDropdownRef","useImperativeHandle","defaultView","resetView","date","value","useEffect","performOnCalendarDateChange","handleMonthDropdownClick","current","focus","handleMonthDropdownKeydown","event","key","preventDefault","nextDate","subtract","add","CalendarHelper","isWithinRange","dayjs","undefined","handleYearDropdownClick","handleYearDropdownKeydown","handleLeftArrowClick","handleRightArrowClick","handleMonthYearSelect","handleCancelButton","initialValue","performOnDismissHandler","action","min","isPreviousYearWithinRange","isPreviousDecadeWithinRange","isPreviousMonthWithinRange","max","isNextYearWithinRange","isNextDecadeWithinRange","isNextMonthWithinRange","renderDropdownButtons","monthLabel","format","fullMonthLabel","yearLabel","beginDecade","endDecade","getStartEndDecade","getYearHeaderText","viewToYearLabel","default","_jsxs","_Fragment","className","clsx","styles.dropdownButton","styles.hidden","type","id","onClick","onKeyDown","tabIndex","_jsx","styles.dropdownText","ChevronDownIcon","styles.icon","styles.iconChevronDown","styles.iconChevronDownExpanded","renderOptionsOverlay","InternalCalendarMonth","isNewSelection","onMonthSelect","InternalCalendarYear","onYearSelect","styles.container","role","selection","styles.header","styles.headerInputDropdown","styles.headerArrows","ClickableIcon","styles.headerArrowButton","disabled","focusHighlight","focusOutline","ChevronLeftIcon","ChevronRightIcon","renderHeader","styles.toggleZone","isDefaultView","styles.defaultView","inert","inertValue","styles.optionsOverlay","renderViews","styles.actionButtonSection","Button","styles.actionButton","styleType","sizeType","renderActionButtons"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"standalone-date-input.js","sources":["../../../src/shared/standalone-date-input/standalone-date-input.tsx"],"sourcesContent":["import clsx from \"clsx\";\nimport dayjs from \"dayjs\";\nimport customParseFormat from \"dayjs/plugin/customParseFormat\";\nimport React, { useEffect, useImperativeHandle, useRef, useState } from \"react\";\n\nimport { DateInputHelper, StringHelper, useStateRef } from \"../../util\";\nimport * as styles from \"./standalone-date-input.styles\";\n\ndayjs.extend(customParseFormat);\n\ntype StartInputNames = [\"start-day\", \"start-month\", \"start-year\"];\ntype EndInputNames = [\"end-day\", \"end-month\", \"end-year\"];\n\nexport type FieldType =\n | StartInputNames[number]\n | EndInputNames[number]\n | \"none\";\n\ninterface Props {\n disabled?: boolean | undefined;\n readOnly?: boolean | undefined;\n hideInputKeyboard?: boolean | undefined;\n names: StartInputNames | EndInputNames;\n value: string | undefined;\n hoverValue?: string | undefined;\n focused: boolean;\n placeholder?: string | undefined;\n label?: string | undefined;\n inputLabels?: string[] | undefined;\n onChange: (value: string) => void;\n onFocus?: ((event: React.FocusEvent) => void) | undefined;\n onBlur?: ((valid: boolean) => void) | undefined;\n}\n\nexport interface StandaloneDateInputRef {\n ref: React.RefObject<HTMLDivElement>;\n resetPlaceholder: () => void;\n resetInput: () => void;\n focusYearRef: () => void;\n}\n\nexport const Component = (\n {\n disabled,\n readOnly,\n names,\n value,\n focused,\n hoverValue,\n placeholder,\n label,\n onChange,\n onFocus,\n onBlur,\n hideInputKeyboard,\n inputLabels = [\"Date\", \"Month\", \"Year\"],\n }: Props,\n ref: React.ForwardedRef<StandaloneDateInputRef>\n) => {\n // =============================================================================\n // CONST, STATE, REF\n // =============================================================================\n const inputMode = hideInputKeyboard ? \"none\" : \"numeric\";\n\n const [dayValue, setDayValue, dayValueRef] = useStateRef<string>(\"\");\n const [monthValue, setMonthValue, monthValueRef] = useStateRef<string>(\"\");\n const [yearValue, setYearValue, yearValueRef] = useStateRef<string>(\"\");\n const [currentFocus, setCurrentFocus] = useState<FieldType>(\"none\");\n const [hidePlaceholder, setHidePlaceholder] = useState<boolean>(false);\n\n const nodeRef = useRef<HTMLDivElement>(null);\n const dayInputRef = useRef<HTMLInputElement>(null);\n const monthInputRef = useRef<HTMLInputElement>(null);\n const yearInputRef = useRef<HTMLInputElement>(null);\n\n const [hoverDayValue, hoverMonthValue, hoverYearValue] =\n parseToInputValues(hoverValue);\n\n // =============================================================================\n // EFFECTS\n // =============================================================================\n useEffect(() => {\n const [day = \"\", month = \"\", year = \"\"] = parseToInputValues(value);\n setDayValue(day);\n setMonthValue(month);\n setYearValue(year);\n\n // re-focus on day input if all 3 inputs get cleared while typing\n if (\n !day &&\n !month &&\n !year &&\n nodeRef.current &&\n nodeRef.current.contains(document.activeElement)\n )\n dayInputRef.current?.focus();\n }, [value]);\n\n useEffect(() => {\n // clear internal focus state\n if (!focused) {\n setCurrentFocus(\"none\");\n }\n\n // ensure at least one input is focused\n if (focused) {\n setHidePlaceholder(true);\n\n if (\n nodeRef.current &&\n !nodeRef.current.contains(document.activeElement)\n ) {\n dayInputRef.current?.focus();\n }\n }\n }, [focused]);\n\n useImperativeHandle(\n ref,\n () => ({\n ref: nodeRef,\n resetPlaceholder() {\n setHidePlaceholder(false);\n },\n resetInput() {\n const [day = \"\", month = \"\", year = \"\"] =\n parseToInputValues(value);\n setDayValue(day);\n setMonthValue(month);\n setYearValue(year);\n },\n focusYearRef() {\n yearInputRef.current?.focus();\n },\n }),\n [setDayValue, setMonthValue, setYearValue, value]\n );\n\n // =============================================================================\n // EVENT HANDLERS\n // =============================================================================\n const handleSectionClick = () => {\n if (disabled || readOnly) {\n return;\n }\n\n setHidePlaceholder(true);\n\n if (\n nodeRef.current &&\n !nodeRef.current.contains(document.activeElement)\n ) {\n dayInputRef.current?.focus();\n }\n };\n\n const handleSectionFocus = (event: React.FocusEvent) => {\n if (disabled) {\n return;\n }\n\n setHidePlaceholder(true);\n\n if (!focused) {\n onFocus?.(event);\n }\n };\n\n const handlePlaceholderClick = (event: React.MouseEvent) => {\n event.preventDefault();\n dayInputRef.current?.focus();\n };\n\n const handleInputFocus = (event: React.FocusEvent<HTMLInputElement>) => {\n event.target.select();\n const targetName = event.target.name as FieldType;\n setCurrentFocus(targetName);\n };\n\n const handleInputBlur = (event: React.FocusEvent<HTMLInputElement>) => {\n const [dayName, monthName, yearName] = names;\n const date = {\n [dayName]: dayValueRef.current,\n [monthName]: monthValueRef.current,\n [yearName]: yearValueRef.current,\n };\n\n const targetName = event.target.name as FieldType;\n const targetValue = date[targetName];\n\n // pad single digits for day and month inputs\n\n const paddedValue =\n targetName !== yearName\n ? StringHelper.padValue(targetValue, true)\n : targetValue;\n\n switch (targetName) {\n case dayName:\n date[dayName] = paddedValue;\n setDayValue(paddedValue);\n break;\n case monthName:\n date[monthName] = paddedValue;\n setMonthValue(paddedValue);\n break;\n case yearName:\n default:\n break;\n }\n\n const value = `${date[yearName]}-${date[monthName]}-${date[dayName]}`;\n const isValid = dayjs(value, \"YYYY-MM-DD\", true).isValid();\n const isEmpty = !date[dayName] && !date[monthName] && !date[yearName];\n const isPadded = targetValue !== paddedValue;\n\n if (isValid && isPadded) {\n onChange(value);\n }\n\n if (nodeRef.current && !nodeRef.current.contains(event.relatedTarget)) {\n // entire field was blurred\n setCurrentFocus(\"none\");\n onBlur?.(isEmpty || isValid);\n }\n };\n\n const handleInputChange = (event: React.ChangeEvent<HTMLInputElement>) => {\n if (hoverValue) {\n // do not modify inputs when selecting date from another source\n return;\n }\n\n const targetName = event.target.name as FieldType;\n const targetValue = event.target.value.replace(/[^0-9]/g, \"\");\n\n const date = {\n day: dayValue,\n month: monthValue,\n year: yearValue,\n };\n\n switch (targetName) {\n case names[0]:\n date.day = targetValue;\n setDayValue(targetValue);\n // auto focus the next input once filled in\n if (targetValue.length === 2) {\n monthInputRef.current?.focus();\n }\n break;\n case names[1]:\n date.month = targetValue;\n setMonthValue(targetValue);\n // auto focus the next input once filled in\n if (targetValue.length === 2) {\n yearInputRef.current?.focus();\n }\n break;\n case names[2]:\n date.year = targetValue;\n setYearValue(targetValue);\n break;\n default:\n break;\n }\n\n if (!date.day && !date.month && !date.year) {\n onChange(\"\");\n return;\n }\n\n const value = `${date.year}-${date.month}-${date.day}`;\n const isValid = dayjs(value, \"YYYY-MM-DD\", true).isValid();\n\n if (isValid) {\n onChange(value);\n }\n };\n\n const handleKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {\n /**\n * Allow going to the field before if user presses Backspace\n * on an empty field\n */\n if (event.code === \"Backspace\" || event.key === \"Backspace\") {\n if (currentFocus === names[1] && monthValue.length === 0) {\n dayInputRef.current?.focus();\n }\n\n if (currentFocus === names[2] && yearValue.length === 0) {\n monthInputRef.current?.focus();\n }\n }\n };\n\n // =============================================================================\n // HELPERS\n // =============================================================================\n function parseToInputValues(stringVal: string | undefined) {\n if (!stringVal) {\n return [undefined, undefined, undefined];\n } else {\n const sanitized = DateInputHelper.sanitizeInput(stringVal);\n\n if (!sanitized) {\n return [undefined, undefined, undefined];\n }\n\n const day = dayjs(sanitized, \"YYYY-MM-DD\", true);\n\n return [\n StringHelper.padValue(day.date().toString()),\n StringHelper.padValue((day.month() + 1).toString()),\n day.year().toString(),\n ];\n }\n }\n\n // =============================================================================\n // RENDER FUNCTIONS\n // =============================================================================\n const renderPlaceholder = () => {\n if (value || readOnly || !placeholder) {\n return;\n }\n\n return (\n <div\n className={clsx(\n styles.placeholder,\n disabled && styles.placeholderDisabled,\n hidePlaceholder && styles.placeholderHide\n )}\n onMouseDown={handlePlaceholderClick}\n >\n {placeholder}\n </div>\n );\n };\n\n return (\n <div\n role=\"group\"\n aria-label={label}\n className={styles.inputSection}\n onClick={handleSectionClick}\n onFocus={handleSectionFocus}\n >\n <div ref={nodeRef} className={styles.inputContainer}>\n <span\n className={clsx(\n styles.inputSizerBase,\n styles.dayInputSizer\n )}\n >\n <input\n ref={dayInputRef}\n name={names[0]}\n maxLength={2}\n value={hoverDayValue ?? dayValue}\n onFocus={handleInputFocus}\n onBlur={handleInputBlur}\n onChange={handleInputChange}\n type=\"text\"\n inputMode={inputMode}\n pattern=\"[0-9]{2}\"\n data-testid={`${names[0]}-input`}\n aria-label={inputLabels[0]}\n disabled={disabled}\n readOnly={readOnly}\n tabIndex={readOnly ? -1 : 0}\n autoComplete=\"off\"\n placeholder={\n currentFocus === names[0] && !readOnly ? \"\" : \"DD\"\n }\n className={clsx(\n styles.baseInput,\n !!hoverValue && styles.baseInputHover\n )}\n />\n </span>\n <span\n className={clsx(\n styles.divider,\n !!hoverValue && styles.dividerHover,\n disabled && styles.dividerDisabled,\n !disabled &&\n dayValue.length === 0 &&\n styles.dividerInactive\n )}\n >\n /\n </span>\n <span\n className={clsx(\n styles.inputSizerBase,\n styles.monthInputSizer\n )}\n >\n <input\n ref={monthInputRef}\n name={names[1]}\n maxLength={2}\n value={hoverMonthValue ?? monthValue}\n onFocus={handleInputFocus}\n onBlur={handleInputBlur}\n onChange={handleInputChange}\n onKeyDown={handleKeyDown}\n type=\"text\"\n inputMode={inputMode}\n pattern=\"[0-9]{2}\"\n data-testid={`${names[1]}-input`}\n aria-label={inputLabels[1]}\n disabled={disabled}\n readOnly={readOnly}\n tabIndex={readOnly ? -1 : 0}\n autoComplete=\"off\"\n placeholder={\n currentFocus === names[1] && !readOnly ? \"\" : \"MM\"\n }\n className={clsx(\n styles.baseInput,\n !!hoverValue && styles.baseInputHover\n )}\n />\n </span>\n <span\n className={clsx(\n styles.divider,\n !!hoverValue && styles.dividerHover,\n disabled && styles.dividerDisabled,\n !disabled &&\n monthValue.length === 0 &&\n styles.dividerInactive\n )}\n >\n /\n </span>\n <span\n className={clsx(\n styles.inputSizerBase,\n styles.yearInputSizer\n )}\n >\n <input\n ref={yearInputRef}\n name={names[2]}\n maxLength={4}\n value={hoverYearValue ?? yearValue}\n onFocus={handleInputFocus}\n onBlur={handleInputBlur}\n onChange={handleInputChange}\n onKeyDown={handleKeyDown}\n type=\"text\"\n inputMode={inputMode}\n pattern=\"[0-9]{4}\"\n data-testid={`${names[2]}-input`}\n aria-label={inputLabels[2]}\n disabled={disabled}\n readOnly={readOnly}\n tabIndex={readOnly ? -1 : 0}\n autoComplete=\"off\"\n placeholder={\n currentFocus === names[2] && !readOnly ? \"\" : \"YYYY\"\n }\n className={clsx(\n styles.baseInput,\n !!hoverValue && styles.baseInputHover\n )}\n />\n </span>\n </div>\n {renderPlaceholder()}\n </div>\n );\n};\n\nexport const StandaloneDateInput = React.forwardRef(Component);\n"],"names":["dayjs","extend","customParseFormat","Component","disabled","readOnly","names","value","focused","hoverValue","placeholder","label","onChange","onFocus","onBlur","hideInputKeyboard","inputLabels","ref","inputMode","dayValue","setDayValue","dayValueRef","useStateRef","monthValue","setMonthValue","monthValueRef","yearValue","setYearValue","yearValueRef","currentFocus","setCurrentFocus","useState","hidePlaceholder","setHidePlaceholder","nodeRef","useRef","dayInputRef","monthInputRef","yearInputRef","hoverDayValue","hoverMonthValue","hoverYearValue","parseToInputValues","useEffect","day","month","year","current","contains","document","activeElement","_a","focus","useImperativeHandle","resetPlaceholder","resetInput","focusYearRef","handlePlaceholderClick","event","preventDefault","handleInputFocus","target","select","targetName","name","handleInputBlur","dayName","monthName","yearName","date","targetValue","paddedValue","StringHelper","padValue","isValid","isEmpty","relatedTarget","handleInputChange","replace","length","_b","handleKeyDown","code","key","stringVal","sanitized","DateInputHelper","sanitizeInput","undefined","toString","_jsxs","role","className","styles.inputSection","onClick","children","styles.inputContainer","_jsx","clsx","styles.inputSizerBase","styles.dayInputSizer","maxLength","type","pattern","tabIndex","autoComplete","styles.baseInput","styles.baseInputHover","styles.divider","styles.dividerHover","styles.dividerDisabled","styles.dividerInactive","styles.monthInputSizer","onKeyDown","styles.yearInputSizer","styles.placeholder","styles.placeholderDisabled","styles.placeholderHide","onMouseDown","renderPlaceholder","StandaloneDateInput","React","forwardRef"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"standalone-date-input.js","sources":["../../../src/shared/standalone-date-input/standalone-date-input.tsx"],"sourcesContent":["import clsx from \"clsx\";\nimport dayjs from \"dayjs\";\nimport customParseFormat from \"dayjs/plugin/customParseFormat\";\nimport React, { useEffect, useImperativeHandle, useRef, useState } from \"react\";\n\nimport { DateInputHelper, StringHelper, useStateRef } from \"../../util\";\nimport * as styles from \"./standalone-date-input.styles\";\n\ndayjs.extend(customParseFormat);\n\ntype StartInputNames = [\"start-day\", \"start-month\", \"start-year\"];\ntype EndInputNames = [\"end-day\", \"end-month\", \"end-year\"];\n\nexport type FieldType =\n | StartInputNames[number]\n | EndInputNames[number]\n | \"none\";\n\ninterface Props {\n disabled?: boolean | undefined;\n readOnly?: boolean | undefined;\n hideInputKeyboard?: boolean | undefined;\n names: StartInputNames | EndInputNames;\n value: string | undefined;\n hoverValue?: string | undefined;\n focused: boolean;\n placeholder?: string | undefined;\n label?: string | undefined;\n inputLabels?: string[] | undefined;\n onChange: (value: string) => void;\n onFocus?: ((event: React.FocusEvent) => void) | undefined;\n onBlur?: ((valid: boolean) => void) | undefined;\n}\n\nexport interface StandaloneDateInputRef {\n ref: React.RefObject<HTMLDivElement>;\n resetPlaceholder: () => void;\n resetInput: () => void;\n focusYearRef: () => void;\n}\n\nexport const Component = (\n {\n disabled,\n readOnly,\n names,\n value,\n focused,\n hoverValue,\n placeholder,\n label,\n onChange,\n onFocus,\n onBlur,\n hideInputKeyboard,\n inputLabels = [\"Date\", \"Month\", \"Year\"],\n }: Props,\n ref: React.ForwardedRef<StandaloneDateInputRef>\n) => {\n // =============================================================================\n // CONST, STATE, REF\n // =============================================================================\n const inputMode = hideInputKeyboard ? \"none\" : \"numeric\";\n\n const [dayValue, setDayValue, dayValueRef] = useStateRef<string>(\"\");\n const [monthValue, setMonthValue, monthValueRef] = useStateRef<string>(\"\");\n const [yearValue, setYearValue, yearValueRef] = useStateRef<string>(\"\");\n const [currentFocus, setCurrentFocus] = useState<FieldType>(\"none\");\n const [hidePlaceholder, setHidePlaceholder] = useState<boolean>(false);\n\n const nodeRef = useRef<HTMLDivElement>(null);\n const dayInputRef = useRef<HTMLInputElement>(null);\n const monthInputRef = useRef<HTMLInputElement>(null);\n const yearInputRef = useRef<HTMLInputElement>(null);\n\n const [hoverDayValue, hoverMonthValue, hoverYearValue] =\n parseToInputValues(hoverValue);\n\n // =============================================================================\n // EFFECTS\n // =============================================================================\n useEffect(() => {\n const [day = \"\", month = \"\", year = \"\"] = parseToInputValues(value);\n setDayValue(day);\n setMonthValue(month);\n setYearValue(year);\n\n // re-focus on day input if all 3 inputs get cleared while typing\n if (\n !day &&\n !month &&\n !year &&\n nodeRef.current &&\n nodeRef.current.contains(document.activeElement)\n )\n dayInputRef.current?.focus();\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [value]);\n\n useEffect(() => {\n // clear internal focus state\n if (!focused) {\n setCurrentFocus(\"none\");\n }\n\n // ensure at least one input is focused\n if (focused) {\n setHidePlaceholder(true);\n\n if (\n nodeRef.current &&\n !nodeRef.current.contains(document.activeElement)\n ) {\n dayInputRef.current?.focus();\n }\n }\n }, [focused]);\n\n useImperativeHandle(\n ref,\n () => ({\n ref: nodeRef,\n resetPlaceholder() {\n setHidePlaceholder(false);\n },\n resetInput() {\n const [day = \"\", month = \"\", year = \"\"] =\n parseToInputValues(value);\n setDayValue(day);\n setMonthValue(month);\n setYearValue(year);\n },\n focusYearRef() {\n yearInputRef.current?.focus();\n },\n }),\n [setDayValue, setMonthValue, setYearValue, value]\n );\n\n // =============================================================================\n // EVENT HANDLERS\n // =============================================================================\n const handleSectionClick = () => {\n if (disabled || readOnly) {\n return;\n }\n\n setHidePlaceholder(true);\n\n if (\n nodeRef.current &&\n !nodeRef.current.contains(document.activeElement)\n ) {\n dayInputRef.current?.focus();\n }\n };\n\n const handleSectionFocus = (event: React.FocusEvent) => {\n if (disabled) {\n return;\n }\n\n setHidePlaceholder(true);\n\n if (!focused) {\n onFocus?.(event);\n }\n };\n\n const handlePlaceholderClick = (event: React.MouseEvent) => {\n event.preventDefault();\n dayInputRef.current?.focus();\n };\n\n const handleInputFocus = (event: React.FocusEvent<HTMLInputElement>) => {\n event.target.select();\n const targetName = event.target.name as FieldType;\n setCurrentFocus(targetName);\n };\n\n const handleInputBlur = (event: React.FocusEvent<HTMLInputElement>) => {\n const [dayName, monthName, yearName] = names;\n const date = {\n [dayName]: dayValueRef.current,\n [monthName]: monthValueRef.current,\n [yearName]: yearValueRef.current,\n };\n\n const targetName = event.target.name as FieldType;\n const targetValue = date[targetName];\n\n // pad single digits for day and month inputs\n\n const paddedValue =\n targetName !== yearName\n ? StringHelper.padValue(targetValue, true)\n : targetValue;\n\n switch (targetName) {\n case dayName:\n date[dayName] = paddedValue;\n setDayValue(paddedValue);\n break;\n case monthName:\n date[monthName] = paddedValue;\n setMonthValue(paddedValue);\n break;\n case yearName:\n default:\n break;\n }\n\n const value = `${date[yearName]}-${date[monthName]}-${date[dayName]}`;\n const isValid = dayjs(value, \"YYYY-MM-DD\", true).isValid();\n const isEmpty = !date[dayName] && !date[monthName] && !date[yearName];\n const isPadded = targetValue !== paddedValue;\n\n if (isValid && isPadded) {\n onChange(value);\n }\n\n if (nodeRef.current && !nodeRef.current.contains(event.relatedTarget)) {\n // entire field was blurred\n setCurrentFocus(\"none\");\n onBlur?.(isEmpty || isValid);\n }\n };\n\n const handleInputChange = (event: React.ChangeEvent<HTMLInputElement>) => {\n if (hoverValue) {\n // do not modify inputs when selecting date from another source\n return;\n }\n\n const targetName = event.target.name as FieldType;\n const targetValue = event.target.value.replace(/[^0-9]/g, \"\");\n\n const date = {\n day: dayValue,\n month: monthValue,\n year: yearValue,\n };\n\n switch (targetName) {\n case names[0]:\n date.day = targetValue;\n setDayValue(targetValue);\n // auto focus the next input once filled in\n if (targetValue.length === 2) {\n monthInputRef.current?.focus();\n }\n break;\n case names[1]:\n date.month = targetValue;\n setMonthValue(targetValue);\n // auto focus the next input once filled in\n if (targetValue.length === 2) {\n yearInputRef.current?.focus();\n }\n break;\n case names[2]:\n date.year = targetValue;\n setYearValue(targetValue);\n break;\n default:\n break;\n }\n\n if (!date.day && !date.month && !date.year) {\n onChange(\"\");\n return;\n }\n\n const value = `${date.year}-${date.month}-${date.day}`;\n const isValid = dayjs(value, \"YYYY-MM-DD\", true).isValid();\n\n if (isValid) {\n onChange(value);\n }\n };\n\n const handleKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {\n /**\n * Allow going to the field before if user presses Backspace\n * on an empty field\n */\n if (event.code === \"Backspace\" || event.key === \"Backspace\") {\n if (currentFocus === names[1] && monthValue.length === 0) {\n dayInputRef.current?.focus();\n }\n\n if (currentFocus === names[2] && yearValue.length === 0) {\n monthInputRef.current?.focus();\n }\n }\n };\n\n // =============================================================================\n // HELPERS\n // =============================================================================\n function parseToInputValues(stringVal: string | undefined) {\n if (!stringVal) {\n return [undefined, undefined, undefined];\n } else {\n const sanitized = DateInputHelper.sanitizeInput(stringVal);\n\n if (!sanitized) {\n return [undefined, undefined, undefined];\n }\n\n const day = dayjs(sanitized, \"YYYY-MM-DD\", true);\n\n return [\n StringHelper.padValue(day.date().toString()),\n StringHelper.padValue((day.month() + 1).toString()),\n day.year().toString(),\n ];\n }\n }\n\n // =============================================================================\n // RENDER FUNCTIONS\n // =============================================================================\n const renderPlaceholder = () => {\n if (value || readOnly || !placeholder) {\n return;\n }\n\n return (\n <div\n className={clsx(\n styles.placeholder,\n disabled && styles.placeholderDisabled,\n hidePlaceholder && styles.placeholderHide\n )}\n onMouseDown={handlePlaceholderClick}\n >\n {placeholder}\n </div>\n );\n };\n\n return (\n <div\n role=\"group\"\n aria-label={label}\n className={styles.inputSection}\n onClick={handleSectionClick}\n onFocus={handleSectionFocus}\n >\n <div ref={nodeRef} className={styles.inputContainer}>\n <span\n className={clsx(\n styles.inputSizerBase,\n styles.dayInputSizer\n )}\n >\n <input\n ref={dayInputRef}\n name={names[0]}\n maxLength={2}\n value={hoverDayValue ?? dayValue}\n onFocus={handleInputFocus}\n onBlur={handleInputBlur}\n onChange={handleInputChange}\n type=\"text\"\n inputMode={inputMode}\n pattern=\"[0-9]{2}\"\n data-testid={`${names[0]}-input`}\n aria-label={inputLabels[0]}\n disabled={disabled}\n readOnly={readOnly}\n tabIndex={readOnly ? -1 : 0}\n autoComplete=\"off\"\n placeholder={\n currentFocus === names[0] && !readOnly ? \"\" : \"DD\"\n }\n className={clsx(\n styles.baseInput,\n !!hoverValue && styles.baseInputHover\n )}\n />\n </span>\n <span\n className={clsx(\n styles.divider,\n !!hoverValue && styles.dividerHover,\n disabled && styles.dividerDisabled,\n !disabled &&\n dayValue.length === 0 &&\n styles.dividerInactive\n )}\n >\n /\n </span>\n <span\n className={clsx(\n styles.inputSizerBase,\n styles.monthInputSizer\n )}\n >\n <input\n ref={monthInputRef}\n name={names[1]}\n maxLength={2}\n value={hoverMonthValue ?? monthValue}\n onFocus={handleInputFocus}\n onBlur={handleInputBlur}\n onChange={handleInputChange}\n onKeyDown={handleKeyDown}\n type=\"text\"\n inputMode={inputMode}\n pattern=\"[0-9]{2}\"\n data-testid={`${names[1]}-input`}\n aria-label={inputLabels[1]}\n disabled={disabled}\n readOnly={readOnly}\n tabIndex={readOnly ? -1 : 0}\n autoComplete=\"off\"\n placeholder={\n currentFocus === names[1] && !readOnly ? \"\" : \"MM\"\n }\n className={clsx(\n styles.baseInput,\n !!hoverValue && styles.baseInputHover\n )}\n />\n </span>\n <span\n className={clsx(\n styles.divider,\n !!hoverValue && styles.dividerHover,\n disabled && styles.dividerDisabled,\n !disabled &&\n monthValue.length === 0 &&\n styles.dividerInactive\n )}\n >\n /\n </span>\n <span\n className={clsx(\n styles.inputSizerBase,\n styles.yearInputSizer\n )}\n >\n <input\n ref={yearInputRef}\n name={names[2]}\n maxLength={4}\n value={hoverYearValue ?? yearValue}\n onFocus={handleInputFocus}\n onBlur={handleInputBlur}\n onChange={handleInputChange}\n onKeyDown={handleKeyDown}\n type=\"text\"\n inputMode={inputMode}\n pattern=\"[0-9]{4}\"\n data-testid={`${names[2]}-input`}\n aria-label={inputLabels[2]}\n disabled={disabled}\n readOnly={readOnly}\n tabIndex={readOnly ? -1 : 0}\n autoComplete=\"off\"\n placeholder={\n currentFocus === names[2] && !readOnly ? \"\" : \"YYYY\"\n }\n className={clsx(\n styles.baseInput,\n !!hoverValue && styles.baseInputHover\n )}\n />\n </span>\n </div>\n {renderPlaceholder()}\n </div>\n );\n};\n\nexport const StandaloneDateInput = React.forwardRef(Component);\n"],"names":["dayjs","extend","customParseFormat","Component","disabled","readOnly","names","value","focused","hoverValue","placeholder","label","onChange","onFocus","onBlur","hideInputKeyboard","inputLabels","ref","inputMode","dayValue","setDayValue","dayValueRef","useStateRef","monthValue","setMonthValue","monthValueRef","yearValue","setYearValue","yearValueRef","currentFocus","setCurrentFocus","useState","hidePlaceholder","setHidePlaceholder","nodeRef","useRef","dayInputRef","monthInputRef","yearInputRef","hoverDayValue","hoverMonthValue","hoverYearValue","parseToInputValues","useEffect","day","month","year","current","contains","document","activeElement","_a","focus","useImperativeHandle","resetPlaceholder","resetInput","focusYearRef","handlePlaceholderClick","event","preventDefault","handleInputFocus","target","select","targetName","name","handleInputBlur","dayName","monthName","yearName","date","targetValue","paddedValue","StringHelper","padValue","isValid","isEmpty","relatedTarget","handleInputChange","replace","length","_b","handleKeyDown","code","key","stringVal","sanitized","DateInputHelper","sanitizeInput","undefined","toString","_jsxs","role","className","styles.inputSection","onClick","children","styles.inputContainer","_jsx","clsx","styles.inputSizerBase","styles.dayInputSizer","maxLength","type","pattern","tabIndex","autoComplete","styles.baseInput","styles.baseInputHover","styles.divider","styles.dividerHover","styles.dividerDisabled","styles.dividerInactive","styles.monthInputSizer","onKeyDown","styles.yearInputSizer","styles.placeholder","styles.placeholderDisabled","styles.placeholderHide","onMouseDown","renderPlaceholder","StandaloneDateInput","React","forwardRef"],"mappings":"y4BAQAA,EAAMC,OAAOC,GAiCN,MAAMC,EAAY,EAEjBC,WACAC,WACAC,QACAC,QACAC,UACAC,aAAUC,YACVA,EACAC,QACAC,WACAC,UACAC,SACAC,oBACAC,cAAc,CAAC,OAAQ,QAAS,SAEpCC,KAKA,MAAMC,EAAYH,EAAoB,OAAS,WAExCI,EAAUC,EAAaC,GAAeC,EAAoB,KAC1DC,EAAYC,EAAeC,GAAiBH,EAAoB,KAChEI,EAAWC,EAAcC,GAAgBN,EAAoB,KAC7DO,EAAcC,GAAmBC,EAAoB,SACrDC,EAAiBC,GAAsBF,GAAkB,GAE1DG,GAAUC,EAAuB,MACjCC,GAAcD,EAAyB,MACvCE,GAAgBF,EAAyB,MACzCG,GAAeH,EAAyB,OAEvCI,GAAeC,GAAiBC,IACnCC,GAAmBjC,GAKvBkC,GAAU,WACN,MAAOC,EAAM,GAAIC,EAAQ,GAAIC,EAAO,IAAMJ,GAAmBnC,GAC7Da,EAAYwB,GACZpB,EAAcqB,GACdlB,EAAamB,GAIRF,GACAC,GACAC,IACDZ,GAAQa,UACRb,GAAQa,QAAQC,SAASC,SAASC,gBAEf,QAAnBC,EAAAf,GAAYW,eAAO,IAAAI,GAAAA,EAAEC,OAAO,GAEjC,CAAC7C,IAEJoC,GAAU,WAEDnC,GACDsB,EAAgB,QAIhBtB,IACAyB,GAAmB,GAGfC,GAAQa,UACPb,GAAQa,QAAQC,SAASC,SAASC,iBAEhB,QAAnBC,EAAAf,GAAYW,eAAO,IAAAI,GAAAA,EAAEC,SAE7B,GACD,CAAC5C,IAEJ6C,EACIpC,GACA,KAAA,CACIA,IAAKiB,GACL,gBAAAoB,GACIrB,GAAmB,EACvB,EACA,UAAAsB,GACI,MAAOX,EAAM,GAAIC,EAAQ,GAAIC,EAAO,IAChCJ,GAAmBnC,GACvBa,EAAYwB,GACZpB,EAAcqB,GACdlB,EAAamB,EACjB,EACA,YAAAU,SACwB,QAApBL,EAAAb,GAAaS,eAAO,IAAAI,GAAAA,EAAEC,OAC1B,KAEJ,CAAChC,EAAaI,EAAeG,EAAcpB,IAM/C,MA2BMkD,GAA0BC,UAC5BA,EAAMC,iBACa,QAAnBR,EAAAf,GAAYW,eAAO,IAAAI,GAAAA,EAAEC,OAAO,EAG1BQ,GAAoBF,IACtBA,EAAMG,OAAOC,SACb,MAAMC,EAAaL,EAAMG,OAAOG,KAChClC,EAAgBiC,EAAW,EAGzBE,GAAmBP,IACrB,MAAOQ,EAASC,EAAWC,GAAY9D,EACjC+D,EAAO,CACTH,CAACA,GAAU7C,EAAY0B,QACvBoB,CAACA,GAAY1C,EAAcsB,QAC3BqB,CAACA,GAAWxC,EAAamB,SAGvBgB,EAAaL,EAAMG,OAAOG,KAC1BM,EAAcD,EAAKN,GAInBQ,EACFR,IAAeK,EACTI,EAAaC,SAASH,GAAa,GACnCA,EAEV,OAAQP,GACJ,KAAKG,EACDG,EAAKH,GAAWK,EAChBnD,EAAYmD,GACZ,MACJ,KAAKJ,EACDE,EAAKF,GAAaI,EAClB/C,EAAc+C,GAOtB,MAAMhE,EAAQ,GAAG8D,EAAKD,MAAaC,EAAKF,MAAcE,EAAKH,KACrDQ,EAAU1E,EAAMO,EAAO,cAAc,GAAMmE,UAC3CC,GAAWN,EAAKH,KAAaG,EAAKF,KAAeE,EAAKD,GAGxDM,GAFaJ,IAAgBC,GAG7B3D,EAASL,GAGT2B,GAAQa,UAAYb,GAAQa,QAAQC,SAASU,EAAMkB,iBAEnD9C,EAAgB,QAChBhB,SAAAA,EAAS6D,GAAWD,GACxB,EAGEG,GAAqBnB,YACvB,GAAIjD,EAEA,OAGJ,MAAMsD,EAAaL,EAAMG,OAAOG,KAC1BM,EAAcZ,EAAMG,OAAOtD,MAAMuE,QAAQ,UAAW,IAEpDT,EAAO,CACTzB,IAAKzB,EACL0B,MAAOtB,EACPuB,KAAMpB,GAGV,OAAQqC,GACJ,KAAKzD,EAAM,GACP+D,EAAKzB,IAAM0B,EACXlD,EAAYkD,GAEe,IAAvBA,EAAYS,SACS,QAArB5B,EAAAd,GAAcU,eAAO,IAAAI,GAAAA,EAAEC,SAE3B,MACJ,KAAK9C,EAAM,GACP+D,EAAKxB,MAAQyB,EACb9C,EAAc8C,GAEa,IAAvBA,EAAYS,SACQ,QAApBC,EAAA1C,GAAaS,eAAO,IAAAiC,GAAAA,EAAE5B,SAE1B,MACJ,KAAK9C,EAAM,GACP+D,EAAKvB,KAAOwB,EACZ3C,EAAa2C,GAMrB,IAAKD,EAAKzB,MAAQyB,EAAKxB,QAAUwB,EAAKvB,KAElC,YADAlC,EAAS,IAIb,MAAML,EAAQ,GAAG8D,EAAKvB,QAAQuB,EAAKxB,SAASwB,EAAKzB,MACjC5C,EAAMO,EAAO,cAAc,GAAMmE,WAG7C9D,EAASL,EACb,EAGE0E,GAAiBvB,YAKA,cAAfA,EAAMwB,MAAsC,cAAdxB,EAAMyB,MAChCtD,IAAiBvB,EAAM,IAA4B,IAAtBiB,EAAWwD,SACrB,QAAnB5B,EAAAf,GAAYW,eAAO,IAAAI,GAAAA,EAAEC,SAGrBvB,IAAiBvB,EAAM,IAA2B,IAArBoB,EAAUqD,SAClB,QAArBC,EAAA3C,GAAcU,eAAO,IAAAiC,GAAAA,EAAE5B,SAE/B,EAMJ,SAASV,GAAmB0C,GACxB,GAAKA,EAEE,CACH,MAAMC,EAAYC,EAAgBC,cAAcH,GAEhD,IAAKC,EACD,MAAO,MAACG,OAAWA,OAAWA,GAGlC,MAAM5C,EAAM5C,EAAMqF,EAAW,cAAc,GAE3C,MAAO,CACHb,EAAaC,SAAS7B,EAAIyB,OAAOoB,YACjCjB,EAAaC,UAAU7B,EAAIC,QAAU,GAAG4C,YACxC7C,EAAIE,OAAO2C,WAEnB,CAfI,MAAO,MAACD,OAAWA,OAAWA,EAgBtC,CAwBA,OACIE,SACIC,KAAK,QAAO,aACAhF,EACZiF,UAAWC,EACXC,QA7MmB,WACnB1F,GAAYC,IAIhB4B,GAAmB,GAGfC,GAAQa,UACPb,GAAQa,QAAQC,SAASC,SAASC,iBAEhB,QAAnBC,EAAAf,GAAYW,eAAO,IAAAI,GAAAA,EAAEC,SACzB,EAkMIvC,QA/LoB6C,IACpBtD,IAIJ6B,GAAmB,GAEdzB,GACDK,SAAAA,EAAU6C,GACd,EAsL+BqC,SAAA,CAE3BL,EAAA,MAAA,CAAKzE,IAAKiB,GAAS0D,UAAWI,YAC1BC,EAAA,OAAA,CACIL,UAAWM,EACPC,EACAC,GACHL,SAEDE,EAAA,QAAA,CACIhF,IAAKmB,GACL4B,KAAM1D,EAAM,GACZ+F,UAAW,EACX9F,MAAOgC,SAAAA,GAAiBpB,EACxBN,QAAS+C,GACT9C,OAAQmD,GACRrD,SAAUiE,GACVyB,KAAK,OACLpF,UAAWA,EACXqF,QAAQ,WAAU,cACL,GAAGjG,EAAM,WAAU,aACpBU,EAAY,GACxBZ,SAAUA,EACVC,SAAUA,EACVmG,SAAUnG,GAAW,EAAK,EAC1BoG,aAAa,MACb/F,YACImB,IAAiBvB,EAAM,IAAOD,EAAgB,KAAL,GAE7CuF,UAAWM,EACPQ,IACEjG,GAAckG,OAI5BV,UACIL,UAAWM,EACPU,IACEnG,GAAcoG,EAChBzG,GAAY0G,GACX1G,GACuB,IAApBe,EAAS4D,QACTgC,kBAKZd,EAAA,OAAA,CACIL,UAAWM,EACPC,EACAa,GACHjB,SAEDE,EAAA,QAAA,CACIhF,IAAKoB,GACL2B,KAAM1D,EAAM,GACZ+F,UAAW,EACX9F,MAAOiC,SAAAA,GAAmBjB,EAC1BV,QAAS+C,GACT9C,OAAQmD,GACRrD,SAAUiE,GACVoC,UAAWhC,GACXqB,KAAK,OACLpF,UAAWA,EACXqF,QAAQ,yBACK,GAAGjG,EAAM,WAAU,aACpBU,EAAY,GACxBZ,SAAUA,EACVC,SAAUA,EACVmG,SAAUnG,KAAgB,EAC1BoG,aAAa,MACb/F,YACImB,IAAiBvB,EAAM,IAAOD,EAAgB,KAAL,GAE7CuF,UAAWM,EACPQ,IACEjG,GAAckG,OAI5BV,UACIL,UAAWM,EACPU,IACEnG,GAAcoG,EAChBzG,GAAY0G,GACX1G,GACyB,IAAtBmB,EAAWwD,QACXgC,GACPhB,SAAA,MAILE,EAAA,OAAA,CACIL,UAAWM,EACPC,EACAe,GACHnB,SAEDE,WACIhF,IAAKqB,GACL0B,KAAM1D,EAAM,GACZ+F,UAAW,EACX9F,MAAOkC,SAAAA,GAAkBf,EACzBb,QAAS+C,GACT9C,OAAQmD,GACRrD,SAAUiE,GACVoC,UAAWhC,GACXqB,KAAK,OACLpF,UAAWA,EACXqF,QAAQ,WAAU,cACL,GAAGjG,EAAM,WAAU,aACpBU,EAAY,GACxBZ,SAAUA,EACVC,SAAUA,EACVmG,SAAUnG,GAAW,EAAK,EAC1BoG,aAAa,MACb/F,YACImB,IAAiBvB,EAAM,IAAOD,EAAgB,OAAL,GAE7CuF,UAAWM,EACPQ,IACEjG,GAAckG,UAlJd,MACtB,IAAIpG,IAASF,GAAaK,EAI1B,OACIuF,EAAA,MAAA,CACIL,UAAWM,EACPiB,EACA/G,GAAYgH,EACZpF,GAAmBqF,GAEvBC,YAAa7D,GAAsBsC,SAElCrF,GACC,EAwIL6G,KACC,EAIDC,EAAsBC,EAAMC,WAAWvH"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import"./singpass-button.
|
|
1
|
+
import"./singpass-button.styles_1fj2lru.css";const s="m18jjb1",m="m6wtgnj",t="mijymjd",j="m1y6qkg6",n="mmpvnp1",p="s1mju8fq",i="sreiq2p";export{s as main,t as mainSizeLarge,m as mainSizeSmall,j as mainStyleRedFilled,n as mainStyleWhiteFilled,p as svgContainer,i as svgContainerSizeLarge};
|
|
2
2
|
//# sourceMappingURL=singpass-button.styles.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"singpass-button.styles.js","sources":["../../src/singpass-button/singpass-button.styles.ts"],"sourcesContent":["import { css } from \"@linaria/core\";\n\nimport { ComponentToken, Motion, Spacing } from \"../theme\";\n\n// =============================================================================\n// MAIN BUTTON\n// =============================================================================\nexport const main = css`\n padding: ${Spacing[\"spacing-8\"]} ${Spacing[\"spacing-16\"]};\n transition: all ${Motion[\"duration-250\"]} ${Motion[\"ease-default\"]};\n border-radius: ${ComponentToken.Button[\"radius\"]};\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n min-height: 3rem;\n`;\n\nexport const mainSizeSmall = css`\n height: 2.5rem;\n
|
|
1
|
+
{"version":3,"file":"singpass-button.styles.js","sources":["../../src/singpass-button/singpass-button.styles.ts"],"sourcesContent":["import { css } from \"@linaria/core\";\n\nimport { Border, ComponentToken, Motion, Spacing } from \"../theme\";\n\n// =============================================================================\n// MAIN BUTTON\n// =============================================================================\nexport const main = css`\n padding: ${Spacing[\"spacing-8\"]} ${Spacing[\"spacing-16\"]};\n transition: all ${Motion[\"duration-250\"]} ${Motion[\"ease-default\"]};\n border-radius: ${ComponentToken.Button[\"radius\"]};\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n min-height: 3rem;\n`;\n\nexport const mainSizeSmall = css`\n min-height: 2.5rem;\n padding: calc(${Spacing[\"spacing-8\"]} - ${Border[\"width-010\"]})\n ${Spacing[\"spacing-16\"]};\n`;\n\nexport const mainSizeLarge = css`\n min-height: 4rem;\n`;\n\nexport const mainStyleRedFilled = css`\n background-color: #f4333d;\n border: none;\n\n &:hover,\n &:active {\n @media (pointer: fine) {\n background-color: #b0262d;\n }\n }\n`;\n\nexport const mainStyleWhiteFilled = css`\n background-color: #ffffff;\n border: 1px #c8c9cc solid;\n\n &:hover,\n &:active {\n @media (pointer: fine) {\n background-color: #f5f5f7;\n }\n }\n`;\n\n// =============================================================================\n// SVG CONTAINER\n// =============================================================================\nexport const svgContainer = css`\n height: 1.5rem;\n\n img {\n height: 100%;\n }\n`;\n\nexport const svgContainerSizeLarge = css`\n height: 2.5rem;\n`;\n"],"names":["main","mainSizeSmall","mainSizeLarge","mainStyleRedFilled","mainStyleWhiteFilled","svgContainer","svgContainerSizeLarge"],"mappings":"4EAOO,MAAMA,EAAI,UAWJC,EAAa,UAMbC,EAAa,UAIbC,EAAkB,WAYlBC,EAAoB,UAepBC,EAAY,WAQZC,EAAqB"}
|
package/singpass-button/{singpass-button.styles_1miyex3.css → singpass-button.styles_1fj2lru.css}
RENAMED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
@layer fds{.m18jjb1{padding:var(--fds-spacing-8) var(--fds-spacing-16);-webkit-transition:all var(--fds-motion-duration-250) var(--fds-motion-timing-ease-default);transition:all var(--fds-motion-duration-250) var(--fds-motion-timing-ease-default);border-radius:var(--fds-button-radius);cursor:pointer;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;-webkit-justify-content:center;justify-content:center;min-height:3rem;}
|
|
2
|
-
.m6wtgnj{height:2.5rem;
|
|
2
|
+
.m6wtgnj{min-height:2.5rem;padding:calc(var(--fds-spacing-8) - var(--fds-border-width-010)) var(--fds-spacing-16);}
|
|
3
3
|
.mijymjd{min-height:4rem;}
|
|
4
4
|
.m1y6qkg6{background-color:#f4333d;border:none;}@media (pointer: fine){.m1y6qkg6:hover,.m1y6qkg6:active{background-color:#b0262d;}}
|
|
5
5
|
.mmpvnp1{background-color:#ffffff;border:1px #c8c9cc solid;}@media (pointer: fine){.mmpvnp1:hover,.mmpvnp1:active{background-color:#f5f5f7;}}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import"./smart-app-banner.
|
|
1
|
+
import"./smart-app-banner.styles_r6yjq9.css";const r={container:{top:"--fds-internal-smartAppBanner-container-top"}},s="s4qb553",t="s1yw94wd",n="s1gji45a",a="s9k7xr8",p="dmwiwc",e="d1cy2w47",c="cp9l7rn",m="pdjtkx9",o="t7s9qr2",d="bece00m",i="b1ti1r81",b="b1rqz1xr",g="tmo9z7m",q="dp7x5g3",w="r1gggq6r",x="sda01s1";export{d as bannerIcon,b as button,i as buttonContainer,c as cross,q as description,e as dismissButton,p as dismissContainer,m as proceedContainer,w as ratingContainer,s as smartAppBannerContainer,a as smartAppBannerContainerAnimated,n as smartAppBannerContainerDark,t as smartAppBannerContainerLight,x as starIcon,o as textContainer,g as title,r as tokens};
|
|
2
2
|
//# sourceMappingURL=smart-app-banner.styles.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"smart-app-banner.styles.js","sources":["../../src/smart-app-banner/smart-app-banner.styles.ts"],"sourcesContent":["import { css } from \"@linaria/core\";\n\nimport { Border, Colour, Font, MediaQuery, Radius, Shadow } from \"../theme\";\n\nexport const tokens = {\n container: {\n top: \"--fds-internal-smartAppBanner-container-top\",\n },\n};\n\nexport const smartAppBannerContainer = css`\n display: flex;\n flex-direction: row-reverse;\n align-items: stretch;\n position: fixed;\n margin: 0.5rem 1.25rem;\n ${tokens.container.top}: initial;\n top: var(${tokens.container.top});\n left: 0;\n width: calc(100% - 2.5rem);\n min-height: 5.5rem;\n z-index: 9001;\n background: ${Colour.bg};\n border-radius: ${Radius.md};\n`;\n\nexport const smartAppBannerContainerLight = css`\n box-shadow: ${Shadow[\"md-subtle\"]};\n`;\n\nexport const smartAppBannerContainerDark = css`\n border: ${Border[\"width-010\"]} ${Border.solid} ${Colour.border};\n`;\n\nexport const smartAppBannerContainerAnimated = css`\n @keyframes smart-app-banner-slide-down {\n from {\n opacity: 0;\n transform: translateY(-20%);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n }\n animation: smart-app-banner-slide-down 0.3s;\n`;\n\nexport const dismissContainer = css`\n display: flex;\n align-items: center;\n padding: 0.5rem 0.25rem 0.5rem 1rem;\n`;\n\nexport const dismissButton = css`\n padding: 0;\n`;\n\nexport const cross = css`\n color: ${Colour.icon};\n height: 1.25rem;\n width: 1.25rem;\n`;\n\nexport const proceedContainer = css`\n flex: 1;\n display: flex;\n align-items: center;\n padding: 0.5rem 1rem 0.5rem 0.25rem;\n cursor: pointer;\n`;\n\nexport const textContainer = css`\n flex: 1;\n display: flex;\n flex-direction: column;\n align-items: left;\n margin: 0.5rem;\n ${MediaQuery.MaxWidth.xs} {\n margin: 0 0.5rem;\n }\n`;\n\nexport const bannerIcon = css`\n width: 2.65rem;\n height: auto;\n align-self: center;\n`;\n\nexport const buttonContainer = css`\n max-width: 30%;\n`;\n\nexport const button = css`\n padding: 0.5rem;\n
|
|
1
|
+
{"version":3,"file":"smart-app-banner.styles.js","sources":["../../src/smart-app-banner/smart-app-banner.styles.ts"],"sourcesContent":["import { css } from \"@linaria/core\";\n\nimport { Border, Colour, Font, MediaQuery, Radius, Shadow } from \"../theme\";\n\nexport const tokens = {\n container: {\n top: \"--fds-internal-smartAppBanner-container-top\",\n },\n};\n\nexport const smartAppBannerContainer = css`\n display: flex;\n flex-direction: row-reverse;\n align-items: stretch;\n position: fixed;\n margin: 0.5rem 1.25rem;\n ${tokens.container.top}: initial;\n top: var(${tokens.container.top});\n left: 0;\n width: calc(100% - 2.5rem);\n min-height: 5.5rem;\n z-index: 9001;\n background: ${Colour.bg};\n border-radius: ${Radius.md};\n`;\n\nexport const smartAppBannerContainerLight = css`\n box-shadow: ${Shadow[\"md-subtle\"]};\n`;\n\nexport const smartAppBannerContainerDark = css`\n border: ${Border[\"width-010\"]} ${Border.solid} ${Colour.border};\n`;\n\nexport const smartAppBannerContainerAnimated = css`\n @keyframes smart-app-banner-slide-down {\n from {\n opacity: 0;\n transform: translateY(-20%);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n }\n animation: smart-app-banner-slide-down 0.3s;\n`;\n\nexport const dismissContainer = css`\n display: flex;\n align-items: center;\n padding: 0.5rem 0.25rem 0.5rem 1rem;\n`;\n\nexport const dismissButton = css`\n padding: 0;\n`;\n\nexport const cross = css`\n color: ${Colour.icon};\n height: 1.25rem;\n width: 1.25rem;\n`;\n\nexport const proceedContainer = css`\n flex: 1;\n display: flex;\n align-items: center;\n padding: 0.5rem 1rem 0.5rem 0.25rem;\n cursor: pointer;\n`;\n\nexport const textContainer = css`\n flex: 1;\n display: flex;\n flex-direction: column;\n align-items: left;\n margin: 0.5rem;\n ${MediaQuery.MaxWidth.xs} {\n margin: 0 0.5rem;\n }\n`;\n\nexport const bannerIcon = css`\n width: 2.65rem;\n height: auto;\n align-self: center;\n`;\n\nexport const buttonContainer = css`\n max-width: 30%;\n`;\n\nexport const button = css`\n padding: 0.5rem;\n & > span {\n overflow-wrap: anywhere;\n ${Font[\"body-xs-semibold\"]}\n }\n`;\n\nexport const title = css`\n font-weight: ${Font.Spec[\"weight-bold\"]};\n overflow-wrap: anywhere;\n ${MediaQuery.MaxWidth.xs} {\n ${Font[\"body-xs-bold\"]}\n }\n`;\n\nexport const description = css`\n overflow-wrap: anywhere;\n`;\n\nexport const ratingContainer = css`\n margin-top: 0.25rem;\n display: flex;\n align-items: center;\n`;\n\nexport const starIcon = css`\n height: 2rem;\n width: 2rem;\n padding-right: 0.25rem;\n color: #ffc107;\n`;\n"],"names":["tokens","container","top","smartAppBannerContainer","smartAppBannerContainerLight","smartAppBannerContainerDark","smartAppBannerContainerAnimated","dismissContainer","dismissButton","cross","proceedContainer","textContainer","bannerIcon","buttonContainer","button","title","description","ratingContainer","starIcon"],"mappings":"6EAIO,MAAMA,EAAS,CAClBC,UAAW,CACPC,IAAK,gDAIAC,EAAuB,UAgBvBC,EAA4B,WAI5BC,EAA2B,WAI3BC,EAA+B,UAc/BC,EAAgB,SAMhBC,EAAa,WAIbC,EAAK,UAMLC,EAAgB,UAQhBC,EAAa,UAWbC,EAAU,UAMVC,EAAe,WAIfC,EAAM,WAQNC,EAAK,UAQLC,EAAW,UAIXC,EAAe,WAMfC,EAAQ"}
|
package/smart-app-banner/{smart-app-banner.styles_15u6yv4.css → smart-app-banner.styles_r6yjq9.css}
RENAMED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
.t7s9qr2{-webkit-flex:1;-ms-flex:1;flex:1;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;-webkit-align-items:left;-webkit-box-align:left;-ms-flex-align:left;align-items:left;margin:0.5rem;}:where(body.fds-breakpoint-xs-max) .t7s9qr2{margin:0 0.5rem;}
|
|
10
10
|
.bece00m{width:2.65rem;height:auto;-webkit-align-self:center;-ms-flex-item-align:center;-ms-grid-row-align:center;align-self:center;}
|
|
11
11
|
.b1ti1r81{max-width:30%;}
|
|
12
|
-
.b1rqz1xr{padding:0.5rem;
|
|
12
|
+
.b1rqz1xr{padding:0.5rem;}.b1rqz1xr>span{overflow-wrap:anywhere;font-family:var(--fds-font-family-body);font-variant:var(--fds-font-variant);font-size:var(--fds-font-body-size-xs);font-weight:var(--fds-font-weight-semibold);line-height:var(--fds-font-body-lh-xs);letter-spacing:var(--fds-font-body-ls-xs);}
|
|
13
13
|
.tmo9z7m{font-weight:var(--fds-font-weight-bold);overflow-wrap:anywhere;}:where(body.fds-breakpoint-xs-max) .tmo9z7m{font-family:var(--fds-font-family-body);font-variant:var(--fds-font-variant);font-size:var(--fds-font-body-size-xs);font-weight:var(--fds-font-weight-bold);line-height:var(--fds-font-body-lh-xs);letter-spacing:var(--fds-font-body-ls-xs);}
|
|
14
14
|
.dp7x5g3{overflow-wrap:anywhere;}
|
|
15
15
|
.r1gggq6r{margin-top:0.25rem;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;}
|