@intlayer/design-system 7.5.6 → 7.5.8
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/dist/esm/components/Breadcrumb/index.mjs +28 -2
- package/dist/esm/components/Breadcrumb/index.mjs.map +1 -1
- package/dist/esm/components/Browser/Browser.mjs +29 -40
- package/dist/esm/components/Browser/Browser.mjs.map +1 -1
- package/dist/esm/components/Browser/{Browser.content.mjs → browser.content.mjs} +42 -4
- package/dist/esm/components/Browser/{Browser.content.mjs.map → browser.content.mjs.map} +1 -1
- package/dist/esm/components/Button/Button.mjs +6 -2
- package/dist/esm/components/Button/Button.mjs.map +1 -1
- package/dist/esm/components/ContentEditor/ContentEditorTextArea.mjs +1 -1
- package/dist/esm/components/DictionaryEditor/DictionaryEditor.mjs +9 -19
- package/dist/esm/components/DictionaryEditor/DictionaryEditor.mjs.map +1 -1
- package/dist/esm/components/DictionaryFieldEditor/ContentEditor.mjs +2 -2
- package/dist/esm/components/DictionaryFieldEditor/ContentEditor.mjs.map +1 -1
- package/dist/esm/components/DictionaryFieldEditor/ContentEditorView/TextEditor.mjs +123 -88
- package/dist/esm/components/DictionaryFieldEditor/ContentEditorView/TextEditor.mjs.map +1 -1
- package/dist/esm/components/DictionaryFieldEditor/DictionaryFieldEditor.mjs +3 -2
- package/dist/esm/components/DictionaryFieldEditor/DictionaryFieldEditor.mjs.map +1 -1
- package/dist/esm/components/DictionaryFieldEditor/KeyPathBreadcrumb.mjs +7 -6
- package/dist/esm/components/DictionaryFieldEditor/KeyPathBreadcrumb.mjs.map +1 -1
- package/dist/esm/components/DictionaryFieldEditor/NavigationView/NavigationViewNode.mjs +28 -6
- package/dist/esm/components/DictionaryFieldEditor/NavigationView/NavigationViewNode.mjs.map +1 -1
- package/dist/esm/components/DictionaryFieldEditor/SaveForm/SaveForm.mjs +2 -0
- package/dist/esm/components/DictionaryFieldEditor/SaveForm/SaveForm.mjs.map +1 -1
- package/dist/esm/components/DictionaryFieldEditor/index.mjs +5 -1
- package/dist/esm/components/DropDown/index.mjs +19 -4
- package/dist/esm/components/DropDown/index.mjs.map +1 -1
- package/dist/esm/components/Flags/Flag.mjs +55 -2
- package/dist/esm/components/Flags/Flag.mjs.map +1 -1
- package/dist/esm/components/Flags/bw.mjs +35 -0
- package/dist/esm/components/Flags/bw.mjs.map +1 -0
- package/dist/esm/components/Flags/cu.mjs +45 -0
- package/dist/esm/components/Flags/cu.mjs.map +1 -0
- package/dist/esm/components/Flags/cv.mjs +45 -0
- package/dist/esm/components/Flags/cv.mjs.map +1 -0
- package/dist/esm/components/Flags/dj.mjs +45 -0
- package/dist/esm/components/Flags/dj.mjs.map +1 -0
- package/dist/esm/components/Flags/flags.mjs +242 -7
- package/dist/esm/components/Flags/flags.mjs.map +1 -1
- package/dist/esm/components/Flags/gh.mjs +38 -0
- package/dist/esm/components/Flags/gh.mjs.map +1 -0
- package/dist/esm/components/Flags/gw.mjs +69 -0
- package/dist/esm/components/Flags/gw.mjs.map +1 -0
- package/dist/esm/components/Flags/km.mjs +54 -0
- package/dist/esm/components/Flags/km.mjs.map +1 -0
- package/dist/esm/components/Flags/lk.mjs +75 -0
- package/dist/esm/components/Flags/lk.mjs.map +1 -0
- package/dist/esm/components/Flags/md.mjs +319 -0
- package/dist/esm/components/Flags/md.mjs.map +1 -0
- package/dist/esm/components/Flags/mr.mjs +39 -0
- package/dist/esm/components/Flags/mr.mjs.map +1 -0
- package/dist/esm/components/Flags/mz.mjs +94 -0
- package/dist/esm/components/Flags/mz.mjs.map +1 -0
- package/dist/esm/components/Flags/ps.mjs +47 -0
- package/dist/esm/components/Flags/ps.mjs.map +1 -0
- package/dist/esm/components/Flags/sd.mjs +46 -0
- package/dist/esm/components/Flags/sd.mjs.map +1 -0
- package/dist/esm/components/Flags/so.mjs +39 -0
- package/dist/esm/components/Flags/so.mjs.map +1 -0
- package/dist/esm/components/Flags/st.mjs +75 -0
- package/dist/esm/components/Flags/st.mjs.map +1 -0
- package/dist/esm/components/Flags/td.mjs +35 -0
- package/dist/esm/components/Flags/td.mjs.map +1 -0
- package/dist/esm/components/Flags/tl.mjs +45 -0
- package/dist/esm/components/Flags/tl.mjs.map +1 -0
- package/dist/esm/components/Flags/tz.mjs +46 -0
- package/dist/esm/components/Flags/tz.mjs.map +1 -0
- package/dist/esm/components/Flags/ug.mjs +147 -0
- package/dist/esm/components/Flags/ug.mjs.map +1 -0
- package/dist/esm/components/Form/FormLabel.mjs +1 -1
- package/dist/esm/components/Form/elements/AutoSizeTextAreaElement.mjs +1 -1
- package/dist/esm/components/Form/elements/EditableFieldTextAreaElement.mjs +1 -1
- package/dist/esm/components/Form/elements/MultiselectElement.mjs +1 -1
- package/dist/esm/components/Form/elements/OTPElement.mjs +2 -2
- package/dist/esm/components/Form/elements/OTPElement.mjs.map +1 -1
- package/dist/esm/components/Form/elements/SelectElement.mjs +1 -1
- package/dist/esm/components/Form/elements/SwitchSelectorElement.mjs +1 -1
- package/dist/esm/components/Form/elements/TextAreaElement.mjs +1 -1
- package/dist/esm/components/IDE/CodeFormatSelector.mjs +1 -1
- package/dist/esm/components/IDE/ContentDeclarationFormatSelector.mjs +1 -1
- package/dist/esm/components/IDE/PackageManagerSelector.mjs +1 -1
- package/dist/esm/components/Input/Input.mjs +3 -1
- package/dist/esm/components/Input/Input.mjs.map +1 -1
- package/dist/esm/components/Input/OTPInput.mjs +2 -2
- package/dist/esm/components/Input/OTPInput.mjs.map +1 -1
- package/dist/esm/components/Input/SearchInput.mjs +1 -1
- package/dist/esm/components/Input/SearchInput.mjs.map +1 -1
- package/dist/esm/components/KeyboardShortcut/KeyboardShortcut.mjs +8 -4
- package/dist/esm/components/KeyboardShortcut/KeyboardShortcut.mjs.map +1 -1
- package/dist/esm/components/Link/Link.mjs +11 -3
- package/dist/esm/components/Link/Link.mjs.map +1 -1
- package/dist/esm/components/Link/index.mjs +2 -2
- package/dist/esm/components/LocaleSwitcherContentDropDown/LocaleSwitcherContent.mjs +20 -14
- package/dist/esm/components/LocaleSwitcherContentDropDown/LocaleSwitcherContent.mjs.map +1 -1
- package/dist/esm/components/MarkDownRender/MarkDownRender.mjs +1 -1
- package/dist/esm/components/MarkDownRender/MarkDownRender.mjs.map +1 -1
- package/dist/esm/components/Modal/Modal.mjs +2 -2
- package/dist/esm/components/Modal/Modal.mjs.map +1 -1
- package/dist/esm/components/RightDrawer/RightDrawer.mjs +83 -127
- package/dist/esm/components/RightDrawer/RightDrawer.mjs.map +1 -1
- package/dist/esm/components/RightDrawer/rightDrawer.content.mjs +51 -0
- package/dist/esm/components/RightDrawer/rightDrawer.content.mjs.map +1 -0
- package/dist/esm/components/Table/Table.mjs +1 -1
- package/dist/esm/components/TextArea/AutocompleteTextArea.mjs +2 -29
- package/dist/esm/components/TextArea/AutocompleteTextArea.mjs.map +1 -1
- package/dist/esm/components/index.mjs +23 -19
- package/dist/esm/hooks/index.mjs +2 -2
- package/dist/esm/hooks/reactQuery.mjs +32 -3
- package/dist/esm/hooks/reactQuery.mjs.map +1 -1
- package/dist/esm/hooks/usePersistedStore.mjs +1 -1
- package/dist/esm/hooks/usePersistedStore.mjs.map +1 -1
- package/dist/types/components/Badge/index.d.ts +2 -2
- package/dist/types/components/Breadcrumb/breadcrumb.content.d.ts +3 -3
- package/dist/types/components/Breadcrumb/index.d.ts +2 -2
- package/dist/types/components/Breadcrumb/index.d.ts.map +1 -1
- package/dist/types/components/Browser/Browser.d.ts +2 -2
- package/dist/types/components/Browser/Browser.d.ts.map +1 -1
- package/dist/types/components/Browser/{Browser.content.d.ts → browser.content.d.ts} +97 -15
- package/dist/types/components/Browser/browser.content.d.ts.map +1 -0
- package/dist/types/components/Button/Button.d.ts +7 -7
- package/dist/types/components/Button/Button.d.ts.map +1 -1
- package/dist/types/components/CollapsibleTable/CollapsibleTable.d.ts +4 -4
- package/dist/types/components/CollapsibleTable/CollapsibleTable.d.ts.map +1 -1
- package/dist/types/components/Command/index.d.ts +16 -16
- package/dist/types/components/Command/index.d.ts.map +1 -1
- package/dist/types/components/Container/index.d.ts +9 -9
- package/dist/types/components/Container/index.d.ts.map +1 -1
- package/dist/types/components/CopyButton/CopyButton.content.d.ts +3 -3
- package/dist/types/components/CopyButton/CopyButton.content.d.ts.map +1 -1
- package/dist/types/components/DictionaryEditor/DictionaryEditor.d.ts +0 -1
- package/dist/types/components/DictionaryEditor/DictionaryEditor.d.ts.map +1 -1
- package/dist/types/components/DictionaryFieldEditor/ContentEditorView/TextEditor.d.ts.map +1 -1
- package/dist/types/components/DictionaryFieldEditor/DictionaryCreationForm/dictionaryCreationForm.content.d.ts +25 -25
- package/dist/types/components/DictionaryFieldEditor/DictionaryCreationForm/useDictionaryFormSchema.content.d.ts +9 -9
- package/dist/types/components/DictionaryFieldEditor/DictionaryCreationForm/useDictionaryFormSchema.content.d.ts.map +1 -1
- package/dist/types/components/DictionaryFieldEditor/DictionaryDetails/dictionaryDetails.content.d.ts +33 -33
- package/dist/types/components/DictionaryFieldEditor/DictionaryDetails/useDictionaryDetailsSchema.content.d.ts +25 -25
- package/dist/types/components/DictionaryFieldEditor/KeyPathBreadcrumb.d.ts +5 -1
- package/dist/types/components/DictionaryFieldEditor/KeyPathBreadcrumb.d.ts.map +1 -1
- package/dist/types/components/DictionaryFieldEditor/NavigationView/navigationViewNode.content.d.ts +25 -25
- package/dist/types/components/DictionaryFieldEditor/NavigationView/navigationViewNode.content.d.ts.map +1 -1
- package/dist/types/components/DictionaryFieldEditor/SaveForm/saveForm.content.d.ts +33 -33
- package/dist/types/components/DictionaryFieldEditor/StructureView/structureView.content.d.ts +9 -9
- package/dist/types/components/DictionaryFieldEditor/VersionSwitcherDropDown/versionSwitcherDropDown.content.d.ts +7 -7
- package/dist/types/components/DictionaryFieldEditor/VersionSwitcherDropDown/versionSwitcherDropDown.content.d.ts.map +1 -1
- package/dist/types/components/DictionaryFieldEditor/dictionaryFieldEditor.content.d.ts +5 -5
- package/dist/types/components/DictionaryFieldEditor/index.d.ts +5 -1
- package/dist/types/components/DictionaryFieldEditor/nodeTypeSelector.content.d.ts +31 -31
- package/dist/types/components/DropDown/index.d.ts +16 -2
- package/dist/types/components/DropDown/index.d.ts.map +1 -1
- package/dist/types/components/ExpandCollapse/expandCollapse.content.d.ts +3 -3
- package/dist/types/components/Flags/Flag.d.ts.map +1 -1
- package/dist/types/components/Flags/flags.d.ts +169 -7
- package/dist/types/components/Flags/flags.d.ts.map +1 -1
- package/dist/types/components/Form/FormBase.d.ts +2 -2
- package/dist/types/components/Form/FormBase.d.ts.map +1 -1
- package/dist/types/components/Form/FormField.d.ts +2 -2
- package/dist/types/components/Form/FormField.d.ts.map +1 -1
- package/dist/types/components/Form/FormItem.d.ts +2 -2
- package/dist/types/components/Form/elements/EditableFieldInputElement.d.ts +2 -2
- package/dist/types/components/Form/elements/EditableFieldInputElement.d.ts.map +1 -1
- package/dist/types/components/Form/elements/EditableFieldTextAreaElement.d.ts +2 -2
- package/dist/types/components/Form/elements/EditableFieldTextAreaElement.d.ts.map +1 -1
- package/dist/types/components/Form/elements/FormElement.d.ts +2 -2
- package/dist/types/components/Form/elements/FormElement.d.ts.map +1 -1
- package/dist/types/components/Form/elements/MultiselectElement.d.ts +2 -2
- package/dist/types/components/Form/elements/OTPElement.d.ts +2 -2
- package/dist/types/components/Form/elements/OTPElement.d.ts.map +1 -1
- package/dist/types/components/Form/elements/SelectElement.d.ts +2 -2
- package/dist/types/components/Form/elements/SwitchSelectorElement.d.ts +2 -2
- package/dist/types/components/IDE/CodeContext.d.ts +2 -2
- package/dist/types/components/IDE/CodeContext.d.ts.map +1 -1
- package/dist/types/components/IDE/code.content.d.ts +5 -5
- package/dist/types/components/IDE/copyCode.content.d.ts +5 -5
- package/dist/types/components/IDE/copyCode.content.d.ts.map +1 -1
- package/dist/types/components/IDE/selectors.content.d.ts +7 -7
- package/dist/types/components/Input/Checkbox.d.ts +4 -4
- package/dist/types/components/Input/Checkbox.d.ts.map +1 -1
- package/dist/types/components/Input/Input.d.ts +6 -9
- package/dist/types/components/Input/Input.d.ts.map +1 -1
- package/dist/types/components/Input/OTPInput.d.ts +6 -6
- package/dist/types/components/Input/OTPInput.d.ts.map +1 -1
- package/dist/types/components/Input/SearchInput.d.ts +2 -2
- package/dist/types/components/Input/SearchInput.d.ts.map +1 -1
- package/dist/types/components/Link/Link.d.ts +9 -8
- package/dist/types/components/Link/Link.d.ts.map +1 -1
- package/dist/types/components/Link/index.d.ts +2 -2
- package/dist/types/components/Loader/index.content.d.ts +3 -3
- package/dist/types/components/Loader/index.content.d.ts.map +1 -1
- package/dist/types/components/Loader/index.d.ts.map +1 -1
- package/dist/types/components/Loader/spinner.d.ts +2 -2
- package/dist/types/components/Loader/spinner.d.ts.map +1 -1
- package/dist/types/components/LocaleSwitcherContentDropDown/localeSwitcher.content.d.ts +17 -17
- package/dist/types/components/LocaleSwitcherContentDropDown/localeSwitcher.content.d.ts.map +1 -1
- package/dist/types/components/LocaleSwitcherDropDown/localeSwitcher.content.d.ts +13 -13
- package/dist/types/components/LocaleSwitcherDropDown/localeSwitcher.content.d.ts.map +1 -1
- package/dist/types/components/MarkDownRender/MarkDownRender.d.ts.map +1 -1
- package/dist/types/components/MarkDownRender/processor.d.ts.map +1 -1
- package/dist/types/components/MaxWidthSmoother/index.d.ts +2 -2
- package/dist/types/components/MaxWidthSmoother/index.d.ts.map +1 -1
- package/dist/types/components/Modal/Modal.d.ts.map +1 -1
- package/dist/types/components/Navbar/Burger.d.ts +2 -2
- package/dist/types/components/Navbar/Burger.d.ts.map +1 -1
- package/dist/types/components/Navbar/DesktopNavbar.d.ts +2 -2
- package/dist/types/components/Navbar/DesktopNavbar.d.ts.map +1 -1
- package/dist/types/components/Navbar/MobileNavbar.d.ts +2 -2
- package/dist/types/components/Navbar/MobileNavbar.d.ts.map +1 -1
- package/dist/types/components/Navbar/index.d.ts +2 -2
- package/dist/types/components/Navbar/index.d.ts.map +1 -1
- package/dist/types/components/Pagination/Pagination.d.ts +4 -4
- package/dist/types/components/Pagination/Pagination.d.ts.map +1 -1
- package/dist/types/components/Pagination/pagination.content.d.ts +11 -11
- package/dist/types/components/RightDrawer/RightDrawer.d.ts +7 -150
- package/dist/types/components/RightDrawer/RightDrawer.d.ts.map +1 -1
- package/dist/types/components/RightDrawer/rightDrawer.content.d.ts +93 -0
- package/dist/types/components/RightDrawer/rightDrawer.content.d.ts.map +1 -0
- package/dist/types/components/RightDrawer/useRightDrawerStore.d.ts +2 -2
- package/dist/types/components/Select/Select.d.ts +3 -3
- package/dist/types/components/Select/Select.d.ts.map +1 -1
- package/dist/types/components/SocialNetworks/index.d.ts +2 -2
- package/dist/types/components/SocialNetworks/index.d.ts.map +1 -1
- package/dist/types/components/SwitchSelector/index.d.ts +7 -7
- package/dist/types/components/SwitchSelector/index.d.ts.map +1 -1
- package/dist/types/components/Tab/Tab.d.ts +6 -6
- package/dist/types/components/Tab/Tab.d.ts.map +1 -1
- package/dist/types/components/Tab/TabContext.d.ts +2 -2
- package/dist/types/components/Tab/TabContext.d.ts.map +1 -1
- package/dist/types/components/TabSelector/TabSelector.d.ts +5 -5
- package/dist/types/components/TabSelector/TabSelector.d.ts.map +1 -1
- package/dist/types/components/Table/table.content.d.ts +3 -3
- package/dist/types/components/Table/table.content.d.ts.map +1 -1
- package/dist/types/components/Tag/index.d.ts +5 -5
- package/dist/types/components/Tag/index.d.ts.map +1 -1
- package/dist/types/components/Terminal/terminal.content.d.ts +5 -5
- package/dist/types/components/Terminal/terminal.content.d.ts.map +1 -1
- package/dist/types/components/Toaster/Toast.d.ts +3 -3
- package/dist/types/components/Toaster/Toast.d.ts.map +1 -1
- package/dist/types/components/Toaster/Toaster.d.ts +2 -2
- package/dist/types/components/Toaster/Toaster.d.ts.map +1 -1
- package/dist/types/components/index.d.ts +7 -3
- package/dist/types/hooks/index.d.ts +2 -2
- package/dist/types/hooks/reactQuery.d.ts +2 -1
- package/dist/types/hooks/reactQuery.d.ts.map +1 -1
- package/dist/types/hooks/useItemSelector.d.ts.map +1 -1
- package/dist/types/hooks/useScrollBlockage/useScrollBlockageStore.d.ts +2 -2
- package/package.json +14 -14
- package/dist/types/components/Browser/Browser.content.d.ts.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LocaleSwitcherContent.mjs","names":["LocaleSwitcherContent: FC<LocaleSwitcherContentProps>","multilingualAvailableLocales: MultilingualAvailableLocales[]"],"sources":["../../../../src/components/LocaleSwitcherContentDropDown/LocaleSwitcherContent.tsx"],"sourcesContent":["'use client';\n\nimport { getHTMLTextDir, getLocaleName } from '@intlayer/core';\nimport { Locales, type LocalesValues } from '@intlayer/types';\nimport Fuse, { type IFuseOptions } from 'fuse.js';\nimport { Check, Globe, MoveVertical } from 'lucide-react';\nimport { type FC, useCallback, useMemo, useRef, useState } from 'react';\nimport { useIntlayer, useLocale } from 'react-intlayer';\nimport { usePersistedStore } from '../../hooks';\nimport {\n Button,\n ButtonColor,\n ButtonSize,\n ButtonTextAlign,\n ButtonVariant,\n} from '../Button';\nimport { Container } from '../Container';\nimport { DropDown, type PanelProps } from '../DropDown';\nimport { Input } from '../Input';\nimport {\n SwitchSelector,\n SwitchSelectorColor,\n SwitchSelectorSize,\n} from '../SwitchSelector';\nimport { useLocaleSwitcherContent } from './LocaleSwitcherContentContext';\n\nexport type LocaleSwitcherContentProps = {\n panelProps?: Omit<PanelProps, 'identifier'>;\n isMultilingual?: boolean;\n};\n\nconst DROPDOWN_IDENTIFIER = 'locale-switcher-content';\n\ntype MultilingualAvailableLocales = {\n locale: LocalesValues;\n englishName: string;\n currentLocaleName: string;\n ownLocaleName: string;\n};\n\nexport const LocaleSwitcherContent: FC<LocaleSwitcherContentProps> = ({\n panelProps,\n isMultilingual = true,\n}) => {\n const {\n switchTo,\n searchInput,\n localeSwitcherLabel,\n languageListLabel,\n seeAllLocalesSwitch,\n } = useIntlayer('locale-switcher-content');\n const inputRef = useRef<HTMLInputElement>(null);\n const { locale } = useLocale();\n const { availableLocales, selectedLocales, setSelectedLocales } =\n useLocaleSwitcherContent();\n\n const multilingualAvailableLocales: MultilingualAvailableLocales[] = useMemo(\n () =>\n availableLocales.map((localeEl) => {\n const englishName = getLocaleName(localeEl, Locales.ENGLISH);\n const currentLocaleName = getLocaleName(localeEl, locale);\n const ownLocaleName = getLocaleName(localeEl);\n return {\n locale: localeEl,\n englishName,\n currentLocaleName,\n ownLocaleName,\n };\n }),\n [availableLocales, locale]\n );\n\n const [results, setResults] = useState<MultilingualAvailableLocales[]>(\n multilingualAvailableLocales\n );\n const [seeAllLocales, setSeeAllLocales] = usePersistedStore(\n 'locale-content-selector-see-all-locales',\n false\n );\n\n // Create a new Fuse instance with the options and documentation data\n const fuse = useMemo(() => {\n const fuseOptions: IFuseOptions<MultilingualAvailableLocales> = {\n keys: [\n { name: 'ownLocaleName', weight: 0.4 },\n { name: 'englishName', weight: 0.2 },\n { name: 'currentLocaleName', weight: 0.2 },\n { name: 'locale', weight: 0.2 },\n ],\n threshold: 0.02, // Defines how fuzzy the matching should be (lower is more strict)\n };\n\n return new Fuse(multilingualAvailableLocales, fuseOptions);\n }, [multilingualAvailableLocales]);\n\n const handleSearch = useCallback(\n (searchQuery: string) => {\n if (searchQuery) {\n // Perform search on every input change\n const searchResults = fuse\n .search(searchQuery)\n .map((result) => result.item);\n setResults(searchResults);\n } else {\n setResults(multilingualAvailableLocales);\n }\n },\n [fuse, multilingualAvailableLocales]\n );\n\n const handleClickLocale = (localeItem: LocalesValues) => {\n if (isMultilingual) {\n if (selectedLocales.includes(localeItem)) {\n if (selectedLocales.length > 1) {\n setSelectedLocales((prev) => prev.filter((el) => el !== localeItem));\n }\n } else {\n setSelectedLocales((prev) => [...prev, localeItem]);\n }\n } else {\n setSelectedLocales([localeItem]);\n }\n };\n\n const handleSeeAllLocales = (value: boolean) => {\n setSeeAllLocales(value);\n if (value) {\n setSelectedLocales(availableLocales);\n } else {\n setSelectedLocales([locale]);\n }\n };\n\n return (\n <div\n className=\"rounded-xl border border-text text-text transition-colors\"\n aria-label={localeSwitcherLabel.value}\n >\n <DropDown identifier={DROPDOWN_IDENTIFIER}>\n <DropDown.Trigger identifier={DROPDOWN_IDENTIFIER}>\n <div className=\"flex w-full items-center justify-between\">\n <div className=\"px-2 py-1\">\n <Globe size={18} />\n </div>\n <MoveVertical className=\"self-center\" size={18} />\n </div>\n </DropDown.Trigger>\n\n <DropDown.Panel\n identifier={DROPDOWN_IDENTIFIER}\n isOverable\n isFocusable\n className=\"right-0 left-auto\"\n {...panelProps}\n >\n <Container\n className=\"max-h-[80vh] min-w-28\"\n separator=\"y\"\n role=\"listbox\"\n transparency=\"sm\"\n border\n roundedSize=\"2xl\"\n borderColor=\"text\"\n aria-label={languageListLabel.value}\n >\n {isMultilingual && (\n <div className=\"m-auto p-2\">\n <SwitchSelector\n defaultValue={false}\n onChange={handleSeeAllLocales}\n color={SwitchSelectorColor.TEXT}\n size={SwitchSelectorSize.SM}\n className=\"!w-60\"\n choices={[\n {\n content: seeAllLocalesSwitch.true.value,\n value: true,\n },\n {\n content: seeAllLocalesSwitch.false.value,\n value: false,\n },\n ]}\n />\n </div>\n )}\n\n {!(isMultilingual && seeAllLocales) && (\n <>\n <div className=\"p-3\">\n <Input\n type=\"search\"\n aria-label={searchInput.ariaLabel.value}\n placeholder={searchInput.placeholder.value}\n onChange={(e) => handleSearch(e.target.value)}\n ref={inputRef}\n />\n </div>\n <ol className=\"divide-y divide-dashed divide-text/20 overflow-y-auto p-1\">\n {results.map(\n ({\n locale: localeItem,\n currentLocaleName,\n ownLocaleName,\n }) => (\n <li className=\"px-1.5 py-1\" key={localeItem}>\n <Button\n onClick={() => handleClickLocale(localeItem)}\n label={`${switchTo} ${currentLocaleName}`}\n disabled={\n !(availableLocales ?? availableLocales).includes(\n localeItem\n )\n }\n isActive={selectedLocales.includes(localeItem)}\n variant={ButtonVariant.HOVERABLE}\n color={ButtonColor.TEXT}\n isFullWidth\n textAlign={ButtonTextAlign.LEFT}\n size={ButtonSize.SM}\n >\n <div className=\"flex flex-row items-center justify-between gap-3 px-2 py-1\">\n {isMultilingual && (\n <div className=\"w-4\">\n {selectedLocales.includes(localeItem) && (\n <Check className=\"size-full\" />\n )}\n </div>\n )}\n <div className=\"flex flex-1 flex-row items-center justify-between gap-3 px-2 py-1\">\n <div className=\"flex flex-col text-nowrap\">\n <span\n dir={getHTMLTextDir(localeItem)}\n lang={localeItem}\n >\n {ownLocaleName}\n </span>\n <span className=\"text-neutral text-xs\">\n {currentLocaleName}\n </span>\n </div>\n <span className=\"text-neutral text-sm\">\n {localeItem.toUpperCase()}\n </span>\n </div>\n </div>\n </Button>\n </li>\n )\n )}\n </ol>\n </>\n )}\n </Container>\n </DropDown.Panel>\n </DropDown>\n </div>\n );\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"LocaleSwitcherContent.mjs","names":["LocaleSwitcherContent: FC<LocaleSwitcherContentProps>","multilingualAvailableLocales: MultilingualAvailableLocales[]"],"sources":["../../../../src/components/LocaleSwitcherContentDropDown/LocaleSwitcherContent.tsx"],"sourcesContent":["'use client';\n\nimport { getHTMLTextDir, getLocaleName } from '@intlayer/core';\nimport { Locales, type LocalesValues } from '@intlayer/types';\nimport Fuse, { type IFuseOptions } from 'fuse.js';\nimport { Check, Globe, MoveVertical } from 'lucide-react';\nimport { type FC, useMemo, useRef, useState } from 'react';\nimport { useIntlayer, useLocale } from 'react-intlayer';\nimport { usePersistedStore } from '../../hooks';\nimport {\n Button,\n ButtonColor,\n ButtonSize,\n ButtonTextAlign,\n ButtonVariant,\n} from '../Button';\nimport { Container } from '../Container';\nimport { DropDown, type PanelProps } from '../DropDown';\nimport { Input } from '../Input';\nimport {\n SwitchSelector,\n SwitchSelectorColor,\n SwitchSelectorSize,\n} from '../SwitchSelector';\nimport { useLocaleSwitcherContent } from './LocaleSwitcherContentContext';\n\nexport type LocaleSwitcherContentProps = {\n panelProps?: Omit<PanelProps, 'identifier'>;\n isMultilingual?: boolean;\n};\n\nconst DROPDOWN_IDENTIFIER = 'locale-switcher-content';\n\ntype MultilingualAvailableLocales = {\n locale: LocalesValues;\n englishName: string;\n currentLocaleName: string;\n ownLocaleName: string;\n};\n\nexport const LocaleSwitcherContent: FC<LocaleSwitcherContentProps> = ({\n panelProps,\n isMultilingual = true,\n}) => {\n const {\n switchTo,\n searchInput,\n localeSwitcherLabel,\n languageListLabel,\n seeAllLocalesSwitch,\n } = useIntlayer('locale-switcher-content');\n const inputRef = useRef<HTMLInputElement>(null);\n const { locale } = useLocale();\n const { availableLocales, selectedLocales, setSelectedLocales } =\n useLocaleSwitcherContent();\n\n // 1. Memoize the list construction so it doesn't rebuild every render\n const multilingualAvailableLocales: MultilingualAvailableLocales[] = useMemo(\n () =>\n availableLocales.map((localeEl) => {\n const englishName = getLocaleName(localeEl, Locales.ENGLISH);\n const currentLocaleName = getLocaleName(localeEl, locale);\n const ownLocaleName = getLocaleName(localeEl);\n return {\n locale: localeEl,\n englishName,\n currentLocaleName,\n ownLocaleName,\n };\n }),\n [availableLocales, locale]\n );\n\n // 2. State for Search Query only (Source of Truth)\n const [searchQuery, setSearchQuery] = useState('');\n\n const [seeAllLocales, setSeeAllLocales] = usePersistedStore(\n 'locale-content-selector-see-all-locales',\n false\n );\n\n // 3. Memoize Fuse instance\n const fuse = useMemo(() => {\n const fuseOptions: IFuseOptions<MultilingualAvailableLocales> = {\n keys: [\n { name: 'ownLocaleName', weight: 0.4 },\n { name: 'englishName', weight: 0.2 },\n { name: 'currentLocaleName', weight: 0.2 },\n { name: 'locale', weight: 0.2 },\n ],\n threshold: 0.02,\n };\n return new Fuse(multilingualAvailableLocales, fuseOptions);\n }, [multilingualAvailableLocales]);\n\n // 4. Derive results from Search Query\n const results = useMemo(() => {\n if (!searchQuery) {\n return multilingualAvailableLocales;\n }\n return fuse.search(searchQuery).map((result) => result.item);\n }, [searchQuery, multilingualAvailableLocales, fuse]);\n\n const handleClickLocale = (localeItem: LocalesValues) => {\n if (isMultilingual) {\n if (selectedLocales.includes(localeItem)) {\n if (selectedLocales.length > 1) {\n setSelectedLocales((prev) => prev.filter((el) => el !== localeItem));\n }\n } else {\n setSelectedLocales((prev) => [...prev, localeItem]);\n }\n } else {\n setSelectedLocales([localeItem]);\n }\n };\n\n const handleSeeAllLocales = (value: boolean) => {\n setSeeAllLocales(value);\n\n if (value) {\n setSelectedLocales(availableLocales);\n } else {\n setSelectedLocales([locale]);\n }\n };\n\n return (\n <div className=\"rounded-xl border border-text text-text transition-colors\">\n <DropDown identifier={DROPDOWN_IDENTIFIER}>\n <DropDown.Trigger\n identifier={DROPDOWN_IDENTIFIER}\n label={localeSwitcherLabel.value}\n className=\"p-0!\"\n roundedSize=\"3xl\"\n >\n <div className=\"flex w-full items-center justify-between\">\n <div className=\"px-2 py-1\">\n <Globe size={16} />\n </div>\n <MoveVertical className=\"self-center\" size={16} />\n </div>\n </DropDown.Trigger>\n\n <DropDown.Panel\n identifier={DROPDOWN_IDENTIFIER}\n isOverable\n isFocusable\n className=\"right-0 left-auto\"\n {...panelProps}\n >\n <Container\n className=\"max-h-[60vh] min-w-28\"\n separator=\"y\"\n role=\"listbox\"\n transparency=\"sm\"\n border\n roundedSize=\"2xl\"\n borderColor=\"text\"\n aria-label={languageListLabel.value}\n >\n {isMultilingual && (\n <div className=\"m-auto p-2\">\n <SwitchSelector\n defaultValue={seeAllLocales} // Ensure this uses the persisted state\n onChange={handleSeeAllLocales}\n color={SwitchSelectorColor.TEXT}\n size={SwitchSelectorSize.SM}\n className=\"!w-60\"\n choices={[\n {\n content: seeAllLocalesSwitch.true.value,\n value: true,\n },\n {\n content: seeAllLocalesSwitch.false.value,\n value: false,\n },\n ]}\n />\n </div>\n )}\n\n {!(isMultilingual && seeAllLocales) && (\n <>\n <div className=\"p-3\">\n <Input\n type=\"search\"\n aria-label={searchInput.ariaLabel.value}\n placeholder={searchInput.placeholder.value}\n // Update search query state directly\n onChange={(e) => setSearchQuery(e.target.value)}\n ref={inputRef}\n />\n </div>\n <ol className=\"divide-y divide-dashed divide-text/20 overflow-y-auto p-1\">\n {results.map(\n ({\n locale: localeItem,\n currentLocaleName,\n ownLocaleName,\n }) => (\n <li className=\"px-1.5 py-1\" key={localeItem}>\n <Button\n onClick={() => handleClickLocale(localeItem)}\n label={`${switchTo} ${currentLocaleName}`}\n disabled={\n !(availableLocales ?? availableLocales).includes(\n localeItem\n )\n }\n isActive={selectedLocales.includes(localeItem)}\n variant={ButtonVariant.HOVERABLE}\n color={ButtonColor.TEXT}\n isFullWidth\n textAlign={ButtonTextAlign.LEFT}\n size={ButtonSize.SM}\n >\n <div className=\"flex flex-row items-center justify-between gap-3 px-2 py-1\">\n {isMultilingual && (\n <div className=\"w-4\">\n {selectedLocales.includes(localeItem) && (\n <Check className=\"size-full\" />\n )}\n </div>\n )}\n <div className=\"flex flex-1 flex-row items-center justify-between gap-3 px-2 py-1\">\n <div className=\"flex flex-col text-nowrap\">\n <span\n dir={getHTMLTextDir(localeItem)}\n lang={localeItem}\n >\n {ownLocaleName}\n </span>\n <span className=\"text-neutral text-xs\">\n {currentLocaleName}\n </span>\n </div>\n <span className=\"text-neutral text-sm\">\n {localeItem.toUpperCase()}\n </span>\n </div>\n </div>\n </Button>\n </li>\n )\n )}\n </ol>\n </>\n )}\n </Container>\n </DropDown.Panel>\n </DropDown>\n </div>\n );\n};\n"],"mappings":"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"}
|
|
@@ -219,7 +219,7 @@ const MarkdownRenderer = ({ children, isDarkMode, locale, options }) => {
|
|
|
219
219
|
isDarkMode,
|
|
220
220
|
language: props.className?.replace("lang-", "") || "plaintext",
|
|
221
221
|
fileName: props.fileName,
|
|
222
|
-
showHeader: Boolean(props.fileName)
|
|
222
|
+
showHeader: Boolean(props.fileName || props.packageManager || props.codeFormat || props.contentDeclarationFormat)
|
|
223
223
|
}),
|
|
224
224
|
blockquote: ({ className, ...props }) => /* @__PURE__ */ jsx("blockquote", {
|
|
225
225
|
className: cn("mt-5 gap-3 border-card border-l-4 pl-5 text-neutral", className),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MarkDownRender.mjs","names":["MarkdownRenderer: FC<MarkdownRendererProps>"],"sources":["../../../../src/components/MarkDownRender/MarkDownRender.tsx"],"sourcesContent":["import type { LocalesValues } from '@intlayer/types';\nimport type { ComponentProps, ComponentPropsWithoutRef, FC } from 'react';\nimport type { BundledLanguage } from 'shiki/bundle/web';\nimport { cn } from '../../utils/cn';\nimport { H1, H2, H3, H4, H5, H6 } from '../Headers';\nimport type { CodeCompAttributes } from '../IDE/Code';\nimport { Code } from '../IDE/Code';\nimport { CodeProvider } from '../IDE/CodeContext';\nimport { Link } from '../Link';\nimport { Tab } from '../Tab';\nimport { TabProvider } from '../Tab/TabContext';\nimport { Table } from '../Table';\nimport { MarkdownProcessor, type MarkdownProcessorOptions } from './processor';\n\ntype MarkdownRendererProps = {\n children: string;\n isDarkMode?: boolean;\n locale?: LocalesValues;\n options?: MarkdownProcessorOptions;\n};\n\n/**\n * Removes frontmatter from markdown content\n * Frontmatter is the YAML metadata block at the beginning of markdown files\n * delimited by --- at the start and end\n */\nconst stripFrontmatter = (markdown: string): string => {\n const lines = markdown.split(/\\r?\\n/);\n\n // Check if the very first non-empty line is the metadata start delimiter\n const firstNonEmptyLine = lines.find((line) => line.trim() !== '');\n\n if (!firstNonEmptyLine || firstNonEmptyLine.trim() !== '---') {\n // No frontmatter, return original content\n return markdown;\n }\n\n let inMetadataBlock = false;\n let endOfMetadataIndex = -1;\n\n for (let i = 0; i < lines.length; i++) {\n const trimmedLine = lines[i].trim();\n\n // Toggle metadata block on encountering the delimiter\n if (trimmedLine === '---') {\n if (!inMetadataBlock) {\n // Begin metadata block\n inMetadataBlock = true;\n } else {\n // End of metadata block\n endOfMetadataIndex = i;\n break;\n }\n }\n }\n\n if (endOfMetadataIndex > -1) {\n // Return content after the frontmatter\n return lines.slice(endOfMetadataIndex + 1).join('\\n');\n }\n\n // If we couldn't find the end delimiter, return original content\n return markdown;\n};\n\n/**\n * MarkdownRenderer Component\n *\n * A comprehensive markdown renderer that transforms markdown text into rich,\n * interactive HTML with custom styling and Intlayer integration. Supports\n * code syntax highlighting, responsive tables, internationalized links,\n * and automatic frontmatter stripping.\n *\n * @component\n * @example\n * Basic usage:\n * ```tsx\n * const markdownContent = `\n * # Hello World\n * This is **bold** and *italic* text.\n * `;\n *\n * <MarkdownRenderer>{markdownContent}</MarkdownRenderer>\n * ```\n *\n * @example\n * With dark mode:\n * ```tsx\n * const codeExample = `\n * # API Documentation\n * \\`\\`\\`javascript\n * const response = await fetch('/api/data');\n * const data = await response.json();\n * \\`\\`\\`\n * `;\n *\n * <MarkdownRenderer isDarkMode={true}>\n * {codeExample}\n * </MarkdownRenderer>\n * ```\n *\n * @example\n * With internationalized links:\n * ```tsx\n * const content = `\n * Visit our [documentation](/docs) for more information.\n * External link: [Google](https://google.com)\n * `;\n *\n * <MarkdownRenderer locale=\"fr\">\n * {content}\n * </MarkdownRenderer>\n * ```\n *\n * @example\n * With custom overrides:\n * ```tsx\n * const customOptions = {\n * overrides: {\n * h1: ({ children }) => (\n * <h1 className=\"custom-title\">{children}</h1>\n * ),\n * },\n * };\n *\n * <MarkdownRenderer options={customOptions}>\n * {markdownContent}\n * </MarkdownRenderer>\n * ```\n *\n * @example\n * With frontmatter (automatically stripped):\n * ```tsx\n * const blogPost = `\n * ---\n * title: \"My Blog Post\"\n * date: \"2023-12-01\"\n * author: \"John Doe\"\n * ---\n * # My Blog Post\n * This content will be rendered without the frontmatter.\n * `;\n *\n * <MarkdownRenderer>{blogPost}</MarkdownRenderer>\n * ```\n *\n * Features:\n * - Automatic frontmatter detection and removal\n * - Syntax-highlighted code blocks with theme support\n * - Clickable headers with anchor links\n * - Internationalized link handling with locale awareness\n * - Responsive tables with hover effects\n * - Custom blockquote, list, and image styling\n * - External link detection and security attributes\n * - Inline code with distinctive styling\n * - Lazy-loaded images with GitHub raw URL support\n * - Horizontal rules with custom styling\n *\n * Supported Markdown Elements:\n * - Headers (h1-h4) with click-to-anchor functionality\n * - Code blocks with language-specific syntax highlighting\n * - Inline code with background styling\n * - Blockquotes with custom border and padding\n * - Ordered and unordered lists with custom spacing\n * - Links (internal and external) with security attributes\n * - Images with lazy loading and responsive sizing\n * - Tables with hover effects and proper styling\n * - Horizontal rules with custom appearance\n * - All standard markdown formatting (bold, italic, etc.)\n *\n * Code Block Support:\n * - Language detection from code fence info\n * - Syntax highlighting through Code component\n * - Dark/light mode theme switching\n * - Line numbers and copy functionality (via Code component)\n * - Support for popular languages (JS, TS, Python, etc.)\n *\n * Link Handling:\n * - Automatic external link detection (starts with 'http')\n * - Security attributes for external links (rel=\"noopener noreferrer\")\n * - Locale-aware internal link routing\n * - Custom Link component integration\n * - Underlined styling for better visibility\n *\n * Image Processing:\n * - Automatic lazy loading for performance\n * - GitHub raw URL transformation for repository images\n * - Responsive sizing with max-width constraints\n * - Rounded corners for visual appeal\n *\n * Accessibility:\n * - Semantic HTML structure with proper heading hierarchy\n * - ARIA attributes through component integration\n * - Screen reader friendly link descriptions\n * - Keyboard navigation support\n * - High contrast styling options\n *\n * Performance:\n * - Lazy loading for images\n * - Efficient re-rendering with React memo patterns\n * - Code syntax highlighting with minimal bundle impact\n * - Optimized markdown parsing with markdown-to-jsx\n *\n * @param props - Component props\n * @param props.children - Raw markdown content to render\n * @param props.isDarkMode - Enable dark mode styling for code blocks\n * @param props.locale - Current locale for link internationalization\n * @param props.options - Additional markdown-to-jsx options\n * @param props.options.overrides - Custom component overrides for markdown elements\n *\n * @returns Rendered markdown content with custom styling and functionality\n */\nexport const MarkdownRenderer: FC<MarkdownRendererProps> = ({\n children,\n isDarkMode,\n locale,\n options,\n}) => {\n const { overrides, ...restOptions } = options ?? {};\n\n // Strip frontmatter from the markdown content before rendering\n const cleanMarkdown = stripFrontmatter(children);\n\n return (\n <CodeProvider>\n <TabProvider>\n <MarkdownProcessor\n options={{\n overrides: {\n h1: (props: ComponentProps<typeof H1>) => (\n <H1 isClickable={true} {...props} />\n ),\n h2: (props: ComponentProps<typeof H2>) => (\n <H2 isClickable={true} className=\"mt-16\" {...props} />\n ),\n h3: (props: ComponentProps<typeof H3>) => (\n <H3 isClickable={true} className=\"mt-5\" {...props} />\n ),\n h4: (props: ComponentProps<typeof H4>) => (\n <H4 isClickable={true} className=\"mt-3\" {...props} />\n ),\n h5: (props: ComponentProps<typeof H5>) => (\n <H5 isClickable={true} className=\"mt-3\" {...props} />\n ),\n h6: (props: ComponentProps<typeof H6>) => (\n <H6 isClickable={true} className=\"mt-3\" {...props} />\n ),\n\n code: (\n props: Omit<ComponentPropsWithoutRef<'code'>, 'children'> &\n Partial<CodeCompAttributes> & { children: string }\n ) =>\n !props.className ? (\n <strong className=\"rounded bg-card/60 box-decoration-clone px-1 py-0.5\">\n {props.children}\n </strong>\n ) : (\n <Code\n {...props}\n isDarkMode={isDarkMode}\n language={\n (props.className?.replace('lang-', '') ||\n 'plaintext') as BundledLanguage\n }\n fileName={props.fileName}\n showHeader={Boolean(props.fileName)}\n />\n ),\n\n blockquote: ({\n className,\n ...props\n }: ComponentPropsWithoutRef<'blockquote'>) => (\n <blockquote\n className={cn(\n 'mt-5 gap-3 border-card border-l-4 pl-5 text-neutral',\n className\n )}\n {...props}\n />\n ),\n ul: ({ className, ...props }: ComponentPropsWithoutRef<'ul'>) => (\n <ul\n className={cn(\n 'mt-5 flex list-disc flex-col gap-3 pl-5',\n className\n )}\n {...props}\n />\n ),\n ol: ({ className, ...props }: ComponentPropsWithoutRef<'ol'>) => (\n <ol\n className={cn(\n 'mt-5 flex list-decimal flex-col gap-3 pl-5',\n className\n )}\n {...props}\n />\n ),\n img: ({\n className,\n ...props\n }: ComponentPropsWithoutRef<'img'>) => (\n <img\n {...props}\n loading=\"lazy\"\n className={cn(\n 'max-h-[80vh] max-w-full rounded-md',\n className\n )}\n src={`${props.src}?raw=true`}\n />\n ),\n a: (props: ComponentProps<typeof Link>) => (\n <Link\n color=\"neutral\"\n isExternalLink={props.href?.startsWith('http')}\n underlined={true}\n locale={locale}\n {...props}\n />\n ),\n pre: (props: ComponentPropsWithoutRef<'pre'>) => props.children,\n\n table: (props: ComponentProps<typeof Table>) => (\n <Table isRollable={true} {...props} />\n ),\n th: ({ className, ...props }: ComponentPropsWithoutRef<'th'>) => (\n <th\n className={cn(\n 'border-neutral border-b bg-neutral/10 p-4',\n className\n )}\n {...props}\n />\n ),\n tr: ({ className, ...props }: ComponentPropsWithoutRef<'tr'>) => (\n <tr\n className={cn('hover:/10 hover:bg-neutral/10', className)}\n {...props}\n />\n ),\n td: ({ className, ...props }: ComponentPropsWithoutRef<'td'>) => (\n <td\n className={cn(\n 'border-neutral-500/50 border-b p-4',\n className\n )}\n {...props}\n />\n ),\n hr: ({ className, ...props }: ComponentPropsWithoutRef<'hr'>) => (\n <hr\n className={cn('mx-6 mt-16 text-neutral', className)}\n {...props}\n />\n ),\n // Support both <Tab> and <Tabs> in markdown\n Tabs: (props: ComponentProps<typeof Tab>) => <Tab {...props} />,\n Tab: (props: ComponentProps<typeof Tab>) => <Tab {...props} />,\n TabItem: (props: ComponentProps<typeof Tab.Item>) => (\n <Tab.Item {...props} />\n ),\n Columns: ({\n className,\n ...props\n }: ComponentPropsWithoutRef<'div'>) => (\n <div\n className={cn('flex gap-4 max-md:flex-col', className)}\n {...props}\n />\n ),\n Column: ({\n className,\n ...props\n }: ComponentPropsWithoutRef<'div'>) => (\n <div className={cn('flex-1', className)} {...props} />\n ),\n ...overrides,\n },\n ...restOptions,\n }}\n >\n {cleanMarkdown ?? ''}\n </MarkdownProcessor>\n </TabProvider>\n </CodeProvider>\n );\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"MarkDownRender.mjs","names":["MarkdownRenderer: FC<MarkdownRendererProps>"],"sources":["../../../../src/components/MarkDownRender/MarkDownRender.tsx"],"sourcesContent":["import type { LocalesValues } from '@intlayer/types';\nimport type { ComponentProps, ComponentPropsWithoutRef, FC } from 'react';\nimport type { BundledLanguage } from 'shiki/bundle/web';\nimport { cn } from '../../utils/cn';\nimport { H1, H2, H3, H4, H5, H6 } from '../Headers';\nimport type { CodeCompAttributes } from '../IDE/Code';\nimport { Code } from '../IDE/Code';\nimport { CodeProvider } from '../IDE/CodeContext';\nimport { Link } from '../Link';\nimport { Tab } from '../Tab';\nimport { TabProvider } from '../Tab/TabContext';\nimport { Table } from '../Table';\nimport { MarkdownProcessor, type MarkdownProcessorOptions } from './processor';\n\ntype MarkdownRendererProps = {\n children: string;\n isDarkMode?: boolean;\n locale?: LocalesValues;\n options?: MarkdownProcessorOptions;\n};\n\n/**\n * Removes frontmatter from markdown content\n * Frontmatter is the YAML metadata block at the beginning of markdown files\n * delimited by --- at the start and end\n */\nconst stripFrontmatter = (markdown: string): string => {\n const lines = markdown.split(/\\r?\\n/);\n\n // Check if the very first non-empty line is the metadata start delimiter\n const firstNonEmptyLine = lines.find((line) => line.trim() !== '');\n\n if (!firstNonEmptyLine || firstNonEmptyLine.trim() !== '---') {\n // No frontmatter, return original content\n return markdown;\n }\n\n let inMetadataBlock = false;\n let endOfMetadataIndex = -1;\n\n for (let i = 0; i < lines.length; i++) {\n const trimmedLine = lines[i].trim();\n\n // Toggle metadata block on encountering the delimiter\n if (trimmedLine === '---') {\n if (!inMetadataBlock) {\n // Begin metadata block\n inMetadataBlock = true;\n } else {\n // End of metadata block\n endOfMetadataIndex = i;\n break;\n }\n }\n }\n\n if (endOfMetadataIndex > -1) {\n // Return content after the frontmatter\n return lines.slice(endOfMetadataIndex + 1).join('\\n');\n }\n\n // If we couldn't find the end delimiter, return original content\n return markdown;\n};\n\n/**\n * MarkdownRenderer Component\n *\n * A comprehensive markdown renderer that transforms markdown text into rich,\n * interactive HTML with custom styling and Intlayer integration. Supports\n * code syntax highlighting, responsive tables, internationalized links,\n * and automatic frontmatter stripping.\n *\n * @component\n * @example\n * Basic usage:\n * ```tsx\n * const markdownContent = `\n * # Hello World\n * This is **bold** and *italic* text.\n * `;\n *\n * <MarkdownRenderer>{markdownContent}</MarkdownRenderer>\n * ```\n *\n * @example\n * With dark mode:\n * ```tsx\n * const codeExample = `\n * # API Documentation\n * \\`\\`\\`javascript\n * const response = await fetch('/api/data');\n * const data = await response.json();\n * \\`\\`\\`\n * `;\n *\n * <MarkdownRenderer isDarkMode={true}>\n * {codeExample}\n * </MarkdownRenderer>\n * ```\n *\n * @example\n * With internationalized links:\n * ```tsx\n * const content = `\n * Visit our [documentation](/docs) for more information.\n * External link: [Google](https://google.com)\n * `;\n *\n * <MarkdownRenderer locale=\"fr\">\n * {content}\n * </MarkdownRenderer>\n * ```\n *\n * @example\n * With custom overrides:\n * ```tsx\n * const customOptions = {\n * overrides: {\n * h1: ({ children }) => (\n * <h1 className=\"custom-title\">{children}</h1>\n * ),\n * },\n * };\n *\n * <MarkdownRenderer options={customOptions}>\n * {markdownContent}\n * </MarkdownRenderer>\n * ```\n *\n * @example\n * With frontmatter (automatically stripped):\n * ```tsx\n * const blogPost = `\n * ---\n * title: \"My Blog Post\"\n * date: \"2023-12-01\"\n * author: \"John Doe\"\n * ---\n * # My Blog Post\n * This content will be rendered without the frontmatter.\n * `;\n *\n * <MarkdownRenderer>{blogPost}</MarkdownRenderer>\n * ```\n *\n * Features:\n * - Automatic frontmatter detection and removal\n * - Syntax-highlighted code blocks with theme support\n * - Clickable headers with anchor links\n * - Internationalized link handling with locale awareness\n * - Responsive tables with hover effects\n * - Custom blockquote, list, and image styling\n * - External link detection and security attributes\n * - Inline code with distinctive styling\n * - Lazy-loaded images with GitHub raw URL support\n * - Horizontal rules with custom styling\n *\n * Supported Markdown Elements:\n * - Headers (h1-h4) with click-to-anchor functionality\n * - Code blocks with language-specific syntax highlighting\n * - Inline code with background styling\n * - Blockquotes with custom border and padding\n * - Ordered and unordered lists with custom spacing\n * - Links (internal and external) with security attributes\n * - Images with lazy loading and responsive sizing\n * - Tables with hover effects and proper styling\n * - Horizontal rules with custom appearance\n * - All standard markdown formatting (bold, italic, etc.)\n *\n * Code Block Support:\n * - Language detection from code fence info\n * - Syntax highlighting through Code component\n * - Dark/light mode theme switching\n * - Line numbers and copy functionality (via Code component)\n * - Support for popular languages (JS, TS, Python, etc.)\n *\n * Link Handling:\n * - Automatic external link detection (starts with 'http')\n * - Security attributes for external links (rel=\"noopener noreferrer\")\n * - Locale-aware internal link routing\n * - Custom Link component integration\n * - Underlined styling for better visibility\n *\n * Image Processing:\n * - Automatic lazy loading for performance\n * - GitHub raw URL transformation for repository images\n * - Responsive sizing with max-width constraints\n * - Rounded corners for visual appeal\n *\n * Accessibility:\n * - Semantic HTML structure with proper heading hierarchy\n * - ARIA attributes through component integration\n * - Screen reader friendly link descriptions\n * - Keyboard navigation support\n * - High contrast styling options\n *\n * Performance:\n * - Lazy loading for images\n * - Efficient re-rendering with React memo patterns\n * - Code syntax highlighting with minimal bundle impact\n * - Optimized markdown parsing with markdown-to-jsx\n *\n * @param props - Component props\n * @param props.children - Raw markdown content to render\n * @param props.isDarkMode - Enable dark mode styling for code blocks\n * @param props.locale - Current locale for link internationalization\n * @param props.options - Additional markdown-to-jsx options\n * @param props.options.overrides - Custom component overrides for markdown elements\n *\n * @returns Rendered markdown content with custom styling and functionality\n */\nexport const MarkdownRenderer: FC<MarkdownRendererProps> = ({\n children,\n isDarkMode,\n locale,\n options,\n}) => {\n const { overrides, ...restOptions } = options ?? {};\n\n // Strip frontmatter from the markdown content before rendering\n const cleanMarkdown = stripFrontmatter(children);\n\n return (\n <CodeProvider>\n <TabProvider>\n <MarkdownProcessor\n options={{\n overrides: {\n h1: (props: ComponentProps<typeof H1>) => (\n <H1 isClickable={true} {...props} />\n ),\n h2: (props: ComponentProps<typeof H2>) => (\n <H2 isClickable={true} className=\"mt-16\" {...props} />\n ),\n h3: (props: ComponentProps<typeof H3>) => (\n <H3 isClickable={true} className=\"mt-5\" {...props} />\n ),\n h4: (props: ComponentProps<typeof H4>) => (\n <H4 isClickable={true} className=\"mt-3\" {...props} />\n ),\n h5: (props: ComponentProps<typeof H5>) => (\n <H5 isClickable={true} className=\"mt-3\" {...props} />\n ),\n h6: (props: ComponentProps<typeof H6>) => (\n <H6 isClickable={true} className=\"mt-3\" {...props} />\n ),\n\n code: (\n props: Omit<ComponentPropsWithoutRef<'code'>, 'children'> &\n Partial<CodeCompAttributes> & { children: string }\n ) =>\n !props.className ? (\n <strong className=\"rounded bg-card/60 box-decoration-clone px-1 py-0.5\">\n {props.children}\n </strong>\n ) : (\n <Code\n {...props}\n isDarkMode={isDarkMode}\n language={\n (props.className?.replace('lang-', '') ||\n 'plaintext') as BundledLanguage\n }\n fileName={props.fileName}\n showHeader={Boolean(\n props.fileName ||\n props.packageManager ||\n props.codeFormat ||\n props.contentDeclarationFormat\n )}\n />\n ),\n\n blockquote: ({\n className,\n ...props\n }: ComponentPropsWithoutRef<'blockquote'>) => (\n <blockquote\n className={cn(\n 'mt-5 gap-3 border-card border-l-4 pl-5 text-neutral',\n className\n )}\n {...props}\n />\n ),\n ul: ({ className, ...props }: ComponentPropsWithoutRef<'ul'>) => (\n <ul\n className={cn(\n 'mt-5 flex list-disc flex-col gap-3 pl-5',\n className\n )}\n {...props}\n />\n ),\n ol: ({ className, ...props }: ComponentPropsWithoutRef<'ol'>) => (\n <ol\n className={cn(\n 'mt-5 flex list-decimal flex-col gap-3 pl-5',\n className\n )}\n {...props}\n />\n ),\n img: ({\n className,\n ...props\n }: ComponentPropsWithoutRef<'img'>) => (\n <img\n {...props}\n loading=\"lazy\"\n className={cn(\n 'max-h-[80vh] max-w-full rounded-md',\n className\n )}\n src={`${props.src}?raw=true`}\n />\n ),\n a: (props: ComponentProps<typeof Link>) => (\n <Link\n color=\"neutral\"\n isExternalLink={props.href?.startsWith('http')}\n underlined={true}\n locale={locale}\n {...props}\n />\n ),\n pre: (props: ComponentPropsWithoutRef<'pre'>) => props.children,\n\n table: (props: ComponentProps<typeof Table>) => (\n <Table isRollable={true} {...props} />\n ),\n th: ({ className, ...props }: ComponentPropsWithoutRef<'th'>) => (\n <th\n className={cn(\n 'border-neutral border-b bg-neutral/10 p-4',\n className\n )}\n {...props}\n />\n ),\n tr: ({ className, ...props }: ComponentPropsWithoutRef<'tr'>) => (\n <tr\n className={cn('hover:/10 hover:bg-neutral/10', className)}\n {...props}\n />\n ),\n td: ({ className, ...props }: ComponentPropsWithoutRef<'td'>) => (\n <td\n className={cn(\n 'border-neutral-500/50 border-b p-4',\n className\n )}\n {...props}\n />\n ),\n hr: ({ className, ...props }: ComponentPropsWithoutRef<'hr'>) => (\n <hr\n className={cn('mx-6 mt-16 text-neutral', className)}\n {...props}\n />\n ),\n // Support both <Tab> and <Tabs> in markdown\n Tabs: (props: ComponentProps<typeof Tab>) => <Tab {...props} />,\n Tab: (props: ComponentProps<typeof Tab>) => <Tab {...props} />,\n TabItem: (props: ComponentProps<typeof Tab.Item>) => (\n <Tab.Item {...props} />\n ),\n Columns: ({\n className,\n ...props\n }: ComponentPropsWithoutRef<'div'>) => (\n <div\n className={cn('flex gap-4 max-md:flex-col', className)}\n {...props}\n />\n ),\n Column: ({\n className,\n ...props\n }: ComponentPropsWithoutRef<'div'>) => (\n <div className={cn('flex-1', className)} {...props} />\n ),\n ...overrides,\n },\n ...restOptions,\n }}\n >\n {cleanMarkdown ?? ''}\n </MarkdownProcessor>\n </TabProvider>\n </CodeProvider>\n );\n};\n"],"mappings":"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"}
|
|
@@ -34,7 +34,7 @@ let ModalSize = /* @__PURE__ */ function(ModalSize$1) {
|
|
|
34
34
|
* Class name variants for different modal sizes using class-variance-authority
|
|
35
35
|
* Defines responsive sizing and scrollable content for modal containers
|
|
36
36
|
*/
|
|
37
|
-
const modalVariants = cva("flex cursor-default flex-col
|
|
37
|
+
const modalVariants = cva("flex cursor-default flex-col p-3 shadow-sm", {
|
|
38
38
|
variants: { size: {
|
|
39
39
|
sm: "h-auto max-h-[30vh] w-[95vw] max-w-xl",
|
|
40
40
|
md: "h-auto max-h-[50vh] w-[95vw] max-w-xl",
|
|
@@ -190,7 +190,7 @@ const Modal = ({ children, isOpen, container, disableScroll = true, onClose, has
|
|
|
190
190
|
size: ButtonSize.ICON_MD
|
|
191
191
|
})]
|
|
192
192
|
}), /* @__PURE__ */ jsx("div", {
|
|
193
|
-
className: "flex w-full flex-1 flex-col
|
|
193
|
+
className: "flex w-full flex-1 flex-col",
|
|
194
194
|
children
|
|
195
195
|
})]
|
|
196
196
|
})
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Modal.mjs","names":["m","Modal: FC<ModalProps>"],"sources":["../../../../src/components/Modal/Modal.tsx"],"sourcesContent":["'use client';\n\nimport { cva } from 'class-variance-authority';\nimport { motion as m } from 'framer-motion';\nimport { X } from 'lucide-react';\nimport { type FC, type ReactNode, useEffect } from 'react';\nimport { createPortal } from 'react-dom';\nimport { useGetElementOrWindow, useScrollBlockage } from '../../hooks/index';\nimport { cn } from '../../utils/cn';\nimport { Button, ButtonColor, ButtonSize, ButtonVariant } from '../Button';\nimport { Container, type ContainerProps } from '../Container';\nimport { H3 } from '../Headers';\n\n/**\n * Enumeration of available modal sizes\n */\nexport enum ModalSize {\n /** Small modal: max height 30vh, max width xl */\n SM = 'sm',\n /** Medium modal: max height 50vh, max width xl */\n MD = 'md',\n /** Large modal: max height 70vh, max width 2xl */\n LG = 'lg',\n /** Extra large modal: max height 95vh, max width 6xl */\n XL = 'xl',\n /** Unset size: max height 95vh, full width responsive */\n UNSET = 'unset',\n}\n\n/**\n * Props for the Modal component\n */\ntype ModalProps = {\n /** Content to be displayed inside the modal */\n children: ReactNode;\n /** Controls whether the modal is visible */\n isOpen: boolean;\n /** Callback function called when the modal should be closed */\n onClose?: () => void;\n /** Container element to render the modal into (defaults to document.body) */\n container?: HTMLElement;\n /** Whether to disable scrolling on the background content */\n disableScroll?: boolean;\n /** Whether to display a close button in the modal header */\n hasCloseButton?: boolean;\n /** Optional title displayed at the top of the modal */\n title?: string;\n /** Size variant for the modal */\n size?: ModalSize | `${ModalSize}`;\n} & Pick<\n ContainerProps,\n | 'className'\n | 'transparency'\n | 'border'\n | 'background'\n | 'roundedSize'\n | 'borderColor'\n | 'padding'\n | 'separator'\n | 'gap'\n>;\n\n/**\n * Class name variants for different modal sizes using class-variance-authority\n * Defines responsive sizing and scrollable content for modal containers\n */\nconst modalVariants = cva(
|
|
1
|
+
{"version":3,"file":"Modal.mjs","names":["m","Modal: FC<ModalProps>"],"sources":["../../../../src/components/Modal/Modal.tsx"],"sourcesContent":["'use client';\n\nimport { cva } from 'class-variance-authority';\nimport { motion as m } from 'framer-motion';\nimport { X } from 'lucide-react';\nimport { type FC, type ReactNode, useEffect } from 'react';\nimport { createPortal } from 'react-dom';\nimport { useGetElementOrWindow, useScrollBlockage } from '../../hooks/index';\nimport { cn } from '../../utils/cn';\nimport { Button, ButtonColor, ButtonSize, ButtonVariant } from '../Button';\nimport { Container, type ContainerProps } from '../Container';\nimport { H3 } from '../Headers';\n\n/**\n * Enumeration of available modal sizes\n */\nexport enum ModalSize {\n /** Small modal: max height 30vh, max width xl */\n SM = 'sm',\n /** Medium modal: max height 50vh, max width xl */\n MD = 'md',\n /** Large modal: max height 70vh, max width 2xl */\n LG = 'lg',\n /** Extra large modal: max height 95vh, max width 6xl */\n XL = 'xl',\n /** Unset size: max height 95vh, full width responsive */\n UNSET = 'unset',\n}\n\n/**\n * Props for the Modal component\n */\ntype ModalProps = {\n /** Content to be displayed inside the modal */\n children: ReactNode;\n /** Controls whether the modal is visible */\n isOpen: boolean;\n /** Callback function called when the modal should be closed */\n onClose?: () => void;\n /** Container element to render the modal into (defaults to document.body) */\n container?: HTMLElement;\n /** Whether to disable scrolling on the background content */\n disableScroll?: boolean;\n /** Whether to display a close button in the modal header */\n hasCloseButton?: boolean;\n /** Optional title displayed at the top of the modal */\n title?: string;\n /** Size variant for the modal */\n size?: ModalSize | `${ModalSize}`;\n} & Pick<\n ContainerProps,\n | 'className'\n | 'transparency'\n | 'border'\n | 'background'\n | 'roundedSize'\n | 'borderColor'\n | 'padding'\n | 'separator'\n | 'gap'\n>;\n\n/**\n * Class name variants for different modal sizes using class-variance-authority\n * Defines responsive sizing and scrollable content for modal containers\n */\nconst modalVariants = cva('flex cursor-default flex-col p-3 shadow-sm', {\n variants: {\n size: {\n /** Small modal: height auto, max-height 30vh, width 95vw, max-width xl */\n sm: 'h-auto max-h-[30vh] w-[95vw] max-w-xl',\n /** Medium modal: height auto, max-height 50vh, width 95vw, max-width xl */\n md: 'h-auto max-h-[50vh] w-[95vw] max-w-xl',\n /** Large modal: height auto, max-height 70vh, width 95vw, max-width 2xl */\n lg: 'h-auto max-h-[70vh] w-[95vw] max-w-2xl',\n /** Extra large modal: height auto, max-height 95vh, width 95vw, max-width 6xl */\n xl: 'h-auto max-h-[95vh] w-[95vw] max-w-6xl',\n /** Unset modal: height auto, max-height 95vh, width 95vw, no max-width */\n unset: 'h-auto max-h-[95vh] w-[95vw]',\n },\n },\n defaultVariants: {\n size: 'unset',\n },\n});\n\n/**\n * Motion-enabled modal component with Framer Motion support\n * Extends Container component with motion capabilities for animations\n */\nconst MotionModal = m.create(Container);\n\n/**\n * Modal Component\n *\n * A highly customizable modal dialog component with portal rendering, Framer Motion animations,\n * and comprehensive accessibility features. Supports multiple size variants and scroll management.\n *\n * Features:\n * - Portal rendering to any container element (defaults to document.body)\n * - Smooth animations with Framer Motion\n * - Size variants: SM, MD, LG, XL, UNSET with responsive sizing\n * - Optional title and close button\n * - Background scroll prevention\n * - Click-outside-to-close functionality\n * - Full accessibility support with ARIA attributes\n * - Keyboard navigation support (ESC to close)\n * - Extensible styling with Container props\n *\n * @example\n * Basic usage:\n * ```jsx\n * <Modal isOpen={isModalOpen} onClose={() => setIsModalOpen(false)}>\n * <p>Modal content goes here</p>\n * </Modal>\n * ```\n *\n * @example\n * With title and close button:\n * ```jsx\n * <Modal\n * isOpen={isOpen}\n * onClose={onClose}\n * title=\"Confirm Action\"\n * hasCloseButton\n * size={ModalSize.LG}\n * >\n * <div>\n * <p>Are you sure you want to continue?</p>\n * <Button onClick={onConfirm}>Confirm</Button>\n * </div>\n * </Modal>\n * ```\n *\n * @example\n * Custom container and styling:\n * ```jsx\n * <Modal\n * isOpen={isOpen}\n * onClose={onClose}\n * container={customContainer}\n * background=\"card\"\n * padding=\"lg\"\n * border=\"default\"\n * >\n * Content with custom styling\n * </Modal>\n * ```\n *\n * Accessibility Notes:\n * - Modal receives focus when opened\n * - Background content is hidden from screen readers when modal is open\n * - ESC key closes modal (handled by browser for role=\"dialog\")\n * - Click outside modal closes it\n * - Close button has descriptive label for screen readers\n *\n * @param props - Modal component props\n * @returns JSX element rendered via createPortal\n */\nexport const Modal: FC<ModalProps> = ({\n children,\n isOpen,\n container,\n disableScroll = true,\n onClose,\n hasCloseButton = false,\n title,\n size = ModalSize.MD,\n className,\n ...props\n}) => {\n const containerElement = useGetElementOrWindow(container);\n\n useScrollBlockage({ key: 'modal', disableScroll: isOpen && disableScroll });\n\n useEffect(() => {\n const handleEscape = (event: KeyboardEvent) => {\n if (event.key === 'Escape' && isOpen && onClose) {\n onClose();\n }\n };\n\n document.addEventListener('keydown', handleEscape);\n\n return () => {\n document.removeEventListener('keydown', handleEscape);\n };\n }, [isOpen, onClose]);\n\n if (!containerElement) return <></>;\n\n const hasTitle = typeof title === 'string';\n\n return createPortal(\n <m.div\n className=\"invisible fixed top-0 left-0 z-50 flex size-full cursor-pointer items-center justify-center overflow-auto bg-background/40 backdrop-blur\"\n animate={isOpen ? 'visible' : 'invisible'}\n variants={{\n visible: {\n opacity: 1,\n visibility: 'visible',\n transition: { duration: 0.1, when: 'beforeChildren' },\n },\n invisible: {\n opacity: 0,\n visibility: 'hidden',\n transition: { duration: 0.1, when: 'afterChildren' },\n },\n }}\n onClick={(e) => {\n e.stopPropagation();\n onClose?.();\n }}\n aria-hidden={!isOpen}\n >\n <MotionModal\n onClick={(e) => e.stopPropagation()}\n initial={{ scale: isOpen ? 0.5 : 1 }}\n animate={{ scale: isOpen ? 1 : 0.5 }}\n transition={{ duration: 0.3 }}\n className={modalVariants({\n size,\n className,\n })}\n role=\"dialog\"\n aria-modal\n roundedSize=\"2xl\"\n {...props}\n >\n <div\n className={cn(\n 'cursor-default',\n hasCloseButton && hasTitle\n ? `flex items-start`\n : hasCloseButton\n ? `flex justify-end`\n : hasTitle\n ? `items-center`\n : `hidden`\n )}\n >\n {hasTitle && (\n <H3 className=\"mt-2 mb-4 ml-4 flex items-center justify-center font-bold text-lg\">\n {title}\n </H3>\n )}\n {hasCloseButton && (\n <Button\n variant={ButtonVariant.HOVERABLE}\n color={ButtonColor.TEXT}\n label=\"Close modal\"\n className=\"ml-auto\"\n onClick={(e) => {\n e.stopPropagation();\n onClose?.();\n }}\n Icon={X}\n size={ButtonSize.ICON_MD}\n />\n )}\n </div>\n <div className=\"flex w-full flex-1 flex-col\">{children}</div>\n </MotionModal>\n </m.div>,\n containerElement\n );\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAgBA,IAAY,kDAAL;;AAEL;;AAEA;;AAEA;;AAEA;;AAEA;;;;;;;AAwCF,MAAM,gBAAgB,IAAI,8CAA8C;CACtE,UAAU,EACR,MAAM;EAEJ,IAAI;EAEJ,IAAI;EAEJ,IAAI;EAEJ,IAAI;EAEJ,OAAO;EACR,EACF;CACD,iBAAiB,EACf,MAAM,SACP;CACF,CAAC;;;;;AAMF,MAAM,cAAcA,OAAE,OAAO,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqEvC,MAAaC,SAAyB,EACpC,UACA,QACA,WACA,gBAAgB,MAChB,SACA,iBAAiB,OACjB,OACA,OAAO,UAAU,IACjB,WACA,GAAG,YACC;CACJ,MAAM,mBAAmB,sBAAsB,UAAU;AAEzD,mBAAkB;EAAE,KAAK;EAAS,eAAe,UAAU;EAAe,CAAC;AAE3E,iBAAgB;EACd,MAAM,gBAAgB,UAAyB;AAC7C,OAAI,MAAM,QAAQ,YAAY,UAAU,QACtC,UAAS;;AAIb,WAAS,iBAAiB,WAAW,aAAa;AAElD,eAAa;AACX,YAAS,oBAAoB,WAAW,aAAa;;IAEtD,CAAC,QAAQ,QAAQ,CAAC;AAErB,KAAI,CAAC,iBAAkB,QAAO,mCAAK;CAEnC,MAAM,WAAW,OAAO,UAAU;AAElC,QAAO,aACL,oBAACD,OAAE;EACD,WAAU;EACV,SAAS,SAAS,YAAY;EAC9B,UAAU;GACR,SAAS;IACP,SAAS;IACT,YAAY;IACZ,YAAY;KAAE,UAAU;KAAK,MAAM;KAAkB;IACtD;GACD,WAAW;IACT,SAAS;IACT,YAAY;IACZ,YAAY;KAAE,UAAU;KAAK,MAAM;KAAiB;IACrD;GACF;EACD,UAAU,MAAM;AACd,KAAE,iBAAiB;AACnB,cAAW;;EAEb,eAAa,CAAC;YAEd,qBAAC;GACC,UAAU,MAAM,EAAE,iBAAiB;GACnC,SAAS,EAAE,OAAO,SAAS,KAAM,GAAG;GACpC,SAAS,EAAE,OAAO,SAAS,IAAI,IAAK;GACpC,YAAY,EAAE,UAAU,IAAK;GAC7B,WAAW,cAAc;IACvB;IACA;IACD,CAAC;GACF,MAAK;GACL;GACA,aAAY;GACZ,GAAI;cAEJ,qBAAC;IACC,WAAW,GACT,kBACA,kBAAkB,WACd,qBACA,iBACE,qBACA,WACE,iBACA,SACT;eAEA,YACC,oBAAC;KAAG,WAAU;eACX;MACE,EAEN,kBACC,oBAAC;KACC,SAAS,cAAc;KACvB,OAAO,YAAY;KACnB,OAAM;KACN,WAAU;KACV,UAAU,MAAM;AACd,QAAE,iBAAiB;AACnB,iBAAW;;KAEb,MAAM;KACN,MAAM,WAAW;MACjB;KAEA,EACN,oBAAC;IAAI,WAAU;IAA+B;KAAe;IACjD;GACR,EACR,iBACD"}
|
|
@@ -4,101 +4,19 @@ import { Container } from "../Container/index.mjs";
|
|
|
4
4
|
import { Button, ButtonColor, ButtonSize, ButtonVariant } from "../Button/Button.mjs";
|
|
5
5
|
import { useDevice } from "../../hooks/useDevice.mjs";
|
|
6
6
|
import { useScrollBlockage } from "../../hooks/useScrollBlockage/index.mjs";
|
|
7
|
+
import { Popover } from "../Popover/dynamic.mjs";
|
|
8
|
+
import { KeyboardShortcut } from "../KeyboardShortcut/KeyboardShortcut.mjs";
|
|
7
9
|
import { MaxWidthSmoother } from "../MaxWidthSmoother/index.mjs";
|
|
8
10
|
import { isElementAtTopAndNotCovered } from "./isElementAtTopAndNotCovered.mjs";
|
|
9
11
|
import { useRightDrawerStore } from "./useRightDrawerStore.mjs";
|
|
10
12
|
import { ChevronLeft, X } from "lucide-react";
|
|
11
13
|
import { useEffect, useRef } from "react";
|
|
12
14
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
15
|
+
import { useIntlayer } from "react-intlayer";
|
|
13
16
|
|
|
14
17
|
//#region src/components/RightDrawer/RightDrawer.tsx
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
*
|
|
18
|
-
* A versatile drawer component that provides an overlay panel for displaying secondary content,
|
|
19
|
-
* forms, details, or navigation. Features responsive design that adapts to mobile devices,
|
|
20
|
-
* configurable close behavior, and integrated state management through Zustand store.
|
|
21
|
-
*
|
|
22
|
-
* ## Key Features
|
|
23
|
-
* - **Responsive Design**: Full-width on mobile, fixed 400px width on desktop
|
|
24
|
-
* - **State Management**: Built-in Zustand store for managing multiple drawer instances
|
|
25
|
-
* - **Accessibility**: Proper ARIA attributes, keyboard navigation, and focus management
|
|
26
|
-
* - **Flexible Layout**: Customizable header, title, and content areas
|
|
27
|
-
* - **Click Outside**: Configurable outside click detection for auto-closing
|
|
28
|
-
* - **Scroll Management**: Automatic body scroll blocking when open
|
|
29
|
-
*
|
|
30
|
-
* ## Use Cases
|
|
31
|
-
* - Navigation menus and sidebars
|
|
32
|
-
* - Detail panels and forms
|
|
33
|
-
* - Settings and configuration interfaces
|
|
34
|
-
* - Shopping carts and checkout processes
|
|
35
|
-
* - User profiles and account management
|
|
36
|
-
* - Multi-step workflows and wizards
|
|
37
|
-
*
|
|
38
|
-
* ## Accessibility
|
|
39
|
-
* - **Focus Management**: Traps focus within the drawer when open
|
|
40
|
-
* - **Keyboard Navigation**: Escape key closes the drawer
|
|
41
|
-
* - **Screen Reader Support**: Proper ARIA labels and announcements
|
|
42
|
-
* - **Touch Support**: Mobile-optimized touch interactions
|
|
43
|
-
*
|
|
44
|
-
* ## State Management
|
|
45
|
-
* The component uses a Zustand store (`useRightDrawerStore`) to manage drawer state:
|
|
46
|
-
* - Multiple drawers can be managed simultaneously using unique identifiers
|
|
47
|
-
* - External components can open/close drawers using the store
|
|
48
|
-
* - Supports both controlled (via props) and uncontrolled (via store) patterns
|
|
49
|
-
*
|
|
50
|
-
* @example
|
|
51
|
-
* Basic usage with store management:
|
|
52
|
-
* ```tsx
|
|
53
|
-
* // Opening the drawer from another component
|
|
54
|
-
* const { open } = useRightDrawerStore();
|
|
55
|
-
*
|
|
56
|
-
* <button onClick={() => open('user-menu')}>
|
|
57
|
-
* Open Menu
|
|
58
|
-
* </button>
|
|
59
|
-
*
|
|
60
|
-
* <RightDrawer identifier="user-menu" title="User Menu">
|
|
61
|
-
* <nav>Navigation items here</nav>
|
|
62
|
-
* </RightDrawer>
|
|
63
|
-
* ```
|
|
64
|
-
*
|
|
65
|
-
* @example
|
|
66
|
-
* Controlled drawer with external state:
|
|
67
|
-
* ```tsx
|
|
68
|
-
* const [showDrawer, setShowDrawer] = useState(false);
|
|
69
|
-
*
|
|
70
|
-
* <RightDrawer
|
|
71
|
-
* identifier="controlled-drawer"
|
|
72
|
-
* title="Settings"
|
|
73
|
-
* isOpen={showDrawer}
|
|
74
|
-
* onClose={() => setShowDrawer(false)}
|
|
75
|
-
* closeOnOutsideClick={false}
|
|
76
|
-
* >
|
|
77
|
-
* <SettingsForm onSave={() => setShowDrawer(false)} />
|
|
78
|
-
* </RightDrawer>
|
|
79
|
-
* ```
|
|
80
|
-
*
|
|
81
|
-
* @example
|
|
82
|
-
* Complex drawer with back button and header:
|
|
83
|
-
* ```tsx
|
|
84
|
-
* <RightDrawer
|
|
85
|
-
* identifier="product-detail"
|
|
86
|
-
* title="Product Details"
|
|
87
|
-
* header={
|
|
88
|
-
* <div className="text-sm text-gray-600">
|
|
89
|
-
* SKU: {product.sku} | Stock: {product.stock}
|
|
90
|
-
* </div>
|
|
91
|
-
* }
|
|
92
|
-
* backButton={{
|
|
93
|
-
* text: "Back to Catalog",
|
|
94
|
-
* onBack: () => navigate('/catalog')
|
|
95
|
-
* }}
|
|
96
|
-
* >
|
|
97
|
-
* <ProductDetailView product={product} />
|
|
98
|
-
* </RightDrawer>
|
|
99
|
-
* ```
|
|
100
|
-
*/
|
|
101
|
-
const RightDrawer = ({ title, identifier, children, header, closeOnOutsideClick = true, backButton, isOpen: isOpenProp, onClose }) => {
|
|
18
|
+
const RightDrawer = ({ title, identifier, children, header, footer, closeOnOutsideClick = true, backButton, isOpen: isOpenProp, onClose }) => {
|
|
19
|
+
const content = useIntlayer("right-drawer");
|
|
102
20
|
const { isMobile } = useDevice("md");
|
|
103
21
|
const panelRef = useRef(null);
|
|
104
22
|
const childrenContainerRef = useRef(null);
|
|
@@ -161,6 +79,16 @@ const RightDrawer = ({ title, identifier, children, header, closeOnOutsideClick
|
|
|
161
79
|
onClose?.();
|
|
162
80
|
}
|
|
163
81
|
};
|
|
82
|
+
const handleSpareSpaceKeyDown = (e) => {
|
|
83
|
+
if (e.target !== e.currentTarget) return;
|
|
84
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
85
|
+
e.preventDefault();
|
|
86
|
+
if (isMobile) {
|
|
87
|
+
closeDrawer(identifier);
|
|
88
|
+
onClose?.();
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
};
|
|
164
92
|
return /* @__PURE__ */ jsx("div", {
|
|
165
93
|
className: "fixed top-0 right-0 z-50 flex h-full justify-end",
|
|
166
94
|
children: /* @__PURE__ */ jsx(MaxWidthSmoother, {
|
|
@@ -170,47 +98,75 @@ const RightDrawer = ({ title, identifier, children, header, closeOnOutsideClick
|
|
|
170
98
|
className: "relative flex h-screen w-screen flex-col text-text md:w-[400px]",
|
|
171
99
|
ref: panelRef,
|
|
172
100
|
roundedSize: "none",
|
|
173
|
-
children: [
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
101
|
+
children: [
|
|
102
|
+
/* @__PURE__ */ jsxs("div", {
|
|
103
|
+
className: "flex shrink-0 flex-col gap-3 px-6 pt-6",
|
|
104
|
+
children: [
|
|
105
|
+
/* @__PURE__ */ jsxs("div", {
|
|
106
|
+
className: "flex justify-between gap-3",
|
|
107
|
+
children: [/* @__PURE__ */ jsx("div", { children: backButton && /* @__PURE__ */ jsx(Button, {
|
|
108
|
+
variant: ButtonVariant.HOVERABLE,
|
|
109
|
+
color: ButtonColor.TEXT,
|
|
110
|
+
label: backButton.text ?? content.goBack.value,
|
|
111
|
+
onClick: backButton.onBack,
|
|
112
|
+
Icon: ChevronLeft,
|
|
113
|
+
children: backButton?.text
|
|
114
|
+
}) }), /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsxs(Popover, {
|
|
115
|
+
identifier: "close-drawer",
|
|
116
|
+
children: [/* @__PURE__ */ jsx(Button, {
|
|
117
|
+
variant: ButtonVariant.HOVERABLE,
|
|
118
|
+
color: ButtonColor.TEXT,
|
|
119
|
+
label: "Close",
|
|
120
|
+
className: "ml-auto",
|
|
121
|
+
onClick: () => {
|
|
122
|
+
closeDrawer(identifier);
|
|
123
|
+
onClose?.();
|
|
124
|
+
},
|
|
125
|
+
Icon: X,
|
|
126
|
+
size: ButtonSize.ICON_MD
|
|
127
|
+
}), /* @__PURE__ */ jsx(Popover.Detail, {
|
|
128
|
+
identifier: "close-drawer",
|
|
129
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
130
|
+
className: "flex items-center gap-2 p-2",
|
|
131
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
132
|
+
className: "whitespace-nowrap text-neutral text-xs",
|
|
133
|
+
children: content.closeDrawer
|
|
134
|
+
}), /* @__PURE__ */ jsx(KeyboardShortcut, {
|
|
135
|
+
shortcut: "Escape",
|
|
136
|
+
size: "sm",
|
|
137
|
+
onTriggered: () => {
|
|
138
|
+
closeDrawer(identifier);
|
|
139
|
+
onClose?.();
|
|
140
|
+
}
|
|
141
|
+
})]
|
|
142
|
+
})
|
|
143
|
+
})]
|
|
144
|
+
}) })]
|
|
145
|
+
}),
|
|
146
|
+
title && /* @__PURE__ */ jsx("h2", {
|
|
147
|
+
className: "flex items-center justify-center font-bold text-lg",
|
|
148
|
+
children: title
|
|
149
|
+
}),
|
|
150
|
+
header
|
|
151
|
+
]
|
|
152
|
+
}),
|
|
153
|
+
/* @__PURE__ */ jsx("div", {
|
|
154
|
+
className: "flex min-h-0 flex-1 flex-col overflow-y-auto p-2",
|
|
155
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
156
|
+
className: "flex flex-1 flex-col outline-none",
|
|
157
|
+
onClick: handleSpareSpaceClick,
|
|
158
|
+
onKeyDown: handleSpareSpaceKeyDown,
|
|
159
|
+
ref: childrenContainerRef,
|
|
160
|
+
role: "button",
|
|
161
|
+
tabIndex: 0,
|
|
162
|
+
children
|
|
163
|
+
})
|
|
164
|
+
}),
|
|
165
|
+
footer && /* @__PURE__ */ jsx("div", {
|
|
166
|
+
className: "shrink-0",
|
|
167
|
+
children: footer
|
|
212
168
|
})
|
|
213
|
-
|
|
169
|
+
]
|
|
214
170
|
})
|
|
215
171
|
})
|
|
216
172
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RightDrawer.mjs","names":["RightDrawer: FC<RightDrawerProps>","handleSpareSpaceClick: MouseEventHandler<HTMLDivElement>"],"sources":["../../../../src/components/RightDrawer/RightDrawer.tsx"],"sourcesContent":["'use client';\n\nimport { ChevronLeft, X } from 'lucide-react';\nimport {\n type FC,\n type MouseEventHandler,\n type ReactNode,\n useEffect,\n useRef,\n} from 'react';\nimport { useDevice } from '../../hooks/useDevice';\nimport { useScrollBlockage } from '../../hooks/useScrollBlockage';\nimport { Button, ButtonColor, ButtonSize, ButtonVariant } from '../Button';\nimport { Container } from '../Container';\nimport { MaxWidthSmoother } from '../MaxWidthSmoother/index';\nimport { isElementAtTopAndNotCovered } from './isElementAtTopAndNotCovered';\nimport { useRightDrawerStore } from './useRightDrawerStore';\n\n/**\n * Configuration for the back button functionality in the RightDrawer\n *\n * @interface BackButtonProps\n */\ntype BackButtonProps = {\n /** Callback function triggered when the back button is clicked */\n onBack: () => void;\n /** Optional custom text for the back button. Defaults to \"Go back\" if not provided */\n text?: string;\n};\n\n/**\n * Props configuration for the RightDrawer component\n *\n * @interface RightDrawerProps\n */\ntype RightDrawerProps = {\n /**\n * Title displayed in the drawer header\n * @example\n * ```tsx\n * <RightDrawer title=\"User Settings\" identifier=\"settings\">\n * Content here\n * </RightDrawer>\n * ```\n */\n title?: ReactNode;\n\n /**\n * Unique identifier for the drawer instance. Required for store management\n * @example\n * ```tsx\n * <RightDrawer identifier=\"user-profile\" title=\"Profile\">\n * Profile content\n * </RightDrawer>\n * ```\n */\n identifier: string;\n\n /** The content to be displayed inside the drawer */\n children?: ReactNode;\n\n /**\n * Optional header content displayed below the title\n * @example\n * ```tsx\n * <RightDrawer\n * title=\"Settings\"\n * header={<div className=\"text-sm opacity-80\">Configure your preferences</div>}\n * identifier=\"settings\"\n * >\n * Settings content\n * </RightDrawer>\n * ```\n */\n header?: ReactNode;\n\n /**\n * Whether the drawer should close when clicking outside of it\n * @default true\n * @example\n * ```tsx\n * <RightDrawer closeOnOutsideClick={false} identifier=\"persistent\">\n * This drawer requires explicit close action\n * </RightDrawer>\n * ```\n */\n closeOnOutsideClick?: boolean;\n\n /**\n * Configuration for an optional back button in the drawer header\n * @example\n * ```tsx\n * <RightDrawer\n * backButton={{\n * text: \"Back to List\",\n * onBack: () => navigate('/list')\n * }}\n * identifier=\"detail-view\"\n * >\n * Detail content\n * </RightDrawer>\n * ```\n */\n backButton?: BackButtonProps;\n\n /**\n * External control for the open state. When provided, overrides internal store state\n * @example\n * ```tsx\n * const [isOpen, setIsOpen] = useState(false);\n *\n * <RightDrawer\n * isOpen={isOpen}\n * onClose={() => setIsOpen(false)}\n * identifier=\"controlled\"\n * >\n * Controlled drawer content\n * </RightDrawer>\n * ```\n */\n isOpen?: boolean;\n\n /**\n * Callback function triggered when the drawer is closed\n * @example\n * ```tsx\n * <RightDrawer\n * onClose={() => console.log('Drawer closed')}\n * identifier=\"tracked\"\n * >\n * Content with close tracking\n * </RightDrawer>\n * ```\n */\n onClose?: () => void;\n};\n\n/**\n * RightDrawer - A slide-out drawer panel that appears from the right side of the screen\n *\n * A versatile drawer component that provides an overlay panel for displaying secondary content,\n * forms, details, or navigation. Features responsive design that adapts to mobile devices,\n * configurable close behavior, and integrated state management through Zustand store.\n *\n * ## Key Features\n * - **Responsive Design**: Full-width on mobile, fixed 400px width on desktop\n * - **State Management**: Built-in Zustand store for managing multiple drawer instances\n * - **Accessibility**: Proper ARIA attributes, keyboard navigation, and focus management\n * - **Flexible Layout**: Customizable header, title, and content areas\n * - **Click Outside**: Configurable outside click detection for auto-closing\n * - **Scroll Management**: Automatic body scroll blocking when open\n *\n * ## Use Cases\n * - Navigation menus and sidebars\n * - Detail panels and forms\n * - Settings and configuration interfaces\n * - Shopping carts and checkout processes\n * - User profiles and account management\n * - Multi-step workflows and wizards\n *\n * ## Accessibility\n * - **Focus Management**: Traps focus within the drawer when open\n * - **Keyboard Navigation**: Escape key closes the drawer\n * - **Screen Reader Support**: Proper ARIA labels and announcements\n * - **Touch Support**: Mobile-optimized touch interactions\n *\n * ## State Management\n * The component uses a Zustand store (`useRightDrawerStore`) to manage drawer state:\n * - Multiple drawers can be managed simultaneously using unique identifiers\n * - External components can open/close drawers using the store\n * - Supports both controlled (via props) and uncontrolled (via store) patterns\n *\n * @example\n * Basic usage with store management:\n * ```tsx\n * // Opening the drawer from another component\n * const { open } = useRightDrawerStore();\n *\n * <button onClick={() => open('user-menu')}>\n * Open Menu\n * </button>\n *\n * <RightDrawer identifier=\"user-menu\" title=\"User Menu\">\n * <nav>Navigation items here</nav>\n * </RightDrawer>\n * ```\n *\n * @example\n * Controlled drawer with external state:\n * ```tsx\n * const [showDrawer, setShowDrawer] = useState(false);\n *\n * <RightDrawer\n * identifier=\"controlled-drawer\"\n * title=\"Settings\"\n * isOpen={showDrawer}\n * onClose={() => setShowDrawer(false)}\n * closeOnOutsideClick={false}\n * >\n * <SettingsForm onSave={() => setShowDrawer(false)} />\n * </RightDrawer>\n * ```\n *\n * @example\n * Complex drawer with back button and header:\n * ```tsx\n * <RightDrawer\n * identifier=\"product-detail\"\n * title=\"Product Details\"\n * header={\n * <div className=\"text-sm text-gray-600\">\n * SKU: {product.sku} | Stock: {product.stock}\n * </div>\n * }\n * backButton={{\n * text: \"Back to Catalog\",\n * onBack: () => navigate('/catalog')\n * }}\n * >\n * <ProductDetailView product={product} />\n * </RightDrawer>\n * ```\n */\nexport const RightDrawer: FC<RightDrawerProps> = ({\n title,\n identifier,\n children,\n header,\n closeOnOutsideClick = true,\n backButton,\n isOpen: isOpenProp,\n onClose,\n}) => {\n const { isMobile } = useDevice('md');\n const panelRef = useRef<HTMLDivElement>(null);\n const childrenContainerRef = useRef<HTMLDivElement>(null);\n const openDrawer = useRightDrawerStore((s) => s.open);\n const closeDrawer = useRightDrawerStore((s) => s.close);\n const storeIsOpen = useRightDrawerStore((s) => s.isOpen(identifier));\n const isOpen = useRightDrawerStore((s) => s.isOpen(identifier));\n\n useScrollBlockage({\n disableScroll: isOpen,\n key: identifier ? `right_drawer_${identifier}` : 'right_drawer',\n });\n\n useEffect(() => {\n const handleClickOutside = (event: MouseEvent) => {\n try {\n if (!panelRef.current) return;\n\n // Check if drawer is open and click outside is enabled\n const isClickAble = isOpen && closeOnOutsideClick;\n\n // Check if click is outside the drawer panel\n const isClickOutside =\n event.target && !panelRef.current.contains(event.target as Node);\n\n // Check if event propagation has been stopped\n const isAtTopAndVisible = isElementAtTopAndNotCovered(panelRef.current);\n\n if (\n (isClickAble && isClickOutside && isAtTopAndVisible) ||\n !event.target\n ) {\n closeDrawer(identifier);\n onClose?.();\n }\n } catch (_e) {\n closeDrawer(identifier);\n onClose?.();\n }\n };\n\n window.addEventListener('mousedown', handleClickOutside);\n return () => window.removeEventListener('mousedown', handleClickOutside);\n }, [isOpen, closeDrawer, onClose, closeOnOutsideClick, identifier]); // Make sure the effect runs only if isOpen or close changes\n\n const onCloseRef = useRef(onClose);\n useEffect(() => {\n onCloseRef.current = onClose;\n }, [onClose]);\n\n useEffect(() => {\n if (isOpenProp === undefined) return;\n\n // prevent redundant set → re-render → effect loop\n if (isOpenProp === storeIsOpen) return;\n\n if (isOpenProp) {\n openDrawer(identifier);\n } else {\n closeDrawer(identifier);\n onCloseRef.current?.();\n }\n }, [isOpenProp, storeIsOpen, identifier, openDrawer, closeDrawer]);\n\n const handleSpareSpaceClick: MouseEventHandler<HTMLDivElement> = (e) => {\n // Check if the click trigger the background\n if (e.target !== e.currentTarget) {\n return;\n }\n\n if (isMobile) {\n closeDrawer(identifier);\n onClose?.();\n }\n };\n\n return (\n <div className=\"fixed top-0 right-0 z-50 flex h-full justify-end\">\n <MaxWidthSmoother isHidden={!isOpen} align=\"right\">\n <Container\n className=\"relative flex h-screen w-screen flex-col text-text md:w-[400px]\"\n ref={panelRef}\n roundedSize=\"none\"\n >\n <div className=\"flex flex-col gap-3 p-6\">\n <div className=\"flex justify-between gap-3\">\n <div>\n {backButton && (\n <Button\n variant={ButtonVariant.HOVERABLE}\n color={ButtonColor.TEXT}\n label={backButton.text ?? 'Go back'}\n onClick={backButton.onBack}\n Icon={ChevronLeft}\n >\n {backButton?.text}\n </Button>\n )}\n </div>\n <div>\n <Button\n variant={ButtonVariant.HOVERABLE}\n color={ButtonColor.TEXT}\n label=\"Close\"\n className=\"ml-auto\"\n onClick={() => {\n closeDrawer(identifier);\n onClose?.();\n }}\n Icon={X}\n size={ButtonSize.ICON_MD}\n />\n </div>\n </div>\n {title && (\n <h2 className=\"flex items-center justify-center font-bold text-lg\">\n {title}\n </h2>\n )}\n {header}\n </div>\n\n <div className=\"flex h-full flex-col overflow-y-auto p-2\">\n <div\n className=\"flex flex-1 flex-col\"\n onClick={handleSpareSpaceClick}\n ref={childrenContainerRef}\n role=\"region\"\n >\n {children}\n </div>\n </div>\n </Container>\n </MaxWidthSmoother>\n </div>\n );\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+NA,MAAaA,eAAqC,EAChD,OACA,YACA,UACA,QACA,sBAAsB,MACtB,YACA,QAAQ,YACR,cACI;CACJ,MAAM,EAAE,aAAa,UAAU,KAAK;CACpC,MAAM,WAAW,OAAuB,KAAK;CAC7C,MAAM,uBAAuB,OAAuB,KAAK;CACzD,MAAM,aAAa,qBAAqB,MAAM,EAAE,KAAK;CACrD,MAAM,cAAc,qBAAqB,MAAM,EAAE,MAAM;CACvD,MAAM,cAAc,qBAAqB,MAAM,EAAE,OAAO,WAAW,CAAC;CACpE,MAAM,SAAS,qBAAqB,MAAM,EAAE,OAAO,WAAW,CAAC;AAE/D,mBAAkB;EAChB,eAAe;EACf,KAAK,aAAa,gBAAgB,eAAe;EAClD,CAAC;AAEF,iBAAgB;EACd,MAAM,sBAAsB,UAAsB;AAChD,OAAI;AACF,QAAI,CAAC,SAAS,QAAS;IAGvB,MAAM,cAAc,UAAU;IAG9B,MAAM,iBACJ,MAAM,UAAU,CAAC,SAAS,QAAQ,SAAS,MAAM,OAAe;IAGlE,MAAM,oBAAoB,4BAA4B,SAAS,QAAQ;AAEvE,QACG,eAAe,kBAAkB,qBAClC,CAAC,MAAM,QACP;AACA,iBAAY,WAAW;AACvB,gBAAW;;YAEN,IAAI;AACX,gBAAY,WAAW;AACvB,eAAW;;;AAIf,SAAO,iBAAiB,aAAa,mBAAmB;AACxD,eAAa,OAAO,oBAAoB,aAAa,mBAAmB;IACvE;EAAC;EAAQ;EAAa;EAAS;EAAqB;EAAW,CAAC;CAEnE,MAAM,aAAa,OAAO,QAAQ;AAClC,iBAAgB;AACd,aAAW,UAAU;IACpB,CAAC,QAAQ,CAAC;AAEb,iBAAgB;AACd,MAAI,eAAe,OAAW;AAG9B,MAAI,eAAe,YAAa;AAEhC,MAAI,WACF,YAAW,WAAW;OACjB;AACL,eAAY,WAAW;AACvB,cAAW,WAAW;;IAEvB;EAAC;EAAY;EAAa;EAAY;EAAY;EAAY,CAAC;CAElE,MAAMC,yBAA4D,MAAM;AAEtE,MAAI,EAAE,WAAW,EAAE,cACjB;AAGF,MAAI,UAAU;AACZ,eAAY,WAAW;AACvB,cAAW;;;AAIf,QACE,oBAAC;EAAI,WAAU;YACb,oBAAC;GAAiB,UAAU,CAAC;GAAQ,OAAM;aACzC,qBAAC;IACC,WAAU;IACV,KAAK;IACL,aAAY;eAEZ,qBAAC;KAAI,WAAU;;MACb,qBAAC;OAAI,WAAU;kBACb,oBAAC,mBACE,cACC,oBAAC;QACC,SAAS,cAAc;QACvB,OAAO,YAAY;QACnB,OAAO,WAAW,QAAQ;QAC1B,SAAS,WAAW;QACpB,MAAM;kBAEL,YAAY;SACN,GAEP,EACN,oBAAC,mBACC,oBAAC;QACC,SAAS,cAAc;QACvB,OAAO,YAAY;QACnB,OAAM;QACN,WAAU;QACV,eAAe;AACb,qBAAY,WAAW;AACvB,oBAAW;;QAEb,MAAM;QACN,MAAM,WAAW;SACjB,GACE;QACF;MACL,SACC,oBAAC;OAAG,WAAU;iBACX;QACE;MAEN;;MACG,EAEN,oBAAC;KAAI,WAAU;eACb,oBAAC;MACC,WAAU;MACV,SAAS;MACT,KAAK;MACL,MAAK;MAEJ;OACG;MACF;KACI;IACK;GACf"}
|
|
1
|
+
{"version":3,"file":"RightDrawer.mjs","names":["RightDrawer: FC<RightDrawerProps>","handleSpareSpaceClick: MouseEventHandler<HTMLDivElement>","handleSpareSpaceKeyDown: KeyboardEventHandler<HTMLDivElement>"],"sources":["../../../../src/components/RightDrawer/RightDrawer.tsx"],"sourcesContent":["'use client';\n\nimport { ChevronLeft, X } from 'lucide-react';\nimport {\n type FC,\n type KeyboardEventHandler,\n type MouseEventHandler,\n type ReactNode,\n useEffect,\n useRef,\n} from 'react';\nimport { useIntlayer } from 'react-intlayer';\nimport { useDevice } from '../../hooks/useDevice';\nimport { useScrollBlockage } from '../../hooks/useScrollBlockage';\nimport { Button, ButtonColor, ButtonSize, ButtonVariant } from '../Button';\nimport { Container } from '../Container';\nimport { KeyboardShortcut } from '../KeyboardShortcut';\nimport { MaxWidthSmoother } from '../MaxWidthSmoother/index';\nimport { Popover } from '../Popover';\nimport { isElementAtTopAndNotCovered } from './isElementAtTopAndNotCovered';\nimport { useRightDrawerStore } from './useRightDrawerStore';\n\n/**\n * Configuration for the back button functionality in the RightDrawer\n *\n * @interface BackButtonProps\n */\ntype BackButtonProps = {\n /** Callback function triggered when the back button is clicked */\n onBack: () => void;\n /** Optional custom text for the back buttoDefaults to \"Go back\" if not provided */\n text?: string;\n};\n\n/**\n * Props configuration for the RightDrawer component\n *\n * @interface RightDrawerProps\n */\ntype RightDrawerProps = {\n /**\n * Title displayed in the drawer header\n */\n title?: ReactNode;\n\n /**\n * Unique identifier for the drawer instancRequired for store management\n */\n identifier: string;\n\n /** The content to be displayed inside the drawer */\n children?: ReactNode;\n\n /**\n * Optional header content displayed below the title\n */\n header?: ReactNode;\n\n /**\n * Optional footer content pinned to the bottom of the drawer\n */\n footer?: ReactNode;\n\n /**\n * Whether the drawer should close when clicking outside of it\n * @default true\n */\n closeOnOutsideClick?: boolean;\n\n /**\n * Configuration for an optional back button in the drawer header\n */\n backButton?: BackButtonProps;\n\n /**\n * External control for the open statWhen provided, overrides internal store state\n */\n isOpen?: boolean;\n\n /**\n * Callback function triggered when the drawer is closed\n */\n onClose?: () => void;\n};\n\nexport const RightDrawer: FC<RightDrawerProps> = ({\n title,\n identifier,\n children,\n header,\n footer,\n closeOnOutsideClick = true,\n backButton,\n isOpen: isOpenProp,\n onClose,\n}) => {\n const content = useIntlayer('right-drawer');\n const { isMobile } = useDevice('md');\n const panelRef = useRef<HTMLDivElement>(null);\n const childrenContainerRef = useRef<HTMLDivElement>(null);\n const openDrawer = useRightDrawerStore((s) => s.open);\n const closeDrawer = useRightDrawerStore((s) => s.close);\n const storeIsOpen = useRightDrawerStore((s) => s.isOpen(identifier));\n const isOpen = useRightDrawerStore((s) => s.isOpen(identifier));\n\n useScrollBlockage({\n disableScroll: isOpen,\n key: identifier ? `right_drawer_${identifier}` : 'right_drawer',\n });\n\n // Handle Click Outside\n useEffect(() => {\n const handleClickOutside = (event: MouseEvent) => {\n try {\n if (!panelRef.current) return;\n\n const isClickAble = isOpen && closeOnOutsideClick;\n const isClickOutside =\n event.target && !panelRef.current.contains(event.target as Node);\n const isAtTopAndVisible = isElementAtTopAndNotCovered(panelRef.current);\n\n if (\n (isClickAble && isClickOutside && isAtTopAndVisible) ||\n !event.target\n ) {\n closeDrawer(identifier);\n onClose?.();\n }\n } catch (_e) {\n closeDrawer(identifier);\n onClose?.();\n }\n };\n\n window.addEventListener('mousedown', handleClickOutside);\n return () => window.removeEventListener('mousedown', handleClickOutside);\n }, [isOpen, closeDrawer, onClose, closeOnOutsideClick, identifier]);\n\n const onCloseRef = useRef(onClose);\n useEffect(() => {\n onCloseRef.current = onClose;\n }, [onClose]);\n\n useEffect(() => {\n if (isOpenProp === undefined) return;\n if (isOpenProp === storeIsOpen) return;\n\n if (isOpenProp) {\n openDrawer(identifier);\n } else {\n closeDrawer(identifier);\n onCloseRef.current?.();\n }\n }, [isOpenProp, storeIsOpen, identifier, openDrawer, closeDrawer]);\n\n const handleSpareSpaceClick: MouseEventHandler<HTMLDivElement> = (e) => {\n if (e.target !== e.currentTarget) {\n return;\n }\n if (isMobile) {\n closeDrawer(identifier);\n onClose?.();\n }\n };\n\n // Handle Keyboard on Spare Space (Linter Fix)\n const handleSpareSpaceKeyDown: KeyboardEventHandler<HTMLDivElement> = (e) => {\n if (e.target !== e.currentTarget) return;\n\n // Allow closing via Enter or Space if focused on the spare area\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n if (isMobile) {\n closeDrawer(identifier);\n onClose?.();\n }\n }\n };\n\n return (\n <div className=\"fixed top-0 right-0 z-50 flex h-full justify-end\">\n <MaxWidthSmoother isHidden={!isOpen} align=\"right\">\n <Container\n className=\"relative flex h-screen w-screen flex-col text-text md:w-[400px]\"\n ref={panelRef}\n roundedSize=\"none\"\n >\n {/* Header */}\n <div className=\"flex shrink-0 flex-col gap-3 px-6 pt-6\">\n <div className=\"flex justify-between gap-3\">\n <div>\n {backButton && (\n <Button\n variant={ButtonVariant.HOVERABLE}\n color={ButtonColor.TEXT}\n label={backButton.text ?? content.goBack.value}\n onClick={backButton.onBack}\n Icon={ChevronLeft}\n >\n {backButton?.text}\n </Button>\n )}\n </div>\n <div>\n <Popover identifier=\"close-drawer\">\n <Button\n variant={ButtonVariant.HOVERABLE}\n color={ButtonColor.TEXT}\n label=\"Close\"\n className=\"ml-auto\"\n onClick={() => {\n closeDrawer(identifier);\n onClose?.();\n }}\n Icon={X}\n size={ButtonSize.ICON_MD}\n />\n\n <Popover.Detail identifier=\"close-drawer\">\n <div className=\"flex items-center gap-2 p-2\">\n <span className=\"whitespace-nowrap text-neutral text-xs\">\n {content.closeDrawer}\n </span>\n <KeyboardShortcut\n shortcut=\"Escape\"\n size=\"sm\"\n onTriggered={() => {\n closeDrawer(identifier);\n onClose?.();\n }}\n />\n </div>\n </Popover.Detail>\n </Popover>\n </div>\n </div>\n {title && (\n <h2 className=\"flex items-center justify-center font-bold text-lg\">\n {title}\n </h2>\n )}\n {header}\n </div>\n\n {/* Body */}\n <div className=\"flex min-h-0 flex-1 flex-col overflow-y-auto p-2\">\n {/** biome-ignore lint/a11y/useSemanticElements: This div is used to handle the spare space click and keydown events */}\n <div\n className=\"flex flex-1 flex-col outline-none\"\n onClick={handleSpareSpaceClick}\n onKeyDown={handleSpareSpaceKeyDown}\n ref={childrenContainerRef}\n role=\"button\" // Semantically acts as a button area\n tabIndex={0} // Makes it focusable to receive key events\n >\n {children}\n </div>\n </div>\n\n {/* Footer */}\n {footer && <div className=\"shrink-0\">{footer}</div>}\n </Container>\n </MaxWidthSmoother>\n </div>\n );\n};\n"],"mappings":"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"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { t } from "intlayer";
|
|
2
|
+
|
|
3
|
+
//#region src/components/RightDrawer/rightDrawer.content.ts
|
|
4
|
+
const rightDrawerContent = {
|
|
5
|
+
key: "right-drawer",
|
|
6
|
+
content: {
|
|
7
|
+
goBack: t({
|
|
8
|
+
en: "Go back",
|
|
9
|
+
"en-GB": "Go back",
|
|
10
|
+
ru: "Назад",
|
|
11
|
+
ja: "戻る",
|
|
12
|
+
fr: "Retour",
|
|
13
|
+
ko: "뒤로",
|
|
14
|
+
zh: "返回",
|
|
15
|
+
es: "Volver",
|
|
16
|
+
de: "Zurück",
|
|
17
|
+
ar: "رجوع",
|
|
18
|
+
it: "Indietro",
|
|
19
|
+
pt: "Voltar",
|
|
20
|
+
hi: "वापस जाएं",
|
|
21
|
+
tr: "Geri dön",
|
|
22
|
+
pl: "Wstecz",
|
|
23
|
+
id: "Kembali",
|
|
24
|
+
vi: "Quay lại"
|
|
25
|
+
}),
|
|
26
|
+
closeDrawer: t({
|
|
27
|
+
en: "Close Drawer",
|
|
28
|
+
"en-GB": "Close Drawer",
|
|
29
|
+
ru: "Закрыть панель",
|
|
30
|
+
ja: "引き出しを閉じる",
|
|
31
|
+
fr: "Fermer le tiroir",
|
|
32
|
+
ko: "서랍 닫기",
|
|
33
|
+
zh: "关闭抽屉",
|
|
34
|
+
es: "Cerrar cajón",
|
|
35
|
+
de: "Schublade schließen",
|
|
36
|
+
ar: "إغلاق الدرج",
|
|
37
|
+
it: "Chiudi cassetto",
|
|
38
|
+
pt: "Fechar gaveta",
|
|
39
|
+
hi: "दराज बंद करें",
|
|
40
|
+
tr: "Çekmeceyi kapat",
|
|
41
|
+
pl: "Zamknij szufladę",
|
|
42
|
+
id: "Tutup laci",
|
|
43
|
+
vi: "Đóng ngăn kéo"
|
|
44
|
+
})
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
var rightDrawer_content_default = rightDrawerContent;
|
|
48
|
+
|
|
49
|
+
//#endregion
|
|
50
|
+
export { rightDrawer_content_default as default };
|
|
51
|
+
//# sourceMappingURL=rightDrawer.content.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rightDrawer.content.mjs","names":[],"sources":["../../../../src/components/RightDrawer/rightDrawer.content.ts"],"sourcesContent":["import { type Dictionary, t } from 'intlayer';\n\nconst rightDrawerContent = {\n key: 'right-drawer',\n content: {\n goBack: t({\n en: 'Go back',\n 'en-GB': 'Go back',\n ru: 'Назад',\n ja: '戻る',\n fr: 'Retour',\n ko: '뒤로',\n zh: '返回',\n es: 'Volver',\n de: 'Zurück',\n ar: 'رجوع',\n it: 'Indietro',\n pt: 'Voltar',\n hi: 'वापस जाएं',\n tr: 'Geri dön',\n pl: 'Wstecz',\n id: 'Kembali',\n vi: 'Quay lại',\n }),\n closeDrawer: t({\n en: 'Close Drawer',\n 'en-GB': 'Close Drawer',\n ru: 'Закрыть панель',\n ja: '引き出しを閉じる',\n fr: 'Fermer le tiroir',\n ko: '서랍 닫기',\n zh: '关闭抽屉',\n es: 'Cerrar cajón',\n de: 'Schublade schließen',\n ar: 'إغلاق الدرج',\n it: 'Chiudi cassetto',\n pt: 'Fechar gaveta',\n hi: 'दराज बंद करें',\n tr: 'Çekmeceyi kapat',\n pl: 'Zamknij szufladę',\n id: 'Tutup laci',\n vi: 'Đóng ngăn kéo',\n }),\n },\n} satisfies Dictionary;\n\nexport default rightDrawerContent;\n"],"mappings":";;;AAEA,MAAM,qBAAqB;CACzB,KAAK;CACL,SAAS;EACP,QAAQ,EAAE;GACR,IAAI;GACJ,SAAS;GACT,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACL,CAAC;EACF,aAAa,EAAE;GACb,IAAI;GACJ,SAAS;GACT,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACL,CAAC;EACH;CACF;AAED,kCAAe"}
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
import { cn } from "../../utils/cn.mjs";
|
|
4
4
|
import { Button } from "../Button/Button.mjs";
|
|
5
|
-
import { Modal, ModalSize } from "../Modal/Modal.mjs";
|
|
6
5
|
import { ExpandCollapse } from "../ExpandCollapse/ExpandCollapse.mjs";
|
|
6
|
+
import { Modal, ModalSize } from "../Modal/Modal.mjs";
|
|
7
7
|
import { MoveDiagonal } from "lucide-react";
|
|
8
8
|
import { useState } from "react";
|
|
9
9
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|