@evolve.ui/core-components 1.1.0 → 1.2.0
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/{BottomSheet-ZV_eq3xt.mjs → BottomSheet-CNVLnEoD.mjs} +3 -3
- package/BottomSheet-CNVLnEoD.mjs.map +1 -0
- package/{BottomSheet-emWP9Fct.cjs → BottomSheet-D5w0WZDl.cjs} +3 -3
- package/BottomSheet-D5w0WZDl.cjs.map +1 -0
- package/Button.cjs +1 -1
- package/Button.mjs +1 -1
- package/{CookieConsent-CIwm0bTz.mjs → CookieConsent-B9dg9WdC.mjs} +2 -2
- package/{CookieConsent-CIwm0bTz.mjs.map → CookieConsent-B9dg9WdC.mjs.map} +1 -1
- package/{CookieConsent-PIglB_bb.cjs → CookieConsent-BSXJHMwX.cjs} +2 -2
- package/{CookieConsent-PIglB_bb.cjs.map → CookieConsent-BSXJHMwX.cjs.map} +1 -1
- package/{Drawer-9HFG45OA.cjs → Drawer-3rA9dGCl.cjs} +2 -2
- package/{Drawer-9HFG45OA.cjs.map → Drawer-3rA9dGCl.cjs.map} +1 -1
- package/Drawer-CFZbwg0R.d.cts.map +1 -1
- package/Drawer-CFZbwg0R.d.mts.map +1 -1
- package/{Drawer-BkCPfK6P.mjs → Drawer-DzKEmewj.mjs} +2 -2
- package/{Drawer-BkCPfK6P.mjs.map → Drawer-DzKEmewj.mjs.map} +1 -1
- package/{FavoriteButton-CC3qL0lR.mjs → FavoriteButton-7nK77lQP.mjs} +6 -6
- package/FavoriteButton-7nK77lQP.mjs.map +1 -0
- package/{FavoriteButton-BGF-3dze.d.cts → FavoriteButton-B8r_qtlj.d.cts} +2 -2
- package/{FavoriteButton-BGF-3dze.d.cts.map → FavoriteButton-B8r_qtlj.d.cts.map} +1 -1
- package/{FavoriteButton-DliYzkfu.cjs → FavoriteButton-BkIaWfgD.cjs} +6 -6
- package/FavoriteButton-BkIaWfgD.cjs.map +1 -0
- package/{FavoriteButton-BZEGWrRo.d.mts → FavoriteButton-hIkGjcKH.d.mts} +2 -2
- package/{FavoriteButton-BZEGWrRo.d.mts.map → FavoriteButton-hIkGjcKH.d.mts.map} +1 -1
- package/{FileUpload-p_pl9NXr.mjs → FileUpload-BfZOMsLs.mjs} +6 -6
- package/FileUpload-BfZOMsLs.mjs.map +1 -0
- package/{FileUpload--e_UJ_ek.cjs → FileUpload-gjRbkgrL.cjs} +6 -6
- package/FileUpload-gjRbkgrL.cjs.map +1 -0
- package/IconButton.cjs +1 -1
- package/IconButton.mjs +1 -1
- package/{ImageSlider-BidXfnLj.cjs → ImageSlider-CAgxQffP.cjs} +3 -3
- package/ImageSlider-CAgxQffP.cjs.map +1 -0
- package/{ImageSlider-CDrg_TbL.mjs → ImageSlider-fdrJ6lIJ.mjs} +3 -3
- package/ImageSlider-fdrJ6lIJ.mjs.map +1 -0
- package/InfoIconTooltip.cjs +1 -1
- package/InfoIconTooltip.cjs.map +1 -1
- package/InfoIconTooltip.mjs +1 -1
- package/InfoIconTooltip.mjs.map +1 -1
- package/InlineButton-CRLbNJZ3.d.mts.map +1 -1
- package/InlineButton-DoXGLiSE.d.cts.map +1 -1
- package/Input.cjs +1 -1
- package/Input.cjs.map +1 -1
- package/Input.mjs +1 -1
- package/Input.mjs.map +1 -1
- package/JumpMenu-BXYZnPIH.cjs.map +1 -1
- package/JumpMenu-DcZjAiej.mjs.map +1 -1
- package/{Menu-Cxu8CaX1.mjs → Menu-Bn4smlEe.mjs} +2 -2
- package/Menu-Bn4smlEe.mjs.map +1 -0
- package/{Menu-ClUogmwE.cjs → Menu-DuDhtoNP.cjs} +2 -2
- package/Menu-DuDhtoNP.cjs.map +1 -0
- package/Modal-DM0aXJZ5.d.cts.map +1 -1
- package/Modal-DM0aXJZ5.d.mts.map +1 -1
- package/{Modal-C6gatdtT.mjs → Modal-DtxWd7Le.mjs} +3 -2
- package/{Modal-C6gatdtT.mjs.map → Modal-DtxWd7Le.mjs.map} +1 -1
- package/{Modal-CiBqXyiK.cjs → Modal-q4HhBAQU.cjs} +3 -2
- package/Modal-q4HhBAQU.cjs.map +1 -0
- package/{Pagination-bAtbN478.cjs → Pagination-Denb9_zB.cjs} +2 -2
- package/{Pagination-bAtbN478.cjs.map → Pagination-Denb9_zB.cjs.map} +1 -1
- package/{Pagination-DIpGKMLz.mjs → Pagination-Dyfeys4B.mjs} +2 -2
- package/{Pagination-DIpGKMLz.mjs.map → Pagination-Dyfeys4B.mjs.map} +1 -1
- package/PhoneInput-B5pkpkdt.mjs.map +1 -1
- package/PhoneInput-BXnkBME4.d.mts.map +1 -1
- package/PhoneInput-Bkrbrins.d.cts.map +1 -1
- package/PhoneInput-CUMPOSxJ.cjs.map +1 -1
- package/{ProgressCircle-BC81D9sU.cjs → ProgressCircle-B6R4dxoV.cjs} +2 -2
- package/{ProgressCircle-BC81D9sU.cjs.map → ProgressCircle-B6R4dxoV.cjs.map} +1 -1
- package/{ProgressCircle-ae8cvZhe.mjs → ProgressCircle-zSai1HTT.mjs} +2 -2
- package/{ProgressCircle-ae8cvZhe.mjs.map → ProgressCircle-zSai1HTT.mjs.map} +1 -1
- package/SearchInput-DYIPC8Cd.d.cts.map +1 -1
- package/SearchInput-IfEWePDQ.d.mts.map +1 -1
- package/{Select-BkZu8OLs.mjs → Select-CH_ZN88G.mjs} +2 -2
- package/Select-CH_ZN88G.mjs.map +1 -0
- package/{Select-BXDjzyDs.cjs → Select-DCCcyLT4.cjs} +2 -2
- package/Select-DCCcyLT4.cjs.map +1 -0
- package/{SplitButton-DcmmLW8j.cjs → SplitButton-B_Y253RU.cjs} +2 -2
- package/{SplitButton-DcmmLW8j.cjs.map → SplitButton-B_Y253RU.cjs.map} +1 -1
- package/{SplitButton-WE5ymwCQ.mjs → SplitButton-_poP9Ykq.mjs} +2 -2
- package/{SplitButton-WE5ymwCQ.mjs.map → SplitButton-_poP9Ykq.mjs.map} +1 -1
- package/{Table-M-rANdMt.mjs → Table-CQGtDpvH.mjs} +3 -3
- package/{Table-M-rANdMt.mjs.map → Table-CQGtDpvH.mjs.map} +1 -1
- package/{Table-CLlDragJ.cjs → Table-D4UYosb1.cjs} +3 -3
- package/{Table-CLlDragJ.cjs.map → Table-D4UYosb1.cjs.map} +1 -1
- package/Typography/InlineButton.cjs +1 -1
- package/Typography/InlineButton.cjs.map +1 -1
- package/Typography/InlineButton.mjs +1 -1
- package/Typography/InlineButton.mjs.map +1 -1
- package/{ViewMore-BBoUvo7p.cjs → ViewMore-BcoSRZSl.cjs} +14 -1
- package/ViewMore-BcoSRZSl.cjs.map +1 -0
- package/{ViewMore-BrZPuE4E.mjs → ViewMore-Be0TQZ_2.mjs} +14 -1
- package/ViewMore-Be0TQZ_2.mjs.map +1 -0
- package/bottomSheet.cjs +1 -1
- package/bottomSheet.mjs +1 -1
- package/{buttonColorClasses-C3hg1at8.cjs → buttonColorClasses-CQQmLYfk.cjs} +4 -4
- package/buttonColorClasses-CQQmLYfk.cjs.map +1 -0
- package/{buttonColorClasses-B7OU4aQA.mjs → buttonColorClasses-CQnqAJXl.mjs} +4 -4
- package/buttonColorClasses-CQnqAJXl.mjs.map +1 -0
- package/card/components/createFavoriteButton.cjs +1 -1
- package/card/components/createFavoriteButton.mjs +1 -1
- package/cookieConsent.cjs +1 -1
- package/cookieConsent.mjs +1 -1
- package/drawer.cjs +1 -1
- package/drawer.mjs +1 -1
- package/favoriteButton.cjs +1 -1
- package/favoriteButton.d.cts +1 -1
- package/favoriteButton.d.mts +1 -1
- package/favoriteButton.mjs +1 -1
- package/featureFlags/hooks.d.cts +1 -1
- package/featureFlags/hooks.d.mts +1 -1
- package/fileUpload/testUtils/mockFilesAndImages.d.cts +3 -3
- package/fileUpload/testUtils/mockFilesAndImages.d.cts.map +1 -1
- package/fileUpload/testUtils/mockFilesAndImages.d.mts +3 -3
- package/fileUpload/testUtils/mockFilesAndImages.d.mts.map +1 -1
- package/fileUpload/testUtils/testUtils.d.cts +1 -1
- package/fileUpload/testUtils/testUtils.d.cts.map +1 -1
- package/fileUpload/testUtils/testUtils.d.mts +1 -1
- package/fileUpload/testUtils/testUtils.d.mts.map +1 -1
- package/fileUpload.cjs +1 -1
- package/fileUpload.mjs +1 -1
- package/imageSlider.cjs +1 -1
- package/imageSlider.mjs +1 -1
- package/index.cjs +14 -14
- package/index.d.cts +1 -1
- package/index.d.mts +1 -1
- package/index.mjs +14 -14
- package/menu.cjs +1 -1
- package/menu.mjs +1 -1
- package/modal/useCloseModal.cjs +2 -1
- package/modal/useCloseModal.cjs.map +1 -1
- package/modal/useCloseModal.mjs +2 -1
- package/modal/useCloseModal.mjs.map +1 -1
- package/modal.cjs +1 -1
- package/modal.mjs +1 -1
- package/package.json +2 -4
- package/pagination.cjs +1 -1
- package/pagination.mjs +1 -1
- package/progressCircle.cjs +1 -1
- package/progressCircle.mjs +1 -1
- package/searchInput.cjs +4 -4
- package/searchInput.cjs.map +1 -1
- package/searchInput.mjs +4 -4
- package/searchInput.mjs.map +1 -1
- package/select.cjs +1 -1
- package/select.mjs +1 -1
- package/selectAsync.cjs +1 -1
- package/selectAsync.mjs +1 -1
- package/selectAsyncCreatable.cjs +1 -1
- package/selectAsyncCreatable.mjs +1 -1
- package/selectCreatable.cjs +1 -1
- package/selectCreatable.mjs +1 -1
- package/splitButton.cjs +1 -1
- package/splitButton.mjs +1 -1
- package/src/BottomSheet/components/BottomSheetContentArea/BottomSheetContentArea.tsx +4 -3
- package/src/BottomSheet/components/BottomSheetOverlay/BottomSheetOverlayTranslate3d.tsx +5 -2
- package/src/Button/buttonColorClasses.ts +8 -3
- package/src/Drawer/Drawer.tsx +5 -8
- package/src/FavoriteButton/components/IconOnlyFavoriteButton/IconOnlyFavoriteButton.tsx +4 -1
- package/src/FavoriteButton/components/LabeledAnimatedFavoriteButton/LabeledAnimatedFavoriteButton.tsx +13 -6
- package/src/FavoriteButton/types/favoriteButton.ts +1 -1
- package/src/FileUpload/components/GridFileCard/GridFileCard.tsx +1 -1
- package/src/FileUpload/components/ListFileCard/ListFileCard.tsx +2 -2
- package/src/ImageSlider/ImageSlider.tsx +3 -1
- package/src/ImageSlider/components/Thumbnails/Thumbnails.tsx +1 -1
- package/src/JumpMenu/components/JumpMenuItem/JumpMenuItem.tsx +4 -1
- package/src/Menu/components/MenuItem/MenuItem.tsx +1 -1
- package/src/Modal/ComposableModal.tsx +9 -1
- package/src/Modal/hooks/useCloseModal.ts +8 -1
- package/src/PhoneInput/PhoneInput.tsx +7 -1
- package/src/ProgressCircle/ProgressCircle.tsx +1 -1
- package/src/SearchInput/SearchInput.tsx +5 -4
- package/src/Select/selectComponents.tsx +1 -2
- package/src/Tabs/Tabs.tsx +4 -4
- package/src/TextArea/TextArea.tsx +2 -0
- package/src/TextInput/TextInput.tsx +1 -1
- package/src/Tooltip/InfoIconTooltip.tsx +1 -1
- package/src/Typography/InlineButton/InlineButton.tsx +4 -3
- package/src/utils/smoothScrollTo.ts +18 -0
- package/table.cjs +1 -1
- package/table.mjs +1 -1
- package/tabs.cjs +1 -1
- package/tabs.cjs.map +1 -1
- package/tabs.mjs +1 -1
- package/tabs.mjs.map +1 -1
- package/textArea.cjs.map +1 -1
- package/textArea.mjs.map +1 -1
- package/viewMore.cjs +1 -1
- package/viewMore.mjs +1 -1
- package/BottomSheet-ZV_eq3xt.mjs.map +0 -1
- package/BottomSheet-emWP9Fct.cjs.map +0 -1
- package/FavoriteButton-CC3qL0lR.mjs.map +0 -1
- package/FavoriteButton-DliYzkfu.cjs.map +0 -1
- package/FileUpload--e_UJ_ek.cjs.map +0 -1
- package/FileUpload-p_pl9NXr.mjs.map +0 -1
- package/ImageSlider-BidXfnLj.cjs.map +0 -1
- package/ImageSlider-CDrg_TbL.mjs.map +0 -1
- package/Menu-ClUogmwE.cjs.map +0 -1
- package/Menu-Cxu8CaX1.mjs.map +0 -1
- package/Modal-CiBqXyiK.cjs.map +0 -1
- package/Select-BXDjzyDs.cjs.map +0 -1
- package/Select-BkZu8OLs.mjs.map +0 -1
- package/ViewMore-BBoUvo7p.cjs.map +0 -1
- package/ViewMore-BrZPuE4E.mjs.map +0 -1
- package/buttonColorClasses-B7OU4aQA.mjs.map +0 -1
- package/buttonColorClasses-C3hg1at8.cjs.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CookieConsent-PIglB_bb.cjs","names":["BodySecondary","InlineButton","Button","LabelStrong","BodySecondary","ToggleSwitch","Caption","Modal","CloseButton","ModalHeader","H2","ModalContent","BodySecondary","ModalActions","Button"],"sources":["../src/CookieConsent/types/cookieConsent.types.ts","../src/CookieConsent/hooks/useCookieConsent.ts","../src/CookieConsent/hooks/useCookieConsentState.ts","../src/CookieConsent/components/CookieConsentBanner/CookieConsentBanner.tsx","../src/CookieConsent/components/CookieCategoryRow/CookieCategoryRow.tsx","../src/CookieConsent/components/CookieConsentModal/CookieConsentModal.tsx","../src/CookieConsent/components/CookieConsent/CookieConsent.tsx"],"sourcesContent":["/**\n * The three non-essential consent categories managed by this component.\n * `necessary` is excluded because it's always implicitly granted.\n */\nexport type ConsentCategories = {\n marketing: boolean;\n preferences: boolean;\n statistics: boolean;\n};\n\n/** Full consent payload including the always-on `necessary` flag. */\nexport type ConsentPayload = ConsentCategories & { necessary: true };\n\n/** Where the user interaction originated. */\nexport enum ConsentSource {\n Banner = 'banner',\n Modal = 'modal',\n}\n\n/** Tracking callbacks for cookie consent analytics. */\nexport type CookieConsentTracking = {\n onBannerViewed?: () => void;\n onPreferencesDismissed?: (source: ConsentSource) => void;\n onPreferencesOpened?: (source: ConsentSource) => void;\n onPreferencesSaved?: (payload: { consent: ConsentPayload; source: ConsentSource }) => void;\n};\n\n/** Params for the useCookieConsentState hook. */\nexport type UseCookieConsentStateParams = {\n /**\n * Controlled consent state. When provided, an external consent-management\n * platform owns the consent state and internal localStorage persistence is\n * bypassed — sync changes back through `onConsentChange`.\n */\n consent?: ConsentCategories;\n onConsentChange?: (consent: ConsentCategories) => void;\n /** localStorage key used to persist consent in uncontrolled mode. */\n storageKey?: string;\n toastMessage: string;\n tracking?: CookieConsentTracking;\n};\n\n/** Definition for a single row in the preferences modal. */\nexport type CookieCategoryConfig = {\n description: string;\n /** Must match a `ConsentCategories` key, or `'necessary'` for the always-on row. */\n key: keyof ConsentCategories | 'necessary';\n label: string;\n /** When `true`, the toggle is locked on and the user cannot opt out. */\n required?: boolean;\n};\n\nexport const DEFAULT_COOKIE_CATEGORIES: CookieCategoryConfig[] = [\n {\n description:\n 'Necessary cookies help make a website usable by enabling basic functions like page navigation and access to secure areas of the website. The website cannot function properly without these cookies.',\n key: 'necessary',\n label: 'Necessary',\n required: true,\n },\n {\n description:\n 'Preference cookies enable a website to remember information that changes the way the website behaves or looks, like your preferred language or the region that you are in.',\n key: 'preferences',\n label: 'Preferences',\n },\n {\n description:\n 'Statistics cookies help website owners to understand how visitors interact with websites by collecting and reporting information anonymously.',\n key: 'statistics',\n label: 'Statistics',\n },\n {\n description:\n 'Marketing cookies are used to track visitors across websites. The intention is to display ads that are relevant and engaging for the individual user and thereby more valuable for publishers and third party advertisers.',\n key: 'marketing',\n label: 'Marketing',\n },\n];\n","import { useCallback, useEffect, useState } from 'react';\n\nimport type { ConsentCategories, ConsentPayload } from '../types/cookieConsent.types';\n\nexport const DEFAULT_CONSENT_STORAGE_KEY = 'hui-cookie-consent';\n\nconst DEFAULT_CONSENT: ConsentCategories = {\n marketing: false,\n preferences: false,\n statistics: false,\n};\n\n/**\n * Reads a previously persisted consent payload from localStorage.\n * Returns `undefined` during SSR, when nothing is stored, or when the stored\n * value is corrupt/unparseable (corrupt values are treated as \"no response yet\"\n * so the banner shows again rather than trusting bad data).\n */\nconst readStoredConsent = (storageKey: string): ConsentCategories | undefined => {\n /* istanbul ignore next -- @preserve: SSR guard; a React test renderer always runs with a defined `window`, so this branch is unreachable under jest/jsdom. */\n if (typeof window === 'undefined') {\n return undefined;\n }\n\n let raw: string | null = null;\n try {\n raw = window.localStorage.getItem(storageKey);\n } catch {\n // localStorage can throw (e.g. disabled in the browser) — treat as no response.\n return undefined;\n }\n\n if (!raw) {\n return undefined;\n }\n\n try {\n const parsed: unknown = JSON.parse(raw);\n if (\n typeof parsed === 'object' &&\n parsed !== null &&\n typeof (parsed as ConsentPayload).marketing === 'boolean' &&\n typeof (parsed as ConsentPayload).preferences === 'boolean' &&\n typeof (parsed as ConsentPayload).statistics === 'boolean'\n ) {\n const payload = parsed as ConsentPayload;\n return {\n marketing: payload.marketing,\n preferences: payload.preferences,\n statistics: payload.statistics,\n };\n }\n } catch {\n // Corrupt JSON — fall through to undefined.\n }\n\n return undefined;\n};\n\n/**\n * Persists a consent payload to localStorage. No-ops during SSR or when\n * localStorage is unavailable.\n */\nconst writeStoredConsent = (storageKey: string, categories: ConsentCategories) => {\n /* istanbul ignore next -- @preserve: SSR guard; consent writes are user-triggered client-side actions and a React test renderer always has a defined `window`, so this branch is unreachable under jest/jsdom. */\n if (typeof window === 'undefined') {\n return;\n }\n\n const payload: ConsentPayload = { ...categories, necessary: true };\n\n try {\n window.localStorage.setItem(storageKey, JSON.stringify(payload));\n } catch {\n // localStorage unavailable — consent still applies for this session via state.\n }\n};\n\n/** Params for the useCookieConsent hook. */\nexport type UseCookieConsentParams = {\n /**\n * Controlled consent state. When provided, an external consent-management\n * platform (CMP) owns the consent state: internal localStorage persistence\n * is bypassed, the banner is never auto-shown, and consent reads reflect\n * this value. Sync user changes back to the CMP via the component's\n * `onConsentChange` callback.\n */\n consent?: ConsentCategories;\n /** localStorage key used to persist consent in uncontrolled mode. */\n storageKey?: string;\n};\n\n/**\n * Low-level consent engine backed by localStorage.\n *\n * Uncontrolled (default) mode: on mount, reads any previously saved consent\n * from localStorage. The banner is visible if and only if no stored consent\n * exists. Action helpers (`acceptAll`, `declineAll`, `submitConsent`) persist\n * the new consent payload and hide the banner.\n *\n * Controlled mode (`consent` param provided): an external CMP owns the state —\n * nothing is read from or written to localStorage and the banner is never\n * auto-shown; the preferences modal remains reachable via\n * `CookieConsentHandle.openModal()`.\n *\n * Exposes `isBannerVisible`, current `consent` state, `hasResponse` (whether\n * the user has already responded), and the action helpers.\n */\nexport const useCookieConsent = ({\n consent: controlledConsent,\n storageKey = DEFAULT_CONSENT_STORAGE_KEY,\n}: UseCookieConsentParams = {}) => {\n const isControlled = controlledConsent !== undefined;\n\n const [isBannerVisible, setIsBannerVisible] = useState(false);\n const [internalConsent, setInternalConsent] = useState<ConsentCategories>(DEFAULT_CONSENT);\n const [hasStoredResponse, setHasStoredResponse] = useState(false);\n\n useEffect(() => {\n if (isControlled) {\n return;\n }\n\n const stored = readStoredConsent(storageKey);\n if (stored) {\n setInternalConsent(stored);\n setHasStoredResponse(true);\n setIsBannerVisible(false);\n } else {\n setIsBannerVisible(true);\n }\n }, [isControlled, storageKey]);\n\n const applyConsent = useCallback(\n (categories: ConsentCategories) => {\n if (!isControlled) {\n writeStoredConsent(storageKey, categories);\n }\n setInternalConsent(categories);\n setHasStoredResponse(true);\n setIsBannerVisible(false);\n },\n [isControlled, storageKey]\n );\n\n const acceptAll = useCallback(() => {\n applyConsent({ marketing: true, preferences: true, statistics: true });\n }, [applyConsent]);\n\n const declineAll = useCallback(() => {\n applyConsent(DEFAULT_CONSENT);\n }, [applyConsent]);\n\n const submitConsent = useCallback(\n (categories: ConsentCategories) => {\n applyConsent(categories);\n },\n [applyConsent]\n );\n\n return {\n acceptAll,\n consent: isControlled ? controlledConsent : internalConsent,\n declineAll,\n /** Whether the user has already responded (controlled mode counts as responded). */\n hasResponse: isControlled || hasStoredResponse,\n isBannerVisible,\n submitConsent,\n };\n};\n","import { AnimationEvent, useCallback, useEffect, useRef, useState } from 'react';\n\nimport { toast } from '../../Toast';\nimport {\n ConsentCategories,\n ConsentPayload,\n ConsentSource,\n UseCookieConsentStateParams,\n} from '../types/cookieConsent.types';\nimport { useCookieConsent } from './useCookieConsent';\n\nconst DEFAULT_LOCAL_CONSENT: ConsentCategories = {\n marketing: true,\n preferences: true,\n statistics: true,\n};\n\nconst buildConsentPayload = (consent: ConsentCategories): ConsentPayload => ({\n ...consent,\n necessary: true,\n});\n\n/**\n * UI state manager for the CookieConsent component.\n *\n * Wraps `useCookieConsent` and owns banner/modal visibility, local consent\n * toggle state, and all user interaction handlers (OK, save, toggle, open/close).\n *\n * Modal toggles default to all-ON (`DEFAULT_LOCAL_CONSENT`). When opening the\n * modal, existing consent is read from the consent engine only if the user has\n * already responded — before a response, consent initializes as all `false`,\n * so we fall back to the all-ON default.\n */\nexport const useCookieConsentState = ({\n consent: controlledConsent,\n onConsentChange,\n storageKey,\n toastMessage,\n tracking,\n}: UseCookieConsentStateParams) => {\n const { acceptAll, consent, hasResponse, isBannerVisible, submitConsent } = useCookieConsent({\n consent: controlledConsent,\n storageKey,\n });\n const trackingRef = useRef(tracking);\n trackingRef.current = tracking;\n\n const [showBanner, setShowBanner] = useState(false);\n const [bannerExiting, setBannerExiting] = useState(false);\n const [showDialog, setShowDialog] = useState(false);\n const [localConsent, setLocalConsent] = useState(DEFAULT_LOCAL_CONSENT);\n\n const readCurrentConsent = useCallback(\n (): ConsentCategories => (hasResponse ? consent : DEFAULT_LOCAL_CONSENT),\n [consent, hasResponse]\n );\n\n useEffect(() => {\n if (isBannerVisible) {\n setShowBanner(true);\n setBannerExiting(false);\n trackingRef.current?.onBannerViewed?.();\n }\n }, [isBannerVisible]);\n\n const openModal = useCallback(() => {\n setLocalConsent(readCurrentConsent());\n setShowDialog(true);\n }, [readCurrentConsent]);\n\n const handleBannerAnimationEnd = useCallback(\n (e: AnimationEvent<HTMLDivElement>) => {\n /* istanbul ignore next -- @preserve: `bannerExiting` is only ever set to false in this hook (faithful hammer parity), so the exit-animation cleanup branch is unreachable. Reported as latent dead code, not modified to preserve parity. */\n if (bannerExiting && e.target === e.currentTarget) {\n setShowBanner(false);\n setBannerExiting(false);\n }\n },\n [bannerExiting]\n );\n\n const openDialog = useCallback(() => {\n setLocalConsent(readCurrentConsent());\n setShowDialog(true);\n setShowBanner(false);\n setBannerExiting(false);\n trackingRef.current?.onPreferencesOpened?.(ConsentSource.Banner);\n }, [readCurrentConsent]);\n\n const closeDialog = useCallback(() => {\n setShowDialog(false);\n trackingRef.current?.onPreferencesDismissed?.(ConsentSource.Modal);\n if (isBannerVisible) {\n setShowBanner(true);\n setBannerExiting(false);\n }\n }, [isBannerVisible]);\n\n const handleOk = useCallback(() => {\n const allConsent: ConsentCategories = { marketing: true, preferences: true, statistics: true };\n acceptAll();\n onConsentChange?.(allConsent);\n setShowBanner(false);\n setBannerExiting(false);\n toast('success', { title: toastMessage });\n trackingRef.current?.onPreferencesSaved?.({\n consent: buildConsentPayload(allConsent),\n source: ConsentSource.Banner,\n });\n }, [acceptAll, onConsentChange, toastMessage]);\n\n const handleSavePreferences = useCallback(() => {\n submitConsent(localConsent);\n onConsentChange?.(localConsent);\n setShowDialog(false);\n setShowBanner(false);\n setBannerExiting(false);\n toast('success', { title: toastMessage });\n trackingRef.current?.onPreferencesSaved?.({\n consent: buildConsentPayload(localConsent),\n source: ConsentSource.Modal,\n });\n }, [localConsent, onConsentChange, submitConsent, toastMessage]);\n\n const handleToggle = useCallback((key: keyof ConsentCategories) => {\n setLocalConsent((prev) => ({ ...prev, [key]: !prev[key] }));\n }, []);\n\n return {\n bannerExiting,\n closeDialog,\n handleBannerAnimationEnd,\n handleOk,\n handleSavePreferences,\n handleToggle,\n localConsent,\n openDialog,\n openModal,\n showBanner,\n showDialog,\n };\n};\n","import { cn } from '@evolve.ui/theme-system';\nimport { AnimationEvent, memo } from 'react';\n\nimport { Button } from '../../../Button/Button';\nimport { InlineButton } from '../../../Typography/InlineButton/InlineButton';\nimport { BodySecondary } from '../../../Typography/Text/Text';\n\ntype Props = {\n isExiting: boolean;\n onAnimationEnd: (e: AnimationEvent<HTMLDivElement>) => void;\n onDismiss: () => void;\n onOpenPreferences: () => void;\n};\n\nexport const CookieConsentBanner = memo(({ isExiting, onAnimationEnd, onDismiss, onOpenPreferences }: Props) => (\n <div\n aria-label=\"Cookie consent\"\n className={cn(\n 'fixed inset-x-0 bottom-md z-[10300] mx-auto w-[calc(100%-48px)] max-w-[1200px] rounded-md border border-border-secondary bg-background-tertiary shadow-01',\n isExiting ? 'animate-slideDown' : 'animate-slideUp'\n )}\n onAnimationEnd={onAnimationEnd}\n role=\"region\"\n >\n <div className=\"flex flex-col gap-xs p-sm smMin:flex-row smMin:items-center smMin:gap-md smMin:p-md\">\n <div className=\"min-w-0 flex-1\">\n <BodySecondary className=\"inline\">\n We use cookies to improve your experience, to analyze website usage, and for marketing purposes.\n </BodySecondary>\n <InlineButton\n className=\"ml-2xs inline text-text-primary underline\"\n onClick={onOpenPreferences}\n size=\"sm\"\n >\n Cookie preferences\n </InlineButton>\n </div>\n <div className=\"shrink-0 self-end smMin:self-auto\">\n <Button\n className=\"min-w-[96px]\"\n onClick={onDismiss}\n size=\"sm\"\n style=\"neutral\"\n variant=\"outlined\"\n >\n OK\n </Button>\n </div>\n </div>\n </div>\n));\n","import { memo } from 'react';\n\nimport { ToggleSwitch } from '../../../ToggleSwitch/ToggleSwitch';\nimport { BodySecondary, Caption, LabelStrong } from '../../../Typography/Text/Text';\n\ntype Props = {\n description: string;\n isToggled: boolean;\n label: string;\n onToggleChange?: () => void;\n required?: boolean;\n};\n\nexport const CookieCategoryRow = memo(({ description, isToggled, label, onToggleChange, required }: Props) => (\n <div className=\"flex flex-col gap-2xs border-b border-border-secondary py-sm\">\n <div className=\"flex h-[22px] items-center justify-between\">\n <LabelStrong>{label}</LabelStrong>\n {required ? (\n <BodySecondary className=\"text-text-primary\">Required</BodySecondary>\n ) : (\n <ToggleSwitch\n aria-label={label}\n isToggled={isToggled}\n onToggleChange={onToggleChange}\n />\n )}\n </div>\n <Caption className=\"text-text-secondary\">{description}</Caption>\n </div>\n));\n","import { memo } from 'react';\n\nimport { Button } from '../../../Button/Button';\nimport { CloseButton, ModalActions, ModalContent, ModalHeader } from '../../../Modal/components';\nimport { Modal } from '../../../Modal/Modal';\nimport { BodySecondary, H2 } from '../../../Typography/Text/Text';\nimport { ConsentCategories, CookieCategoryConfig, DEFAULT_COOKIE_CATEGORIES } from '../../types/cookieConsent.types';\nimport { CookieCategoryRow } from '../CookieCategoryRow/CookieCategoryRow';\n\ntype Props = {\n categories?: CookieCategoryConfig[];\n localConsent: ConsentCategories;\n onClose: () => void;\n onSave: () => void;\n onToggle: (key: keyof ConsentCategories) => void;\n show: boolean;\n};\n\nexport const CookieConsentModal = memo(\n ({ categories = DEFAULT_COOKIE_CATEGORIES, localConsent, onClose, onSave, onToggle, show }: Props) => (\n <Modal\n className=\"max-w-[588px]\"\n handleClose={onClose}\n show={show}\n type=\"composable\"\n >\n <CloseButton />\n <ModalHeader>\n <H2>Cookie Preferences</H2>\n </ModalHeader>\n <ModalContent className=\"max-w-460px pb-sm\">\n <BodySecondary className=\"mb-sm\">\n Our platform uses various types of cookies, each of which has a specific function. Manage your\n preferences below:\n </BodySecondary>\n <div className=\"border-b border-border-secondary pb-sm\"></div>\n <div className=\"flex flex-col\">\n {categories.map((cat) => (\n <CookieCategoryRow\n description={cat.description}\n isToggled={cat.required ? true : localConsent[cat.key as keyof ConsentCategories]}\n key={cat.key}\n label={cat.label}\n onToggleChange={\n cat.required ? undefined : () => onToggle(cat.key as keyof ConsentCategories)\n }\n required={cat.required}\n />\n ))}\n </div>\n </ModalContent>\n <ModalActions>\n <Button\n onClick={onSave}\n size=\"md\"\n style=\"primary\"\n variant=\"filled\"\n >\n SAVE PREFERENCES\n </Button>\n </ModalActions>\n </Modal>\n )\n);\n","import { forwardRef, useImperativeHandle } from 'react';\n\nimport type { ConsentCategories, CookieCategoryConfig, CookieConsentTracking } from '../../types/cookieConsent.types';\n\nimport { useCookieConsentState } from '../../hooks/useCookieConsentState';\nimport { CookieConsentBanner } from '../CookieConsentBanner/CookieConsentBanner';\nimport { CookieConsentModal } from '../CookieConsentModal/CookieConsentModal';\n\nconst DEFAULT_TOAST_MESSAGE = 'Your privacy preferences have been saved.';\n\ntype Props = {\n categories?: CookieCategoryConfig[];\n /**\n * Controlled consent state. When provided, an external consent-management\n * platform (CMP) owns the consent state: internal localStorage persistence\n * is bypassed and the banner is never auto-shown. Sync user changes back to\n * the CMP via `onConsentChange`.\n */\n consent?: ConsentCategories;\n onConsentChange?: (consent: ConsentCategories) => void;\n /** localStorage key used to persist consent in uncontrolled mode (default `'hui-cookie-consent'`). */\n storageKey?: string;\n toastMessage?: string;\n tracking?: CookieConsentTracking;\n};\n\nexport type CookieConsentHandle = {\n openModal: () => void;\n};\n\n/**\n * Custom cookie consent UI (banner + preferences modal).\n *\n * Renders the consent banner and modal. By default consent is persisted to\n * localStorage via `useCookieConsentState`; pass the `consent` prop to let an\n * external consent-management platform own the state instead. Exposes\n * `openModal()` through a ref for programmatic access (e.g. footer\n * \"Cookie Preferences\" link).\n */\nexport const CookieConsent = forwardRef<CookieConsentHandle, Props>(\n (\n { categories, consent, onConsentChange, storageKey, toastMessage = DEFAULT_TOAST_MESSAGE, tracking } = {},\n ref\n ) => {\n const state = useCookieConsentState({ consent, onConsentChange, storageKey, toastMessage, tracking });\n\n useImperativeHandle(ref, () => ({ openModal: state.openModal }), [state.openModal]);\n\n if (!state.showBanner && !state.showDialog) {\n return null;\n }\n\n return (\n <>\n {state.showBanner && (\n <CookieConsentBanner\n isExiting={state.bannerExiting}\n onAnimationEnd={state.handleBannerAnimationEnd}\n onDismiss={state.handleOk}\n onOpenPreferences={state.openDialog}\n />\n )}\n <CookieConsentModal\n categories={categories}\n localConsent={state.localConsent}\n onClose={state.closeDialog}\n onSave={state.handleSavePreferences}\n onToggle={state.handleToggle}\n show={state.showDialog}\n />\n </>\n );\n }\n);\n"],"mappings":";;;;;;;;;;;;AAcA,IAAY,gBAAL,yBAAA,eAAA;CACH,cAAA,YAAA;CACA,cAAA,WAAA;;AACJ,EAAA,CAAA,CAAA;AAmCA,MAAa,4BAAoD;CAC7D;EACI,aACI;EACJ,KAAK;EACL,OAAO;EACP,UAAU;CACd;CACA;EACI,aACI;EACJ,KAAK;EACL,OAAO;CACX;CACA;EACI,aACI;EACJ,KAAK;EACL,OAAO;CACX;CACA;EACI,aACI;EACJ,KAAK;EACL,OAAO;CACX;AACJ;;;AC1EA,MAAa,8BAA8B;AAE3C,MAAM,kBAAqC;CACvC,WAAW;CACX,aAAa;CACb,YAAY;AAChB;;;;;;;AAQA,MAAM,qBAAqB,eAAsD;;CAE7E,IAAI,OAAO,WAAW,aAClB;CAGJ,IAAI,MAAqB;CACzB,IAAI;EACA,MAAM,OAAO,aAAa,QAAQ,UAAU;CAChD,QAAQ;EAEJ;CACJ;CAEA,IAAI,CAAC,KACD;CAGJ,IAAI;EACA,MAAM,SAAkB,KAAK,MAAM,GAAG;EACtC,IACI,OAAO,WAAW,YAClB,WAAW,QACX,OAAQ,OAA0B,cAAc,aAChD,OAAQ,OAA0B,gBAAgB,aAClD,OAAQ,OAA0B,eAAe,WACnD;GACE,MAAM,UAAU;GAChB,OAAO;IACH,WAAW,QAAQ;IACnB,aAAa,QAAQ;IACrB,YAAY,QAAQ;GACxB;EACJ;CACJ,QAAQ,CAER;AAGJ;;;;;AAMA,MAAM,sBAAsB,YAAoB,eAAkC;;CAE9E,IAAI,OAAO,WAAW,aAClB;CAGJ,MAAM,UAA0B;EAAE,GAAG;EAAY,WAAW;CAAK;CAEjE,IAAI;EACA,OAAO,aAAa,QAAQ,YAAY,KAAK,UAAU,OAAO,CAAC;CACnE,QAAQ,CAER;AACJ;;;;;;;;;;;;;;;;;AAgCA,MAAa,oBAAoB,EAC7B,SAAS,mBACT,aAAa,gCACW,CAAC,MAAM;CAC/B,MAAM,eAAe,sBAAsB,KAAA;CAE3C,MAAM,CAAC,iBAAiB,uBAAA,GAAA,MAAA,SAAA,CAA+B,KAAK;CAC5D,MAAM,CAAC,iBAAiB,uBAAA,GAAA,MAAA,SAAA,CAAkD,eAAe;CACzF,MAAM,CAAC,mBAAmB,yBAAA,GAAA,MAAA,SAAA,CAAiC,KAAK;CAEhE,CAAA,GAAA,MAAA,UAAA,OAAgB;EACZ,IAAI,cACA;EAGJ,MAAM,SAAS,kBAAkB,UAAU;EAC3C,IAAI,QAAQ;GACR,mBAAmB,MAAM;GACzB,qBAAqB,IAAI;GACzB,mBAAmB,KAAK;EAC5B,OACI,mBAAmB,IAAI;CAE/B,GAAG,CAAC,cAAc,UAAU,CAAC;CAE7B,MAAM,gBAAA,GAAA,MAAA,YAAA,EACD,eAAkC;EAC/B,IAAI,CAAC,cACD,mBAAmB,YAAY,UAAU;EAE7C,mBAAmB,UAAU;EAC7B,qBAAqB,IAAI;EACzB,mBAAmB,KAAK;CAC5B,GACA,CAAC,cAAc,UAAU,CAC7B;CAEA,MAAM,aAAA,GAAA,MAAA,YAAA,OAA8B;EAChC,aAAa;GAAE,WAAW;GAAM,aAAa;GAAM,YAAY;EAAK,CAAC;CACzE,GAAG,CAAC,YAAY,CAAC;CAEjB,MAAM,cAAA,GAAA,MAAA,YAAA,OAA+B;EACjC,aAAa,eAAe;CAChC,GAAG,CAAC,YAAY,CAAC;CAEjB,MAAM,iBAAA,GAAA,MAAA,YAAA,EACD,eAAkC;EAC/B,aAAa,UAAU;CAC3B,GACA,CAAC,YAAY,CACjB;CAEA,OAAO;EACH;EACA,SAAS,eAAe,oBAAoB;EAC5C;;EAEA,aAAa,gBAAgB;EAC7B;EACA;CACJ;AACJ;;;AC9JA,MAAM,wBAA2C;CAC7C,WAAW;CACX,aAAa;CACb,YAAY;AAChB;AAEA,MAAM,uBAAuB,aAAgD;CACzE,GAAG;CACH,WAAW;AACf;;;;;;;;;;;;AAaA,MAAa,yBAAyB,EAClC,SAAS,mBACT,iBACA,YACA,cACA,eAC+B;CAC/B,MAAM,EAAE,WAAW,SAAS,aAAa,iBAAiB,kBAAkB,iBAAiB;EACzF,SAAS;EACT;CACJ,CAAC;CACD,MAAM,eAAA,GAAA,MAAA,OAAA,CAAqB,QAAQ;CACnC,YAAY,UAAU;CAEtB,MAAM,CAAC,YAAY,kBAAA,GAAA,MAAA,SAAA,CAA0B,KAAK;CAClD,MAAM,CAAC,eAAe,qBAAA,GAAA,MAAA,SAAA,CAA6B,KAAK;CACxD,MAAM,CAAC,YAAY,kBAAA,GAAA,MAAA,SAAA,CAA0B,KAAK;CAClD,MAAM,CAAC,cAAc,oBAAA,GAAA,MAAA,SAAA,CAA4B,qBAAqB;CAEtE,MAAM,sBAAA,GAAA,MAAA,YAAA,OACwB,cAAc,UAAU,uBAClD,CAAC,SAAS,WAAW,CACzB;CAEA,CAAA,GAAA,MAAA,UAAA,OAAgB;EACZ,IAAI,iBAAiB;GACjB,cAAc,IAAI;GAClB,iBAAiB,KAAK;GACtB,YAAY,SAAS,iBAAiB;EAC1C;CACJ,GAAG,CAAC,eAAe,CAAC;CAEpB,MAAM,aAAA,GAAA,MAAA,YAAA,OAA8B;EAChC,gBAAgB,mBAAmB,CAAC;EACpC,cAAc,IAAI;CACtB,GAAG,CAAC,kBAAkB,CAAC;CAEvB,MAAM,4BAAA,GAAA,MAAA,YAAA,EACD,MAAsC;;EAEnC,IAAI,iBAAiB,EAAE,WAAW,EAAE,eAAe;GAC/C,cAAc,KAAK;GACnB,iBAAiB,KAAK;EAC1B;CACJ,GACA,CAAC,aAAa,CAClB;CAEA,MAAM,cAAA,GAAA,MAAA,YAAA,OAA+B;EACjC,gBAAgB,mBAAmB,CAAC;EACpC,cAAc,IAAI;EAClB,cAAc,KAAK;EACnB,iBAAiB,KAAK;EACtB,YAAY,SAAS,sBAAA,QAA0C;CACnE,GAAG,CAAC,kBAAkB,CAAC;CAyCvB,OAAO;EACH;EACA,cAAA,GAAA,MAAA,YAAA,OAzCkC;GAClC,cAAc,KAAK;GACnB,YAAY,SAAS,yBAAA,OAA4C;GACjE,IAAI,iBAAiB;IACjB,cAAc,IAAI;IAClB,iBAAiB,KAAK;GAC1B;EACJ,GAAG,CAAC,eAAe,CAkCL;EACV;EACA,WAAA,GAAA,MAAA,YAAA,OAlC+B;GAC/B,MAAM,aAAgC;IAAE,WAAW;IAAM,aAAa;IAAM,YAAY;GAAK;GAC7F,UAAU;GACV,kBAAkB,UAAU;GAC5B,cAAc,KAAK;GACnB,iBAAiB,KAAK;GACtB,cAAA,MAAM,WAAW,EAAE,OAAO,aAAa,CAAC;GACxC,YAAY,SAAS,qBAAqB;IACtC,SAAS,oBAAoB,UAAU;IACvC,QAAA;GACJ,CAAC;EACL,GAAG;GAAC;GAAW;GAAiB;EAAY,CAuBjC;EACP,wBAAA,GAAA,MAAA,YAAA,OAtB4C;GAC5C,cAAc,YAAY;GAC1B,kBAAkB,YAAY;GAC9B,cAAc,KAAK;GACnB,cAAc,KAAK;GACnB,iBAAiB,KAAK;GACtB,cAAA,MAAM,WAAW,EAAE,OAAO,aAAa,CAAC;GACxC,YAAY,SAAS,qBAAqB;IACtC,SAAS,oBAAoB,YAAY;IACzC,QAAA;GACJ,CAAC;EACL,GAAG;GAAC;GAAc;GAAiB;GAAe;EAAY,CAWtC;EACpB,eAAA,GAAA,MAAA,YAAA,EAV8B,QAAiC;GAC/D,iBAAiB,UAAU;IAAE,GAAG;KAAO,MAAM,CAAC,KAAK;GAAK,EAAE;EAC9D,GAAG,CAAC,CAQW;EACX;EACA;EACA;EACA;EACA;CACJ;AACJ;;;AC/HA,MAAa,uBAAA,GAAA,MAAA,KAAA,EAA4B,EAAE,WAAW,gBAAgB,WAAW,wBAC7E,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;CACI,cAAW;CACX,YAAA,GAAA,wBAAA,GAAA,CACI,6JACA,YAAY,sBAAsB,iBACtC;CACgB;CAChB,MAAK;WAEL,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;EAAK,WAAU;YAAf,CACI,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;GAAK,WAAU;aAAf,CACI,iBAAA,GAAA,kBAAA,IAAA,CAACA,wBAAAA,eAAD;IAAe,WAAU;cAAS;GAEnB,CAAA,GACf,iBAAA,GAAA,kBAAA,IAAA,CAACC,gCAAAA,cAAD;IACI,WAAU;IACV,SAAS;IACT,MAAK;cACR;GAEa,CAAA,CACb;MACL,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;GAAK,WAAU;aACX,iBAAA,GAAA,kBAAA,IAAA,CAACC,eAAAA,QAAD;IACI,WAAU;IACV,SAAS;IACT,MAAK;IACL,OAAM;IACN,SAAQ;cACX;GAEO,CAAA;EACP,CAAA,CACJ;;AACJ,CAAA,CACR;;;ACrCD,MAAa,qBAAA,GAAA,MAAA,KAAA,EAA0B,EAAE,aAAa,WAAW,OAAO,gBAAgB,eACpF,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;CAAK,WAAU;WAAf,CACI,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;EAAK,WAAU;YAAf,CACI,iBAAA,GAAA,kBAAA,IAAA,CAACC,wBAAAA,aAAD,EAAA,UAAc,MAAmB,CAAA,GAChC,WACG,iBAAA,GAAA,kBAAA,IAAA,CAACC,wBAAAA,eAAD;GAAe,WAAU;aAAoB;EAAuB,CAAA,IAEpE,iBAAA,GAAA,kBAAA,IAAA,CAACC,qBAAAA,cAAD;GACI,cAAY;GACD;GACK;EACnB,CAAA,CAEJ;KACL,iBAAA,GAAA,kBAAA,IAAA,CAACC,wBAAAA,SAAD;EAAS,WAAU;YAAuB;CAAqB,CAAA,CAC9D;EACR;;;ACXD,MAAa,sBAAA,GAAA,MAAA,KAAA,EACR,EAAE,aAAa,2BAA2B,cAAc,SAAS,QAAQ,UAAU,WAChF,iBAAA,GAAA,kBAAA,KAAA,CAACC,cAAAA,OAAD;CACI,WAAU;CACV,aAAa;CACP;CACN,MAAK;WAJT;EAMI,iBAAA,GAAA,kBAAA,IAAA,CAACC,mBAAAA,aAAD,CAAc,CAAA;EACd,iBAAA,GAAA,kBAAA,IAAA,CAACC,mBAAAA,aAAD,EAAA,UACI,iBAAA,GAAA,kBAAA,IAAA,CAACC,wBAAAA,IAAD,EAAA,UAAI,qBAAsB,CAAA,EACjB,CAAA;EACb,iBAAA,GAAA,kBAAA,KAAA,CAACC,mBAAAA,cAAD;GAAc,WAAU;aAAxB;IACI,iBAAA,GAAA,kBAAA,IAAA,CAACC,wBAAAA,eAAD;KAAe,WAAU;eAAQ;IAGlB,CAAA;IACf,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD,EAAK,WAAU,yCAA8C,CAAA;IAC7D,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;KAAK,WAAU;eACV,WAAW,KAAK,QACb,iBAAA,GAAA,kBAAA,IAAA,CAAC,mBAAD;MACI,aAAa,IAAI;MACjB,WAAW,IAAI,WAAW,OAAO,aAAa,IAAI;MAElD,OAAO,IAAI;MACX,gBACI,IAAI,WAAW,KAAA,UAAkB,SAAS,IAAI,GAA8B;MAEhF,UAAU,IAAI;KACjB,GANQ,IAAI,GAMZ,CACJ;IACA,CAAA;GACK;;EACd,iBAAA,GAAA,kBAAA,IAAA,CAACC,mBAAAA,cAAD,EAAA,UACI,iBAAA,GAAA,kBAAA,IAAA,CAACC,eAAAA,QAAD;GACI,SAAS;GACT,MAAK;GACL,OAAM;GACN,SAAQ;aACX;EAEO,CAAA,EACE,CAAA;CACX;EAEf;;;ACvDA,MAAM,wBAAwB;;;;;;;;;;AA+B9B,MAAa,iBAAA,GAAA,MAAA,WAAA,EAEL,EAAE,YAAY,SAAS,iBAAiB,YAAY,eAAe,uBAAuB,aAAa,CAAC,GACxG,QACC;CACD,MAAM,QAAQ,sBAAsB;EAAE;EAAS;EAAiB;EAAY;EAAc;CAAS,CAAC;CAEpG,CAAA,GAAA,MAAA,oBAAA,CAAoB,YAAY,EAAE,WAAW,MAAM,UAAU,IAAI,CAAC,MAAM,SAAS,CAAC;CAElF,IAAI,CAAC,MAAM,cAAc,CAAC,MAAM,YAC5B,OAAO;CAGX,OACI,iBAAA,GAAA,kBAAA,KAAA,CAAA,kBAAA,UAAA,EAAA,UAAA,CACK,MAAM,cACH,iBAAA,GAAA,kBAAA,IAAA,CAAC,qBAAD;EACI,WAAW,MAAM;EACjB,gBAAgB,MAAM;EACtB,WAAW,MAAM;EACjB,mBAAmB,MAAM;CAC5B,CAAA,GAEL,iBAAA,GAAA,kBAAA,IAAA,CAAC,oBAAD;EACgB;EACZ,cAAc,MAAM;EACpB,SAAS,MAAM;EACf,QAAQ,MAAM;EACd,UAAU,MAAM;EAChB,MAAM,MAAM;CACf,CAAA,CACH,EAAA,CAAA;AAEV,CACJ"}
|
|
1
|
+
{"version":3,"file":"CookieConsent-BSXJHMwX.cjs","names":["BodySecondary","InlineButton","Button","LabelStrong","BodySecondary","ToggleSwitch","Caption","Modal","CloseButton","ModalHeader","H2","ModalContent","BodySecondary","ModalActions","Button"],"sources":["../src/CookieConsent/types/cookieConsent.types.ts","../src/CookieConsent/hooks/useCookieConsent.ts","../src/CookieConsent/hooks/useCookieConsentState.ts","../src/CookieConsent/components/CookieConsentBanner/CookieConsentBanner.tsx","../src/CookieConsent/components/CookieCategoryRow/CookieCategoryRow.tsx","../src/CookieConsent/components/CookieConsentModal/CookieConsentModal.tsx","../src/CookieConsent/components/CookieConsent/CookieConsent.tsx"],"sourcesContent":["/**\n * The three non-essential consent categories managed by this component.\n * `necessary` is excluded because it's always implicitly granted.\n */\nexport type ConsentCategories = {\n marketing: boolean;\n preferences: boolean;\n statistics: boolean;\n};\n\n/** Full consent payload including the always-on `necessary` flag. */\nexport type ConsentPayload = ConsentCategories & { necessary: true };\n\n/** Where the user interaction originated. */\nexport enum ConsentSource {\n Banner = 'banner',\n Modal = 'modal',\n}\n\n/** Tracking callbacks for cookie consent analytics. */\nexport type CookieConsentTracking = {\n onBannerViewed?: () => void;\n onPreferencesDismissed?: (source: ConsentSource) => void;\n onPreferencesOpened?: (source: ConsentSource) => void;\n onPreferencesSaved?: (payload: { consent: ConsentPayload; source: ConsentSource }) => void;\n};\n\n/** Params for the useCookieConsentState hook. */\nexport type UseCookieConsentStateParams = {\n /**\n * Controlled consent state. When provided, an external consent-management\n * platform owns the consent state and internal localStorage persistence is\n * bypassed — sync changes back through `onConsentChange`.\n */\n consent?: ConsentCategories;\n onConsentChange?: (consent: ConsentCategories) => void;\n /** localStorage key used to persist consent in uncontrolled mode. */\n storageKey?: string;\n toastMessage: string;\n tracking?: CookieConsentTracking;\n};\n\n/** Definition for a single row in the preferences modal. */\nexport type CookieCategoryConfig = {\n description: string;\n /** Must match a `ConsentCategories` key, or `'necessary'` for the always-on row. */\n key: keyof ConsentCategories | 'necessary';\n label: string;\n /** When `true`, the toggle is locked on and the user cannot opt out. */\n required?: boolean;\n};\n\nexport const DEFAULT_COOKIE_CATEGORIES: CookieCategoryConfig[] = [\n {\n description:\n 'Necessary cookies help make a website usable by enabling basic functions like page navigation and access to secure areas of the website. The website cannot function properly without these cookies.',\n key: 'necessary',\n label: 'Necessary',\n required: true,\n },\n {\n description:\n 'Preference cookies enable a website to remember information that changes the way the website behaves or looks, like your preferred language or the region that you are in.',\n key: 'preferences',\n label: 'Preferences',\n },\n {\n description:\n 'Statistics cookies help website owners to understand how visitors interact with websites by collecting and reporting information anonymously.',\n key: 'statistics',\n label: 'Statistics',\n },\n {\n description:\n 'Marketing cookies are used to track visitors across websites. The intention is to display ads that are relevant and engaging for the individual user and thereby more valuable for publishers and third party advertisers.',\n key: 'marketing',\n label: 'Marketing',\n },\n];\n","import { useCallback, useEffect, useState } from 'react';\n\nimport type { ConsentCategories, ConsentPayload } from '../types/cookieConsent.types';\n\nexport const DEFAULT_CONSENT_STORAGE_KEY = 'hui-cookie-consent';\n\nconst DEFAULT_CONSENT: ConsentCategories = {\n marketing: false,\n preferences: false,\n statistics: false,\n};\n\n/**\n * Reads a previously persisted consent payload from localStorage.\n * Returns `undefined` during SSR, when nothing is stored, or when the stored\n * value is corrupt/unparseable (corrupt values are treated as \"no response yet\"\n * so the banner shows again rather than trusting bad data).\n */\nconst readStoredConsent = (storageKey: string): ConsentCategories | undefined => {\n /* istanbul ignore next -- @preserve: SSR guard; a React test renderer always runs with a defined `window`, so this branch is unreachable under jest/jsdom. */\n if (typeof window === 'undefined') {\n return undefined;\n }\n\n let raw: string | null = null;\n try {\n raw = window.localStorage.getItem(storageKey);\n } catch {\n // localStorage can throw (e.g. disabled in the browser) — treat as no response.\n return undefined;\n }\n\n if (!raw) {\n return undefined;\n }\n\n try {\n const parsed: unknown = JSON.parse(raw);\n if (\n typeof parsed === 'object' &&\n parsed !== null &&\n typeof (parsed as ConsentPayload).marketing === 'boolean' &&\n typeof (parsed as ConsentPayload).preferences === 'boolean' &&\n typeof (parsed as ConsentPayload).statistics === 'boolean'\n ) {\n const payload = parsed as ConsentPayload;\n return {\n marketing: payload.marketing,\n preferences: payload.preferences,\n statistics: payload.statistics,\n };\n }\n } catch {\n // Corrupt JSON — fall through to undefined.\n }\n\n return undefined;\n};\n\n/**\n * Persists a consent payload to localStorage. No-ops during SSR or when\n * localStorage is unavailable.\n */\nconst writeStoredConsent = (storageKey: string, categories: ConsentCategories) => {\n /* istanbul ignore next -- @preserve: SSR guard; consent writes are user-triggered client-side actions and a React test renderer always has a defined `window`, so this branch is unreachable under jest/jsdom. */\n if (typeof window === 'undefined') {\n return;\n }\n\n const payload: ConsentPayload = { ...categories, necessary: true };\n\n try {\n window.localStorage.setItem(storageKey, JSON.stringify(payload));\n } catch {\n // localStorage unavailable — consent still applies for this session via state.\n }\n};\n\n/** Params for the useCookieConsent hook. */\nexport type UseCookieConsentParams = {\n /**\n * Controlled consent state. When provided, an external consent-management\n * platform (CMP) owns the consent state: internal localStorage persistence\n * is bypassed, the banner is never auto-shown, and consent reads reflect\n * this value. Sync user changes back to the CMP via the component's\n * `onConsentChange` callback.\n */\n consent?: ConsentCategories;\n /** localStorage key used to persist consent in uncontrolled mode. */\n storageKey?: string;\n};\n\n/**\n * Low-level consent engine backed by localStorage.\n *\n * Uncontrolled (default) mode: on mount, reads any previously saved consent\n * from localStorage. The banner is visible if and only if no stored consent\n * exists. Action helpers (`acceptAll`, `declineAll`, `submitConsent`) persist\n * the new consent payload and hide the banner.\n *\n * Controlled mode (`consent` param provided): an external CMP owns the state —\n * nothing is read from or written to localStorage and the banner is never\n * auto-shown; the preferences modal remains reachable via\n * `CookieConsentHandle.openModal()`.\n *\n * Exposes `isBannerVisible`, current `consent` state, `hasResponse` (whether\n * the user has already responded), and the action helpers.\n */\nexport const useCookieConsent = ({\n consent: controlledConsent,\n storageKey = DEFAULT_CONSENT_STORAGE_KEY,\n}: UseCookieConsentParams = {}) => {\n const isControlled = controlledConsent !== undefined;\n\n const [isBannerVisible, setIsBannerVisible] = useState(false);\n const [internalConsent, setInternalConsent] = useState<ConsentCategories>(DEFAULT_CONSENT);\n const [hasStoredResponse, setHasStoredResponse] = useState(false);\n\n useEffect(() => {\n if (isControlled) {\n return;\n }\n\n const stored = readStoredConsent(storageKey);\n if (stored) {\n setInternalConsent(stored);\n setHasStoredResponse(true);\n setIsBannerVisible(false);\n } else {\n setIsBannerVisible(true);\n }\n }, [isControlled, storageKey]);\n\n const applyConsent = useCallback(\n (categories: ConsentCategories) => {\n if (!isControlled) {\n writeStoredConsent(storageKey, categories);\n }\n setInternalConsent(categories);\n setHasStoredResponse(true);\n setIsBannerVisible(false);\n },\n [isControlled, storageKey]\n );\n\n const acceptAll = useCallback(() => {\n applyConsent({ marketing: true, preferences: true, statistics: true });\n }, [applyConsent]);\n\n const declineAll = useCallback(() => {\n applyConsent(DEFAULT_CONSENT);\n }, [applyConsent]);\n\n const submitConsent = useCallback(\n (categories: ConsentCategories) => {\n applyConsent(categories);\n },\n [applyConsent]\n );\n\n return {\n acceptAll,\n consent: isControlled ? controlledConsent : internalConsent,\n declineAll,\n /** Whether the user has already responded (controlled mode counts as responded). */\n hasResponse: isControlled || hasStoredResponse,\n isBannerVisible,\n submitConsent,\n };\n};\n","import { AnimationEvent, useCallback, useEffect, useRef, useState } from 'react';\n\nimport { toast } from '../../Toast';\nimport {\n ConsentCategories,\n ConsentPayload,\n ConsentSource,\n UseCookieConsentStateParams,\n} from '../types/cookieConsent.types';\nimport { useCookieConsent } from './useCookieConsent';\n\nconst DEFAULT_LOCAL_CONSENT: ConsentCategories = {\n marketing: true,\n preferences: true,\n statistics: true,\n};\n\nconst buildConsentPayload = (consent: ConsentCategories): ConsentPayload => ({\n ...consent,\n necessary: true,\n});\n\n/**\n * UI state manager for the CookieConsent component.\n *\n * Wraps `useCookieConsent` and owns banner/modal visibility, local consent\n * toggle state, and all user interaction handlers (OK, save, toggle, open/close).\n *\n * Modal toggles default to all-ON (`DEFAULT_LOCAL_CONSENT`). When opening the\n * modal, existing consent is read from the consent engine only if the user has\n * already responded — before a response, consent initializes as all `false`,\n * so we fall back to the all-ON default.\n */\nexport const useCookieConsentState = ({\n consent: controlledConsent,\n onConsentChange,\n storageKey,\n toastMessage,\n tracking,\n}: UseCookieConsentStateParams) => {\n const { acceptAll, consent, hasResponse, isBannerVisible, submitConsent } = useCookieConsent({\n consent: controlledConsent,\n storageKey,\n });\n const trackingRef = useRef(tracking);\n trackingRef.current = tracking;\n\n const [showBanner, setShowBanner] = useState(false);\n const [bannerExiting, setBannerExiting] = useState(false);\n const [showDialog, setShowDialog] = useState(false);\n const [localConsent, setLocalConsent] = useState(DEFAULT_LOCAL_CONSENT);\n\n const readCurrentConsent = useCallback(\n (): ConsentCategories => (hasResponse ? consent : DEFAULT_LOCAL_CONSENT),\n [consent, hasResponse]\n );\n\n useEffect(() => {\n if (isBannerVisible) {\n setShowBanner(true);\n setBannerExiting(false);\n trackingRef.current?.onBannerViewed?.();\n }\n }, [isBannerVisible]);\n\n const openModal = useCallback(() => {\n setLocalConsent(readCurrentConsent());\n setShowDialog(true);\n }, [readCurrentConsent]);\n\n const handleBannerAnimationEnd = useCallback(\n (e: AnimationEvent<HTMLDivElement>) => {\n /* istanbul ignore next -- @preserve: `bannerExiting` is only ever set to false in this hook (faithful hammer parity), so the exit-animation cleanup branch is unreachable. Reported as latent dead code, not modified to preserve parity. */\n if (bannerExiting && e.target === e.currentTarget) {\n setShowBanner(false);\n setBannerExiting(false);\n }\n },\n [bannerExiting]\n );\n\n const openDialog = useCallback(() => {\n setLocalConsent(readCurrentConsent());\n setShowDialog(true);\n setShowBanner(false);\n setBannerExiting(false);\n trackingRef.current?.onPreferencesOpened?.(ConsentSource.Banner);\n }, [readCurrentConsent]);\n\n const closeDialog = useCallback(() => {\n setShowDialog(false);\n trackingRef.current?.onPreferencesDismissed?.(ConsentSource.Modal);\n if (isBannerVisible) {\n setShowBanner(true);\n setBannerExiting(false);\n }\n }, [isBannerVisible]);\n\n const handleOk = useCallback(() => {\n const allConsent: ConsentCategories = { marketing: true, preferences: true, statistics: true };\n acceptAll();\n onConsentChange?.(allConsent);\n setShowBanner(false);\n setBannerExiting(false);\n toast('success', { title: toastMessage });\n trackingRef.current?.onPreferencesSaved?.({\n consent: buildConsentPayload(allConsent),\n source: ConsentSource.Banner,\n });\n }, [acceptAll, onConsentChange, toastMessage]);\n\n const handleSavePreferences = useCallback(() => {\n submitConsent(localConsent);\n onConsentChange?.(localConsent);\n setShowDialog(false);\n setShowBanner(false);\n setBannerExiting(false);\n toast('success', { title: toastMessage });\n trackingRef.current?.onPreferencesSaved?.({\n consent: buildConsentPayload(localConsent),\n source: ConsentSource.Modal,\n });\n }, [localConsent, onConsentChange, submitConsent, toastMessage]);\n\n const handleToggle = useCallback((key: keyof ConsentCategories) => {\n setLocalConsent((prev) => ({ ...prev, [key]: !prev[key] }));\n }, []);\n\n return {\n bannerExiting,\n closeDialog,\n handleBannerAnimationEnd,\n handleOk,\n handleSavePreferences,\n handleToggle,\n localConsent,\n openDialog,\n openModal,\n showBanner,\n showDialog,\n };\n};\n","import { cn } from '@evolve.ui/theme-system';\nimport { AnimationEvent, memo } from 'react';\n\nimport { Button } from '../../../Button/Button';\nimport { InlineButton } from '../../../Typography/InlineButton/InlineButton';\nimport { BodySecondary } from '../../../Typography/Text/Text';\n\ntype Props = {\n isExiting: boolean;\n onAnimationEnd: (e: AnimationEvent<HTMLDivElement>) => void;\n onDismiss: () => void;\n onOpenPreferences: () => void;\n};\n\nexport const CookieConsentBanner = memo(({ isExiting, onAnimationEnd, onDismiss, onOpenPreferences }: Props) => (\n <div\n aria-label=\"Cookie consent\"\n className={cn(\n 'fixed inset-x-0 bottom-md z-[10300] mx-auto w-[calc(100%-48px)] max-w-[1200px] rounded-md border border-border-secondary bg-background-tertiary shadow-01',\n isExiting ? 'animate-slideDown' : 'animate-slideUp'\n )}\n onAnimationEnd={onAnimationEnd}\n role=\"region\"\n >\n <div className=\"flex flex-col gap-xs p-sm smMin:flex-row smMin:items-center smMin:gap-md smMin:p-md\">\n <div className=\"min-w-0 flex-1\">\n <BodySecondary className=\"inline\">\n We use cookies to improve your experience, to analyze website usage, and for marketing purposes.\n </BodySecondary>\n <InlineButton\n className=\"ml-2xs inline text-text-primary underline\"\n onClick={onOpenPreferences}\n size=\"sm\"\n >\n Cookie preferences\n </InlineButton>\n </div>\n <div className=\"shrink-0 self-end smMin:self-auto\">\n <Button\n className=\"min-w-[96px]\"\n onClick={onDismiss}\n size=\"sm\"\n style=\"neutral\"\n variant=\"outlined\"\n >\n OK\n </Button>\n </div>\n </div>\n </div>\n));\n","import { memo } from 'react';\n\nimport { ToggleSwitch } from '../../../ToggleSwitch/ToggleSwitch';\nimport { BodySecondary, Caption, LabelStrong } from '../../../Typography/Text/Text';\n\ntype Props = {\n description: string;\n isToggled: boolean;\n label: string;\n onToggleChange?: () => void;\n required?: boolean;\n};\n\nexport const CookieCategoryRow = memo(({ description, isToggled, label, onToggleChange, required }: Props) => (\n <div className=\"flex flex-col gap-2xs border-b border-border-secondary py-sm\">\n <div className=\"flex h-[22px] items-center justify-between\">\n <LabelStrong>{label}</LabelStrong>\n {required ? (\n <BodySecondary className=\"text-text-primary\">Required</BodySecondary>\n ) : (\n <ToggleSwitch\n aria-label={label}\n isToggled={isToggled}\n onToggleChange={onToggleChange}\n />\n )}\n </div>\n <Caption className=\"text-text-secondary\">{description}</Caption>\n </div>\n));\n","import { memo } from 'react';\n\nimport { Button } from '../../../Button/Button';\nimport { CloseButton, ModalActions, ModalContent, ModalHeader } from '../../../Modal/components';\nimport { Modal } from '../../../Modal/Modal';\nimport { BodySecondary, H2 } from '../../../Typography/Text/Text';\nimport { ConsentCategories, CookieCategoryConfig, DEFAULT_COOKIE_CATEGORIES } from '../../types/cookieConsent.types';\nimport { CookieCategoryRow } from '../CookieCategoryRow/CookieCategoryRow';\n\ntype Props = {\n categories?: CookieCategoryConfig[];\n localConsent: ConsentCategories;\n onClose: () => void;\n onSave: () => void;\n onToggle: (key: keyof ConsentCategories) => void;\n show: boolean;\n};\n\nexport const CookieConsentModal = memo(\n ({ categories = DEFAULT_COOKIE_CATEGORIES, localConsent, onClose, onSave, onToggle, show }: Props) => (\n <Modal\n className=\"max-w-[588px]\"\n handleClose={onClose}\n show={show}\n type=\"composable\"\n >\n <CloseButton />\n <ModalHeader>\n <H2>Cookie Preferences</H2>\n </ModalHeader>\n <ModalContent className=\"max-w-460px pb-sm\">\n <BodySecondary className=\"mb-sm\">\n Our platform uses various types of cookies, each of which has a specific function. Manage your\n preferences below:\n </BodySecondary>\n <div className=\"border-b border-border-secondary pb-sm\"></div>\n <div className=\"flex flex-col\">\n {categories.map((cat) => (\n <CookieCategoryRow\n description={cat.description}\n isToggled={cat.required ? true : localConsent[cat.key as keyof ConsentCategories]}\n key={cat.key}\n label={cat.label}\n onToggleChange={\n cat.required ? undefined : () => onToggle(cat.key as keyof ConsentCategories)\n }\n required={cat.required}\n />\n ))}\n </div>\n </ModalContent>\n <ModalActions>\n <Button\n onClick={onSave}\n size=\"md\"\n style=\"primary\"\n variant=\"filled\"\n >\n SAVE PREFERENCES\n </Button>\n </ModalActions>\n </Modal>\n )\n);\n","import { forwardRef, useImperativeHandle } from 'react';\n\nimport type { ConsentCategories, CookieCategoryConfig, CookieConsentTracking } from '../../types/cookieConsent.types';\n\nimport { useCookieConsentState } from '../../hooks/useCookieConsentState';\nimport { CookieConsentBanner } from '../CookieConsentBanner/CookieConsentBanner';\nimport { CookieConsentModal } from '../CookieConsentModal/CookieConsentModal';\n\nconst DEFAULT_TOAST_MESSAGE = 'Your privacy preferences have been saved.';\n\ntype Props = {\n categories?: CookieCategoryConfig[];\n /**\n * Controlled consent state. When provided, an external consent-management\n * platform (CMP) owns the consent state: internal localStorage persistence\n * is bypassed and the banner is never auto-shown. Sync user changes back to\n * the CMP via `onConsentChange`.\n */\n consent?: ConsentCategories;\n onConsentChange?: (consent: ConsentCategories) => void;\n /** localStorage key used to persist consent in uncontrolled mode (default `'hui-cookie-consent'`). */\n storageKey?: string;\n toastMessage?: string;\n tracking?: CookieConsentTracking;\n};\n\nexport type CookieConsentHandle = {\n openModal: () => void;\n};\n\n/**\n * Custom cookie consent UI (banner + preferences modal).\n *\n * Renders the consent banner and modal. By default consent is persisted to\n * localStorage via `useCookieConsentState`; pass the `consent` prop to let an\n * external consent-management platform own the state instead. Exposes\n * `openModal()` through a ref for programmatic access (e.g. footer\n * \"Cookie Preferences\" link).\n */\nexport const CookieConsent = forwardRef<CookieConsentHandle, Props>(\n (\n { categories, consent, onConsentChange, storageKey, toastMessage = DEFAULT_TOAST_MESSAGE, tracking } = {},\n ref\n ) => {\n const state = useCookieConsentState({ consent, onConsentChange, storageKey, toastMessage, tracking });\n\n useImperativeHandle(ref, () => ({ openModal: state.openModal }), [state.openModal]);\n\n if (!state.showBanner && !state.showDialog) {\n return null;\n }\n\n return (\n <>\n {state.showBanner && (\n <CookieConsentBanner\n isExiting={state.bannerExiting}\n onAnimationEnd={state.handleBannerAnimationEnd}\n onDismiss={state.handleOk}\n onOpenPreferences={state.openDialog}\n />\n )}\n <CookieConsentModal\n categories={categories}\n localConsent={state.localConsent}\n onClose={state.closeDialog}\n onSave={state.handleSavePreferences}\n onToggle={state.handleToggle}\n show={state.showDialog}\n />\n </>\n );\n }\n);\n"],"mappings":"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"}
|
|
@@ -199,7 +199,7 @@ const Drawer = ({ actions, anchor = "right", children, className, closeOnEscape
|
|
|
199
199
|
}, [show]);
|
|
200
200
|
const renderWhenClosed = keepInDOMWhileClosed || renderDrawer;
|
|
201
201
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
202
|
-
className: (0, _evolve_ui_theme_system.cn)("
|
|
202
|
+
className: (0, _evolve_ui_theme_system.cn)("invisible fixed inset-0 z-30 bg-background-overlay opacity-0 duration-500", {
|
|
203
203
|
"opacity-1 visible": renderDrawer,
|
|
204
204
|
"pointer-events-none invisible opacity-0": !renderDrawer,
|
|
205
205
|
"transition-none": removeTransitionForTest
|
|
@@ -256,4 +256,4 @@ Object.defineProperty(exports, "Drawer", {
|
|
|
256
256
|
}
|
|
257
257
|
});
|
|
258
258
|
|
|
259
|
-
//# sourceMappingURL=Drawer-
|
|
259
|
+
//# sourceMappingURL=Drawer-3rA9dGCl.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Drawer-9HFG45OA.cjs","names":["ModalContext","ModalContext","effectEventListener","ModalContext","IconButton","ArrowLeft","H2","Close","nodeEnv","effectEventListener"],"sources":["../src/utils/keepTransition.ts","../src/Drawer/components/DialogActions/DialogActions.tsx","../src/Drawer/components/DialogContent/DialogContent.tsx","../src/Drawer/components/DialogHeader/DialogHeader.tsx","../src/Drawer/Drawer.tsx"],"sourcesContent":["declare const process:\n | {\n env?: {\n KEEP_TRANSITION?: string;\n };\n }\n | undefined;\n\n/**\n * Test-only escape hatch, read at call time: Drawer specs set\n * `process.env.KEEP_TRANSITION = 'true'` at runtime to opt back into CSS\n * transitions. Unlike `nodeEnv` (a module-load-time read), a call-time read\n * sees that mutation.\n */\nexport const keepTransition = () => (typeof process === 'undefined' ? undefined : process.env?.KEEP_TRANSITION);\n","import { cn } from '@evolve.ui/theme-system';\nimport { useAtomValue } from 'jotai';\nimport { ReactNode, useContext } from 'react';\n\nimport { ModalContext } from '../../../Modal/context';\n\ntype Props = {\n children: ReactNode;\n className?: string;\n density?: 'compact' | 'comfortable';\n useCustomButtonContainer?: boolean;\n};\n\nexport const DialogActions = ({ children, className, density, useCustomButtonContainer }: Props) => {\n const { showBottomScrollHintAtom } = useContext(ModalContext);\n const showBottomScrollHint = useAtomValue(showBottomScrollHintAtom);\n\n return (\n <div\n className={cn(\n 'flex grow-0 gap-sm p-sm',\n {\n '[&_button]:grow-[1]': !useCustomButtonContainer,\n 'p-xs': density === 'compact',\n 'shadow-05': showBottomScrollHint,\n },\n className\n )}\n >\n {children}\n </div>\n );\n};\n","import { cn } from '@evolve.ui/theme-system';\nimport { useSetAtom } from 'jotai';\nimport { ReactNode, useCallback, useContext, useEffect, useRef } from 'react';\n\nimport { ModalContext } from '../../../Modal/context';\nimport { effectEventListener } from '../../../utils/effectEventListener';\n\ntype Props = {\n children: ReactNode;\n density?: 'compact' | 'comfortable';\n disableScroll?: boolean;\n renderWhenClosed: boolean;\n};\n\nexport const DialogContent = ({ children, density, disableScroll = false, renderWhenClosed }: Props) => {\n const { showBottomScrollHintAtom, showTopScrollHintAtom } = useContext(ModalContext);\n const setShowBottomScrollHint = useSetAtom(showBottomScrollHintAtom);\n const setShowTopScrollHint = useSetAtom(showTopScrollHintAtom);\n\n const handleScroll = useCallback(\n (contentRef: HTMLDivElement) => () => {\n if (contentRef.scrollHeight > contentRef.clientHeight + 32) {\n const atTheBottom =\n Math.round(contentRef.scrollHeight - contentRef.scrollTop) - 5 < contentRef.clientHeight;\n const atTheTop = contentRef.scrollTop < 25;\n\n setShowBottomScrollHint(!atTheBottom);\n setShowTopScrollHint(!atTheTop);\n } else if (contentRef.scrollTop === 0) {\n setShowBottomScrollHint(false);\n setShowTopScrollHint(false);\n }\n },\n [setShowBottomScrollHint, setShowTopScrollHint]\n );\n\n const onScrollRef = useRef<ReturnType<typeof handleScroll>>(null);\n\n // Trigger handleScroll on window resize\n useEffect(() => {\n return effectEventListener(window, 'resize', () => onScrollRef.current?.());\n }, [handleScroll]);\n\n return (\n <div\n className={cn('grow-[1] border-y border-solid border-border-secondary', {\n 'flex flex-col overflow-hidden': disableScroll,\n 'h-[100vh] overflow-y-auto': !disableScroll,\n 'p-sm': !disableScroll && density !== 'compact',\n 'p-xs': !disableScroll && density === 'compact',\n })}\n data-testid=\"dialog-content\"\n ref={(ref) => {\n if (!ref) {\n return;\n }\n\n const onScroll = handleScroll(ref);\n onScrollRef.current = onScroll;\n\n const resizeObserver = new ResizeObserver(() => {\n const scrollHeight = ref.scrollHeight;\n const clientHeight = ref.clientHeight;\n\n if (scrollHeight === clientHeight + 32) {\n setShowBottomScrollHint(false);\n setShowTopScrollHint(false);\n } else {\n onScroll();\n }\n });\n\n resizeObserver.observe(ref);\n ref.addEventListener('scroll', onScroll);\n }}\n >\n {renderWhenClosed ? children : null}\n </div>\n );\n};\n","import { cn } from '@evolve.ui/theme-system';\nimport { useAtomValue } from 'jotai';\nimport { ReactNode, useContext } from 'react';\n\nimport { IconButton } from '../../../IconButton/IconButton';\nimport { ArrowLeft, Close } from '../../../Icons';\nimport { ModalContext } from '../../../Modal/context';\nimport { H2 } from '../../../Typography/Text/Text';\n\ntype Props = {\n children?: ReactNode;\n density: 'compact' | 'comfortable';\n onBackButtonClick?: () => void;\n onCloseButtonClick: () => void;\n textAlign?: 'center' | 'left' | 'right';\n};\n\nexport const DialogHeader = ({\n children,\n density = 'comfortable',\n onBackButtonClick,\n onCloseButtonClick,\n textAlign = 'center',\n}: Props) => {\n const { showTopScrollHintAtom } = useContext(ModalContext);\n const showTopScrollHint = useAtomValue(showTopScrollHintAtom);\n\n return (\n <div\n className={cn('relative grid grid-cols-[42px_1fr_42px] gap-[4px] p-sm', {\n 'p-xs': density === 'compact',\n 'shadow-01': showTopScrollHint,\n })}\n >\n {onBackButtonClick !== undefined && (\n <IconButton\n aria-label=\"Go Back\"\n className={cn('col-start-1 col-end-2')}\n data-testid=\"back-button\"\n hideTooltip\n icon={ArrowLeft}\n onClick={onBackButtonClick}\n size=\"md\"\n type=\"button\"\n />\n )}\n <div\n className={cn('col-start-2 col-end-3 flex', {\n 'justify-center text-center': textAlign === 'center',\n 'justify-end text-right': textAlign === 'right',\n 'justify-start text-left': textAlign === 'left',\n })}\n data-testid=\"dialog-header-text-container\"\n >\n {typeof children === 'string' ? <H2 className=\"pt-[6px]\">{children}</H2> : children}\n </div>\n <IconButton\n className={cn('col-start-3 col-end-4')}\n data-testid=\"close-button\"\n hideTooltip\n icon={Close}\n onClick={onCloseButtonClick}\n size=\"md\"\n type=\"button\"\n />\n </div>\n );\n};\n","import { cn } from '@evolve.ui/theme-system';\nimport { ReactNode, useCallback, useEffect, useRef, useState } from 'react';\n\nimport { effectEventListener } from '../utils/effectEventListener';\nimport { keepTransition } from '../utils/keepTransition';\nimport { nodeEnv } from '../utils/nodeEnv';\nimport { DialogActions } from './components/DialogActions/DialogActions';\nimport { DialogContent } from './components/DialogContent/DialogContent';\nimport { DialogHeader } from './components/DialogHeader/DialogHeader';\n\ntype ReasonForClose = 'backdrop' | 'closeButton' | 'escape' | 'external';\n\ntype Props = {\n /**\n * Optional actions to display at the bottom of the drawer\n * Actions container has these styles:\n * ```css\n * display: flex;\n * gap: 16px;\n * > button {\n * flex-grow: 1;\n * }\n * ```\n *\n * Usage:\n * ```tsx\n * <Drawer actions={<Button>Save</Button>} />\n * ```\n *\n */\n actions?: ReactNode;\n /**\n * Optional anchor for the drawer\n *\n * Usage:\n * ```tsx\n * <Drawer anchor=\"left\" />\n * ```\n *\n * @default 'right'\n */\n anchor?: 'left' | 'right';\n /**\n * Children of the drawer are the content of the drawer\n *\n * Usage:\n * ```tsx\n * <Drawer><div>Hello World</div></Drawer>\n * ```\n *\n */\n children?: ReactNode;\n /**\n * Optional class name for the drawer\n *\n * Usage:\n * ```tsx\n * <Drawer className=\"bg-red-500\" />\n * ```\n *\n */\n className?: string;\n /**\n * Optional flag to close the drawer when the user clicks outside\n *\n * Usage:\n * ```tsx\n * <Drawer closeOnOutsideClick={false} />\n * ```\n *\n * @default true\n */\n closeOnOutsideClick?: boolean;\n /**\n * Optional flag to close the drawer when the user presses the Escape key\n *\n * Usage:\n * ```tsx\n * <Drawer closeOnEscape={false} />\n * ```\n *\n * @default true\n */\n closeOnEscape?: boolean;\n /**\n * Optional custom header to replace the default DialogHeader\n *\n * Usage:\n * ```tsx\n * <Drawer customHeader={<div>Custom Header</div>} />\n * ```\n *\n */\n customHeader?: ReactNode;\n /**\n * Optional density for the drawer\n *\n * Usage:\n * ```tsx\n * <Drawer density=\"compact\" />\n * ```\n *\n * @default 'comfortable'\n */\n density?: 'compact' | 'comfortable';\n /**\n * Optional flag to disable scrolling in the drawer content area\n * Useful when the content has its own scrollable areas (e.g., tabs)\n *\n * Usage:\n * ```tsx\n * <Drawer disableScroll />\n * ```\n *\n * @default false\n */\n disableScroll?: boolean;\n /**\n * Required function call when drawer closes, this will almost always be a call to `setShowState(false)`\n *\n * Usage:\n * ```tsx\n * const [show, setShow] = useState(false);\n * ...\n * <Drawer handleClose={() => setShow(false)} />\n * ```\n *\n */\n handleClose: (reason?: ReasonForClose) => void;\n /**\n * Optional flag that controls whether the drawer has a drop shadow\n *\n * Usage:\n * ```tsx\n * <Drawer hasShadow />\n * ```\n *\n */\n hasShadow?: boolean;\n /**\n * Optional header text for the drawer, appears at the top of the drawer\n *\n * Usage:\n * ```tsx\n * <Drawer headerText=\"Hello World\" />\n * ```\n *\n */\n headerText?: string | ReactNode;\n /**\n * Optional alignment for the header text\n *\n * Usage:\n * ```tsx\n * <Drawer headerTextAlign=\"left\" />\n * ```\n *\n * @default 'center'\n */\n headerTextAlign?: 'center' | 'left' | 'right';\n /**\n * Optional flag to keep the drawer in the DOM while closed\n *\n * Usage:\n * ```tsx\n * <Drawer keepInDOMWhileClosed={false} />\n * ```\n * @default true\n */\n keepInDOMWhileClosed?: boolean;\n\n /**\n * Optional function call when the back button is clicked\n *\n * Usage:\n * ```tsx\n * <Drawer onBackButtonClick={() => console.log('Back button clicked')} />\n * ```\n *\n */\n onBackButtonClick?: () => void;\n /**\n * Required flag to show the drawer\n *\n * Usage:\n * ```tsx\n * <Drawer show />\n * ```\n *\n */\n show: boolean;\n /**\n * Optional size for the drawer\n *\n * Usage:\n * ```tsx\n * <Drawer size=\"wide\" />\n * ```\n *\n * @default 'narrow'\n */\n size?: 'narrow' | 'wide' | 'extended' | 'full';\n /**\n * Optional flag to control the action container\n *\n * Usage:\n * ```tsx\n * <Drawer useCustomButtonContainer />\n * ```\n *\n */\n useCustomButtonContainer?: boolean;\n};\n\n// Open drawers share a single body scroll-lock. Module-scoped so the lock is\n// released only when the last open drawer closes, and so the body's original\n// overflow / padding are captured once (when the first drawer opens) and\n// restored at the end rather than hardcoding values.\nlet openDrawerCount = 0;\nlet previousBodyOverflow = '';\nlet previousBodyPaddingRight = '';\n\n// Identities of currently-open drawers, in open order. Escape only closes the\n// last one pushed (the top-most), so stacked drawers close one at a time\n// instead of all collapsing on a single keypress. Per-instance ref objects are\n// used as identities rather than useId so this doesn't consume React's id\n// sequence and shift autogenerated ids in consumer snapshots.\nconst openDrawerStack: object[] = [];\n\n/**\n * A drawer component using the `dialog` element\n * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dialog\n */\nexport const Drawer = ({\n actions,\n anchor = 'right',\n children,\n className,\n closeOnEscape = true,\n closeOnOutsideClick = true,\n customHeader,\n density = 'comfortable',\n disableScroll = false,\n handleClose,\n hasShadow = false,\n headerText,\n headerTextAlign = 'center',\n keepInDOMWhileClosed = true,\n onBackButtonClick,\n show,\n size = 'narrow',\n useCustomButtonContainer = false,\n}: Props) => {\n const reasonForClose = useRef<ReasonForClose>('external');\n // Per-instance ref instead of a shared id: several Drawers can be mounted at\n // once, and a duplicate id would make a lookup match the wrong backdrop.\n const backdropRef = useRef<HTMLDivElement>(null);\n const drawerIdRef = useRef<object>({});\n const [renderDrawer, setRenderDrawer] = useState(show);\n\n const removeTransitionForTest = Boolean(nodeEnv === 'test') && Boolean(keepTransition() !== 'true');\n\n const startCloseTransition = useCallback(\n (reason: ReasonForClose) => {\n setRenderDrawer(false);\n reasonForClose.current = reason;\n\n // Close the drawer immediately in test environment\n if (removeTransitionForTest) {\n handleClose(reason);\n }\n },\n [handleClose, removeTransitionForTest]\n );\n\n // Close the drawer when the show prop changes to false\n useEffect(() => {\n if (renderDrawer && !show) {\n startCloseTransition('external');\n }\n }, [renderDrawer, show, startCloseTransition]);\n\n // Show the drawer when the show prop changes to true\n useEffect(() => {\n if (show) {\n setRenderDrawer(true);\n }\n }, [show]);\n\n // Close the drawer when the escape key is pressed. Only listen while this\n // drawer is open so a closed instance never preventDefaults Escape for\n // other components, and only the top-most open drawer reacts so stacked\n // drawers close one at a time rather than all at once.\n useEffect(() => {\n if (!renderDrawer || !closeOnEscape) {\n return;\n }\n\n const drawerIdentity = drawerIdRef.current;\n openDrawerStack.push(drawerIdentity);\n\n const removeListener = effectEventListener(window, 'keydown', (event) => {\n if (!(event instanceof KeyboardEvent) || event.key !== 'Escape') {\n return;\n }\n if (openDrawerStack[openDrawerStack.length - 1] !== drawerIdentity) {\n return;\n }\n event.preventDefault();\n startCloseTransition('escape');\n });\n\n return () => {\n const index = openDrawerStack.lastIndexOf(drawerIdentity);\n if (index !== -1) {\n openDrawerStack.splice(index, 1);\n }\n removeListener();\n };\n }, [renderDrawer, closeOnEscape, startCloseTransition]);\n\n // Close the drawer when the backdrop is clicked\n useEffect(() => {\n const handleBackdropClick = (event: MouseEvent) => {\n if (event.target === backdropRef.current && closeOnOutsideClick) {\n startCloseTransition('backdrop');\n }\n };\n\n window.addEventListener('click', handleBackdropClick);\n\n return () => {\n window.removeEventListener('click', handleBackdropClick);\n };\n }, [closeOnOutsideClick, startCloseTransition]);\n\n // Prevent body scrolling while any drawer is open. Ref-counted across\n // instances so closing one drawer does not unlock scroll while another is\n // still open; the first drawer to open captures the body's prior overflow\n // and padding and the last to close restores them. The scrollbar's width is\n // added as padding-right while locked so hiding the scrollbar doesn't shift\n // the page (mirrors modal/PreventModalScroll).\n useEffect(() => {\n if (!show) {\n return;\n }\n\n if (openDrawerCount === 0) {\n previousBodyOverflow = document.body.style.overflow;\n previousBodyPaddingRight = document.body.style.paddingRight;\n\n const scrollbarWidth = window.innerWidth - document.documentElement.clientWidth;\n if (scrollbarWidth > 0) {\n document.body.style.paddingRight = `${scrollbarWidth}px`;\n }\n }\n openDrawerCount += 1;\n document.body.style.overflow = 'hidden';\n\n return () => {\n openDrawerCount -= 1;\n if (openDrawerCount === 0) {\n document.body.style.overflow = previousBodyOverflow;\n document.body.style.paddingRight = previousBodyPaddingRight;\n }\n };\n }, [show]);\n\n // Render children when the drawer is closed and keepInDOMWhileClosed is true\n const renderWhenClosed = keepInDOMWhileClosed || renderDrawer;\n\n return (\n <>\n <div\n className={cn(\n 'hui-focus-visible-outline invisible fixed inset-0 z-30 bg-background-overlay opacity-0 duration-500 focus:m-2xs focus:transition-none',\n {\n 'opacity-1 visible': renderDrawer,\n 'pointer-events-none invisible opacity-0': !renderDrawer,\n 'transition-none': removeTransitionForTest,\n }\n )}\n data-testid=\"drawer-backdrop\"\n ref={backdropRef}\n />\n <dialog\n aria-label=\"Drawer Menu\"\n className={cn(\n // GENERAL\n 'm-w-[320px] fixed top-0 z-40 flex h-full max-h-full w-full flex-col p-0',\n // SIZE\n {\n 'h-[100vh] w-[100vw]': size === 'full',\n 'max-w-[320px]': size === 'narrow',\n 'max-w-[480px]': size === 'wide',\n 'max-w-[720px]': size === 'extended',\n },\n // SHADOW\n { 'shadow-04': hasShadow },\n // ANCHOR\n { 'left-0 ml-0': anchor === 'left', 'right-0 mr-0': anchor === 'right' },\n // ANIMATION\n {\n 'invisible -translate-x-full opacity-0 transition-all': !renderDrawer && anchor === 'left',\n 'invisible translate-x-full opacity-0 transition-all': !renderDrawer && anchor === 'right',\n 'opacity-1 -translate-x-0 transition-all': renderDrawer && anchor === 'left',\n 'opacity-1 translate-x-0 transition-all': renderDrawer && anchor === 'right',\n 'transition-none': removeTransitionForTest,\n },\n className\n )}\n data-hui-id=\"Drawer\"\n onTransitionEnd={() => !renderDrawer && handleClose(reasonForClose.current)}\n open={renderDrawer}\n >\n {customHeader !== undefined ? (\n customHeader\n ) : (\n <DialogHeader\n density={density}\n onBackButtonClick={onBackButtonClick}\n onCloseButtonClick={() => startCloseTransition('closeButton')}\n textAlign={headerTextAlign}\n >\n {headerText}\n </DialogHeader>\n )}\n <DialogContent\n density={density}\n disableScroll={disableScroll}\n renderWhenClosed={renderWhenClosed}\n >\n {children}\n </DialogContent>\n {actions && (\n <DialogActions\n density={density}\n useCustomButtonContainer={useCustomButtonContainer}\n >\n {actions}\n </DialogActions>\n )}\n </dialog>\n </>\n );\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Drawer-3rA9dGCl.cjs","names":["ModalContext","ModalContext","effectEventListener","ModalContext","IconButton","ArrowLeft","H2","Close","nodeEnv","effectEventListener"],"sources":["../src/utils/keepTransition.ts","../src/Drawer/components/DialogActions/DialogActions.tsx","../src/Drawer/components/DialogContent/DialogContent.tsx","../src/Drawer/components/DialogHeader/DialogHeader.tsx","../src/Drawer/Drawer.tsx"],"sourcesContent":["declare const process:\n | {\n env?: {\n KEEP_TRANSITION?: string;\n };\n }\n | undefined;\n\n/**\n * Test-only escape hatch, read at call time: Drawer specs set\n * `process.env.KEEP_TRANSITION = 'true'` at runtime to opt back into CSS\n * transitions. Unlike `nodeEnv` (a module-load-time read), a call-time read\n * sees that mutation.\n */\nexport const keepTransition = () => (typeof process === 'undefined' ? undefined : process.env?.KEEP_TRANSITION);\n","import { cn } from '@evolve.ui/theme-system';\nimport { useAtomValue } from 'jotai';\nimport { ReactNode, useContext } from 'react';\n\nimport { ModalContext } from '../../../Modal/context';\n\ntype Props = {\n children: ReactNode;\n className?: string;\n density?: 'compact' | 'comfortable';\n useCustomButtonContainer?: boolean;\n};\n\nexport const DialogActions = ({ children, className, density, useCustomButtonContainer }: Props) => {\n const { showBottomScrollHintAtom } = useContext(ModalContext);\n const showBottomScrollHint = useAtomValue(showBottomScrollHintAtom);\n\n return (\n <div\n className={cn(\n 'flex grow-0 gap-sm p-sm',\n {\n '[&_button]:grow-[1]': !useCustomButtonContainer,\n 'p-xs': density === 'compact',\n 'shadow-05': showBottomScrollHint,\n },\n className\n )}\n >\n {children}\n </div>\n );\n};\n","import { cn } from '@evolve.ui/theme-system';\nimport { useSetAtom } from 'jotai';\nimport { ReactNode, useCallback, useContext, useEffect, useRef } from 'react';\n\nimport { ModalContext } from '../../../Modal/context';\nimport { effectEventListener } from '../../../utils/effectEventListener';\n\ntype Props = {\n children: ReactNode;\n density?: 'compact' | 'comfortable';\n disableScroll?: boolean;\n renderWhenClosed: boolean;\n};\n\nexport const DialogContent = ({ children, density, disableScroll = false, renderWhenClosed }: Props) => {\n const { showBottomScrollHintAtom, showTopScrollHintAtom } = useContext(ModalContext);\n const setShowBottomScrollHint = useSetAtom(showBottomScrollHintAtom);\n const setShowTopScrollHint = useSetAtom(showTopScrollHintAtom);\n\n const handleScroll = useCallback(\n (contentRef: HTMLDivElement) => () => {\n if (contentRef.scrollHeight > contentRef.clientHeight + 32) {\n const atTheBottom =\n Math.round(contentRef.scrollHeight - contentRef.scrollTop) - 5 < contentRef.clientHeight;\n const atTheTop = contentRef.scrollTop < 25;\n\n setShowBottomScrollHint(!atTheBottom);\n setShowTopScrollHint(!atTheTop);\n } else if (contentRef.scrollTop === 0) {\n setShowBottomScrollHint(false);\n setShowTopScrollHint(false);\n }\n },\n [setShowBottomScrollHint, setShowTopScrollHint]\n );\n\n const onScrollRef = useRef<ReturnType<typeof handleScroll>>(null);\n\n // Trigger handleScroll on window resize\n useEffect(() => {\n return effectEventListener(window, 'resize', () => onScrollRef.current?.());\n }, [handleScroll]);\n\n return (\n <div\n className={cn('grow-[1] border-y border-solid border-border-secondary', {\n 'flex flex-col overflow-hidden': disableScroll,\n 'h-[100vh] overflow-y-auto': !disableScroll,\n 'p-sm': !disableScroll && density !== 'compact',\n 'p-xs': !disableScroll && density === 'compact',\n })}\n data-testid=\"dialog-content\"\n ref={(ref) => {\n if (!ref) {\n return;\n }\n\n const onScroll = handleScroll(ref);\n onScrollRef.current = onScroll;\n\n const resizeObserver = new ResizeObserver(() => {\n const scrollHeight = ref.scrollHeight;\n const clientHeight = ref.clientHeight;\n\n if (scrollHeight === clientHeight + 32) {\n setShowBottomScrollHint(false);\n setShowTopScrollHint(false);\n } else {\n onScroll();\n }\n });\n\n resizeObserver.observe(ref);\n ref.addEventListener('scroll', onScroll);\n }}\n >\n {renderWhenClosed ? children : null}\n </div>\n );\n};\n","import { cn } from '@evolve.ui/theme-system';\nimport { useAtomValue } from 'jotai';\nimport { ReactNode, useContext } from 'react';\n\nimport { IconButton } from '../../../IconButton/IconButton';\nimport { ArrowLeft, Close } from '../../../Icons';\nimport { ModalContext } from '../../../Modal/context';\nimport { H2 } from '../../../Typography/Text/Text';\n\ntype Props = {\n children?: ReactNode;\n density: 'compact' | 'comfortable';\n onBackButtonClick?: () => void;\n onCloseButtonClick: () => void;\n textAlign?: 'center' | 'left' | 'right';\n};\n\nexport const DialogHeader = ({\n children,\n density = 'comfortable',\n onBackButtonClick,\n onCloseButtonClick,\n textAlign = 'center',\n}: Props) => {\n const { showTopScrollHintAtom } = useContext(ModalContext);\n const showTopScrollHint = useAtomValue(showTopScrollHintAtom);\n\n return (\n <div\n className={cn('relative grid grid-cols-[42px_1fr_42px] gap-[4px] p-sm', {\n 'p-xs': density === 'compact',\n 'shadow-01': showTopScrollHint,\n })}\n >\n {onBackButtonClick !== undefined && (\n <IconButton\n aria-label=\"Go Back\"\n className={cn('col-start-1 col-end-2')}\n data-testid=\"back-button\"\n hideTooltip\n icon={ArrowLeft}\n onClick={onBackButtonClick}\n size=\"md\"\n type=\"button\"\n />\n )}\n <div\n className={cn('col-start-2 col-end-3 flex', {\n 'justify-center text-center': textAlign === 'center',\n 'justify-end text-right': textAlign === 'right',\n 'justify-start text-left': textAlign === 'left',\n })}\n data-testid=\"dialog-header-text-container\"\n >\n {typeof children === 'string' ? <H2 className=\"pt-[6px]\">{children}</H2> : children}\n </div>\n <IconButton\n className={cn('col-start-3 col-end-4')}\n data-testid=\"close-button\"\n hideTooltip\n icon={Close}\n onClick={onCloseButtonClick}\n size=\"md\"\n type=\"button\"\n />\n </div>\n );\n};\n","import { cn } from '@evolve.ui/theme-system';\nimport { ReactNode, useCallback, useEffect, useRef, useState } from 'react';\n\nimport { effectEventListener } from '../utils/effectEventListener';\nimport { keepTransition } from '../utils/keepTransition';\nimport { nodeEnv } from '../utils/nodeEnv';\nimport { DialogActions } from './components/DialogActions/DialogActions';\nimport { DialogContent } from './components/DialogContent/DialogContent';\nimport { DialogHeader } from './components/DialogHeader/DialogHeader';\n\ntype ReasonForClose = 'backdrop' | 'closeButton' | 'escape' | 'external';\n\ntype Props = {\n /**\n * Optional actions to display at the bottom of the drawer\n * Actions container has these styles:\n * ```css\n * display: flex;\n * gap: 16px;\n * > button {\n * flex-grow: 1;\n * }\n * ```\n *\n * Usage:\n * ```tsx\n * <Drawer actions={<Button>Save</Button>} />\n * ```\n *\n */\n actions?: ReactNode;\n /**\n * Optional anchor for the drawer\n *\n * Usage:\n * ```tsx\n * <Drawer anchor=\"left\" />\n * ```\n *\n * @default 'right'\n */\n anchor?: 'left' | 'right';\n /**\n * Children of the drawer are the content of the drawer\n *\n * Usage:\n * ```tsx\n * <Drawer><div>Hello World</div></Drawer>\n * ```\n *\n */\n children?: ReactNode;\n /**\n * Optional class name for the drawer\n *\n * Usage:\n * ```tsx\n * <Drawer className=\"bg-red-500\" />\n * ```\n *\n */\n className?: string;\n /**\n * Optional flag to close the drawer when the user clicks outside\n *\n * Usage:\n * ```tsx\n * <Drawer closeOnOutsideClick={false} />\n * ```\n *\n * @default true\n */\n closeOnOutsideClick?: boolean;\n /**\n * Optional flag to close the drawer when the user presses the Escape key\n *\n * Usage:\n * ```tsx\n * <Drawer closeOnEscape={false} />\n * ```\n *\n * @default true\n */\n closeOnEscape?: boolean;\n /**\n * Optional custom header to replace the default DialogHeader\n *\n * Usage:\n * ```tsx\n * <Drawer customHeader={<div>Custom Header</div>} />\n * ```\n *\n */\n customHeader?: ReactNode;\n /**\n * Optional density for the drawer\n *\n * Usage:\n * ```tsx\n * <Drawer density=\"compact\" />\n * ```\n *\n * @default 'comfortable'\n */\n density?: 'compact' | 'comfortable';\n /**\n * Optional flag to disable scrolling in the drawer content area\n * Useful when the content has its own scrollable areas (e.g., tabs)\n *\n * Usage:\n * ```tsx\n * <Drawer disableScroll />\n * ```\n *\n * @default false\n */\n disableScroll?: boolean;\n /**\n * Required function call when drawer closes, this will almost always be a call to `setShowState(false)`\n *\n * Usage:\n * ```tsx\n * const [show, setShow] = useState(false);\n * ...\n * <Drawer handleClose={() => setShow(false)} />\n * ```\n *\n */\n handleClose: (reason?: ReasonForClose) => void;\n /**\n * Optional flag that controls whether the drawer has a drop shadow\n *\n * Usage:\n * ```tsx\n * <Drawer hasShadow />\n * ```\n *\n */\n hasShadow?: boolean;\n /**\n * Optional header text for the drawer, appears at the top of the drawer\n *\n * Usage:\n * ```tsx\n * <Drawer headerText=\"Hello World\" />\n * ```\n *\n */\n headerText?: string | ReactNode;\n /**\n * Optional alignment for the header text\n *\n * Usage:\n * ```tsx\n * <Drawer headerTextAlign=\"left\" />\n * ```\n *\n * @default 'center'\n */\n headerTextAlign?: 'center' | 'left' | 'right';\n /**\n * Optional flag to keep the drawer in the DOM while closed\n *\n * Usage:\n * ```tsx\n * <Drawer keepInDOMWhileClosed={false} />\n * ```\n * @default true\n */\n keepInDOMWhileClosed?: boolean;\n\n /**\n * Optional function call when the back button is clicked\n *\n * Usage:\n * ```tsx\n * <Drawer onBackButtonClick={() => console.log('Back button clicked')} />\n * ```\n *\n */\n onBackButtonClick?: () => void;\n /**\n * Required flag to show the drawer\n *\n * Usage:\n * ```tsx\n * <Drawer show />\n * ```\n *\n */\n show: boolean;\n /**\n * Optional size for the drawer\n *\n * Usage:\n * ```tsx\n * <Drawer size=\"wide\" />\n * ```\n *\n * @default 'narrow'\n */\n size?: 'narrow' | 'wide' | 'extended' | 'full';\n /**\n * Optional flag to control the action container\n *\n * Usage:\n * ```tsx\n * <Drawer useCustomButtonContainer />\n * ```\n *\n */\n useCustomButtonContainer?: boolean;\n};\n\n// Open drawers share a single body scroll-lock. Module-scoped so the lock is\n// released only when the last open drawer closes, and so the body's original\n// overflow / padding are captured once (when the first drawer opens) and\n// restored at the end rather than hardcoding values.\nlet openDrawerCount = 0;\nlet previousBodyOverflow = '';\nlet previousBodyPaddingRight = '';\n\n// Identities of currently-open drawers, in open order. Escape only closes the\n// last one pushed (the top-most), so stacked drawers close one at a time\n// instead of all collapsing on a single keypress. Per-instance ref objects are\n// used as identities rather than useId so this doesn't consume React's id\n// sequence and shift autogenerated ids in consumer snapshots.\nconst openDrawerStack: object[] = [];\n\n/**\n * A drawer component using the `dialog` element\n * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dialog\n */\nexport const Drawer = ({\n actions,\n anchor = 'right',\n children,\n className,\n closeOnEscape = true,\n closeOnOutsideClick = true,\n customHeader,\n density = 'comfortable',\n disableScroll = false,\n handleClose,\n hasShadow = false,\n headerText,\n headerTextAlign = 'center',\n keepInDOMWhileClosed = true,\n onBackButtonClick,\n show,\n size = 'narrow',\n useCustomButtonContainer = false,\n}: Props) => {\n const reasonForClose = useRef<ReasonForClose>('external');\n // Per-instance ref instead of a shared id: several Drawers can be mounted at\n // once, and a duplicate id would make a lookup match the wrong backdrop.\n const backdropRef = useRef<HTMLDivElement>(null);\n const drawerIdRef = useRef<object>({});\n const [renderDrawer, setRenderDrawer] = useState(show);\n\n const removeTransitionForTest = Boolean(nodeEnv === 'test') && Boolean(keepTransition() !== 'true');\n\n const startCloseTransition = useCallback(\n (reason: ReasonForClose) => {\n setRenderDrawer(false);\n reasonForClose.current = reason;\n\n // Close the drawer immediately in test environment\n if (removeTransitionForTest) {\n handleClose(reason);\n }\n },\n [handleClose, removeTransitionForTest]\n );\n\n // Close the drawer when the show prop changes to false\n useEffect(() => {\n if (renderDrawer && !show) {\n startCloseTransition('external');\n }\n }, [renderDrawer, show, startCloseTransition]);\n\n // Show the drawer when the show prop changes to true\n useEffect(() => {\n if (show) {\n setRenderDrawer(true);\n }\n }, [show]);\n\n // Close the drawer when the escape key is pressed. Only listen while this\n // drawer is open so a closed instance never preventDefaults Escape for\n // other components, and only the top-most open drawer reacts so stacked\n // drawers close one at a time rather than all at once.\n useEffect(() => {\n if (!renderDrawer || !closeOnEscape) {\n return;\n }\n\n const drawerIdentity = drawerIdRef.current;\n openDrawerStack.push(drawerIdentity);\n\n const removeListener = effectEventListener(window, 'keydown', (event) => {\n if (!(event instanceof KeyboardEvent) || event.key !== 'Escape') {\n return;\n }\n if (openDrawerStack[openDrawerStack.length - 1] !== drawerIdentity) {\n return;\n }\n event.preventDefault();\n startCloseTransition('escape');\n });\n\n return () => {\n const index = openDrawerStack.lastIndexOf(drawerIdentity);\n if (index !== -1) {\n openDrawerStack.splice(index, 1);\n }\n removeListener();\n };\n }, [renderDrawer, closeOnEscape, startCloseTransition]);\n\n // Close the drawer when the backdrop is clicked\n useEffect(() => {\n const handleBackdropClick = (event: MouseEvent) => {\n if (event.target === backdropRef.current && closeOnOutsideClick) {\n startCloseTransition('backdrop');\n }\n };\n\n window.addEventListener('click', handleBackdropClick);\n\n return () => {\n window.removeEventListener('click', handleBackdropClick);\n };\n }, [closeOnOutsideClick, startCloseTransition]);\n\n // Prevent body scrolling while any drawer is open. Ref-counted across\n // instances so closing one drawer does not unlock scroll while another is\n // still open; the first drawer to open captures the body's prior overflow\n // and padding and the last to close restores them. The scrollbar's width is\n // added as padding-right while locked so hiding the scrollbar doesn't shift\n // the page (mirrors modal/PreventModalScroll).\n useEffect(() => {\n if (!show) {\n return;\n }\n\n if (openDrawerCount === 0) {\n previousBodyOverflow = document.body.style.overflow;\n previousBodyPaddingRight = document.body.style.paddingRight;\n\n const scrollbarWidth = window.innerWidth - document.documentElement.clientWidth;\n if (scrollbarWidth > 0) {\n document.body.style.paddingRight = `${scrollbarWidth}px`;\n }\n }\n openDrawerCount += 1;\n document.body.style.overflow = 'hidden';\n\n return () => {\n openDrawerCount -= 1;\n if (openDrawerCount === 0) {\n document.body.style.overflow = previousBodyOverflow;\n document.body.style.paddingRight = previousBodyPaddingRight;\n }\n };\n }, [show]);\n\n // Render children when the drawer is closed and keepInDOMWhileClosed is true\n const renderWhenClosed = keepInDOMWhileClosed || renderDrawer;\n\n return (\n <>\n <div\n className={cn('invisible fixed inset-0 z-30 bg-background-overlay opacity-0 duration-500', {\n 'opacity-1 visible': renderDrawer,\n 'pointer-events-none invisible opacity-0': !renderDrawer,\n 'transition-none': removeTransitionForTest,\n })}\n data-testid=\"drawer-backdrop\"\n ref={backdropRef}\n />\n <dialog\n aria-label=\"Drawer Menu\"\n className={cn(\n // GENERAL\n 'm-w-[320px] fixed top-0 z-40 flex h-full max-h-full w-full flex-col p-0',\n // SIZE\n {\n 'h-[100vh] w-[100vw]': size === 'full',\n 'max-w-[320px]': size === 'narrow',\n 'max-w-[480px]': size === 'wide',\n 'max-w-[720px]': size === 'extended',\n },\n // SHADOW\n { 'shadow-04': hasShadow },\n // ANCHOR\n { 'left-0 ml-0': anchor === 'left', 'right-0 mr-0': anchor === 'right' },\n // ANIMATION\n {\n 'invisible -translate-x-full opacity-0 transition-all': !renderDrawer && anchor === 'left',\n 'invisible translate-x-full opacity-0 transition-all': !renderDrawer && anchor === 'right',\n 'opacity-1 -translate-x-0 transition-all': renderDrawer && anchor === 'left',\n 'opacity-1 translate-x-0 transition-all': renderDrawer && anchor === 'right',\n 'transition-none': removeTransitionForTest,\n },\n className\n )}\n data-hui-id=\"Drawer\"\n onTransitionEnd={() => !renderDrawer && handleClose(reasonForClose.current)}\n open={renderDrawer}\n >\n {customHeader !== undefined ? (\n customHeader\n ) : (\n <DialogHeader\n density={density}\n onBackButtonClick={onBackButtonClick}\n onCloseButtonClick={() => startCloseTransition('closeButton')}\n textAlign={headerTextAlign}\n >\n {headerText}\n </DialogHeader>\n )}\n <DialogContent\n density={density}\n disableScroll={disableScroll}\n renderWhenClosed={renderWhenClosed}\n >\n {children}\n </DialogContent>\n {actions && (\n <DialogActions\n density={density}\n useCustomButtonContainer={useCustomButtonContainer}\n >\n {actions}\n </DialogActions>\n )}\n </dialog>\n </>\n );\n};\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Drawer-CFZbwg0R.d.cts","names":[],"sources":["../src/Drawer/Drawer.tsx"],"mappings":";;;KAUK,cAAA;AAAA,KAEA,KAAA;EAFA;;;;AAAc;AAAA;;;;;;;;;;;;EAoBf,OAAA,GAAU,SAAA;EAqBV;;;;;;;;;;EAVA,MAAA;EAuFc;;;;;;;;;EA7Ed,QAAA,GAAW,SAAA;EAgKa;AAAA;AAsB5B;;;;;;;EA5KI,SAAA;EA4KmB;;;;;;;;;;EAjKnB,mBAAA;EAiKmB;;;;;;;;;;EAtJnB,aAAA;EAsJmB;;;;;;;;;EA5InB,YAAA,GAAe,SAAA;EA4II;;;;;;;;;;EAjInB,OAAA;EAiImB;;;;;;;;;;;EArHnB,aAAA;
|
|
1
|
+
{"version":3,"file":"Drawer-CFZbwg0R.d.cts","names":[],"sources":["../src/Drawer/Drawer.tsx"],"mappings":";;;KAUK,cAAA;AAAA,KAEA,KAAA;EAFA;;;;AAAc;AAAA;;;;;;;;;;;;EAoBf,OAAA,GAAU,SAAA;EAqBV;;;;;;;;;;EAVA,MAAA;EAuFc;;;;;;;;;EA7Ed,QAAA,GAAW,SAAA;EAgKa;AAAA;AAsB5B;;;;;;;EA5KI,SAAA;EA4KmB;;;;;;;;;;EAjKnB,mBAAA;EAiKmB;;;;;;;;;;EAtJnB,aAAA;EAsJmB;;;;;;;;;EA5InB,YAAA,GAAe,SAAA;EA4II;;;;;;;;;;EAjInB,OAAA;EAiImB;;;;;;;;;;;EArHnB,aAAA;EAsUH;AAAA;;;;;;;;;;EA1TG,WAAA,GAAc,MAAA,GAAS,cAAA;;;;;;;;;;EAUvB,SAAA;;;;;;;;;;EAUA,UAAA,YAAsB,SAAA;;;;;;;;;;;EAWtB,eAAA;;;;;;;;;;EAUA,oBAAA;;;;;;;;;;EAWA,iBAAA;;;;;;;;;;EAUA,IAAA;;;;;;;;;;;EAWA,IAAA;;;;;;;;;;EAUA,wBAAA;AAAA;;;;;cAsBS,MAAA;EAAU,OAAA;EAAA,MAAA;EAAA,QAAA;EAAA,SAAA;EAAA,aAAA;EAAA,mBAAA;EAAA,YAAA;EAAA,OAAA;EAAA,aAAA;EAAA,WAAA;EAAA,SAAA;EAAA,UAAA;EAAA,eAAA;EAAA,oBAAA;EAAA,iBAAA;EAAA,IAAA;EAAA,IAAA;EAAA;AAAA,GAmBpB,KAAA,iCAAK,GAAA,CAAA,OAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Drawer-CFZbwg0R.d.mts","names":[],"sources":["../src/Drawer/Drawer.tsx"],"mappings":";;;KAUK,cAAA;AAAA,KAEA,KAAA;EAFA;;;;AAAc;AAAA;;;;;;;;;;;;EAoBf,OAAA,GAAU,SAAA;EAqBV;;;;;;;;;;EAVA,MAAA;EAuFc;;;;;;;;;EA7Ed,QAAA,GAAW,SAAA;EAgKa;AAAA;AAsB5B;;;;;;;EA5KI,SAAA;EA4KmB;;;;;;;;;;EAjKnB,mBAAA;EAiKmB;;;;;;;;;;EAtJnB,aAAA;EAsJmB;;;;;;;;;EA5InB,YAAA,GAAe,SAAA;EA4II;;;;;;;;;;EAjInB,OAAA;EAiImB;;;;;;;;;;;EArHnB,aAAA;
|
|
1
|
+
{"version":3,"file":"Drawer-CFZbwg0R.d.mts","names":[],"sources":["../src/Drawer/Drawer.tsx"],"mappings":";;;KAUK,cAAA;AAAA,KAEA,KAAA;EAFA;;;;AAAc;AAAA;;;;;;;;;;;;EAoBf,OAAA,GAAU,SAAA;EAqBV;;;;;;;;;;EAVA,MAAA;EAuFc;;;;;;;;;EA7Ed,QAAA,GAAW,SAAA;EAgKa;AAAA;AAsB5B;;;;;;;EA5KI,SAAA;EA4KmB;;;;;;;;;;EAjKnB,mBAAA;EAiKmB;;;;;;;;;;EAtJnB,aAAA;EAsJmB;;;;;;;;;EA5InB,YAAA,GAAe,SAAA;EA4II;;;;;;;;;;EAjInB,OAAA;EAiImB;;;;;;;;;;;EArHnB,aAAA;EAsUH;AAAA;;;;;;;;;;EA1TG,WAAA,GAAc,MAAA,GAAS,cAAA;;;;;;;;;;EAUvB,SAAA;;;;;;;;;;EAUA,UAAA,YAAsB,SAAA;;;;;;;;;;;EAWtB,eAAA;;;;;;;;;;EAUA,oBAAA;;;;;;;;;;EAWA,iBAAA;;;;;;;;;;EAUA,IAAA;;;;;;;;;;;EAWA,IAAA;;;;;;;;;;EAUA,wBAAA;AAAA;;;;;cAsBS,MAAA;EAAU,OAAA;EAAA,MAAA;EAAA,QAAA;EAAA,SAAA;EAAA,aAAA;EAAA,mBAAA;EAAA,YAAA;EAAA,OAAA;EAAA,aAAA;EAAA,WAAA;EAAA,SAAA;EAAA,UAAA;EAAA,eAAA;EAAA,oBAAA;EAAA,iBAAA;EAAA,IAAA;EAAA,IAAA;EAAA;AAAA,GAmBpB,KAAA,iCAAK,GAAA,CAAA,OAAA"}
|
|
@@ -199,7 +199,7 @@ const Drawer = ({ actions, anchor = "right", children, className, closeOnEscape
|
|
|
199
199
|
}, [show]);
|
|
200
200
|
const renderWhenClosed = keepInDOMWhileClosed || renderDrawer;
|
|
201
201
|
return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("div", {
|
|
202
|
-
className: cn("
|
|
202
|
+
className: cn("invisible fixed inset-0 z-30 bg-background-overlay opacity-0 duration-500", {
|
|
203
203
|
"opacity-1 visible": renderDrawer,
|
|
204
204
|
"pointer-events-none invisible opacity-0": !renderDrawer,
|
|
205
205
|
"transition-none": removeTransitionForTest
|
|
@@ -251,4 +251,4 @@ const Drawer = ({ actions, anchor = "right", children, className, closeOnEscape
|
|
|
251
251
|
//#endregion
|
|
252
252
|
export { Drawer as t };
|
|
253
253
|
|
|
254
|
-
//# sourceMappingURL=Drawer-
|
|
254
|
+
//# sourceMappingURL=Drawer-DzKEmewj.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Drawer-BkCPfK6P.mjs","names":[],"sources":["../src/utils/keepTransition.ts","../src/Drawer/components/DialogActions/DialogActions.tsx","../src/Drawer/components/DialogContent/DialogContent.tsx","../src/Drawer/components/DialogHeader/DialogHeader.tsx","../src/Drawer/Drawer.tsx"],"sourcesContent":["declare const process:\n | {\n env?: {\n KEEP_TRANSITION?: string;\n };\n }\n | undefined;\n\n/**\n * Test-only escape hatch, read at call time: Drawer specs set\n * `process.env.KEEP_TRANSITION = 'true'` at runtime to opt back into CSS\n * transitions. Unlike `nodeEnv` (a module-load-time read), a call-time read\n * sees that mutation.\n */\nexport const keepTransition = () => (typeof process === 'undefined' ? undefined : process.env?.KEEP_TRANSITION);\n","import { cn } from '@evolve.ui/theme-system';\nimport { useAtomValue } from 'jotai';\nimport { ReactNode, useContext } from 'react';\n\nimport { ModalContext } from '../../../Modal/context';\n\ntype Props = {\n children: ReactNode;\n className?: string;\n density?: 'compact' | 'comfortable';\n useCustomButtonContainer?: boolean;\n};\n\nexport const DialogActions = ({ children, className, density, useCustomButtonContainer }: Props) => {\n const { showBottomScrollHintAtom } = useContext(ModalContext);\n const showBottomScrollHint = useAtomValue(showBottomScrollHintAtom);\n\n return (\n <div\n className={cn(\n 'flex grow-0 gap-sm p-sm',\n {\n '[&_button]:grow-[1]': !useCustomButtonContainer,\n 'p-xs': density === 'compact',\n 'shadow-05': showBottomScrollHint,\n },\n className\n )}\n >\n {children}\n </div>\n );\n};\n","import { cn } from '@evolve.ui/theme-system';\nimport { useSetAtom } from 'jotai';\nimport { ReactNode, useCallback, useContext, useEffect, useRef } from 'react';\n\nimport { ModalContext } from '../../../Modal/context';\nimport { effectEventListener } from '../../../utils/effectEventListener';\n\ntype Props = {\n children: ReactNode;\n density?: 'compact' | 'comfortable';\n disableScroll?: boolean;\n renderWhenClosed: boolean;\n};\n\nexport const DialogContent = ({ children, density, disableScroll = false, renderWhenClosed }: Props) => {\n const { showBottomScrollHintAtom, showTopScrollHintAtom } = useContext(ModalContext);\n const setShowBottomScrollHint = useSetAtom(showBottomScrollHintAtom);\n const setShowTopScrollHint = useSetAtom(showTopScrollHintAtom);\n\n const handleScroll = useCallback(\n (contentRef: HTMLDivElement) => () => {\n if (contentRef.scrollHeight > contentRef.clientHeight + 32) {\n const atTheBottom =\n Math.round(contentRef.scrollHeight - contentRef.scrollTop) - 5 < contentRef.clientHeight;\n const atTheTop = contentRef.scrollTop < 25;\n\n setShowBottomScrollHint(!atTheBottom);\n setShowTopScrollHint(!atTheTop);\n } else if (contentRef.scrollTop === 0) {\n setShowBottomScrollHint(false);\n setShowTopScrollHint(false);\n }\n },\n [setShowBottomScrollHint, setShowTopScrollHint]\n );\n\n const onScrollRef = useRef<ReturnType<typeof handleScroll>>(null);\n\n // Trigger handleScroll on window resize\n useEffect(() => {\n return effectEventListener(window, 'resize', () => onScrollRef.current?.());\n }, [handleScroll]);\n\n return (\n <div\n className={cn('grow-[1] border-y border-solid border-border-secondary', {\n 'flex flex-col overflow-hidden': disableScroll,\n 'h-[100vh] overflow-y-auto': !disableScroll,\n 'p-sm': !disableScroll && density !== 'compact',\n 'p-xs': !disableScroll && density === 'compact',\n })}\n data-testid=\"dialog-content\"\n ref={(ref) => {\n if (!ref) {\n return;\n }\n\n const onScroll = handleScroll(ref);\n onScrollRef.current = onScroll;\n\n const resizeObserver = new ResizeObserver(() => {\n const scrollHeight = ref.scrollHeight;\n const clientHeight = ref.clientHeight;\n\n if (scrollHeight === clientHeight + 32) {\n setShowBottomScrollHint(false);\n setShowTopScrollHint(false);\n } else {\n onScroll();\n }\n });\n\n resizeObserver.observe(ref);\n ref.addEventListener('scroll', onScroll);\n }}\n >\n {renderWhenClosed ? children : null}\n </div>\n );\n};\n","import { cn } from '@evolve.ui/theme-system';\nimport { useAtomValue } from 'jotai';\nimport { ReactNode, useContext } from 'react';\n\nimport { IconButton } from '../../../IconButton/IconButton';\nimport { ArrowLeft, Close } from '../../../Icons';\nimport { ModalContext } from '../../../Modal/context';\nimport { H2 } from '../../../Typography/Text/Text';\n\ntype Props = {\n children?: ReactNode;\n density: 'compact' | 'comfortable';\n onBackButtonClick?: () => void;\n onCloseButtonClick: () => void;\n textAlign?: 'center' | 'left' | 'right';\n};\n\nexport const DialogHeader = ({\n children,\n density = 'comfortable',\n onBackButtonClick,\n onCloseButtonClick,\n textAlign = 'center',\n}: Props) => {\n const { showTopScrollHintAtom } = useContext(ModalContext);\n const showTopScrollHint = useAtomValue(showTopScrollHintAtom);\n\n return (\n <div\n className={cn('relative grid grid-cols-[42px_1fr_42px] gap-[4px] p-sm', {\n 'p-xs': density === 'compact',\n 'shadow-01': showTopScrollHint,\n })}\n >\n {onBackButtonClick !== undefined && (\n <IconButton\n aria-label=\"Go Back\"\n className={cn('col-start-1 col-end-2')}\n data-testid=\"back-button\"\n hideTooltip\n icon={ArrowLeft}\n onClick={onBackButtonClick}\n size=\"md\"\n type=\"button\"\n />\n )}\n <div\n className={cn('col-start-2 col-end-3 flex', {\n 'justify-center text-center': textAlign === 'center',\n 'justify-end text-right': textAlign === 'right',\n 'justify-start text-left': textAlign === 'left',\n })}\n data-testid=\"dialog-header-text-container\"\n >\n {typeof children === 'string' ? <H2 className=\"pt-[6px]\">{children}</H2> : children}\n </div>\n <IconButton\n className={cn('col-start-3 col-end-4')}\n data-testid=\"close-button\"\n hideTooltip\n icon={Close}\n onClick={onCloseButtonClick}\n size=\"md\"\n type=\"button\"\n />\n </div>\n );\n};\n","import { cn } from '@evolve.ui/theme-system';\nimport { ReactNode, useCallback, useEffect, useRef, useState } from 'react';\n\nimport { effectEventListener } from '../utils/effectEventListener';\nimport { keepTransition } from '../utils/keepTransition';\nimport { nodeEnv } from '../utils/nodeEnv';\nimport { DialogActions } from './components/DialogActions/DialogActions';\nimport { DialogContent } from './components/DialogContent/DialogContent';\nimport { DialogHeader } from './components/DialogHeader/DialogHeader';\n\ntype ReasonForClose = 'backdrop' | 'closeButton' | 'escape' | 'external';\n\ntype Props = {\n /**\n * Optional actions to display at the bottom of the drawer\n * Actions container has these styles:\n * ```css\n * display: flex;\n * gap: 16px;\n * > button {\n * flex-grow: 1;\n * }\n * ```\n *\n * Usage:\n * ```tsx\n * <Drawer actions={<Button>Save</Button>} />\n * ```\n *\n */\n actions?: ReactNode;\n /**\n * Optional anchor for the drawer\n *\n * Usage:\n * ```tsx\n * <Drawer anchor=\"left\" />\n * ```\n *\n * @default 'right'\n */\n anchor?: 'left' | 'right';\n /**\n * Children of the drawer are the content of the drawer\n *\n * Usage:\n * ```tsx\n * <Drawer><div>Hello World</div></Drawer>\n * ```\n *\n */\n children?: ReactNode;\n /**\n * Optional class name for the drawer\n *\n * Usage:\n * ```tsx\n * <Drawer className=\"bg-red-500\" />\n * ```\n *\n */\n className?: string;\n /**\n * Optional flag to close the drawer when the user clicks outside\n *\n * Usage:\n * ```tsx\n * <Drawer closeOnOutsideClick={false} />\n * ```\n *\n * @default true\n */\n closeOnOutsideClick?: boolean;\n /**\n * Optional flag to close the drawer when the user presses the Escape key\n *\n * Usage:\n * ```tsx\n * <Drawer closeOnEscape={false} />\n * ```\n *\n * @default true\n */\n closeOnEscape?: boolean;\n /**\n * Optional custom header to replace the default DialogHeader\n *\n * Usage:\n * ```tsx\n * <Drawer customHeader={<div>Custom Header</div>} />\n * ```\n *\n */\n customHeader?: ReactNode;\n /**\n * Optional density for the drawer\n *\n * Usage:\n * ```tsx\n * <Drawer density=\"compact\" />\n * ```\n *\n * @default 'comfortable'\n */\n density?: 'compact' | 'comfortable';\n /**\n * Optional flag to disable scrolling in the drawer content area\n * Useful when the content has its own scrollable areas (e.g., tabs)\n *\n * Usage:\n * ```tsx\n * <Drawer disableScroll />\n * ```\n *\n * @default false\n */\n disableScroll?: boolean;\n /**\n * Required function call when drawer closes, this will almost always be a call to `setShowState(false)`\n *\n * Usage:\n * ```tsx\n * const [show, setShow] = useState(false);\n * ...\n * <Drawer handleClose={() => setShow(false)} />\n * ```\n *\n */\n handleClose: (reason?: ReasonForClose) => void;\n /**\n * Optional flag that controls whether the drawer has a drop shadow\n *\n * Usage:\n * ```tsx\n * <Drawer hasShadow />\n * ```\n *\n */\n hasShadow?: boolean;\n /**\n * Optional header text for the drawer, appears at the top of the drawer\n *\n * Usage:\n * ```tsx\n * <Drawer headerText=\"Hello World\" />\n * ```\n *\n */\n headerText?: string | ReactNode;\n /**\n * Optional alignment for the header text\n *\n * Usage:\n * ```tsx\n * <Drawer headerTextAlign=\"left\" />\n * ```\n *\n * @default 'center'\n */\n headerTextAlign?: 'center' | 'left' | 'right';\n /**\n * Optional flag to keep the drawer in the DOM while closed\n *\n * Usage:\n * ```tsx\n * <Drawer keepInDOMWhileClosed={false} />\n * ```\n * @default true\n */\n keepInDOMWhileClosed?: boolean;\n\n /**\n * Optional function call when the back button is clicked\n *\n * Usage:\n * ```tsx\n * <Drawer onBackButtonClick={() => console.log('Back button clicked')} />\n * ```\n *\n */\n onBackButtonClick?: () => void;\n /**\n * Required flag to show the drawer\n *\n * Usage:\n * ```tsx\n * <Drawer show />\n * ```\n *\n */\n show: boolean;\n /**\n * Optional size for the drawer\n *\n * Usage:\n * ```tsx\n * <Drawer size=\"wide\" />\n * ```\n *\n * @default 'narrow'\n */\n size?: 'narrow' | 'wide' | 'extended' | 'full';\n /**\n * Optional flag to control the action container\n *\n * Usage:\n * ```tsx\n * <Drawer useCustomButtonContainer />\n * ```\n *\n */\n useCustomButtonContainer?: boolean;\n};\n\n// Open drawers share a single body scroll-lock. Module-scoped so the lock is\n// released only when the last open drawer closes, and so the body's original\n// overflow / padding are captured once (when the first drawer opens) and\n// restored at the end rather than hardcoding values.\nlet openDrawerCount = 0;\nlet previousBodyOverflow = '';\nlet previousBodyPaddingRight = '';\n\n// Identities of currently-open drawers, in open order. Escape only closes the\n// last one pushed (the top-most), so stacked drawers close one at a time\n// instead of all collapsing on a single keypress. Per-instance ref objects are\n// used as identities rather than useId so this doesn't consume React's id\n// sequence and shift autogenerated ids in consumer snapshots.\nconst openDrawerStack: object[] = [];\n\n/**\n * A drawer component using the `dialog` element\n * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dialog\n */\nexport const Drawer = ({\n actions,\n anchor = 'right',\n children,\n className,\n closeOnEscape = true,\n closeOnOutsideClick = true,\n customHeader,\n density = 'comfortable',\n disableScroll = false,\n handleClose,\n hasShadow = false,\n headerText,\n headerTextAlign = 'center',\n keepInDOMWhileClosed = true,\n onBackButtonClick,\n show,\n size = 'narrow',\n useCustomButtonContainer = false,\n}: Props) => {\n const reasonForClose = useRef<ReasonForClose>('external');\n // Per-instance ref instead of a shared id: several Drawers can be mounted at\n // once, and a duplicate id would make a lookup match the wrong backdrop.\n const backdropRef = useRef<HTMLDivElement>(null);\n const drawerIdRef = useRef<object>({});\n const [renderDrawer, setRenderDrawer] = useState(show);\n\n const removeTransitionForTest = Boolean(nodeEnv === 'test') && Boolean(keepTransition() !== 'true');\n\n const startCloseTransition = useCallback(\n (reason: ReasonForClose) => {\n setRenderDrawer(false);\n reasonForClose.current = reason;\n\n // Close the drawer immediately in test environment\n if (removeTransitionForTest) {\n handleClose(reason);\n }\n },\n [handleClose, removeTransitionForTest]\n );\n\n // Close the drawer when the show prop changes to false\n useEffect(() => {\n if (renderDrawer && !show) {\n startCloseTransition('external');\n }\n }, [renderDrawer, show, startCloseTransition]);\n\n // Show the drawer when the show prop changes to true\n useEffect(() => {\n if (show) {\n setRenderDrawer(true);\n }\n }, [show]);\n\n // Close the drawer when the escape key is pressed. Only listen while this\n // drawer is open so a closed instance never preventDefaults Escape for\n // other components, and only the top-most open drawer reacts so stacked\n // drawers close one at a time rather than all at once.\n useEffect(() => {\n if (!renderDrawer || !closeOnEscape) {\n return;\n }\n\n const drawerIdentity = drawerIdRef.current;\n openDrawerStack.push(drawerIdentity);\n\n const removeListener = effectEventListener(window, 'keydown', (event) => {\n if (!(event instanceof KeyboardEvent) || event.key !== 'Escape') {\n return;\n }\n if (openDrawerStack[openDrawerStack.length - 1] !== drawerIdentity) {\n return;\n }\n event.preventDefault();\n startCloseTransition('escape');\n });\n\n return () => {\n const index = openDrawerStack.lastIndexOf(drawerIdentity);\n if (index !== -1) {\n openDrawerStack.splice(index, 1);\n }\n removeListener();\n };\n }, [renderDrawer, closeOnEscape, startCloseTransition]);\n\n // Close the drawer when the backdrop is clicked\n useEffect(() => {\n const handleBackdropClick = (event: MouseEvent) => {\n if (event.target === backdropRef.current && closeOnOutsideClick) {\n startCloseTransition('backdrop');\n }\n };\n\n window.addEventListener('click', handleBackdropClick);\n\n return () => {\n window.removeEventListener('click', handleBackdropClick);\n };\n }, [closeOnOutsideClick, startCloseTransition]);\n\n // Prevent body scrolling while any drawer is open. Ref-counted across\n // instances so closing one drawer does not unlock scroll while another is\n // still open; the first drawer to open captures the body's prior overflow\n // and padding and the last to close restores them. The scrollbar's width is\n // added as padding-right while locked so hiding the scrollbar doesn't shift\n // the page (mirrors modal/PreventModalScroll).\n useEffect(() => {\n if (!show) {\n return;\n }\n\n if (openDrawerCount === 0) {\n previousBodyOverflow = document.body.style.overflow;\n previousBodyPaddingRight = document.body.style.paddingRight;\n\n const scrollbarWidth = window.innerWidth - document.documentElement.clientWidth;\n if (scrollbarWidth > 0) {\n document.body.style.paddingRight = `${scrollbarWidth}px`;\n }\n }\n openDrawerCount += 1;\n document.body.style.overflow = 'hidden';\n\n return () => {\n openDrawerCount -= 1;\n if (openDrawerCount === 0) {\n document.body.style.overflow = previousBodyOverflow;\n document.body.style.paddingRight = previousBodyPaddingRight;\n }\n };\n }, [show]);\n\n // Render children when the drawer is closed and keepInDOMWhileClosed is true\n const renderWhenClosed = keepInDOMWhileClosed || renderDrawer;\n\n return (\n <>\n <div\n className={cn(\n 'hui-focus-visible-outline invisible fixed inset-0 z-30 bg-background-overlay opacity-0 duration-500 focus:m-2xs focus:transition-none',\n {\n 'opacity-1 visible': renderDrawer,\n 'pointer-events-none invisible opacity-0': !renderDrawer,\n 'transition-none': removeTransitionForTest,\n }\n )}\n data-testid=\"drawer-backdrop\"\n ref={backdropRef}\n />\n <dialog\n aria-label=\"Drawer Menu\"\n className={cn(\n // GENERAL\n 'm-w-[320px] fixed top-0 z-40 flex h-full max-h-full w-full flex-col p-0',\n // SIZE\n {\n 'h-[100vh] w-[100vw]': size === 'full',\n 'max-w-[320px]': size === 'narrow',\n 'max-w-[480px]': size === 'wide',\n 'max-w-[720px]': size === 'extended',\n },\n // SHADOW\n { 'shadow-04': hasShadow },\n // ANCHOR\n { 'left-0 ml-0': anchor === 'left', 'right-0 mr-0': anchor === 'right' },\n // ANIMATION\n {\n 'invisible -translate-x-full opacity-0 transition-all': !renderDrawer && anchor === 'left',\n 'invisible translate-x-full opacity-0 transition-all': !renderDrawer && anchor === 'right',\n 'opacity-1 -translate-x-0 transition-all': renderDrawer && anchor === 'left',\n 'opacity-1 translate-x-0 transition-all': renderDrawer && anchor === 'right',\n 'transition-none': removeTransitionForTest,\n },\n className\n )}\n data-hui-id=\"Drawer\"\n onTransitionEnd={() => !renderDrawer && handleClose(reasonForClose.current)}\n open={renderDrawer}\n >\n {customHeader !== undefined ? (\n customHeader\n ) : (\n <DialogHeader\n density={density}\n onBackButtonClick={onBackButtonClick}\n onCloseButtonClick={() => startCloseTransition('closeButton')}\n textAlign={headerTextAlign}\n >\n {headerText}\n </DialogHeader>\n )}\n <DialogContent\n density={density}\n disableScroll={disableScroll}\n renderWhenClosed={renderWhenClosed}\n >\n {children}\n </DialogContent>\n {actions && (\n <DialogActions\n density={density}\n useCustomButtonContainer={useCustomButtonContainer}\n >\n {actions}\n </DialogActions>\n )}\n </dialog>\n </>\n );\n};\n"],"mappings":";;;;;;;;;;;;;;;;;AAcA,MAAa,uBAAwB,OAAO,YAAY,cAAc,KAAA,IAAY,QAAQ,KAAK;;;ACD/F,MAAa,iBAAiB,EAAE,UAAU,WAAW,SAAS,+BAAsC;CAChG,MAAM,EAAE,6BAA6B,WAAW,YAAY;CAC5D,MAAM,uBAAuB,aAAa,wBAAwB;CAElE,OACI,oBAAC,OAAD;EACI,WAAW,GACP,2BACA;GACI,uBAAuB,CAAC;GACxB,QAAQ,YAAY;GACpB,aAAa;EACjB,GACA,SACJ;EAEC;CACA,CAAA;AAEb;;;AClBA,MAAa,iBAAiB,EAAE,UAAU,SAAS,gBAAgB,OAAO,uBAA8B;CACpG,MAAM,EAAE,0BAA0B,0BAA0B,WAAW,YAAY;CACnF,MAAM,0BAA0B,WAAW,wBAAwB;CACnE,MAAM,uBAAuB,WAAW,qBAAqB;CAE7D,MAAM,eAAe,aAChB,qBAAqC;EAClC,IAAI,WAAW,eAAe,WAAW,eAAe,IAAI;GACxD,MAAM,cACF,KAAK,MAAM,WAAW,eAAe,WAAW,SAAS,IAAI,IAAI,WAAW;GAChF,MAAM,WAAW,WAAW,YAAY;GAExC,wBAAwB,CAAC,WAAW;GACpC,qBAAqB,CAAC,QAAQ;EAClC,OAAO,IAAI,WAAW,cAAc,GAAG;GACnC,wBAAwB,KAAK;GAC7B,qBAAqB,KAAK;EAC9B;CACJ,GACA,CAAC,yBAAyB,oBAAoB,CAClD;CAEA,MAAM,cAAc,OAAwC,IAAI;CAGhE,gBAAgB;EACZ,OAAO,oBAAoB,QAAQ,gBAAgB,YAAY,UAAU,CAAC;CAC9E,GAAG,CAAC,YAAY,CAAC;CAEjB,OACI,oBAAC,OAAD;EACI,WAAW,GAAG,0DAA0D;GACpE,iCAAiC;GACjC,6BAA6B,CAAC;GAC9B,QAAQ,CAAC,iBAAiB,YAAY;GACtC,QAAQ,CAAC,iBAAiB,YAAY;EAC1C,CAAC;EACD,eAAY;EACZ,MAAM,QAAQ;GACV,IAAI,CAAC,KACD;GAGJ,MAAM,WAAW,aAAa,GAAG;GACjC,YAAY,UAAU;GActB,IAZ2B,qBAAqB;IAI5C,IAHqB,IAAI,iBACJ,IAAI,eAEW,IAAI;KACpC,wBAAwB,KAAK;KAC7B,qBAAqB,KAAK;IAC9B,OACI,SAAS;GAEjB,CAEa,CAAC,CAAC,QAAQ,GAAG;GAC1B,IAAI,iBAAiB,UAAU,QAAQ;EAC3C;YAEC,mBAAmB,WAAW;CAC9B,CAAA;AAEb;;;AC9DA,MAAa,gBAAgB,EACzB,UACA,UAAU,eACV,mBACA,oBACA,YAAY,eACH;CACT,MAAM,EAAE,0BAA0B,WAAW,YAAY;CACzD,MAAM,oBAAoB,aAAa,qBAAqB;CAE5D,OACI,qBAAC,OAAD;EACI,WAAW,GAAG,0DAA0D;GACpE,QAAQ,YAAY;GACpB,aAAa;EACjB,CAAC;YAJL;GAMK,sBAAsB,KAAA,KACnB,oBAAC,YAAD;IACI,cAAW;IACX,WAAW,GAAG,uBAAuB;IACrC,eAAY;IACZ,aAAA;IACA,MAAM;IACN,SAAS;IACT,MAAK;IACL,MAAK;GACR,CAAA;GAEL,oBAAC,OAAD;IACI,WAAW,GAAG,8BAA8B;KACxC,8BAA8B,cAAc;KAC5C,0BAA0B,cAAc;KACxC,2BAA2B,cAAc;IAC7C,CAAC;IACD,eAAY;cAEX,OAAO,aAAa,WAAW,oBAAC,IAAD;KAAI,WAAU;KAAY;IAAa,CAAA,IAAI;GAC1E,CAAA;GACL,oBAAC,YAAD;IACI,WAAW,GAAG,uBAAuB;IACrC,eAAY;IACZ,aAAA;IACA,MAAM;IACN,SAAS;IACT,MAAK;IACL,MAAK;GACR,CAAA;EACA;;AAEb;;;ACuJA,IAAI,kBAAkB;AACtB,IAAI,uBAAuB;AAC3B,IAAI,2BAA2B;AAO/B,MAAM,kBAA4B,CAAC;;;;;AAMnC,MAAa,UAAU,EACnB,SACA,SAAS,SACT,UACA,WACA,gBAAgB,MAChB,sBAAsB,MACtB,cACA,UAAU,eACV,gBAAgB,OAChB,aACA,YAAY,OACZ,YACA,kBAAkB,UAClB,uBAAuB,MACvB,mBACA,MACA,OAAO,UACP,2BAA2B,YAClB;CACT,MAAM,iBAAiB,OAAuB,UAAU;CAGxD,MAAM,cAAc,OAAuB,IAAI;CAC/C,MAAM,cAAc,OAAe,CAAC,CAAC;CACrC,MAAM,CAAC,cAAc,mBAAmB,SAAS,IAAI;CAErD,MAAM,0BAA0B,QAAQ,YAAY,MAAM,KAAK,QAAQ,eAAe,MAAM,MAAM;CAElG,MAAM,uBAAuB,aACxB,WAA2B;EACxB,gBAAgB,KAAK;EACrB,eAAe,UAAU;EAGzB,IAAI,yBACA,YAAY,MAAM;CAE1B,GACA,CAAC,aAAa,uBAAuB,CACzC;CAGA,gBAAgB;EACZ,IAAI,gBAAgB,CAAC,MACjB,qBAAqB,UAAU;CAEvC,GAAG;EAAC;EAAc;EAAM;CAAoB,CAAC;CAG7C,gBAAgB;EACZ,IAAI,MACA,gBAAgB,IAAI;CAE5B,GAAG,CAAC,IAAI,CAAC;CAMT,gBAAgB;EACZ,IAAI,CAAC,gBAAgB,CAAC,eAClB;EAGJ,MAAM,iBAAiB,YAAY;EACnC,gBAAgB,KAAK,cAAc;EAEnC,MAAM,iBAAiB,oBAAoB,QAAQ,YAAY,UAAU;GACrE,IAAI,EAAE,iBAAiB,kBAAkB,MAAM,QAAQ,UACnD;GAEJ,IAAI,gBAAgB,gBAAgB,SAAS,OAAO,gBAChD;GAEJ,MAAM,eAAe;GACrB,qBAAqB,QAAQ;EACjC,CAAC;EAED,aAAa;GACT,MAAM,QAAQ,gBAAgB,YAAY,cAAc;GACxD,IAAI,UAAU,IACV,gBAAgB,OAAO,OAAO,CAAC;GAEnC,eAAe;EACnB;CACJ,GAAG;EAAC;EAAc;EAAe;CAAoB,CAAC;CAGtD,gBAAgB;EACZ,MAAM,uBAAuB,UAAsB;GAC/C,IAAI,MAAM,WAAW,YAAY,WAAW,qBACxC,qBAAqB,UAAU;EAEvC;EAEA,OAAO,iBAAiB,SAAS,mBAAmB;EAEpD,aAAa;GACT,OAAO,oBAAoB,SAAS,mBAAmB;EAC3D;CACJ,GAAG,CAAC,qBAAqB,oBAAoB,CAAC;CAQ9C,gBAAgB;EACZ,IAAI,CAAC,MACD;EAGJ,IAAI,oBAAoB,GAAG;GACvB,uBAAuB,SAAS,KAAK,MAAM;GAC3C,2BAA2B,SAAS,KAAK,MAAM;GAE/C,MAAM,iBAAiB,OAAO,aAAa,SAAS,gBAAgB;GACpE,IAAI,iBAAiB,GACjB,SAAS,KAAK,MAAM,eAAe,GAAG,eAAe;EAE7D;EACA,mBAAmB;EACnB,SAAS,KAAK,MAAM,WAAW;EAE/B,aAAa;GACT,mBAAmB;GACnB,IAAI,oBAAoB,GAAG;IACvB,SAAS,KAAK,MAAM,WAAW;IAC/B,SAAS,KAAK,MAAM,eAAe;GACvC;EACJ;CACJ,GAAG,CAAC,IAAI,CAAC;CAGT,MAAM,mBAAmB,wBAAwB;CAEjD,OACI,qBAAA,UAAA,EAAA,UAAA,CACI,oBAAC,OAAD;EACI,WAAW,GACP,yIACA;GACI,qBAAqB;GACrB,2CAA2C,CAAC;GAC5C,mBAAmB;EACvB,CACJ;EACA,eAAY;EACZ,KAAK;CACR,CAAA,GACD,qBAAC,UAAD;EACI,cAAW;EACX,WAAW,GAEP,2EAEA;GACI,uBAAuB,SAAS;GAChC,iBAAiB,SAAS;GAC1B,iBAAiB,SAAS;GAC1B,iBAAiB,SAAS;EAC9B,GAEA,EAAE,aAAa,UAAU,GAEzB;GAAE,eAAe,WAAW;GAAQ,gBAAgB,WAAW;EAAQ,GAEvE;GACI,wDAAwD,CAAC,gBAAgB,WAAW;GACpF,uDAAuD,CAAC,gBAAgB,WAAW;GACnF,2CAA2C,gBAAgB,WAAW;GACtE,0CAA0C,gBAAgB,WAAW;GACrE,mBAAmB;EACvB,GACA,SACJ;EACA,eAAY;EACZ,uBAAuB,CAAC,gBAAgB,YAAY,eAAe,OAAO;EAC1E,MAAM;YA5BV;GA8BK,iBAAiB,KAAA,IACd,eAEA,oBAAC,cAAD;IACa;IACU;IACnB,0BAA0B,qBAAqB,aAAa;IAC5D,WAAW;cAEV;GACS,CAAA;GAElB,oBAAC,eAAD;IACa;IACM;IACG;IAEjB;GACU,CAAA;GACd,WACG,oBAAC,eAAD;IACa;IACiB;cAEzB;GACU,CAAA;EAEf;GACV,EAAA,CAAA;AAEV"}
|
|
1
|
+
{"version":3,"file":"Drawer-DzKEmewj.mjs","names":[],"sources":["../src/utils/keepTransition.ts","../src/Drawer/components/DialogActions/DialogActions.tsx","../src/Drawer/components/DialogContent/DialogContent.tsx","../src/Drawer/components/DialogHeader/DialogHeader.tsx","../src/Drawer/Drawer.tsx"],"sourcesContent":["declare const process:\n | {\n env?: {\n KEEP_TRANSITION?: string;\n };\n }\n | undefined;\n\n/**\n * Test-only escape hatch, read at call time: Drawer specs set\n * `process.env.KEEP_TRANSITION = 'true'` at runtime to opt back into CSS\n * transitions. Unlike `nodeEnv` (a module-load-time read), a call-time read\n * sees that mutation.\n */\nexport const keepTransition = () => (typeof process === 'undefined' ? undefined : process.env?.KEEP_TRANSITION);\n","import { cn } from '@evolve.ui/theme-system';\nimport { useAtomValue } from 'jotai';\nimport { ReactNode, useContext } from 'react';\n\nimport { ModalContext } from '../../../Modal/context';\n\ntype Props = {\n children: ReactNode;\n className?: string;\n density?: 'compact' | 'comfortable';\n useCustomButtonContainer?: boolean;\n};\n\nexport const DialogActions = ({ children, className, density, useCustomButtonContainer }: Props) => {\n const { showBottomScrollHintAtom } = useContext(ModalContext);\n const showBottomScrollHint = useAtomValue(showBottomScrollHintAtom);\n\n return (\n <div\n className={cn(\n 'flex grow-0 gap-sm p-sm',\n {\n '[&_button]:grow-[1]': !useCustomButtonContainer,\n 'p-xs': density === 'compact',\n 'shadow-05': showBottomScrollHint,\n },\n className\n )}\n >\n {children}\n </div>\n );\n};\n","import { cn } from '@evolve.ui/theme-system';\nimport { useSetAtom } from 'jotai';\nimport { ReactNode, useCallback, useContext, useEffect, useRef } from 'react';\n\nimport { ModalContext } from '../../../Modal/context';\nimport { effectEventListener } from '../../../utils/effectEventListener';\n\ntype Props = {\n children: ReactNode;\n density?: 'compact' | 'comfortable';\n disableScroll?: boolean;\n renderWhenClosed: boolean;\n};\n\nexport const DialogContent = ({ children, density, disableScroll = false, renderWhenClosed }: Props) => {\n const { showBottomScrollHintAtom, showTopScrollHintAtom } = useContext(ModalContext);\n const setShowBottomScrollHint = useSetAtom(showBottomScrollHintAtom);\n const setShowTopScrollHint = useSetAtom(showTopScrollHintAtom);\n\n const handleScroll = useCallback(\n (contentRef: HTMLDivElement) => () => {\n if (contentRef.scrollHeight > contentRef.clientHeight + 32) {\n const atTheBottom =\n Math.round(contentRef.scrollHeight - contentRef.scrollTop) - 5 < contentRef.clientHeight;\n const atTheTop = contentRef.scrollTop < 25;\n\n setShowBottomScrollHint(!atTheBottom);\n setShowTopScrollHint(!atTheTop);\n } else if (contentRef.scrollTop === 0) {\n setShowBottomScrollHint(false);\n setShowTopScrollHint(false);\n }\n },\n [setShowBottomScrollHint, setShowTopScrollHint]\n );\n\n const onScrollRef = useRef<ReturnType<typeof handleScroll>>(null);\n\n // Trigger handleScroll on window resize\n useEffect(() => {\n return effectEventListener(window, 'resize', () => onScrollRef.current?.());\n }, [handleScroll]);\n\n return (\n <div\n className={cn('grow-[1] border-y border-solid border-border-secondary', {\n 'flex flex-col overflow-hidden': disableScroll,\n 'h-[100vh] overflow-y-auto': !disableScroll,\n 'p-sm': !disableScroll && density !== 'compact',\n 'p-xs': !disableScroll && density === 'compact',\n })}\n data-testid=\"dialog-content\"\n ref={(ref) => {\n if (!ref) {\n return;\n }\n\n const onScroll = handleScroll(ref);\n onScrollRef.current = onScroll;\n\n const resizeObserver = new ResizeObserver(() => {\n const scrollHeight = ref.scrollHeight;\n const clientHeight = ref.clientHeight;\n\n if (scrollHeight === clientHeight + 32) {\n setShowBottomScrollHint(false);\n setShowTopScrollHint(false);\n } else {\n onScroll();\n }\n });\n\n resizeObserver.observe(ref);\n ref.addEventListener('scroll', onScroll);\n }}\n >\n {renderWhenClosed ? children : null}\n </div>\n );\n};\n","import { cn } from '@evolve.ui/theme-system';\nimport { useAtomValue } from 'jotai';\nimport { ReactNode, useContext } from 'react';\n\nimport { IconButton } from '../../../IconButton/IconButton';\nimport { ArrowLeft, Close } from '../../../Icons';\nimport { ModalContext } from '../../../Modal/context';\nimport { H2 } from '../../../Typography/Text/Text';\n\ntype Props = {\n children?: ReactNode;\n density: 'compact' | 'comfortable';\n onBackButtonClick?: () => void;\n onCloseButtonClick: () => void;\n textAlign?: 'center' | 'left' | 'right';\n};\n\nexport const DialogHeader = ({\n children,\n density = 'comfortable',\n onBackButtonClick,\n onCloseButtonClick,\n textAlign = 'center',\n}: Props) => {\n const { showTopScrollHintAtom } = useContext(ModalContext);\n const showTopScrollHint = useAtomValue(showTopScrollHintAtom);\n\n return (\n <div\n className={cn('relative grid grid-cols-[42px_1fr_42px] gap-[4px] p-sm', {\n 'p-xs': density === 'compact',\n 'shadow-01': showTopScrollHint,\n })}\n >\n {onBackButtonClick !== undefined && (\n <IconButton\n aria-label=\"Go Back\"\n className={cn('col-start-1 col-end-2')}\n data-testid=\"back-button\"\n hideTooltip\n icon={ArrowLeft}\n onClick={onBackButtonClick}\n size=\"md\"\n type=\"button\"\n />\n )}\n <div\n className={cn('col-start-2 col-end-3 flex', {\n 'justify-center text-center': textAlign === 'center',\n 'justify-end text-right': textAlign === 'right',\n 'justify-start text-left': textAlign === 'left',\n })}\n data-testid=\"dialog-header-text-container\"\n >\n {typeof children === 'string' ? <H2 className=\"pt-[6px]\">{children}</H2> : children}\n </div>\n <IconButton\n className={cn('col-start-3 col-end-4')}\n data-testid=\"close-button\"\n hideTooltip\n icon={Close}\n onClick={onCloseButtonClick}\n size=\"md\"\n type=\"button\"\n />\n </div>\n );\n};\n","import { cn } from '@evolve.ui/theme-system';\nimport { ReactNode, useCallback, useEffect, useRef, useState } from 'react';\n\nimport { effectEventListener } from '../utils/effectEventListener';\nimport { keepTransition } from '../utils/keepTransition';\nimport { nodeEnv } from '../utils/nodeEnv';\nimport { DialogActions } from './components/DialogActions/DialogActions';\nimport { DialogContent } from './components/DialogContent/DialogContent';\nimport { DialogHeader } from './components/DialogHeader/DialogHeader';\n\ntype ReasonForClose = 'backdrop' | 'closeButton' | 'escape' | 'external';\n\ntype Props = {\n /**\n * Optional actions to display at the bottom of the drawer\n * Actions container has these styles:\n * ```css\n * display: flex;\n * gap: 16px;\n * > button {\n * flex-grow: 1;\n * }\n * ```\n *\n * Usage:\n * ```tsx\n * <Drawer actions={<Button>Save</Button>} />\n * ```\n *\n */\n actions?: ReactNode;\n /**\n * Optional anchor for the drawer\n *\n * Usage:\n * ```tsx\n * <Drawer anchor=\"left\" />\n * ```\n *\n * @default 'right'\n */\n anchor?: 'left' | 'right';\n /**\n * Children of the drawer are the content of the drawer\n *\n * Usage:\n * ```tsx\n * <Drawer><div>Hello World</div></Drawer>\n * ```\n *\n */\n children?: ReactNode;\n /**\n * Optional class name for the drawer\n *\n * Usage:\n * ```tsx\n * <Drawer className=\"bg-red-500\" />\n * ```\n *\n */\n className?: string;\n /**\n * Optional flag to close the drawer when the user clicks outside\n *\n * Usage:\n * ```tsx\n * <Drawer closeOnOutsideClick={false} />\n * ```\n *\n * @default true\n */\n closeOnOutsideClick?: boolean;\n /**\n * Optional flag to close the drawer when the user presses the Escape key\n *\n * Usage:\n * ```tsx\n * <Drawer closeOnEscape={false} />\n * ```\n *\n * @default true\n */\n closeOnEscape?: boolean;\n /**\n * Optional custom header to replace the default DialogHeader\n *\n * Usage:\n * ```tsx\n * <Drawer customHeader={<div>Custom Header</div>} />\n * ```\n *\n */\n customHeader?: ReactNode;\n /**\n * Optional density for the drawer\n *\n * Usage:\n * ```tsx\n * <Drawer density=\"compact\" />\n * ```\n *\n * @default 'comfortable'\n */\n density?: 'compact' | 'comfortable';\n /**\n * Optional flag to disable scrolling in the drawer content area\n * Useful when the content has its own scrollable areas (e.g., tabs)\n *\n * Usage:\n * ```tsx\n * <Drawer disableScroll />\n * ```\n *\n * @default false\n */\n disableScroll?: boolean;\n /**\n * Required function call when drawer closes, this will almost always be a call to `setShowState(false)`\n *\n * Usage:\n * ```tsx\n * const [show, setShow] = useState(false);\n * ...\n * <Drawer handleClose={() => setShow(false)} />\n * ```\n *\n */\n handleClose: (reason?: ReasonForClose) => void;\n /**\n * Optional flag that controls whether the drawer has a drop shadow\n *\n * Usage:\n * ```tsx\n * <Drawer hasShadow />\n * ```\n *\n */\n hasShadow?: boolean;\n /**\n * Optional header text for the drawer, appears at the top of the drawer\n *\n * Usage:\n * ```tsx\n * <Drawer headerText=\"Hello World\" />\n * ```\n *\n */\n headerText?: string | ReactNode;\n /**\n * Optional alignment for the header text\n *\n * Usage:\n * ```tsx\n * <Drawer headerTextAlign=\"left\" />\n * ```\n *\n * @default 'center'\n */\n headerTextAlign?: 'center' | 'left' | 'right';\n /**\n * Optional flag to keep the drawer in the DOM while closed\n *\n * Usage:\n * ```tsx\n * <Drawer keepInDOMWhileClosed={false} />\n * ```\n * @default true\n */\n keepInDOMWhileClosed?: boolean;\n\n /**\n * Optional function call when the back button is clicked\n *\n * Usage:\n * ```tsx\n * <Drawer onBackButtonClick={() => console.log('Back button clicked')} />\n * ```\n *\n */\n onBackButtonClick?: () => void;\n /**\n * Required flag to show the drawer\n *\n * Usage:\n * ```tsx\n * <Drawer show />\n * ```\n *\n */\n show: boolean;\n /**\n * Optional size for the drawer\n *\n * Usage:\n * ```tsx\n * <Drawer size=\"wide\" />\n * ```\n *\n * @default 'narrow'\n */\n size?: 'narrow' | 'wide' | 'extended' | 'full';\n /**\n * Optional flag to control the action container\n *\n * Usage:\n * ```tsx\n * <Drawer useCustomButtonContainer />\n * ```\n *\n */\n useCustomButtonContainer?: boolean;\n};\n\n// Open drawers share a single body scroll-lock. Module-scoped so the lock is\n// released only when the last open drawer closes, and so the body's original\n// overflow / padding are captured once (when the first drawer opens) and\n// restored at the end rather than hardcoding values.\nlet openDrawerCount = 0;\nlet previousBodyOverflow = '';\nlet previousBodyPaddingRight = '';\n\n// Identities of currently-open drawers, in open order. Escape only closes the\n// last one pushed (the top-most), so stacked drawers close one at a time\n// instead of all collapsing on a single keypress. Per-instance ref objects are\n// used as identities rather than useId so this doesn't consume React's id\n// sequence and shift autogenerated ids in consumer snapshots.\nconst openDrawerStack: object[] = [];\n\n/**\n * A drawer component using the `dialog` element\n * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dialog\n */\nexport const Drawer = ({\n actions,\n anchor = 'right',\n children,\n className,\n closeOnEscape = true,\n closeOnOutsideClick = true,\n customHeader,\n density = 'comfortable',\n disableScroll = false,\n handleClose,\n hasShadow = false,\n headerText,\n headerTextAlign = 'center',\n keepInDOMWhileClosed = true,\n onBackButtonClick,\n show,\n size = 'narrow',\n useCustomButtonContainer = false,\n}: Props) => {\n const reasonForClose = useRef<ReasonForClose>('external');\n // Per-instance ref instead of a shared id: several Drawers can be mounted at\n // once, and a duplicate id would make a lookup match the wrong backdrop.\n const backdropRef = useRef<HTMLDivElement>(null);\n const drawerIdRef = useRef<object>({});\n const [renderDrawer, setRenderDrawer] = useState(show);\n\n const removeTransitionForTest = Boolean(nodeEnv === 'test') && Boolean(keepTransition() !== 'true');\n\n const startCloseTransition = useCallback(\n (reason: ReasonForClose) => {\n setRenderDrawer(false);\n reasonForClose.current = reason;\n\n // Close the drawer immediately in test environment\n if (removeTransitionForTest) {\n handleClose(reason);\n }\n },\n [handleClose, removeTransitionForTest]\n );\n\n // Close the drawer when the show prop changes to false\n useEffect(() => {\n if (renderDrawer && !show) {\n startCloseTransition('external');\n }\n }, [renderDrawer, show, startCloseTransition]);\n\n // Show the drawer when the show prop changes to true\n useEffect(() => {\n if (show) {\n setRenderDrawer(true);\n }\n }, [show]);\n\n // Close the drawer when the escape key is pressed. Only listen while this\n // drawer is open so a closed instance never preventDefaults Escape for\n // other components, and only the top-most open drawer reacts so stacked\n // drawers close one at a time rather than all at once.\n useEffect(() => {\n if (!renderDrawer || !closeOnEscape) {\n return;\n }\n\n const drawerIdentity = drawerIdRef.current;\n openDrawerStack.push(drawerIdentity);\n\n const removeListener = effectEventListener(window, 'keydown', (event) => {\n if (!(event instanceof KeyboardEvent) || event.key !== 'Escape') {\n return;\n }\n if (openDrawerStack[openDrawerStack.length - 1] !== drawerIdentity) {\n return;\n }\n event.preventDefault();\n startCloseTransition('escape');\n });\n\n return () => {\n const index = openDrawerStack.lastIndexOf(drawerIdentity);\n if (index !== -1) {\n openDrawerStack.splice(index, 1);\n }\n removeListener();\n };\n }, [renderDrawer, closeOnEscape, startCloseTransition]);\n\n // Close the drawer when the backdrop is clicked\n useEffect(() => {\n const handleBackdropClick = (event: MouseEvent) => {\n if (event.target === backdropRef.current && closeOnOutsideClick) {\n startCloseTransition('backdrop');\n }\n };\n\n window.addEventListener('click', handleBackdropClick);\n\n return () => {\n window.removeEventListener('click', handleBackdropClick);\n };\n }, [closeOnOutsideClick, startCloseTransition]);\n\n // Prevent body scrolling while any drawer is open. Ref-counted across\n // instances so closing one drawer does not unlock scroll while another is\n // still open; the first drawer to open captures the body's prior overflow\n // and padding and the last to close restores them. The scrollbar's width is\n // added as padding-right while locked so hiding the scrollbar doesn't shift\n // the page (mirrors modal/PreventModalScroll).\n useEffect(() => {\n if (!show) {\n return;\n }\n\n if (openDrawerCount === 0) {\n previousBodyOverflow = document.body.style.overflow;\n previousBodyPaddingRight = document.body.style.paddingRight;\n\n const scrollbarWidth = window.innerWidth - document.documentElement.clientWidth;\n if (scrollbarWidth > 0) {\n document.body.style.paddingRight = `${scrollbarWidth}px`;\n }\n }\n openDrawerCount += 1;\n document.body.style.overflow = 'hidden';\n\n return () => {\n openDrawerCount -= 1;\n if (openDrawerCount === 0) {\n document.body.style.overflow = previousBodyOverflow;\n document.body.style.paddingRight = previousBodyPaddingRight;\n }\n };\n }, [show]);\n\n // Render children when the drawer is closed and keepInDOMWhileClosed is true\n const renderWhenClosed = keepInDOMWhileClosed || renderDrawer;\n\n return (\n <>\n <div\n className={cn('invisible fixed inset-0 z-30 bg-background-overlay opacity-0 duration-500', {\n 'opacity-1 visible': renderDrawer,\n 'pointer-events-none invisible opacity-0': !renderDrawer,\n 'transition-none': removeTransitionForTest,\n })}\n data-testid=\"drawer-backdrop\"\n ref={backdropRef}\n />\n <dialog\n aria-label=\"Drawer Menu\"\n className={cn(\n // GENERAL\n 'm-w-[320px] fixed top-0 z-40 flex h-full max-h-full w-full flex-col p-0',\n // SIZE\n {\n 'h-[100vh] w-[100vw]': size === 'full',\n 'max-w-[320px]': size === 'narrow',\n 'max-w-[480px]': size === 'wide',\n 'max-w-[720px]': size === 'extended',\n },\n // SHADOW\n { 'shadow-04': hasShadow },\n // ANCHOR\n { 'left-0 ml-0': anchor === 'left', 'right-0 mr-0': anchor === 'right' },\n // ANIMATION\n {\n 'invisible -translate-x-full opacity-0 transition-all': !renderDrawer && anchor === 'left',\n 'invisible translate-x-full opacity-0 transition-all': !renderDrawer && anchor === 'right',\n 'opacity-1 -translate-x-0 transition-all': renderDrawer && anchor === 'left',\n 'opacity-1 translate-x-0 transition-all': renderDrawer && anchor === 'right',\n 'transition-none': removeTransitionForTest,\n },\n className\n )}\n data-hui-id=\"Drawer\"\n onTransitionEnd={() => !renderDrawer && handleClose(reasonForClose.current)}\n open={renderDrawer}\n >\n {customHeader !== undefined ? (\n customHeader\n ) : (\n <DialogHeader\n density={density}\n onBackButtonClick={onBackButtonClick}\n onCloseButtonClick={() => startCloseTransition('closeButton')}\n textAlign={headerTextAlign}\n >\n {headerText}\n </DialogHeader>\n )}\n <DialogContent\n density={density}\n disableScroll={disableScroll}\n renderWhenClosed={renderWhenClosed}\n >\n {children}\n </DialogContent>\n {actions && (\n <DialogActions\n density={density}\n useCustomButtonContainer={useCustomButtonContainer}\n >\n {actions}\n </DialogActions>\n )}\n </dialog>\n </>\n );\n};\n"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { HeartStraight } from "./Icons.mjs";
|
|
2
|
-
import { a as outlinedCriticalClasses, s as outlinedNeutralClasses } from "./buttonColorClasses-
|
|
2
|
+
import { a as outlinedCriticalClasses, s as outlinedNeutralClasses } from "./buttonColorClasses-CQnqAJXl.mjs";
|
|
3
3
|
import { Button } from "./Button.mjs";
|
|
4
4
|
import { Tooltip } from "./Tooltip.mjs";
|
|
5
5
|
import { t as SaveConfetti } from "./SaveConfetti-DI0MTd63.mjs";
|
|
@@ -43,7 +43,7 @@ const IconOnlyFavoriteButton = forwardRef(({ "aria-label": ariaLabel = "Favorite
|
|
|
43
43
|
className: cn("group flex h-[30px] w-[30px] cursor-pointer items-center justify-center border border-solid", {
|
|
44
44
|
"rounded-container": shape === "square",
|
|
45
45
|
"rounded-full": shape === "circle"
|
|
46
|
-
}, "bg-background-primary text-surface-500", { "bg-background-primary text-critical-500": favorited }, "
|
|
46
|
+
}, "bg-background-primary text-surface-500", { "bg-background-primary text-critical-500": favorited }, "hui-focus-visible-outline focus-visible:outline-offset-1", "active:text-border-critical-400 active:bg-critical-50", "hover:bg-critical-50 hover:text-critical-400", "disabled:cursor-not-allowed disabled:bg-background-primary disabled:text-border-disabled", className),
|
|
47
47
|
"data-hui-id": "FavoriteButton",
|
|
48
48
|
disabled,
|
|
49
49
|
onClick,
|
|
@@ -87,7 +87,7 @@ const LabeledAnimatedFavoriteButton = forwardRef(({ "aria-label": ariaLabel = "F
|
|
|
87
87
|
"aria-label": ariaLabel,
|
|
88
88
|
"aria-live": "polite",
|
|
89
89
|
"aria-pressed": favorited ?? false,
|
|
90
|
-
className: cn("hui-focus-visible-outline relative flex max-w-full items-center justify-center whitespace-nowrap rounded-button text-center font-primary tracking-[var(--letter-spacing-button)] outline outline-1 -outline-offset-1 transition-colors disabled:text-text-disabled", favorited ? outlinedCriticalClasses : outlinedNeutralClasses, "gap-[4px] px-sm py-[13px] leading-[8px]", "h-[34px]", { "border-critical-500 text-critical-500": favorited }, "hover:border-critical-700 hover:bg-critical-50 hover:text-critical-700", "active:border-critical-900 active:bg-critical-100 active:text-critical-900", isWiggling && "animate-saveButtonWiggle
|
|
90
|
+
className: cn("hui-focus-visible-outline relative flex max-w-full items-center justify-center whitespace-nowrap rounded-button text-center font-primary tracking-[var(--letter-spacing-button)] outline outline-1 -outline-offset-1 transition-colors disabled:text-text-disabled", favorited ? outlinedCriticalClasses : outlinedNeutralClasses, "gap-[4px] px-sm py-[13px] leading-[8px]", "h-[34px]", { "border-critical-500 text-critical-500": favorited }, "hover:border-critical-700 hover:bg-critical-50 hover:text-critical-700", "active:border-critical-900 active:bg-critical-100 active:text-critical-900", isWiggling && "animate-saveButtonWiggle", isWiggling && !favorited && "hui-fb-color-flash", isActivating && "animate-saveButtonPulse", className),
|
|
91
91
|
"data-hui-id": "FavoriteButton",
|
|
92
92
|
disabled,
|
|
93
93
|
onClick,
|
|
@@ -98,14 +98,14 @@ const LabeledAnimatedFavoriteButton = forwardRef(({ "aria-label": ariaLabel = "F
|
|
|
98
98
|
style: BUTTON_INLINE_STYLES,
|
|
99
99
|
...restProps,
|
|
100
100
|
children: [/* @__PURE__ */ jsx("span", {
|
|
101
|
-
className: cn("hui-fb-icon-frame relative flex items-center justify-center", isWiggling && !favorited && "text-critical-500", isWiggling && "animate-saveHeartTwirlBloom
|
|
101
|
+
className: cn("hui-fb-icon-frame relative flex items-center justify-center", isWiggling && !favorited && "text-critical-500", isWiggling && "animate-saveHeartTwirlBloom"),
|
|
102
102
|
style: {
|
|
103
103
|
height: "14px",
|
|
104
104
|
perspective: "200px",
|
|
105
105
|
width: "14px"
|
|
106
106
|
},
|
|
107
107
|
children: /* @__PURE__ */ jsx(HeartStraight, {
|
|
108
|
-
className: cn("[transform-style:preserve-3d]", isActivating && "animate-saveHeartPop
|
|
108
|
+
className: cn("[transform-style:preserve-3d]", isActivating && "animate-saveHeartPop"),
|
|
109
109
|
color: "inherit",
|
|
110
110
|
size: "xs",
|
|
111
111
|
style: favorited || isActive || isWiggling ? "fill" : "bold"
|
|
@@ -196,4 +196,4 @@ const FavoriteButton = forwardRef((props, ref) => {
|
|
|
196
196
|
//#endregion
|
|
197
197
|
export { FavoriteButton as t };
|
|
198
198
|
|
|
199
|
-
//# sourceMappingURL=FavoriteButton-
|
|
199
|
+
//# sourceMappingURL=FavoriteButton-7nK77lQP.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FavoriteButton-7nK77lQP.mjs","names":[],"sources":["../src/FavoriteButton/hooks/useFavoriteButtonState.ts","../src/FavoriteButton/components/IconOnlyFavoriteButton/IconOnlyFavoriteButton.tsx","../src/FavoriteButton/components/LabeledAnimatedFavoriteButton/LabeledAnimatedFavoriteButton.tsx","../src/FavoriteButton/components/SmallHeartStraightIcon/SmallHeartStraightIcon.tsx","../src/FavoriteButton/components/LabeledFavoriteButton/LabeledFavoriteButton.tsx","../src/FavoriteButton/FavoriteButton.tsx"],"sourcesContent":["import { useState } from 'react';\n\n/**\n * Custom hook for managing the active state of the FavoriteButton\n * @returns Object containing the active state and event handlers\n */\nexport const useFavoriteButtonState = () => {\n const [isActive, setIsActive] = useState(false);\n\n const handleMouseDown = () => {\n setIsActive(true);\n };\n\n const handleMouseUp = () => {\n setIsActive(false);\n };\n\n const handleMouseLeave = () => {\n if (isActive) {\n setIsActive(false);\n }\n };\n\n return {\n handleMouseDown,\n handleMouseLeave,\n handleMouseUp,\n isActive,\n };\n};\n","import { cn } from '@evolve.ui/theme-system';\nimport { forwardRef } from 'react';\n\nimport { HeartStraight } from '../../../Icons';\nimport { useFavoriteButtonState } from '../../hooks/useFavoriteButtonState';\nimport { IconOnlyFavoriteButtonProps } from '../../types/favoriteButton';\n\n/**\n * Icon-only variant of the FavoriteButton component\n * Displays only a heart icon in either a circle or square shape\n */\nexport const IconOnlyFavoriteButton = forwardRef<HTMLButtonElement, IconOnlyFavoriteButtonProps>(\n (\n {\n 'aria-label': ariaLabel = 'Favorite Toggle',\n className,\n disabled,\n favorited,\n onClick,\n shape,\n type,\n ...restProps\n },\n ref\n ) => {\n const { handleMouseDown, handleMouseLeave, handleMouseUp, isActive } = useFavoriteButtonState();\n\n return (\n <button\n aria-label={ariaLabel}\n aria-pressed={Boolean(favorited)}\n className={cn(\n // Base styles\n 'group flex h-[30px] w-[30px] cursor-pointer items-center justify-center border border-solid',\n // Shape styles\n {\n 'rounded-container': shape === 'square',\n 'rounded-full': shape === 'circle',\n },\n // Default state\n 'bg-background-primary text-surface-500',\n // Selected state\n {\n 'bg-background-primary text-critical-500': favorited,\n },\n // Focus state\n // Atomic: the bare-focus outline suppression had to go in the same edit as the de-prefix.\n // Prefixed,\n // the ring was 0,3,0 and beat it; bare it is 0,2,0 and would lose (DS-98 Phase 0).\n 'hui-focus-visible-outline focus-visible:outline-offset-1',\n // Active state - immediately show critical color when clicked\n 'active:text-border-critical-400 active:bg-critical-50',\n // Hover state\n 'hover:bg-critical-50 hover:text-critical-400',\n // Disabled state\n 'disabled:cursor-not-allowed disabled:bg-background-primary disabled:text-border-disabled',\n className\n )}\n data-hui-id=\"FavoriteButton\"\n disabled={disabled}\n onClick={onClick}\n onMouseDown={handleMouseDown}\n onMouseLeave={handleMouseLeave}\n onMouseUp={handleMouseUp}\n ref={ref}\n type={type as 'button' | 'submit' | 'reset' | undefined}\n {...restProps}\n >\n <HeartStraight\n className={cn(\n 'mt-[1px] bg-transparent text-current transition-transform duration-200 ease-in-out',\n {\n 'group-hover:scale-[1.125]': !disabled,\n }\n )}\n color=\"inherit\"\n size=\"sm\"\n style={favorited || isActive ? 'fill' : 'regular'}\n />\n </button>\n );\n }\n);\n","import { cn } from '@evolve.ui/theme-system';\nimport { ButtonHTMLAttributes, CSSProperties, forwardRef, useEffect, useImperativeHandle, useRef } from 'react';\n\nimport { outlinedCriticalClasses, outlinedNeutralClasses } from '../../../Button/buttonColorClasses';\nimport { HeartStraight } from '../../../Icons';\nimport { SaveConfetti, type SaveConfettiHandle } from '../../../SaveConfetti/SaveConfetti';\nimport { useFavoriteButtonState } from '../../hooks/useFavoriteButtonState';\n\n/**\n * Labeled-animated variant of the FavoriteButton component.\n *\n * Visually identical to the `labeled` variant but exposes `isWiggling` and\n * `isActivating` props that trigger the enhanced save-button nudge animations:\n *\n * - `isWiggling`: side-to-side wiggle (button), 3D twirl + bloom (heart icon),\n * color flash (critical fill pulse on heart when not favorited), and shimmer (label text).\n * During nudge the heart uses `fill` weight with critical color; at rest unfavorited uses `bold`.\n * Apply for ~650ms, then reset to false to re-arm.\n *\n * - `isActivating`: pulse (button) and heart pop (icon). Apply for ~500ms.\n *\n * Animation CSS is driven by Tailwind `animate-*` utilities from the theme plugin\n * (`theme.extend.animation`) — no runtime style injection. The shimmer uses the\n * `.hui-fb-shimmer` component class from the plugin for its multi-property CSS.\n * The heart-color flash uses `.hui-fb-color-flash` to animate fill on the nested\n * SVG path via a descendant selector. Icon weight: `bold` when unfavorited at rest,\n * `fill` during nudge, favorited, or active press — matching the static `labeled` variant at rest.\n *\n * Reduced motion is gated once at the registry level\n * (`theme-system/src/tailwind/reducedMotion.ts`), so these call sites deliberately carry no\n * `motion-reduce:` variants — adding them back would reintroduce a second mechanism. The\n * shimmer is the one exception: `.hui-fb-shimmer` also drops its gradient under reduce, because\n * the label is painted *by* that gradient (`-webkit-text-fill-color: transparent`) and would\n * otherwise be illegible.\n */\n\ntype Props = {\n /** Accessible label for screen readers. @default 'Favorite Toggle' */\n 'aria-label'?: string;\n /** Whether the item is currently favorited. */\n favorited?: boolean;\n /** Label text shown when favorited. @default 'Saved' */\n favoritedLabel?: string;\n /**\n * When true, fires the save-click animation (button pulse + heart pop) and\n * a mini confetti burst from the button center.\n * Reset to false after ~500ms to re-arm.\n */\n isActivating?: boolean;\n /**\n * When true, fires the nudge animation (wiggle + twirl + shimmer + color flash).\n * Reset to false after ~650ms to re-arm.\n */\n isWiggling?: boolean;\n /** Label text shown when not favorited. @default 'Save' */\n label?: string;\n} & Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'children' | 'style'>;\n\ntype AnimationPaletteCSSVar =\n | '--hui-save-color-critical-500'\n | '--hui-save-color-critical-300'\n | '--hui-save-color-critical-200'\n | '--hui-save-color-tertiary-400'\n | '--hui-save-color-tertiary-200';\n\nconst BUTTON_INLINE_STYLES: CSSProperties & Record<AnimationPaletteCSSVar, string> = {\n fontSize: 'var(--font-size-button-200)',\n fontWeight: 'var(--font-weight-button)',\n textTransform: 'var(--text-transform-button)' as CSSProperties['textTransform'],\n // Expose canonical animation palette tokens for downstream orchestration.\n '--hui-save-color-critical-500': 'var(--color-critical-500)',\n '--hui-save-color-critical-300': 'var(--color-critical-300)',\n '--hui-save-color-critical-200': 'var(--color-critical-200)',\n '--hui-save-color-tertiary-400': 'var(--color-tertiary-400)',\n '--hui-save-color-tertiary-200': 'var(--color-tertiary-200)',\n};\n\nexport const LabeledAnimatedFavoriteButton = forwardRef<HTMLButtonElement, Props>(\n (\n {\n 'aria-label': ariaLabel = 'Favorite Toggle',\n className,\n disabled,\n favorited,\n favoritedLabel = 'Saved',\n isActivating,\n isWiggling,\n label = 'Save',\n onClick,\n ...restProps\n },\n ref\n ) => {\n const { handleMouseDown, handleMouseLeave, handleMouseUp, isActive } = useFavoriteButtonState();\n\n const internalButtonRef = useRef<HTMLButtonElement>(null);\n const confettiRef = useRef<SaveConfettiHandle>(null);\n\n // Preserve consumer-facing ref contract while keeping internal button access for confetti\n useImperativeHandle(ref, () => internalButtonRef.current!);\n\n // Fire confetti burst when the save-click animation triggers\n useEffect(() => {\n if (!isActivating || !internalButtonRef.current) {\n return;\n }\n confettiRef.current?.fire(internalButtonRef.current);\n }, [isActivating]);\n\n return (\n <>\n <button\n aria-busy={false}\n aria-label={ariaLabel}\n aria-live=\"polite\"\n aria-pressed={favorited ?? false}\n className={cn(\n // Base — exact match to Button's base class string\n 'hui-focus-visible-outline relative flex max-w-full items-center justify-center whitespace-nowrap rounded-button text-center font-primary tracking-[var(--letter-spacing-button)] outline outline-1 -outline-offset-1 transition-colors disabled:text-text-disabled',\n // Color classes — same conditional used by LabeledFavoriteButton\n favorited ? outlinedCriticalClasses : outlinedNeutralClasses,\n // sm size\n 'gap-[4px] px-sm py-[13px] leading-[8px]',\n // Height override (matches LabeledFavoriteButton)\n 'h-[34px]',\n // Favorited state border\n { 'border-critical-500 text-critical-500': favorited },\n // Hover/active overrides — same className passed by LabeledFavoriteButton to Button\n 'hover:border-critical-700 hover:bg-critical-50 hover:text-critical-700',\n 'active:border-critical-900 active:bg-critical-100 active:text-critical-900',\n // Nudge animation — wiggle on button root + color flash on nested SVG path\n isWiggling && 'animate-saveButtonWiggle',\n isWiggling && !favorited && 'hui-fb-color-flash',\n // Save-click animation — pulse on button root\n isActivating && 'animate-saveButtonPulse',\n className\n )}\n data-hui-id=\"FavoriteButton\"\n disabled={disabled}\n onClick={onClick}\n onMouseDown={handleMouseDown}\n onMouseLeave={handleMouseLeave}\n onMouseUp={handleMouseUp}\n ref={internalButtonRef}\n style={BUTTON_INLINE_STYLES}\n {...restProps}\n >\n {/*\n * Perspective wrapper — 3D twirl animation targets this element.\n * Width/height matches Button's internal iconLeft container (14px for xs icon).\n */}\n <span\n className={cn(\n 'hui-fb-icon-frame relative flex items-center justify-center',\n // Critical color during nudge so fill weight reads red immediately (not surface-500 grey)\n isWiggling && !favorited && 'text-critical-500',\n // Nudge animation — 3D twirl + bloom on icon frame\n isWiggling && 'animate-saveHeartTwirlBloom'\n )}\n style={{ height: '14px', perspective: '200px', width: '14px' }}\n >\n <HeartStraight\n className={cn(\n '[transform-style:preserve-3d]',\n // Save-click animation — heart pop on SVG element\n isActivating && 'animate-saveHeartPop'\n )}\n color=\"inherit\"\n size=\"xs\"\n style={favorited || isActive || isWiggling ? 'fill' : 'bold'}\n />\n </span>\n {/* Shimmer wrapper — .hui-fb-shimmer bundles background-clip + gradient + animation */}\n <span\n className={cn('hui-fb-animated-label', isWiggling && 'hui-fb-shimmer animate-saveLabelShimmer')}\n >\n {favorited ? favoritedLabel : label}\n </span>\n </button>\n <SaveConfetti ref={confettiRef} />\n </>\n );\n }\n);\n\nLabeledAnimatedFavoriteButton.displayName = 'LabeledAnimatedFavoriteButton';\n","import { ComponentProps, forwardRef } from 'react';\n\nimport { CaretRight, HeartStraight } from '../../../Icons';\n\nexport const SmallHeartStraightIcon = forwardRef<SVGSVGElement, ComponentProps<typeof CaretRight>>((props, ref) => {\n return (\n <HeartStraight\n style=\"bold\"\n {...props}\n ref={ref}\n size=\"xs\"\n />\n );\n});\n","import { cn } from '@evolve.ui/theme-system';\nimport { ButtonHTMLAttributes, forwardRef } from 'react';\n\nimport { Button } from '../../../Button/Button';\nimport { useFavoriteButtonState } from '../../hooks/useFavoriteButtonState';\nimport { SmallHeartStraightIcon } from '../SmallHeartStraightIcon/SmallHeartStraightIcon';\n\n/**\n * Labeled variant of the FavoriteButton component\n * Displays a button with text and a heart icon\n */\n\ntype Props = {\n 'aria-label'?: string;\n favorited?: boolean;\n favoritedLabel?: string;\n label?: string;\n} & Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'style' | 'children'>;\n\nexport const LabeledFavoriteButton = forwardRef<HTMLButtonElement, Props>(\n (\n {\n 'aria-label': ariaLabel = 'Favorite Toggle',\n className,\n disabled,\n favorited,\n favoritedLabel = 'Saved',\n label = 'Save',\n onClick,\n ...restProps\n },\n ref\n ) => {\n const { handleMouseDown, handleMouseLeave, handleMouseUp, isActive } = useFavoriteButtonState();\n\n return (\n <Button\n aria-label={ariaLabel}\n aria-pressed={favorited ? true : false}\n className={cn(\n // Base styles\n 'h-[34px] text-surface-500',\n // Selected state\n {\n 'border-critical-500 text-critical-500': favorited,\n },\n // Hover state - same for both favorited and non-favorited\n 'hover:border-critical-700 hover:bg-critical-50 hover:text-critical-700',\n // Active states - different for favorited and non-favorited\n 'active:border-critical-900 active:bg-critical-100 active:text-critical-900',\n className\n )}\n data-hui-id=\"FavoriteButton\"\n disabled={disabled}\n iconLeft={SmallHeartStraightIcon}\n iconStyle={favorited || isActive ? 'fill' : 'bold'}\n onClick={onClick}\n onMouseDown={handleMouseDown}\n onMouseLeave={handleMouseLeave}\n onMouseUp={handleMouseUp}\n ref={ref}\n size=\"sm\"\n style={favorited ? 'critical' : 'neutral'}\n variant=\"outlined\"\n {...restProps}\n >\n {favorited ? favoritedLabel : label}\n </Button>\n );\n }\n);\n","import { forwardRef } from 'react';\n\nimport { Tooltip } from '../Tooltip/Tooltip';\nimport { IconOnlyFavoriteButton } from './components/IconOnlyFavoriteButton/IconOnlyFavoriteButton';\nimport { LabeledAnimatedFavoriteButton } from './components/LabeledAnimatedFavoriteButton/LabeledAnimatedFavoriteButton';\nimport { LabeledFavoriteButton } from './components/LabeledFavoriteButton/LabeledFavoriteButton';\nimport { FavoriteButtonProps } from './types/favoriteButton';\n\n/**\n * A button that allows users to mark an item as a favorite.\n * The button displays a heart icon that changes appearance when favorited.\n *\n * Be aware that if you're using the tooltip option, make sure to use a unique id\n * and set the `anchorSelect` prop on the tooltip to the id of the button.\n *\n * Available in four variants:\n * - `circle`: Shows only the heart icon in a circular button (default)\n * - `square`: Shows only the heart icon in a square button\n * - `labeled`: Shows a button with text and the heart icon\n * - `labeled-animated`: Shows a labeled button with animation-ready wrappers\n */\nexport const FavoriteButton = forwardRef<HTMLButtonElement, FavoriteButtonProps>((props, ref) => {\n const { isActivating, isWiggling, tooltipProps, variant = 'circle', ...restProps } = props;\n const { enabled = false, ...tooltipRestProps } = tooltipProps ?? {};\n\n // Use a mapping object to determine which component to render\n const variantComponents = {\n circle: (\n <IconOnlyFavoriteButton\n ref={ref}\n shape=\"circle\"\n {...restProps}\n />\n ),\n labeled: (\n <LabeledFavoriteButton\n ref={ref}\n {...restProps}\n />\n ),\n 'labeled-animated': (\n <LabeledAnimatedFavoriteButton\n ref={ref}\n isActivating={isActivating}\n isWiggling={isWiggling}\n {...restProps}\n />\n ),\n square: (\n <IconOnlyFavoriteButton\n ref={ref}\n shape=\"square\"\n {...restProps}\n />\n ),\n };\n\n return (\n <>\n {enabled && <Tooltip {...tooltipRestProps} />}\n {variantComponents[variant]}\n </>\n );\n});\n"],"mappings":"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"}
|