@intlayer/design-system 8.11.3 → 8.12.0-canary.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/api/hooks/project.mjs +110 -1
- package/dist/esm/api/hooks/project.mjs.map +1 -1
- package/dist/esm/api/index.mjs +2 -2
- package/dist/esm/api/useAuth/useOAuth2.mjs +1 -1
- package/dist/esm/api/useIntlayerAPI.mjs +1 -1
- package/dist/esm/components/Accordion/Accordion.mjs.map +1 -1
- package/dist/esm/components/Badge/index.mjs +18 -55
- package/dist/esm/components/Badge/index.mjs.map +1 -1
- package/dist/esm/components/Breadcrumb/index.mjs +12 -12
- package/dist/esm/components/Breadcrumb/index.mjs.map +1 -1
- package/dist/esm/components/Browser/Browser.mjs +1 -1
- package/dist/esm/components/Browser/Browser.mjs.map +1 -1
- package/dist/esm/components/Button/Button.mjs +60 -117
- package/dist/esm/components/Button/Button.mjs.map +1 -1
- package/dist/esm/components/Button/index.mjs +2 -2
- package/dist/esm/components/Carousel/index.mjs +3 -3
- package/dist/esm/components/Carousel/index.mjs.map +1 -1
- package/dist/esm/components/Container/index.mjs +1 -71
- package/dist/esm/components/Container/index.mjs.map +1 -1
- package/dist/esm/components/ContentEditor/ContentEditor.mjs +0 -1
- package/dist/esm/components/ContentEditor/ContentEditor.mjs.map +1 -1
- package/dist/esm/components/ContentEditor/ContentEditorInput.mjs +2 -2
- package/dist/esm/components/ContentEditor/ContentEditorInput.mjs.map +1 -1
- package/dist/esm/components/ContentEditor/ContentEditorTextArea.mjs +2 -2
- package/dist/esm/components/ContentEditor/ContentEditorTextArea.mjs.map +1 -1
- package/dist/esm/components/ContentEditor/index.mjs +1 -1
- package/dist/esm/components/CopyButton/index.mjs +4 -4
- package/dist/esm/components/CopyButton/index.mjs.map +1 -1
- package/dist/esm/components/DictionaryFieldEditor/ContentEditorView/TextEditor.mjs +6 -7
- package/dist/esm/components/DictionaryFieldEditor/ContentEditorView/TextEditor.mjs.map +1 -1
- package/dist/esm/components/DictionaryFieldEditor/DictionaryCreationForm/DictionaryCreationForm.mjs +0 -1
- package/dist/esm/components/DictionaryFieldEditor/DictionaryCreationForm/DictionaryCreationForm.mjs.map +1 -1
- package/dist/esm/components/DictionaryFieldEditor/DictionaryDetails/DictionaryDetailsForm.mjs +3 -4
- package/dist/esm/components/DictionaryFieldEditor/DictionaryDetails/DictionaryDetailsForm.mjs.map +1 -1
- package/dist/esm/components/DictionaryFieldEditor/DictionaryFieldEditor.mjs +3 -3
- package/dist/esm/components/DictionaryFieldEditor/DictionaryFieldEditor.mjs.map +1 -1
- package/dist/esm/components/DictionaryFieldEditor/NavigationView/NavigationViewNode.mjs +3 -3
- package/dist/esm/components/DictionaryFieldEditor/NavigationView/NavigationViewNode.mjs.map +1 -1
- package/dist/esm/components/DictionaryFieldEditor/SaveForm/SaveForm.mjs +2 -3
- package/dist/esm/components/DictionaryFieldEditor/SaveForm/SaveForm.mjs.map +1 -1
- package/dist/esm/components/DictionaryFieldEditor/StructureView/StructureView.mjs +2 -3
- package/dist/esm/components/DictionaryFieldEditor/StructureView/StructureView.mjs.map +1 -1
- package/dist/esm/components/DictionaryFieldEditor/VersionSwitcherDropDown/VersionSwitcher.mjs +1 -1
- package/dist/esm/components/DictionaryFieldEditor/VersionSwitcherDropDown/VersionSwitcher.mjs.map +1 -1
- package/dist/esm/components/DropDown/index.mjs +3 -23
- package/dist/esm/components/DropDown/index.mjs.map +1 -1
- package/dist/esm/components/EditableField/EditableFieldLayout.mjs +1 -1
- package/dist/esm/components/EditableField/EditableFieldLayout.mjs.map +1 -1
- package/dist/esm/components/EditableField/EditableFieldTextArea.mjs +1 -1
- package/dist/esm/components/IDE/CopyCode.mjs +0 -1
- package/dist/esm/components/IDE/CopyCode.mjs.map +1 -1
- package/dist/esm/components/Input/Checkbox.mjs +2 -22
- package/dist/esm/components/Input/Checkbox.mjs.map +1 -1
- package/dist/esm/components/Input/Input.mjs +1 -11
- package/dist/esm/components/Input/Input.mjs.map +1 -1
- package/dist/esm/components/Input/Radio.mjs +82 -0
- package/dist/esm/components/Input/Radio.mjs.map +1 -0
- package/dist/esm/components/Input/index.mjs +4 -3
- package/dist/esm/components/KeyboardShortcut/KeyboardShortcut.mjs +1 -52
- package/dist/esm/components/KeyboardShortcut/KeyboardShortcut.mjs.map +1 -1
- package/dist/esm/components/KeyboardShortcut/index.mjs +2 -2
- package/dist/esm/components/Link/Link.mjs +33 -85
- 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 +2 -2
- package/dist/esm/components/LocaleSwitcherContentDropDown/LocaleSwitcherContent.mjs.map +1 -1
- package/dist/esm/components/LocaleSwitcherDropDown/LocaleSwitcher.mjs +1 -1
- package/dist/esm/components/LocaleSwitcherDropDown/LocaleSwitcher.mjs.map +1 -1
- package/dist/esm/components/MarkDownRender/MarkDownIframe.mjs +3 -3
- package/dist/esm/components/MarkDownRender/MarkDownIframe.mjs.map +1 -1
- package/dist/esm/components/Modal/Modal.mjs +3 -14
- package/dist/esm/components/Modal/Modal.mjs.map +1 -1
- package/dist/esm/components/Modal/index.mjs +2 -2
- package/dist/esm/components/Navbar/DesktopNavbar.mjs +1 -1
- package/dist/esm/components/Navbar/DesktopNavbar.mjs.map +1 -1
- package/dist/esm/components/Pagination/Pagination.mjs +2 -14
- package/dist/esm/components/Pagination/Pagination.mjs.map +1 -1
- package/dist/esm/components/Pagination/index.mjs +2 -2
- package/dist/esm/components/Pattern/DotPattern.mjs +1 -1
- package/dist/esm/components/Pattern/DotPattern.mjs.map +1 -1
- package/dist/esm/components/Popover/dynamic.mjs +4 -4
- package/dist/esm/components/Popover/dynamic.mjs.map +1 -1
- package/dist/esm/components/Popover/index.mjs +2 -2
- package/dist/esm/components/Popover/static.mjs +6 -28
- package/dist/esm/components/Popover/static.mjs.map +1 -1
- package/dist/esm/components/RightDrawer/RightDrawer.mjs +1 -1
- package/dist/esm/components/RightDrawer/RightDrawer.mjs.map +1 -1
- package/dist/esm/components/Select/Multiselect.mjs +4 -4
- package/dist/esm/components/Select/Multiselect.mjs.map +1 -1
- package/dist/esm/components/Select/Select.mjs +3 -15
- package/dist/esm/components/Select/Select.mjs.map +1 -1
- package/dist/esm/components/Select/index.mjs +2 -2
- package/dist/esm/components/Steps/index.mjs +37 -27
- package/dist/esm/components/Steps/index.mjs.map +1 -1
- package/dist/esm/components/Steps/steps.content.mjs +55 -0
- package/dist/esm/components/Steps/steps.content.mjs.map +1 -0
- package/dist/esm/components/SwitchSelector/SwitchSelector.mjs +19 -35
- package/dist/esm/components/SwitchSelector/SwitchSelector.mjs.map +1 -1
- package/dist/esm/components/SwitchSelector/VerticalSwitchSelector.mjs +20 -20
- package/dist/esm/components/SwitchSelector/VerticalSwitchSelector.mjs.map +1 -1
- package/dist/esm/components/SwitchSelector/index.mjs +2 -2
- package/dist/esm/components/Tab/Tab.mjs +2 -2
- package/dist/esm/components/Tab/Tab.mjs.map +1 -1
- package/dist/esm/components/TabSelector/TabSelector.mjs +1 -11
- package/dist/esm/components/TabSelector/TabSelector.mjs.map +1 -1
- package/dist/esm/components/TabSelector/index.mjs +2 -2
- package/dist/esm/components/Table/ExpandButton.mjs +0 -1
- package/dist/esm/components/Table/ExpandButton.mjs.map +1 -1
- package/dist/esm/components/Table/SmartTable.mjs +1 -1
- package/dist/esm/components/Table/SmartTable.mjs.map +1 -1
- package/dist/esm/components/Tag/index.mjs +51 -205
- package/dist/esm/components/Tag/index.mjs.map +1 -1
- package/dist/esm/components/TechLogo/TechLogo.mjs +36 -37
- package/dist/esm/components/TechLogo/TechLogo.mjs.map +1 -1
- package/dist/esm/components/TechLogo/index.mjs +1 -2
- package/dist/esm/components/TechLogo/types.mjs +0 -44
- package/dist/esm/components/TextArea/AutoSizeTextArea.mjs +1 -1
- package/dist/esm/components/TextArea/AutoSizeTextArea.mjs.map +1 -1
- package/dist/esm/components/TextArea/ContentEditableTextArea.mjs.map +1 -1
- package/dist/esm/components/TextArea/TextArea.mjs +2 -2
- package/dist/esm/components/TextArea/TextArea.mjs.map +1 -1
- package/dist/esm/components/TextArea/index.mjs +2 -2
- package/dist/esm/components/ThemeSwitcherDropDown/DesktopThemeSwitcher.mjs +1 -2
- package/dist/esm/components/ThemeSwitcherDropDown/DesktopThemeSwitcher.mjs.map +1 -1
- package/dist/esm/components/ThemeSwitcherDropDown/MobileThemeSwitcher.mjs +0 -1
- package/dist/esm/components/ThemeSwitcherDropDown/MobileThemeSwitcher.mjs.map +1 -1
- package/dist/esm/components/ThemeSwitcherDropDown/index.mjs +1 -2
- package/dist/esm/components/ThemeSwitcherDropDown/types.mjs +0 -11
- package/dist/esm/components/index.mjs +24 -23
- package/dist/types/api/hooks/project.d.ts +8 -1
- package/dist/types/api/hooks/project.d.ts.map +1 -1
- package/dist/types/api/index.d.ts +2 -2
- package/dist/types/api/useIntlayerAPI.d.ts +10 -3
- package/dist/types/api/useIntlayerAPI.d.ts.map +1 -1
- package/dist/types/components/Accordion/Accordion.d.ts.map +1 -1
- package/dist/types/components/Badge/index.d.ts +6 -25
- package/dist/types/components/Badge/index.d.ts.map +1 -1
- package/dist/types/components/Breadcrumb/index.d.ts +1 -1
- package/dist/types/components/Browser/Browser.d.ts +1 -1
- package/dist/types/components/Browser/Browser.d.ts.map +1 -1
- package/dist/types/components/Button/Button.d.ts +9 -45
- package/dist/types/components/Button/Button.d.ts.map +1 -1
- package/dist/types/components/Carousel/index.d.ts.map +1 -1
- package/dist/types/components/CollapsibleTable/CollapsibleTable.d.ts +2 -2
- package/dist/types/components/Command/index.d.ts +3 -3
- package/dist/types/components/Command/index.d.ts.map +1 -1
- package/dist/types/components/Container/index.d.ts +11 -60
- package/dist/types/components/Container/index.d.ts.map +1 -1
- package/dist/types/components/ContentEditor/ContentEditor.d.ts.map +1 -1
- package/dist/types/components/CopyButton/index.d.ts +3 -3
- package/dist/types/components/CopyButton/index.d.ts.map +1 -1
- package/dist/types/components/DictionaryFieldEditor/ContentEditorView/SafeHtmlRenderer.d.ts +1 -1
- package/dist/types/components/DictionaryFieldEditor/ContentEditorView/SafeHtmlRenderer.d.ts.map +1 -1
- package/dist/types/components/DictionaryFieldEditor/ContentEditorView/TextEditor.d.ts.map +1 -1
- package/dist/types/components/DictionaryFieldEditor/DictionaryCreationForm/DictionaryCreationForm.d.ts.map +1 -1
- package/dist/types/components/DictionaryFieldEditor/NavigationView/NavigationViewNode.d.ts.map +1 -1
- package/dist/types/components/DictionaryFieldEditor/SaveForm/SaveForm.d.ts.map +1 -1
- package/dist/types/components/DictionaryFieldEditor/StructureView/StructureView.d.ts.map +1 -1
- package/dist/types/components/DictionaryFieldEditor/VersionSwitcherDropDown/VersionSwitcher.d.ts.map +1 -1
- package/dist/types/components/DropDown/index.d.ts +4 -14
- package/dist/types/components/DropDown/index.d.ts.map +1 -1
- package/dist/types/components/Form/FormBase.d.ts +1 -1
- package/dist/types/components/Form/FormBase.d.ts.map +1 -1
- package/dist/types/components/Form/FormField.d.ts +1 -1
- package/dist/types/components/Form/FormField.d.ts.map +1 -1
- package/dist/types/components/Form/elements/EditableFieldInputElement.d.ts +1 -1
- package/dist/types/components/Form/elements/EditableFieldInputElement.d.ts.map +1 -1
- package/dist/types/components/Form/elements/EditableFieldTextAreaElement.d.ts +1 -1
- package/dist/types/components/Form/elements/EditableFieldTextAreaElement.d.ts.map +1 -1
- package/dist/types/components/Form/elements/FormElement.d.ts +1 -1
- package/dist/types/components/Form/elements/FormElement.d.ts.map +1 -1
- package/dist/types/components/Form/elements/MultiselectElement.d.ts +1 -1
- package/dist/types/components/Form/elements/MultiselectElement.d.ts.map +1 -1
- package/dist/types/components/Form/elements/OTPElement.d.ts +1 -1
- package/dist/types/components/Form/elements/OTPElement.d.ts.map +1 -1
- package/dist/types/components/Form/elements/SelectElement.d.ts +1 -1
- package/dist/types/components/Form/elements/SelectElement.d.ts.map +1 -1
- package/dist/types/components/Form/elements/SwitchSelectorElement.d.ts +1 -1
- package/dist/types/components/Form/elements/SwitchSelectorElement.d.ts.map +1 -1
- package/dist/types/components/IDE/CodeBlockHighlight.d.ts +1 -1
- package/dist/types/components/IDE/CodeBlockHighlight.d.ts.map +1 -1
- package/dist/types/components/Input/Checkbox.d.ts +4 -20
- package/dist/types/components/Input/Checkbox.d.ts.map +1 -1
- package/dist/types/components/Input/Input.d.ts +3 -9
- package/dist/types/components/Input/Input.d.ts.map +1 -1
- package/dist/types/components/Input/OTPInput.d.ts +1 -1
- package/dist/types/components/Input/OTPInput.d.ts.map +1 -1
- package/dist/types/components/Input/Radio.d.ts +25 -0
- package/dist/types/components/Input/Radio.d.ts.map +1 -0
- package/dist/types/components/Input/SearchInput.d.ts +1 -1
- package/dist/types/components/Input/SearchInput.d.ts.map +1 -1
- package/dist/types/components/Input/index.d.ts +2 -1
- package/dist/types/components/KeyboardShortcut/KeyboardShortcut.d.ts +1 -47
- package/dist/types/components/KeyboardShortcut/KeyboardShortcut.d.ts.map +1 -1
- package/dist/types/components/Link/Link.d.ts +8 -47
- package/dist/types/components/Link/Link.d.ts.map +1 -1
- package/dist/types/components/Loader/spinner.d.ts +1 -1
- package/dist/types/components/Loader/spinner.d.ts.map +1 -1
- package/dist/types/components/LocaleSwitcherContentDropDown/LocaleSwitcherContent.d.ts.map +1 -1
- package/dist/types/components/MarkDownRender/MarkDownRender.d.ts +44 -44
- package/dist/types/components/MarkDownRender/MarkDownRender.d.ts.map +1 -1
- package/dist/types/components/MaxWidthSmoother/index.d.ts +1 -1
- package/dist/types/components/MaxWidthSmoother/index.d.ts.map +1 -1
- package/dist/types/components/Modal/Modal.d.ts +2 -8
- package/dist/types/components/Modal/Modal.d.ts.map +1 -1
- package/dist/types/components/Navbar/Burger.d.ts +1 -1
- package/dist/types/components/Navbar/Burger.d.ts.map +1 -1
- package/dist/types/components/Navbar/DesktopNavbar.d.ts +1 -1
- package/dist/types/components/Navbar/DesktopNavbar.d.ts.map +1 -1
- package/dist/types/components/Navbar/MobileNavbar.d.ts +1 -1
- package/dist/types/components/Navbar/MobileNavbar.d.ts.map +1 -1
- package/dist/types/components/Navbar/index.d.ts +1 -1
- package/dist/types/components/Navbar/index.d.ts.map +1 -1
- package/dist/types/components/Pagination/Pagination.d.ts +2 -10
- package/dist/types/components/Pagination/Pagination.d.ts.map +1 -1
- package/dist/types/components/Popover/dynamic.d.ts.map +1 -1
- package/dist/types/components/Popover/static.d.ts +5 -17
- package/dist/types/components/Popover/static.d.ts.map +1 -1
- package/dist/types/components/Select/Multiselect.d.ts +3 -3
- package/dist/types/components/Select/Select.d.ts +3 -8
- package/dist/types/components/Select/Select.d.ts.map +1 -1
- package/dist/types/components/SocialNetworks/index.d.ts +1 -1
- package/dist/types/components/Steps/index.d.ts +4 -4
- package/dist/types/components/Steps/index.d.ts.map +1 -1
- package/dist/types/components/Steps/steps.content.d.ts +52 -0
- package/dist/types/components/Steps/steps.content.d.ts.map +1 -0
- package/dist/types/components/SwitchSelector/SwitchSelector.d.ts +4 -16
- package/dist/types/components/SwitchSelector/SwitchSelector.d.ts.map +1 -1
- package/dist/types/components/SwitchSelector/VerticalSwitchSelector.d.ts +2 -2
- package/dist/types/components/SwitchSelector/VerticalSwitchSelector.d.ts.map +1 -1
- package/dist/types/components/Tab/Tab.d.ts +2 -2
- package/dist/types/components/Tab/Tab.d.ts.map +1 -1
- package/dist/types/components/TabSelector/TabSelector.d.ts +2 -10
- package/dist/types/components/TabSelector/TabSelector.d.ts.map +1 -1
- package/dist/types/components/Table/TableElements.d.ts +4 -4
- package/dist/types/components/Table/TableElements.d.ts.map +1 -1
- package/dist/types/components/Tag/index.d.ts +44 -83
- package/dist/types/components/Tag/index.d.ts.map +1 -1
- package/dist/types/components/TechLogo/TechLogo.d.ts.map +1 -1
- package/dist/types/components/TechLogo/index.d.ts +1 -1
- package/dist/types/components/TechLogo/logos/Lit.d.ts +1 -1
- package/dist/types/components/TechLogo/logos/Lit.d.ts.map +1 -1
- package/dist/types/components/TechLogo/logos/Vanilla.d.ts +1 -1
- package/dist/types/components/TechLogo/logos/Vanilla.d.ts.map +1 -1
- package/dist/types/components/TechLogo/types.d.ts +1 -38
- package/dist/types/components/TechLogo/types.d.ts.map +1 -1
- package/dist/types/components/TextArea/AutoSizeTextArea.d.ts +1 -1
- package/dist/types/components/TextArea/ContentEditableTextArea.d.ts +3 -3
- package/dist/types/components/TextArea/TextArea.d.ts +6 -6
- package/dist/types/components/TextArea/TextArea.d.ts.map +1 -1
- package/dist/types/components/ThemeSwitcherDropDown/types.d.ts +1 -5
- package/dist/types/components/ThemeSwitcherDropDown/types.d.ts.map +1 -1
- package/dist/types/components/Toaster/Toast.d.ts +1 -1
- package/dist/types/components/Toaster/Toaster.d.ts +1 -1
- package/dist/types/components/Toaster/Toaster.d.ts.map +1 -1
- package/dist/types/components/index.d.ts +5 -2
- package/package.json +23 -24
- package/dist/esm/components/TechLogo/types.mjs.map +0 -1
- package/dist/esm/components/ThemeSwitcherDropDown/types.mjs.map +0 -1
|
@@ -6,100 +6,48 @@ import { jsx, jsxs } from "react/jsx-runtime";
|
|
|
6
6
|
import { getLocalizedUrl } from "@intlayer/core/localization";
|
|
7
7
|
|
|
8
8
|
//#region src/components/Link/Link.tsx
|
|
9
|
-
/**
|
|
10
|
-
* Visual style variants for Link component
|
|
11
|
-
*/
|
|
12
|
-
let LinkVariant = /* @__PURE__ */ function(LinkVariant) {
|
|
13
|
-
LinkVariant["DEFAULT"] = "default";
|
|
14
|
-
LinkVariant["INVISIBLE_LINK"] = "invisible-link";
|
|
15
|
-
LinkVariant["BUTTON"] = "button";
|
|
16
|
-
LinkVariant["BUTTON_OUTLINED"] = "button-outlined";
|
|
17
|
-
LinkVariant["HOVERABLE"] = "hoverable";
|
|
18
|
-
return LinkVariant;
|
|
19
|
-
}({});
|
|
20
|
-
/**
|
|
21
|
-
* Color theme variants for Link component
|
|
22
|
-
*/
|
|
23
|
-
let LinkColor = /* @__PURE__ */ function(LinkColor) {
|
|
24
|
-
LinkColor["PRIMARY"] = "primary";
|
|
25
|
-
LinkColor["SECONDARY"] = "secondary";
|
|
26
|
-
LinkColor["NEUTRAL"] = "neutral";
|
|
27
|
-
LinkColor["LIGHT"] = "light";
|
|
28
|
-
LinkColor["DARK"] = "dark";
|
|
29
|
-
LinkColor["TEXT"] = "text";
|
|
30
|
-
LinkColor["TEXT_INVERSE"] = "text-inverse";
|
|
31
|
-
LinkColor["ERROR"] = "error";
|
|
32
|
-
LinkColor["SUCCESS"] = "success";
|
|
33
|
-
LinkColor["CUSTOM"] = "custom";
|
|
34
|
-
return LinkColor;
|
|
35
|
-
}({});
|
|
36
|
-
let LinkRoundedSize = /* @__PURE__ */ function(LinkRoundedSize) {
|
|
37
|
-
LinkRoundedSize["NONE"] = "none";
|
|
38
|
-
LinkRoundedSize["SM"] = "sm";
|
|
39
|
-
LinkRoundedSize["MD"] = "md";
|
|
40
|
-
LinkRoundedSize["LG"] = "lg";
|
|
41
|
-
LinkRoundedSize["XL"] = "xl";
|
|
42
|
-
LinkRoundedSize["TWO_XL"] = "2xl";
|
|
43
|
-
LinkRoundedSize["THREE_XL"] = "3xl";
|
|
44
|
-
LinkRoundedSize["FULL"] = "full";
|
|
45
|
-
return LinkRoundedSize;
|
|
46
|
-
}({});
|
|
47
|
-
let LinkSize = /* @__PURE__ */ function(LinkSize) {
|
|
48
|
-
LinkSize["SM"] = "sm";
|
|
49
|
-
LinkSize["MD"] = "md";
|
|
50
|
-
LinkSize["LG"] = "lg";
|
|
51
|
-
LinkSize["XL"] = "xl";
|
|
52
|
-
LinkSize["CUSTOM"] = "custom";
|
|
53
|
-
return LinkSize;
|
|
54
|
-
}({});
|
|
55
|
-
let LinkUnderlined = /* @__PURE__ */ function(LinkUnderlined) {
|
|
56
|
-
LinkUnderlined["DEFAULT"] = "default";
|
|
57
|
-
LinkUnderlined["TRUE"] = "true";
|
|
58
|
-
LinkUnderlined["FALSE"] = "false";
|
|
59
|
-
return LinkUnderlined;
|
|
60
|
-
}({});
|
|
61
9
|
const linkVariants = cva("gap-3 transition-all duration-300 focus-visible:outline-none disabled:pointer-events-none disabled:opacity-50", {
|
|
62
10
|
variants: {
|
|
63
11
|
variant: {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
12
|
+
default: "h-auto justify-start border-inherit bg-current/0 px-1 font-medium decoration-[1.5] underline-offset-5 hover:bg-current/0 hover:text-current/80 hover:underline hover:underline-offset-6",
|
|
13
|
+
"invisible-link": "h-auto justify-start border-inherit bg-current/0 px-1 underline-offset-5 hover:bg-current/0 aria-[current]:bg-current/5",
|
|
14
|
+
button: "relative flex cursor-pointer flex-row items-center justify-center gap-2 rounded-full bg-current text-center font-medium text-text ring-0 *:text-text-opposite hover:bg-current/90 hover:ring-5 aria-selected:ring-5 aria-[current]:ring-5",
|
|
15
|
+
"button-outlined": "relative flex cursor-pointer flex-row items-center justify-center gap-2 rounded-full border-[1.3px] border-current text-center font-medium text-text ring-0 *:text-text hover:bg-current/20 hover:ring-5 aria-selected:ring-5 aria-[current]:ring-5",
|
|
16
|
+
hoverable: "rounded-lg border-none bg-current/0 transition *:text-current! hover:bg-current/20 aria-[current]:bg-current/5"
|
|
69
17
|
},
|
|
70
18
|
roundedSize: {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
19
|
+
none: "rounded-none",
|
|
20
|
+
sm: "rounded-lg [corner-shape:squircle] supports-[corner-shape:squircle]:rounded-xl",
|
|
21
|
+
md: "rounded-xl [corner-shape:squircle] supports-[corner-shape:squircle]:rounded-2xl",
|
|
22
|
+
lg: "rounded-2xl [corner-shape:squircle] supports-[corner-shape:squircle]:rounded-3xl",
|
|
23
|
+
xl: "rounded-3xl [corner-shape:squircle] supports-[corner-shape:squircle]:rounded-4xl",
|
|
24
|
+
"2xl": "rounded-4xl [corner-shape:squircle] supports-[corner-shape:squircle]:rounded-[2.5rem]",
|
|
25
|
+
"3xl": "rounded-[2.5rem] [corner-shape:squircle] supports-[corner-shape:squircle]:rounded-[3rem]",
|
|
26
|
+
full: "rounded-full"
|
|
79
27
|
},
|
|
80
28
|
color: {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
29
|
+
primary: "text-primary",
|
|
30
|
+
secondary: "text-secondary",
|
|
31
|
+
neutral: "text-neutral",
|
|
32
|
+
light: "text-white",
|
|
33
|
+
dark: "text-neutral-800",
|
|
34
|
+
text: "text-text",
|
|
35
|
+
"text-inverse": "text-text-opposite",
|
|
36
|
+
error: "text-error",
|
|
37
|
+
success: "text-success",
|
|
38
|
+
custom: ""
|
|
91
39
|
},
|
|
92
40
|
size: {
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
41
|
+
sm: "text-sm",
|
|
42
|
+
md: "text-base",
|
|
43
|
+
lg: "text-lg",
|
|
44
|
+
xl: "text-xl",
|
|
45
|
+
custom: ""
|
|
98
46
|
},
|
|
99
47
|
underlined: {
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
48
|
+
default: "",
|
|
49
|
+
true: "underline",
|
|
50
|
+
false: "no-underline"
|
|
103
51
|
}
|
|
104
52
|
},
|
|
105
53
|
compoundVariants: [
|
|
@@ -183,7 +131,7 @@ const linkVariants = cva("gap-3 transition-all duration-300 focus-visible:outlin
|
|
|
183
131
|
variant: "default",
|
|
184
132
|
roundedSize: "md",
|
|
185
133
|
underlined: "default",
|
|
186
|
-
size: "
|
|
134
|
+
size: "custom"
|
|
187
135
|
}
|
|
188
136
|
});
|
|
189
137
|
const checkIsExternalLink = ({ href, isExternalLink: isExternalLinkProp }, url) => {
|
|
@@ -240,5 +188,5 @@ const Link = (props) => {
|
|
|
240
188
|
};
|
|
241
189
|
|
|
242
190
|
//#endregion
|
|
243
|
-
export { Link,
|
|
191
|
+
export { Link, checkIsExternalLink, isTextChildren, linkVariants };
|
|
244
192
|
//# sourceMappingURL=Link.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Link.mjs","names":[],"sources":["../../../../src/components/Link/Link.tsx"],"sourcesContent":["import { getLocalizedUrl } from '@intlayer/core/localization';\nimport type { LocalesValues } from '@intlayer/types/module_augmentation';\nimport { cn } from '@utils/cn';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { ExternalLink, MoveRight } from 'lucide-react';\nimport {\n type AnchorHTMLAttributes,\n type DetailedHTMLProps,\n type FC,\n isValidElement,\n type ReactNode,\n} from 'react';\n\n/**\n * Visual style variants for Link component\n */\nexport enum LinkVariant {\n DEFAULT = 'default',\n INVISIBLE_LINK = 'invisible-link',\n BUTTON = 'button',\n BUTTON_OUTLINED = 'button-outlined',\n HOVERABLE = 'hoverable',\n}\n\n/**\n * Color theme variants for Link component\n */\nexport enum LinkColor {\n PRIMARY = 'primary',\n SECONDARY = 'secondary',\n NEUTRAL = 'neutral',\n LIGHT = 'light',\n DARK = 'dark',\n TEXT = 'text',\n TEXT_INVERSE = 'text-inverse',\n ERROR = 'error',\n SUCCESS = 'success',\n CUSTOM = 'custom',\n}\n\nexport enum LinkRoundedSize {\n NONE = 'none',\n SM = 'sm',\n MD = 'md',\n LG = 'lg',\n XL = 'xl',\n TWO_XL = '2xl',\n THREE_XL = '3xl',\n FULL = 'full',\n}\n\nexport enum LinkSize {\n SM = 'sm',\n MD = 'md',\n LG = 'lg',\n XL = 'xl',\n CUSTOM = 'custom',\n}\n\nexport enum LinkUnderlined {\n DEFAULT = 'default',\n TRUE = 'true',\n FALSE = 'false',\n}\n\nexport const linkVariants = cva(\n 'gap-3 transition-all duration-300 focus-visible:outline-none disabled:pointer-events-none disabled:opacity-50',\n {\n variants: {\n variant: {\n [`${LinkVariant.DEFAULT}`]:\n 'h-auto justify-start border-inherit bg-current/0 px-1 font-medium decoration-[1.5] underline-offset-5 hover:bg-current/0 hover:text-current/80 hover:underline hover:underline-offset-6',\n [`${LinkVariant.INVISIBLE_LINK}`]:\n 'h-auto justify-start border-inherit bg-current/0 px-1 underline-offset-5 hover:bg-current/0 aria-[current]:bg-current/5',\n\n [`${LinkVariant.BUTTON}`]:\n 'relative flex cursor-pointer flex-row items-center justify-center gap-2 rounded-full bg-current text-center font-medium text-text ring-0 *:text-text-opposite hover:bg-current/90 hover:ring-5 aria-selected:ring-5 aria-[current]:ring-5',\n\n [`${LinkVariant.BUTTON_OUTLINED}`]:\n 'relative flex cursor-pointer flex-row items-center justify-center gap-2 rounded-full border-[1.3px] border-current text-center font-medium text-text ring-0 *:text-text hover:bg-current/20 hover:ring-5 aria-selected:ring-5 aria-[current]:ring-5',\n\n [`${LinkVariant.HOVERABLE}`]:\n 'rounded-lg border-none bg-current/0 transition *:text-current! hover:bg-current/20 aria-[current]:bg-current/5',\n },\n roundedSize: {\n [`${LinkRoundedSize.NONE}`]: 'rounded-none',\n [`${LinkRoundedSize.SM}`]:\n 'rounded-lg [corner-shape:squircle] supports-[corner-shape:squircle]:rounded-xl',\n [`${LinkRoundedSize.MD}`]:\n 'rounded-xl [corner-shape:squircle] supports-[corner-shape:squircle]:rounded-2xl',\n [`${LinkRoundedSize.LG}`]:\n 'rounded-2xl [corner-shape:squircle] supports-[corner-shape:squircle]:rounded-3xl',\n [`${LinkRoundedSize.XL}`]:\n 'rounded-3xl [corner-shape:squircle] supports-[corner-shape:squircle]:rounded-4xl',\n [`${LinkRoundedSize.TWO_XL}`]:\n 'rounded-4xl [corner-shape:squircle] supports-[corner-shape:squircle]:rounded-[2.5rem]',\n [`${LinkRoundedSize.THREE_XL}`]:\n 'rounded-[2.5rem] [corner-shape:squircle] supports-[corner-shape:squircle]:rounded-[3rem]',\n [`${LinkRoundedSize.FULL}`]: 'rounded-full',\n },\n color: {\n [`${LinkColor.PRIMARY}`]: 'text-primary',\n [`${LinkColor.SECONDARY}`]: 'text-secondary',\n [`${LinkColor.NEUTRAL}`]: 'text-neutral',\n [`${LinkColor.LIGHT}`]: 'text-white',\n [`${LinkColor.DARK}`]: 'text-neutral-800',\n [`${LinkColor.TEXT}`]: 'text-text',\n [`${LinkColor.TEXT_INVERSE}`]: 'text-text-opposite',\n [`${LinkColor.ERROR}`]: 'text-error',\n [`${LinkColor.SUCCESS}`]: 'text-success',\n [`${LinkColor.CUSTOM}`]: '',\n },\n size: {\n [`${LinkSize.SM}`]: 'text-sm',\n [`${LinkSize.MD}`]: 'text-base',\n [`${LinkSize.LG}`]: 'text-lg',\n [`${LinkSize.XL}`]: 'text-xl',\n [`${LinkSize.CUSTOM}`]: '',\n },\n underlined: {\n [LinkUnderlined.DEFAULT]: '',\n [LinkUnderlined.TRUE]: 'underline',\n [LinkUnderlined.FALSE]: 'no-underline',\n },\n },\n // Compound variants handle height and padding\n compoundVariants: [\n // ---------------------------------------------------------\n // FIX START: Correctly Handle Contrast for TEXT_INVERSE\n // ---------------------------------------------------------\n {\n // Filled Button + Inverse Color (e.g., White Button):\n // We DO NOT override parent text color (it must remain 'text-opposite' so bg-current is white).\n // We ONLY override children to be 'text-text' (Dark) so they show up on white.\n variant: LinkVariant.BUTTON,\n color: LinkColor.TEXT_INVERSE,\n class: '*:text-text',\n },\n {\n // Outlined Button + Inverse Color (e.g., White Border):\n // Parent is 'text-opposite' (Border is white).\n // Children must also be 'text-opposite' (White text) to show on dark background.\n variant: LinkVariant.BUTTON_OUTLINED,\n color: LinkColor.TEXT_INVERSE,\n class: 'text-text-opposite *:text-text-opposite',\n },\n\n // Min height and padding for button variants\n {\n variant: [LinkVariant.BUTTON, LinkVariant.BUTTON_OUTLINED],\n size: LinkSize.SM,\n class: 'min-h-7 px-3 max-md:py-1',\n },\n {\n variant: [LinkVariant.BUTTON, LinkVariant.BUTTON_OUTLINED],\n size: LinkSize.MD,\n class: 'min-h-8 px-6 max-md:py-2',\n },\n {\n variant: [LinkVariant.BUTTON, LinkVariant.BUTTON_OUTLINED],\n size: LinkSize.LG,\n class: 'min-h-10 px-8 max-md:py-3',\n },\n {\n variant: [LinkVariant.BUTTON, LinkVariant.BUTTON_OUTLINED],\n size: LinkSize.XL,\n class: 'min-h-11 px-10 max-md:py-4',\n },\n // Ring color variants\n {\n variant: [LinkVariant.BUTTON, LinkVariant.BUTTON_OUTLINED],\n color: LinkColor.PRIMARY,\n class: 'ring-primary/20',\n },\n {\n variant: [LinkVariant.BUTTON, LinkVariant.BUTTON_OUTLINED],\n color: LinkColor.SECONDARY,\n class: 'ring-secondary/20',\n },\n {\n variant: [LinkVariant.BUTTON, LinkVariant.BUTTON_OUTLINED],\n color: LinkColor.NEUTRAL,\n class: 'ring-neutral/20',\n },\n {\n variant: [LinkVariant.BUTTON, LinkVariant.BUTTON_OUTLINED],\n color: LinkColor.LIGHT,\n class: 'ring-white/20',\n },\n {\n variant: [LinkVariant.BUTTON, LinkVariant.BUTTON_OUTLINED],\n color: LinkColor.DARK,\n class: 'ring-neutral-800/20',\n },\n {\n variant: [LinkVariant.BUTTON, LinkVariant.BUTTON_OUTLINED],\n color: LinkColor.TEXT,\n class: 'ring-text/20',\n },\n {\n variant: [LinkVariant.BUTTON, LinkVariant.BUTTON_OUTLINED],\n color: LinkColor.TEXT_INVERSE,\n class: 'ring-text-opposite/20',\n },\n {\n variant: [LinkVariant.BUTTON, LinkVariant.BUTTON_OUTLINED],\n color: LinkColor.ERROR,\n class: 'ring-error/20',\n },\n {\n variant: [LinkVariant.BUTTON, LinkVariant.BUTTON_OUTLINED],\n color: LinkColor.SUCCESS,\n class: 'ring-success/20',\n },\n ],\n\n defaultVariants: {\n variant: LinkVariant.DEFAULT,\n roundedSize: LinkRoundedSize.MD,\n underlined: LinkUnderlined.DEFAULT,\n size: LinkSize.MD,\n },\n }\n);\n\nexport type LinkProps = DetailedHTMLProps<\n AnchorHTMLAttributes<HTMLAnchorElement>,\n HTMLAnchorElement\n> &\n VariantProps<typeof linkVariants> & {\n label: string;\n isExternalLink?: boolean;\n isPageSection?: boolean;\n isActive?: boolean;\n locale?: LocalesValues;\n };\n\nexport const checkIsExternalLink = (\n {\n href,\n isExternalLink: isExternalLinkProp,\n }: Pick<LinkProps, 'href' | 'isExternalLink'>,\n url?: string\n): boolean => {\n // Explicit prop override takes precedence\n if (typeof isExternalLinkProp === 'boolean') {\n return isExternalLinkProp;\n }\n\n const isValidHref = typeof href === 'string' && href.trim() !== '';\n\n if (!isValidHref) return false;\n\n // Relative URLs (e.g., '/about') are always internal\n if (!/^https?:\\/\\//.test(href)) {\n return false;\n }\n\n // Compare base domains\n if (url) {\n try {\n const hrefHost = new URL(href).hostname;\n // Ensure the reference url has a protocol so URL() can parse it correctly\n const currentHost = new URL(\n url.startsWith('http') ? url : `https://${url}`\n ).hostname;\n\n // Extract the root domain (e.g., 'app.intlayer.org' -> 'intlayer.org')\n const getBaseDomain = (host: string) =>\n host.split('.').slice(-2).join('.');\n\n return getBaseDomain(hrefHost) !== getBaseDomain(currentHost);\n } catch {\n // If URL parsing fails for any reason, default to treating it as external\n return true;\n }\n }\n\n // Absolute URL with no comparison URL provided\n return true;\n};\n\nexport const isTextChildren = (children: ReactNode): boolean => {\n if (typeof children === 'string' || typeof children === 'number') {\n return true;\n }\n if (Array.isArray(children)) {\n return children.every(isTextChildren);\n }\n if (isValidElement(children)) {\n return isTextChildren(\n (children.props as { children?: ReactNode }).children\n );\n }\n return false;\n};\n\nexport const Link: FC<LinkProps> = (props) => {\n const {\n variant = LinkVariant.DEFAULT,\n color = LinkColor.CUSTOM,\n roundedSize,\n children,\n label,\n className,\n isActive,\n underlined,\n locale,\n size,\n isExternalLink: isExternalLinkProp,\n isPageSection: isPageSectionProp,\n href: hrefProp,\n ...otherProps\n } = props;\n\n const isExternalLink = isExternalLinkProp ?? checkIsExternalLink(props);\n const isPageSection = isPageSectionProp ?? hrefProp?.startsWith('#') ?? false;\n\n const isChildrenString = isTextChildren(children);\n const isButton =\n variant === LinkVariant.BUTTON || variant === LinkVariant.BUTTON_OUTLINED;\n\n const rel = isExternalLink ? 'noopener noreferrer nofollow' : undefined;\n\n const target = isExternalLink ? '_blank' : '_self';\n\n const resolvedHref =\n locale && hrefProp && !isExternalLink && !isPageSection\n ? getLocalizedUrl(hrefProp, locale)\n : hrefProp;\n\n const href = resolvedHref === '' ? undefined : resolvedHref;\n\n return (\n <a\n href={href}\n aria-label={label}\n rel={rel}\n target={target}\n aria-current={isActive ? 'page' : undefined}\n suppressHydrationWarning\n className={cn(\n linkVariants({\n variant,\n color,\n roundedSize,\n underlined,\n size,\n className,\n })\n )}\n {...otherProps}\n >\n {isButton && isChildrenString ? <span>{children}</span> : children}\n\n {isExternalLink && isChildrenString && (\n <ExternalLink className=\"ml-2 inline-block size-4\" />\n )}\n {isPageSection && <MoveRight className=\"ml-2 inline-block size-4\" />}\n </a>\n );\n};\n"],"mappings":";;;;;;;;;;;AAgBA,IAAY,cAAL;CACL;CACA;CACA;CACA;CACA;;AACF;;;;AAKA,IAAY,YAAL;CACL;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;;AACF;AAEA,IAAY,kBAAL;CACL;CACA;CACA;CACA;CACA;CACA;CACA;CACA;;AACF;AAEA,IAAY,WAAL;CACL;CACA;CACA;CACA;CACA;;AACF;AAEA,IAAY,iBAAL;CACL;CACA;CACA;;AACF;AAEA,MAAa,eAAe,IAC1B,iHACA;CACE,UAAU;EACR,SAAS;IACN,YACC;IACD,mBACC;IAED,WACC;IAED,oBACC;IAED,cACC;EACJ;EACA,aAAa;IACV,SAA4B;IAC5B,OACC;IACD,OACC;IACD,OACC;IACD,OACC;IACD,QACC;IACD,QACC;IACD,SAA4B;EAC/B;EACA,OAAO;IACJ,YAAyB;IACzB,cAA2B;IAC3B,YAAyB;IACzB,UAAuB;IACvB,SAAsB;IACtB,SAAsB;IACtB,iBAA8B;IAC9B,UAAuB;IACvB,YAAyB;IACzB,WAAwB;EAC3B;EACA,MAAM;IACH,OAAmB;IACnB,OAAmB;IACnB,OAAmB;IACnB,OAAmB;IACnB,WAAuB;EAC1B;EACA,YAAY;gBACgB;aACH;cACC;EAC1B;CACF;CAEA,kBAAkB;EAIhB;GAIE;GACA;GACA,OAAO;EACT;EACA;GAIE;GACA;GACA,OAAO;EACT;EAGA;GACE,SAAS,4BAAgD;GACzD;GACA,OAAO;EACT;EACA;GACE,SAAS,4BAAgD;GACzD;GACA,OAAO;EACT;EACA;GACE,SAAS,4BAAgD;GACzD;GACA,OAAO;EACT;EACA;GACE,SAAS,4BAAgD;GACzD;GACA,OAAO;EACT;EAEA;GACE,SAAS,4BAAgD;GACzD;GACA,OAAO;EACT;EACA;GACE,SAAS,4BAAgD;GACzD;GACA,OAAO;EACT;EACA;GACE,SAAS,4BAAgD;GACzD;GACA,OAAO;EACT;EACA;GACE,SAAS,4BAAgD;GACzD;GACA,OAAO;EACT;EACA;GACE,SAAS,4BAAgD;GACzD;GACA,OAAO;EACT;EACA;GACE,SAAS,4BAAgD;GACzD;GACA,OAAO;EACT;EACA;GACE,SAAS,4BAAgD;GACzD;GACA,OAAO;EACT;EACA;GACE,SAAS,4BAAgD;GACzD;GACA,OAAO;EACT;EACA;GACE,SAAS,4BAAgD;GACzD;GACA,OAAO;EACT;CACF;CAEA,iBAAiB;EACf;EACA;EACA;EACA;CACF;AACF,CACF;AAcA,MAAa,uBACX,EACE,MACA,gBAAgB,sBAElB,QACY;CAEZ,IAAI,OAAO,uBAAuB,WAChC,OAAO;CAKT,IAAI,EAFgB,OAAO,SAAS,YAAY,KAAK,KAAK,MAAM,KAE9C,OAAO;CAGzB,IAAI,CAAC,eAAe,KAAK,IAAI,GAC3B,OAAO;CAIT,IAAI,KACF,IAAI;EACF,MAAM,WAAW,IAAI,IAAI,IAAI,EAAE;EAE/B,MAAM,cAAc,IAAI,IACtB,IAAI,WAAW,MAAM,IAAI,MAAM,WAAW,KAC5C,EAAE;EAGF,MAAM,iBAAiB,SACrB,KAAK,MAAM,GAAG,EAAE,MAAM,EAAE,EAAE,KAAK,GAAG;EAEpC,OAAO,cAAc,QAAQ,MAAM,cAAc,WAAW;CAC9D,QAAQ;EAEN,OAAO;CACT;CAIF,OAAO;AACT;AAEA,MAAa,kBAAkB,aAAiC;CAC9D,IAAI,OAAO,aAAa,YAAY,OAAO,aAAa,UACtD,OAAO;CAET,IAAI,MAAM,QAAQ,QAAQ,GACxB,OAAO,SAAS,MAAM,cAAc;CAEtC,IAAI,eAAe,QAAQ,GACzB,OAAO,eACJ,SAAS,MAAmC,QAC/C;CAEF,OAAO;AACT;AAEA,MAAa,QAAuB,UAAU;CAC5C,MAAM,EACJ,qBACA,kBACA,aACA,UACA,OACA,WACA,UACA,YACA,QACA,MACA,gBAAgB,oBAChB,eAAe,mBACf,MAAM,UACN,GAAG,eACD;CAEJ,MAAM,iBAAiB,sBAAsB,oBAAoB,KAAK;CACtE,MAAM,gBAAgB,qBAAqB,UAAU,WAAW,GAAG,KAAK;CAExE,MAAM,mBAAmB,eAAe,QAAQ;CAChD,MAAM,WACJ,wBAAkC;CAEpC,MAAM,MAAM,iBAAiB,iCAAiC;CAE9D,MAAM,SAAS,iBAAiB,WAAW;CAE3C,MAAM,eACJ,UAAU,YAAY,CAAC,kBAAkB,CAAC,gBACtC,gBAAgB,UAAU,MAAM,IAChC;CAIN,OACE,qBAAC,KAAD;EACE,MAJS,iBAAiB,KAAK,SAAY;EAK3C,cAAY;EACP;EACG;EACR,gBAAc,WAAW,SAAS;EAClC;EACA,WAAW,GACT,aAAa;GACX;GACA;GACA;GACA;GACA;GACA;EACF,CAAC,CACH;EACA,GAAI;YAjBN;GAmBG,YAAY,mBAAmB,oBAAC,QAAD,EAAO,SAAe,KAAI;GAEzD,kBAAkB,oBACjB,oBAAC,cAAD,EAAc,WAAU,2BAA4B;GAErD,iBAAiB,oBAAC,WAAD,EAAW,WAAU,2BAA4B;EAClE;;AAEP"}
|
|
1
|
+
{"version":3,"file":"Link.mjs","names":[],"sources":["../../../../src/components/Link/Link.tsx"],"sourcesContent":["import { getLocalizedUrl } from '@intlayer/core/localization';\nimport type { LocalesValues } from '@intlayer/types/module_augmentation';\nimport { cn } from '@utils/cn';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { ExternalLink, MoveRight } from 'lucide-react';\nimport {\n type AnchorHTMLAttributes,\n type DetailedHTMLProps,\n type FC,\n isValidElement,\n type ReactNode,\n} from 'react';\n\nexport type LinkVariant =\n | 'default'\n | 'invisible-link'\n | 'button'\n | 'button-outlined'\n | 'hoverable';\n\n/**\n * Color theme variants for Link component\n */\nexport type LinkColor =\n | 'primary'\n | 'secondary'\n | 'neutral'\n | 'light'\n | 'dark'\n | 'text'\n | 'text-inverse'\n | 'error'\n | 'success'\n | 'custom';\n\nexport type LinkRoundedSize =\n | 'none'\n | 'sm'\n | 'md'\n | 'lg'\n | 'xl'\n | '2xl'\n | '3xl'\n | 'full';\n\nexport type LinkSize = 'sm' | 'md' | 'lg' | 'xl' | 'custom';\n\nexport type LinkUnderlined = 'default' | 'true' | 'false';\n\nexport const linkVariants = cva(\n 'gap-3 transition-all duration-300 focus-visible:outline-none disabled:pointer-events-none disabled:opacity-50',\n {\n variants: {\n variant: {\n default:\n 'h-auto justify-start border-inherit bg-current/0 px-1 font-medium decoration-[1.5] underline-offset-5 hover:bg-current/0 hover:text-current/80 hover:underline hover:underline-offset-6',\n 'invisible-link':\n 'h-auto justify-start border-inherit bg-current/0 px-1 underline-offset-5 hover:bg-current/0 aria-[current]:bg-current/5',\n\n button:\n 'relative flex cursor-pointer flex-row items-center justify-center gap-2 rounded-full bg-current text-center font-medium text-text ring-0 *:text-text-opposite hover:bg-current/90 hover:ring-5 aria-selected:ring-5 aria-[current]:ring-5',\n\n 'button-outlined':\n 'relative flex cursor-pointer flex-row items-center justify-center gap-2 rounded-full border-[1.3px] border-current text-center font-medium text-text ring-0 *:text-text hover:bg-current/20 hover:ring-5 aria-selected:ring-5 aria-[current]:ring-5',\n\n hoverable:\n 'rounded-lg border-none bg-current/0 transition *:text-current! hover:bg-current/20 aria-[current]:bg-current/5',\n },\n roundedSize: {\n none: 'rounded-none',\n sm:\n 'rounded-lg [corner-shape:squircle] supports-[corner-shape:squircle]:rounded-xl',\n md:\n 'rounded-xl [corner-shape:squircle] supports-[corner-shape:squircle]:rounded-2xl',\n lg:\n 'rounded-2xl [corner-shape:squircle] supports-[corner-shape:squircle]:rounded-3xl',\n xl:\n 'rounded-3xl [corner-shape:squircle] supports-[corner-shape:squircle]:rounded-4xl',\n '2xl':\n 'rounded-4xl [corner-shape:squircle] supports-[corner-shape:squircle]:rounded-[2.5rem]',\n '3xl':\n 'rounded-[2.5rem] [corner-shape:squircle] supports-[corner-shape:squircle]:rounded-[3rem]',\n full: 'rounded-full',\n },\n color: {\n primary: 'text-primary',\n secondary: 'text-secondary',\n neutral: 'text-neutral',\n light: 'text-white',\n dark: 'text-neutral-800',\n text: 'text-text',\n 'text-inverse': 'text-text-opposite',\n error: 'text-error',\n success: 'text-success',\n custom: '',\n },\n size: {\n sm: 'text-sm',\n md: 'text-base',\n lg: 'text-lg',\n xl: 'text-xl',\n custom: '',\n },\n underlined: {\n default: '',\n true: 'underline',\n false: 'no-underline',\n },\n },\n // Compound variants handle height and padding\n compoundVariants: [\n // ---------------------------------------------------------\n // FIX START: Correctly Handle Contrast for TEXT_INVERSE\n // ---------------------------------------------------------\n {\n // Filled Button + Inverse Color (e.g., White Button):\n // We DO NOT override parent text color (it must remain 'text-opposite' so bg-current is white).\n // We ONLY override children to be 'text-text' (Dark) so they show up on white.\n variant: 'button',\n color: 'text-inverse',\n class: '*:text-text',\n },\n {\n // Outlined Button + Inverse Color (e.g., White Border):\n // Parent is 'text-opposite' (Border is white).\n // Children must also be 'text-opposite' (White text) to show on dark background.\n variant: 'button-outlined',\n color: 'text-inverse',\n class: 'text-text-opposite *:text-text-opposite',\n },\n\n // Min height and padding for button variants\n {\n variant: ['button', 'button-outlined'],\n size: 'sm',\n class: 'min-h-7 px-3 max-md:py-1',\n },\n {\n variant: ['button', 'button-outlined'],\n size: 'md',\n class: 'min-h-8 px-6 max-md:py-2',\n },\n {\n variant: ['button', 'button-outlined'],\n size: 'lg',\n class: 'min-h-10 px-8 max-md:py-3',\n },\n {\n variant: ['button', 'button-outlined'],\n size: 'xl',\n class: 'min-h-11 px-10 max-md:py-4',\n },\n // Ring color variants\n {\n variant: ['button', 'button-outlined'],\n color: 'primary',\n class: 'ring-primary/20',\n },\n {\n variant: ['button', 'button-outlined'],\n color: 'secondary',\n class: 'ring-secondary/20',\n },\n {\n variant: ['button', 'button-outlined'],\n color: 'neutral',\n class: 'ring-neutral/20',\n },\n {\n variant: ['button', 'button-outlined'],\n color: 'light',\n class: 'ring-white/20',\n },\n {\n variant: ['button', 'button-outlined'],\n color: 'dark',\n class: 'ring-neutral-800/20',\n },\n {\n variant: ['button', 'button-outlined'],\n color: 'text',\n class: 'ring-text/20',\n },\n {\n variant: ['button', 'button-outlined'],\n color: 'text-inverse',\n class: 'ring-text-opposite/20',\n },\n {\n variant: ['button', 'button-outlined'],\n color: 'error',\n class: 'ring-error/20',\n },\n {\n variant: ['button', 'button-outlined'],\n color: 'success',\n class: 'ring-success/20',\n },\n ],\n\n defaultVariants: {\n variant: 'default',\n roundedSize: 'md',\n underlined: 'default',\n size: 'custom',\n },\n }\n);\n\nexport type LinkProps = DetailedHTMLProps<\n AnchorHTMLAttributes<HTMLAnchorElement>,\n HTMLAnchorElement\n> &\n VariantProps<typeof linkVariants> & {\n label: string;\n isExternalLink?: boolean;\n isPageSection?: boolean;\n isActive?: boolean;\n locale?: LocalesValues;\n };\n\nexport const checkIsExternalLink = (\n {\n href,\n isExternalLink: isExternalLinkProp,\n }: Pick<LinkProps, 'href' | 'isExternalLink'>,\n url?: string\n): boolean => {\n // Explicit prop override takes precedence\n if (typeof isExternalLinkProp === 'boolean') {\n return isExternalLinkProp;\n }\n\n const isValidHref = typeof href === 'string' && href.trim() !== '';\n\n if (!isValidHref) return false;\n\n // Relative URLs (e.g., '/about') are always internal\n if (!/^https?:\\/\\//.test(href)) {\n return false;\n }\n\n // Compare base domains\n if (url) {\n try {\n const hrefHost = new URL(href).hostname;\n // Ensure the reference url has a protocol so URL() can parse it correctly\n const currentHost = new URL(\n url.startsWith('http') ? url : `https://${url}`\n ).hostname;\n\n // Extract the root domain (e.g., 'app.intlayer.org' -> 'intlayer.org')\n const getBaseDomain = (host: string) =>\n host.split('.').slice(-2).join('.');\n\n return getBaseDomain(hrefHost) !== getBaseDomain(currentHost);\n } catch {\n // If URL parsing fails for any reason, default to treating it as external\n return true;\n }\n }\n\n // Absolute URL with no comparison URL provided\n return true;\n};\n\nexport const isTextChildren = (children: ReactNode): boolean => {\n if (typeof children === 'string' || typeof children === 'number') {\n return true;\n }\n if (Array.isArray(children)) {\n return children.every(isTextChildren);\n }\n if (isValidElement(children)) {\n return isTextChildren(\n (children.props as { children?: ReactNode }).children\n );\n }\n return false;\n};\n\nexport const Link: FC<LinkProps> = (props) => {\n const {\n variant = 'default',\n color = 'custom',\n roundedSize,\n children,\n label,\n className,\n isActive,\n underlined,\n locale,\n size,\n isExternalLink: isExternalLinkProp,\n isPageSection: isPageSectionProp,\n href: hrefProp,\n ...otherProps\n } = props;\n\n const isExternalLink = isExternalLinkProp ?? checkIsExternalLink(props);\n const isPageSection = isPageSectionProp ?? hrefProp?.startsWith('#') ?? false;\n\n const isChildrenString = isTextChildren(children);\n const isButton =\n variant === 'button' || variant === 'button-outlined';\n\n const rel = isExternalLink ? 'noopener noreferrer nofollow' : undefined;\n\n const target = isExternalLink ? '_blank' : '_self';\n\n const resolvedHref =\n locale && hrefProp && !isExternalLink && !isPageSection\n ? getLocalizedUrl(hrefProp, locale)\n : hrefProp;\n\n const href = resolvedHref === '' ? undefined : resolvedHref;\n\n return (\n <a\n href={href}\n aria-label={label}\n rel={rel}\n target={target}\n aria-current={isActive ? 'page' : undefined}\n suppressHydrationWarning\n className={cn(\n linkVariants({\n variant,\n color,\n roundedSize,\n underlined,\n size,\n className,\n })\n )}\n {...otherProps}\n >\n {isButton && isChildrenString ? <span>{children}</span> : children}\n\n {isExternalLink && isChildrenString && (\n <ExternalLink className=\"ml-2 inline-block size-4\" />\n )}\n {isPageSection && <MoveRight className=\"ml-2 inline-block size-4\" />}\n </a>\n );\n};\n"],"mappings":"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"}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { Link,
|
|
1
|
+
import { Link, checkIsExternalLink, isTextChildren, linkVariants } from "./Link.mjs";
|
|
2
2
|
|
|
3
|
-
export { Link,
|
|
3
|
+
export { Link, checkIsExternalLink, isTextChildren, linkVariants };
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
+
import { Button } from "../Button/Button.mjs";
|
|
3
4
|
import { Container } from "../Container/index.mjs";
|
|
4
|
-
import { Button, ButtonColor, ButtonSize, ButtonTextAlign, ButtonVariant } from "../Button/Button.mjs";
|
|
5
5
|
import { DropDown } from "../DropDown/index.mjs";
|
|
6
6
|
import { Input } from "../Input/Input.mjs";
|
|
7
|
-
import { SwitchSelector
|
|
7
|
+
import { SwitchSelector } from "../SwitchSelector/SwitchSelector.mjs";
|
|
8
8
|
import { usePersistedStore } from "../../hooks/usePersistedStore.mjs";
|
|
9
9
|
import { useLocaleSwitcherContent } from "./LocaleSwitcherContentContext.mjs";
|
|
10
10
|
import { useMemo, useRef, useState } from "react";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LocaleSwitcherContent.mjs","names":[],"sources":["../../../../src/components/LocaleSwitcherContentDropDown/LocaleSwitcherContent.tsx"],"sourcesContent":["'use client';\n\nimport { usePersistedStore } from '@hooks/usePersistedStore';\nimport { getHTMLTextDir, getLocaleName } from '@intlayer/core/localization';\nimport { ENGLISH } from '@intlayer/types/locales';\nimport type { LocalesValues } from '@intlayer/types/module_augmentation';\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 {\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, 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 color=\"text\"\n variant=\"hoverable\"\n >\n <div className=\"flex w-full items-center justify-between text-text\">\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 align=\"end\"\n {...panelProps}\n >\n <Container\n className=\"max-h-[60vh] min-w-28\"\n separator=\"y\"\n role=\"listbox\"\n transparency=\"xs\"\n border\n roundedSize=\"3xl\"\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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"}
|
|
1
|
+
{"version":3,"file":"LocaleSwitcherContent.mjs","names":[],"sources":["../../../../src/components/LocaleSwitcherContentDropDown/LocaleSwitcherContent.tsx"],"sourcesContent":["'use client';\n\nimport { usePersistedStore } from '@hooks/usePersistedStore';\nimport { getHTMLTextDir, getLocaleName } from '@intlayer/core/localization';\nimport { ENGLISH } from '@intlayer/types/locales';\nimport type { LocalesValues } from '@intlayer/types/module_augmentation';\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 { Button } from '../Button';\nimport { Container } from '../Container';\nimport { DropDown, type PanelProps } from '../DropDown';\nimport { Input } from '../Input';\nimport { SwitchSelector } 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, 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 color=\"text\"\n variant=\"hoverable\"\n >\n <div className=\"flex w-full items-center justify-between text-text\">\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 align=\"end\"\n {...panelProps}\n >\n <Container\n className=\"max-h-[60vh] min-w-28\"\n separator=\"y\"\n role=\"listbox\"\n transparency=\"xs\"\n border\n roundedSize=\"3xl\"\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=\"text\"\n size=\"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=\"hoverable\"\n color=\"text\"\n isFullWidth\n textAlign=\"left\"\n size=\"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,7 +1,7 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
+
import { Button } from "../Button/Button.mjs";
|
|
3
4
|
import { Container } from "../Container/index.mjs";
|
|
4
|
-
import { Button, ButtonColor, ButtonTextAlign, ButtonVariant } from "../Button/Button.mjs";
|
|
5
5
|
import { DropDown } from "../DropDown/index.mjs";
|
|
6
6
|
import { Input } from "../Input/Input.mjs";
|
|
7
7
|
import { useCallback, useMemo, useRef, useState } from "react";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LocaleSwitcher.mjs","names":[],"sources":["../../../../src/components/LocaleSwitcherDropDown/LocaleSwitcher.tsx"],"sourcesContent":["'use client';\n\nimport { getHTMLTextDir, getLocaleName } from '@intlayer/core/localization';\nimport type { Locale } from '@intlayer/types/allLocales';\nimport { ENGLISH } from '@intlayer/types/locales';\nimport Fuse, { type IFuseOptions } from 'fuse.js';\nimport { MoveVertical } from 'lucide-react';\nimport { type FC, useCallback, useMemo, useRef, useState } from 'react';\nimport { useIntlayer } from 'react-intlayer';\nimport { Button
|
|
1
|
+
{"version":3,"file":"LocaleSwitcher.mjs","names":[],"sources":["../../../../src/components/LocaleSwitcherDropDown/LocaleSwitcher.tsx"],"sourcesContent":["'use client';\n\nimport { getHTMLTextDir, getLocaleName } from '@intlayer/core/localization';\nimport type { Locale } from '@intlayer/types/allLocales';\nimport { ENGLISH } from '@intlayer/types/locales';\nimport Fuse, { type IFuseOptions } from 'fuse.js';\nimport { MoveVertical } from 'lucide-react';\nimport { type FC, useCallback, useMemo, useRef, useState } from 'react';\nimport { useIntlayer } from 'react-intlayer';\nimport { Button } from '../Button';\nimport { Container } from '../Container';\nimport { DropDown, type PanelProps } from '../DropDown';\nimport { Input } from '../Input';\n\nexport type LocaleSwitcherProps = {\n locale?: Locale;\n localeList: Locale[];\n availableLocales?: Locale[];\n fullLocaleName?: boolean;\n setLocale: (locale: Locale) => void;\n panelProps?: Omit<PanelProps, 'identifier'>;\n};\n\nconst DROPDOWN_IDENTIFIER = 'locale-switcher';\n\ntype MultilingualAvailableLocales = {\n locale: Locale;\n englishName: string;\n currentLocaleName: string;\n ownLocaleName: string;\n};\n\nexport const LocaleSwitcher: FC<LocaleSwitcherProps> = ({\n locale,\n localeList,\n availableLocales,\n fullLocaleName = true,\n setLocale,\n panelProps,\n}) => {\n let localeName = 'Select a locale';\n const { switchTo, searchInput, languageListLabel, localeSwitcherLabel } =\n useIntlayer('locale-switcher');\n const inputRef = useRef<HTMLInputElement>(null);\n\n const multilingualAvailableLocales: MultilingualAvailableLocales[] = useMemo(\n () =>\n localeList.map((localeEl) => {\n const englishName = getLocaleName(localeEl, 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 [localeList, locale]\n );\n\n const [results, setResults] = useState<MultilingualAvailableLocales[]>(\n multilingualAvailableLocales\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 if (locale) {\n localeName = fullLocaleName ? getLocaleName(locale) : locale.toUpperCase();\n }\n\n return (\n <nav\n className=\"rounded-xl border border-text\"\n aria-label={localeSwitcherLabel.value}\n >\n <DropDown identifier={DROPDOWN_IDENTIFIER}>\n <DropDown.Trigger identifier={DROPDOWN_IDENTIFIER} color=\"text\">\n <div className=\"flex w-full items-center justify-between\">\n <div className=\"text-nowrap px-2\">{localeName}</div>\n <MoveVertical className=\"w-5 self-center\" />\n </div>\n </DropDown.Trigger>\n\n <DropDown.Panel\n identifier={DROPDOWN_IDENTIFIER}\n isOverable\n isFocusable\n align=\"end\"\n {...panelProps}\n >\n <Container\n className=\"max-h-[80vh] min-w-28\"\n separator=\"y\"\n role=\"listbox\"\n transparency=\"xs\"\n aria-label={languageListLabel.value}\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 ({ locale: localeItem, currentLocaleName, ownLocaleName }) => (\n <li className=\"px-1.5 py-1\" key={localeItem}>\n <Button\n onClick={() => setLocale(localeItem)}\n label={`${switchTo} ${currentLocaleName}`}\n disabled={\n !(availableLocales ?? localeList).includes(localeItem)\n }\n isActive={locale === localeItem}\n variant=\"hoverable\"\n color=\"text\"\n isFullWidth\n textAlign=\"left\"\n >\n <div className=\"flex 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 suppressHydrationWarning\n >\n {ownLocaleName}\n </span>\n <span\n className=\"text-neutral text-xs\"\n suppressHydrationWarning\n >\n {currentLocaleName}\n </span>\n </div>\n <span className=\"text-neutral text-sm\">\n {localeItem.toUpperCase()}\n </span>\n </div>\n </Button>\n </li>\n )\n )}\n </ol>\n </Container>\n </DropDown.Panel>\n </DropDown>\n </nav>\n );\n};\n"],"mappings":";;;;;;;;;;;;;;;AAuBA,MAAM,sBAAsB;AAS5B,MAAa,kBAA2C,EACtD,QACA,YACA,kBACA,iBAAiB,MACjB,WACA,iBACI;CACJ,IAAI,aAAa;CACjB,MAAM,EAAE,UAAU,aAAa,mBAAmB,wBAChD,YAAY,iBAAiB;CAC/B,MAAM,WAAW,OAAyB,IAAI;CAE9C,MAAM,+BAA+D,cAEjE,WAAW,KAAK,aAAa;EAI3B,OAAO;GACL,QAAQ;GACR,aALkB,cAAc,UAAU,OAKhC;GACV,mBALwB,cAAc,UAAU,MAKhC;GAChB,eALoB,cAAc,QAKtB;EACd;CACF,CAAC,GACH,CAAC,YAAY,MAAM,CACrB;CAEA,MAAM,CAAC,SAAS,cAAc,SAC5B,4BACF;CAGA,MAAM,OAAO,cAAc;EAWzB,OAAO,IAAI,KAAK,8BAA8B;GAT5C,MAAM;IACJ;KAAE,MAAM;KAAiB,QAAQ;IAAI;IACrC;KAAE,MAAM;KAAe,QAAQ;IAAI;IACnC;KAAE,MAAM;KAAqB,QAAQ;IAAI;IACzC;KAAE,MAAM;KAAU,QAAQ;IAAI;GAChC;GACA,WAAW;EAG2C,CAAC;CAC3D,GAAG,CAAC,4BAA4B,CAAC;CAEjC,MAAM,eAAe,aAClB,gBAAwB;EACvB,IAAI,aAKF,WAHsB,KACnB,OAAO,WAAW,EAClB,KAAK,WAAW,OAAO,IACH,CAAC;OAExB,WAAW,4BAA4B;CAE3C,GACA,CAAC,MAAM,4BAA4B,CACrC;CAEA,IAAI,QACF,aAAa,iBAAiB,cAAc,MAAM,IAAI,OAAO,YAAY;CAG3E,OACE,oBAAC,OAAD;EACE,WAAU;EACV,cAAY,oBAAoB;YAEhC,qBAAC,UAAD;GAAU,YAAY;aAAtB,CACE,oBAAC,SAAS,SAAV;IAAkB,YAAY;IAAqB,OAAM;cACvD,qBAAC,OAAD;KAAK,WAAU;eAAf,CACE,oBAAC,OAAD;MAAK,WAAU;gBAAoB;KAAgB,IACnD,oBAAC,cAAD,EAAc,WAAU,kBAAmB,EACxC;;GACW,IAElB,oBAAC,SAAS,OAAV;IACE,YAAY;IACZ;IACA;IACA,OAAM;IACN,GAAI;cAEJ,qBAAC,WAAD;KACE,WAAU;KACV,WAAU;KACV,MAAK;KACL,cAAa;KACb,cAAY,kBAAkB;eALhC,CAOE,oBAAC,OAAD;MAAK,WAAU;gBACb,oBAAC,OAAD;OACE,MAAK;OACL,cAAY,YAAY,UAAU;OAClC,aAAa,YAAY,YAAY;OACrC,WAAW,MAAM,aAAa,EAAE,OAAO,KAAK;OAC5C,KAAK;MACN;KACE,IACL,oBAAC,MAAD;MAAI,WAAU;gBACX,QAAQ,KACN,EAAE,QAAQ,YAAY,mBAAmB,oBACxC,oBAAC,MAAD;OAAI,WAAU;iBACZ,oBAAC,QAAD;QACE,eAAe,UAAU,UAAU;QACnC,OAAO,GAAG,SAAS,GAAG;QACtB,UACE,EAAE,oBAAoB,YAAY,SAAS,UAAU;QAEvD,UAAU,WAAW;QACrB,SAAQ;QACR,OAAM;QACN;QACA,WAAU;kBAEV,qBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,qBAAC,OAAD;UAAK,WAAU;oBAAf,CACE,oBAAC,QAAD;WACE,KAAK,eAAe,UAAU;WAC9B,MAAM;WACN;qBAEC;UACG,IACN,oBAAC,QAAD;WACE,WAAU;WACV;qBAEC;UACG,EACH;aACL,oBAAC,QAAD;UAAM,WAAU;oBACb,WAAW,YAAY;SACpB,EACH;;OACC;MACN,GAlC6B,UAkC7B,CAER;KACE,EACK;;GACG,EACR;;CACP;AAET"}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import { cn } from "../../utils/cn.mjs";
|
|
4
|
-
import {
|
|
5
|
-
import { Button, ButtonSize, ButtonVariant } from "../Button/Button.mjs";
|
|
4
|
+
import { Button } from "../Button/Button.mjs";
|
|
6
5
|
import { Link } from "../Link/Link.mjs";
|
|
7
|
-
import {
|
|
6
|
+
import { Container } from "../Container/index.mjs";
|
|
7
|
+
import { Modal } from "../Modal/Modal.mjs";
|
|
8
8
|
import { useState } from "react";
|
|
9
9
|
import { MoveDiagonal } from "lucide-react";
|
|
10
10
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MarkDownIframe.mjs","names":[],"sources":["../../../../src/components/MarkDownRender/MarkDownIframe.tsx"],"sourcesContent":["'use client';\n\nimport { Button
|
|
1
|
+
{"version":3,"file":"MarkDownIframe.mjs","names":[],"sources":["../../../../src/components/MarkDownRender/MarkDownIframe.tsx"],"sourcesContent":["'use client';\n\nimport { Button } from '@components/Button';\nimport { Container } from '@components/Container';\nimport { Link } from '@components/Link';\nimport { Modal } from '@components/Modal';\nimport { cn } from '@utils/cn';\nimport { MoveDiagonal } from 'lucide-react';\nimport { type ComponentProps, type FC, useState } from 'react';\n\nfunction embedLinkMeta(src: string | undefined): {\n href: string;\n label: string;\n} {\n if (!src) return { href: '', label: '' };\n if (/^https?:\\/\\//i.test(src)) {\n try {\n const url = new URL(src);\n return { href: url.href, label: url.host };\n } catch {\n return { href: src, label: src };\n }\n }\n return { href: src, label: src };\n}\n\nexport const MarkDownIframe: FC<ComponentProps<'iframe'>> = (props) => {\n const { src, className, title, ...rest } = props;\n const [isModalOpen, setIsModalOpen] = useState(false);\n const { href, label } = embedLinkMeta(src);\n\n return (\n <Container\n roundedSize=\"2xl\"\n border\n borderColor=\"neutral\"\n className=\"overflow-hidden p-0\"\n gap=\"none\"\n >\n <iframe\n {...rest}\n src={src}\n title={title}\n className={cn(\n 'block max-h-[80vh] min-h-[12rem] w-full border-0',\n className\n )}\n />\n <div className=\"flex items-center justify-between gap-3 px-3 py-1\">\n {href ? (\n <Link\n href={href}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n label=\"\"\n color=\"neutral\"\n className=\"inline-flex min-w-0 max-w-[calc(100%-3rem)] items-center gap-2 text-neutral text-xs underline-offset-2 hover:text-text hover:underline\"\n >\n {label}\n </Link>\n ) : (\n <span className=\"text-neutral text-sm\">Embedded frame</span>\n )}\n <Button\n variant=\"hoverable\"\n size=\"icon-md\"\n onClick={() => setIsModalOpen(true)}\n label=\"Open embedded page in fullscreen\"\n Icon={MoveDiagonal}\n />\n </div>\n\n <Modal\n isOpen={isModalOpen}\n onClose={() => setIsModalOpen(false)}\n size=\"unset\"\n hasCloseButton\n isScrollable\n padding=\"sm\"\n >\n {isModalOpen && src ? (\n <Container\n roundedSize=\"2xl\"\n border\n borderColor=\"neutral\"\n className=\"overflow-hidden p-0\"\n gap=\"none\"\n >\n <iframe\n {...rest}\n src={src}\n title={title ?? 'Embedded content'}\n allowFullScreen\n className=\"block min-h-[82vh] w-full border-0\"\n />\n </Container>\n ) : null}\n </Modal>\n </Container>\n );\n};\n"],"mappings":";;;;;;;;;;;;AAUA,SAAS,cAAc,KAGrB;CACA,IAAI,CAAC,KAAK,OAAO;EAAE,MAAM;EAAI,OAAO;CAAG;CACvC,IAAI,gBAAgB,KAAK,GAAG,GAC1B,IAAI;EACF,MAAM,MAAM,IAAI,IAAI,GAAG;EACvB,OAAO;GAAE,MAAM,IAAI;GAAM,OAAO,IAAI;EAAK;CAC3C,QAAQ;EACN,OAAO;GAAE,MAAM;GAAK,OAAO;EAAI;CACjC;CAEF,OAAO;EAAE,MAAM;EAAK,OAAO;CAAI;AACjC;AAEA,MAAa,kBAAgD,UAAU;CACrE,MAAM,EAAE,KAAK,WAAW,OAAO,GAAG,SAAS;CAC3C,MAAM,CAAC,aAAa,kBAAkB,SAAS,KAAK;CACpD,MAAM,EAAE,MAAM,UAAU,cAAc,GAAG;CAEzC,OACE,qBAAC,WAAD;EACE,aAAY;EACZ;EACA,aAAY;EACZ,WAAU;EACV,KAAI;YALN;GAOE,oBAAC,UAAD;IACE,GAAI;IACC;IACE;IACP,WAAW,GACT,oDACA,SACF;GACD;GACD,qBAAC,OAAD;IAAK,WAAU;cAAf,CACG,OACC,oBAAC,MAAD;KACQ;KACN,QAAO;KACP,KAAI;KACJ,OAAM;KACN,OAAM;KACN,WAAU;eAET;IACG,KAEN,oBAAC,QAAD;KAAM,WAAU;eAAuB;IAAoB,IAE7D,oBAAC,QAAD;KACE,SAAQ;KACR,MAAK;KACL,eAAe,eAAe,IAAI;KAClC,OAAM;KACN,MAAM;IACP,EACE;;GAEL,oBAAC,OAAD;IACE,QAAQ;IACR,eAAe,eAAe,KAAK;IACnC,MAAK;IACL;IACA;IACA,SAAQ;cAEP,eAAe,MACd,oBAAC,WAAD;KACE,aAAY;KACZ;KACA,aAAY;KACZ,WAAU;KACV,KAAI;eAEJ,oBAAC,UAAD;MACE,GAAI;MACC;MACL,OAAO,SAAS;MAChB;MACA,WAAU;KACX;IACQ,KACT;GACC;EACE;;AAEf"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import { cn } from "../../utils/cn.mjs";
|
|
4
|
+
import { Button } from "../Button/Button.mjs";
|
|
4
5
|
import { Container } from "../Container/index.mjs";
|
|
5
|
-
import { Button, ButtonColor, ButtonSize, ButtonVariant } from "../Button/Button.mjs";
|
|
6
6
|
import { useGetElementOrWindow } from "../../hooks/useGetElementOrWindow.mjs";
|
|
7
7
|
import { useScrollBlockage } from "../../hooks/useScrollBlockage/index.mjs";
|
|
8
8
|
import { H3 } from "../Headers/index.mjs";
|
|
@@ -14,17 +14,6 @@ import { motion } from "framer-motion";
|
|
|
14
14
|
import { createPortal } from "react-dom";
|
|
15
15
|
|
|
16
16
|
//#region src/components/Modal/Modal.tsx
|
|
17
|
-
/**
|
|
18
|
-
* Enumeration of available modal sizes
|
|
19
|
-
*/
|
|
20
|
-
let ModalSize = /* @__PURE__ */ function(ModalSize) {
|
|
21
|
-
ModalSize["SM"] = "sm";
|
|
22
|
-
ModalSize["MD"] = "md";
|
|
23
|
-
ModalSize["LG"] = "lg";
|
|
24
|
-
ModalSize["XL"] = "xl";
|
|
25
|
-
ModalSize["UNSET"] = "unset";
|
|
26
|
-
return ModalSize;
|
|
27
|
-
}({});
|
|
28
17
|
const modalVariants = cva("flex cursor-default flex-col overflow-hidden shadow-sm", {
|
|
29
18
|
variants: { size: {
|
|
30
19
|
sm: "h-auto max-h-[30vh] w-[95vw] max-w-xl",
|
|
@@ -77,7 +66,7 @@ const MotionModal = motion.create(Container);
|
|
|
77
66
|
* onClose={onClose}
|
|
78
67
|
* title="Confirm Action"
|
|
79
68
|
* hasCloseButton
|
|
80
|
-
* size=
|
|
69
|
+
* size="lg"
|
|
81
70
|
* >
|
|
82
71
|
* <div>
|
|
83
72
|
* <p>Are you sure you want to continue?</p>
|
|
@@ -198,5 +187,5 @@ const Modal = ({ children, isOpen, container, onClose, hasCloseButton = false, t
|
|
|
198
187
|
};
|
|
199
188
|
|
|
200
189
|
//#endregion
|
|
201
|
-
export { Modal
|
|
190
|
+
export { Modal };
|
|
202
191
|
//# sourceMappingURL=Modal.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Modal.mjs","names":["m"],"sources":["../../../../src/components/Modal/Modal.tsx"],"sourcesContent":["'use client';\n\nimport { useGetElementOrWindow, useScrollBlockage } from '@hooks/index';\nimport { cn } from '@utils/cn';\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 { 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 SM = 'sm',\n MD = 'md',\n LG = 'lg',\n XL = 'xl',\n UNSET = 'unset',\n}\n\ntype ModalProps = {\n children: ReactNode;\n isOpen: boolean;\n onClose?: () => void;\n container?: HTMLElement;\n disableScroll?: boolean;\n hasCloseButton?: boolean;\n title?: ReactNode;\n size?: ModalSize | `${ModalSize}`;\n /**\n * Defines if the modal content area is scrollable.\n */\n isScrollable?: boolean | 'x' | 'y';\n} & Partial<\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\nconst modalVariants = cva(\n 'flex cursor-default flex-col overflow-hidden shadow-sm',\n {\n variants: {\n size: {\n sm: 'h-auto max-h-[30vh] w-[95vw] max-w-xl',\n md: 'h-auto max-h-[50vh] w-[95vw] max-w-xl',\n lg: 'h-auto max-h-[70vh] w-[95vw] max-w-4xl',\n xl: 'h-auto max-h-[95vh] w-[95vw] max-w-6xl',\n unset: 'h-auto max-h-[95vh] w-[95vw]',\n },\n },\n defaultVariants: {\n size: 'unset',\n },\n }\n);\n\n// Mapped from Container/index.tsx to apply internally\nconst contentPaddingVariants = {\n none: 'p-0',\n sm: 'px-2 py-4',\n md: 'px-4 py-6',\n lg: 'px-6 py-8',\n xl: 'px-8 py-10',\n '2xl': 'px-10 py-12',\n};\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 onClose,\n hasCloseButton = false,\n title,\n size = ModalSize.MD,\n className,\n isScrollable = false, // Enable the scroll of the content\n disableScroll = true, // Disable the scroll of the background\n padding = 'none', // Extract padding here\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 document.addEventListener('keydown', handleEscape);\n return () => {\n document.removeEventListener('keydown', handleEscape);\n };\n }, [isOpen, onClose]);\n\n if (!containerElement) return <></>;\n\n const hasTitle = Boolean(title);\n\n // Determine the class for the inner content based on the padding prop\n const contentPaddingClass =\n contentPaddingVariants[\n (padding as keyof typeof contentPaddingVariants) || 'none'\n ];\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-hidden 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({ size, className })}\n role=\"dialog\"\n aria-modal\n roundedSize=\"4xl\"\n // Force the outer container to have no padding so scrollbars hit the edge\n padding=\"none\"\n {...props}\n >\n {/* HEADER SECTION */}\n <div\n className={cn(\n 'relative flex-none px-4 pt-4',\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=\"mb-2 ml-1 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\n {/* SCROLLABLE WRAPPER - Full width, no padding */}\n <div\n className={cn(\n 'flex min-h-0 w-full flex-1 flex-col',\n // Scrollbars will now appear at the very edge of this div (the modal edge)\n isScrollable === true && 'overflow-auto',\n isScrollable === 'y' && 'overflow-y-auto overflow-x-hidden',\n isScrollable === 'x' && 'overflow-x-auto overflow-y-hidden',\n !isScrollable && 'overflow-visible'\n )}\n >\n {/* CONTENT PADDING WRAPPER */}\n {/* We apply the padding class here, effectively putting content inside the scroll area */}\n <div\n className={cn(\n 'flex size-full flex-1 flex-col',\n contentPaddingClass\n )}\n >\n {children}\n </div>\n </div>\n </MotionModal>\n </m.div>,\n containerElement\n );\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAgBA,IAAY,YAAL;CACL;CACA;CACA;CACA;CACA;;AACF;AA8BA,MAAM,gBAAgB,IACpB,0DACA;CACE,UAAU,EACR,MAAM;EACJ,IAAI;EACJ,IAAI;EACJ,IAAI;EACJ,IAAI;EACJ,OAAO;CACT,EACF;CACA,iBAAiB,EACf,MAAM,QACR;AACF,CACF;AAGA,MAAM,yBAAyB;CAC7B,MAAM;CACN,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,OAAO;AACT;AAEA,MAAM,cAAcA,OAAE,OAAO,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqEtC,MAAa,SAAyB,EACpC,UACA,QACA,WACA,SACA,iBAAiB,OACjB,OACA,aACA,WACA,eAAe,OACf,gBAAgB,MAChB,UAAU,QACV,GAAG,YACC;CACJ,MAAM,mBAAmB,sBAAsB,SAAS;CAExD,kBAAkB;EAAE,KAAK;EAAS,eAAe,UAAU;CAAc,CAAC;CAE1E,gBAAgB;EACd,MAAM,gBAAgB,UAAyB;GAC7C,IAAI,MAAM,QAAQ,YAAY,UAAU,SACtC,QAAQ;EAEZ;EACA,SAAS,iBAAiB,WAAW,YAAY;EACjD,aAAa;GACX,SAAS,oBAAoB,WAAW,YAAY;EACtD;CACF,GAAG,CAAC,QAAQ,OAAO,CAAC;CAEpB,IAAI,CAAC,kBAAkB,OAAO,iCAAI;CAElC,MAAM,WAAW,QAAQ,KAAK;CAG9B,MAAM,sBACJ,uBACG,WAAmD;CAGxD,OAAO,aACL,oBAACA,OAAE,KAAH;EACE,WAAU;EACV,SAAS,SAAS,YAAY;EAC9B,UAAU;GACR,SAAS;IACP,SAAS;IACT,YAAY;IACZ,YAAY;KAAE,UAAU;KAAK,MAAM;IAAiB;GACtD;GACA,WAAW;IACT,SAAS;IACT,YAAY;IACZ,YAAY;KAAE,UAAU;KAAK,MAAM;IAAgB;GACrD;EACF;EACA,UAAU,MAAM;GACd,EAAE,gBAAgB;GAClB,UAAU;EACZ;EACA,eAAa,CAAC;YAEd,qBAAC,aAAD;GACE,UAAU,MAAM,EAAE,gBAAgB;GAClC,SAAS,EAAE,OAAO,SAAS,KAAM,EAAE;GACnC,SAAS,EAAE,OAAO,SAAS,IAAI,GAAI;GACnC,YAAY,EAAE,UAAU,GAAI;GAC5B,WAAW,cAAc;IAAE;IAAM;GAAU,CAAC;GAC5C,MAAK;GACL;GACA,aAAY;GAEZ,SAAQ;GACR,GAAI;aAXN,CAcE,qBAAC,OAAD;IACE,WAAW,GACT,gCACA,kBAAkB,WACd,qBACA,iBACE,qBACA,WACE,iBACA,QACV;cAVF,CAYG,YACC,oBAAC,IAAD;KAAI,WAAU;eACX;IACC,IAEL,kBACC,oBAAC,QAAD;KACE;KACA;KACA,OAAM;KACN,WAAU;KACV,UAAU,MAAM;MACd,EAAE,gBAAgB;MAClB,UAAU;KACZ;KACA,MAAM;KACN;IACD,EAEA;OAGL,oBAAC,OAAD;IACE,WAAW,GACT,uCAEA,iBAAiB,QAAQ,iBACzB,iBAAiB,OAAO,qCACxB,iBAAiB,OAAO,qCACxB,CAAC,gBAAgB,kBACnB;cAIA,oBAAC,OAAD;KACE,WAAW,GACT,kCACA,mBACF;KAEC;IACE;GACF,EACM;;CACR,IACP,gBACF;AACF"}
|
|
1
|
+
{"version":3,"file":"Modal.mjs","names":["m"],"sources":["../../../../src/components/Modal/Modal.tsx"],"sourcesContent":["'use client';\n\nimport { useGetElementOrWindow, useScrollBlockage } from '@hooks/index';\nimport { cn } from '@utils/cn';\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 { Button } from '../Button';\nimport { Container, type ContainerProps } from '../Container';\nimport { H3 } from '../Headers';\n\n/**\n * Enumeration of available modal sizes\n */\nexport type ModalSize = \n | 'sm' |\n 'md' |\n 'lg' |\n 'xl' |\n 'unset';\n\ntype ModalProps = {\n children: ReactNode;\n isOpen: boolean;\n onClose?: () => void;\n container?: HTMLElement;\n disableScroll?: boolean;\n hasCloseButton?: boolean;\n title?: ReactNode;\n size?: ModalSize | `${ModalSize}`;\n /**\n * Defines if the modal content area is scrollable.\n */\n isScrollable?: boolean | 'x' | 'y';\n} & Partial<\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\nconst modalVariants = cva(\n 'flex cursor-default flex-col overflow-hidden shadow-sm',\n {\n variants: {\n size: {\n sm: 'h-auto max-h-[30vh] w-[95vw] max-w-xl',\n md: 'h-auto max-h-[50vh] w-[95vw] max-w-xl',\n lg: 'h-auto max-h-[70vh] w-[95vw] max-w-4xl',\n xl: 'h-auto max-h-[95vh] w-[95vw] max-w-6xl',\n unset: 'h-auto max-h-[95vh] w-[95vw]',\n },\n },\n defaultVariants: {\n size: 'unset',\n },\n }\n);\n\n// Mapped from Container/index.tsx to apply internally\nconst contentPaddingVariants = {\n none: 'p-0',\n sm: 'px-2 py-4',\n md: 'px-4 py-6',\n lg: 'px-6 py-8',\n xl: 'px-8 py-10',\n '2xl': 'px-10 py-12',\n};\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=\"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 onClose,\n hasCloseButton = false,\n title,\n size = 'md',\n className,\n isScrollable = false, // Enable the scroll of the content\n disableScroll = true, // Disable the scroll of the background\n padding = 'none', // Extract padding here\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 document.addEventListener('keydown', handleEscape);\n return () => {\n document.removeEventListener('keydown', handleEscape);\n };\n }, [isOpen, onClose]);\n\n if (!containerElement) return <></>;\n\n const hasTitle = Boolean(title);\n\n // Determine the class for the inner content based on the padding prop\n const contentPaddingClass =\n contentPaddingVariants[\n (padding as keyof typeof contentPaddingVariants) || 'none'\n ];\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-hidden 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({ size, className })}\n role=\"dialog\"\n aria-modal\n roundedSize=\"4xl\"\n // Force the outer container to have no padding so scrollbars hit the edge\n padding=\"none\"\n {...props}\n >\n {/* HEADER SECTION */}\n <div\n className={cn(\n 'relative flex-none px-4 pt-4',\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=\"mb-2 ml-1 flex items-center justify-center font-bold text-lg\">\n {title}\n </H3>\n )}\n {hasCloseButton && (\n <Button\n variant=\"hoverable\"\n color=\"text\"\n label=\"Close modal\"\n className=\"ml-auto\"\n onClick={(e) => {\n e.stopPropagation();\n onClose?.();\n }}\n Icon={X}\n size=\"icon-md\"\n />\n )}\n </div>\n\n {/* SCROLLABLE WRAPPER - Full width, no padding */}\n <div\n className={cn(\n 'flex min-h-0 w-full flex-1 flex-col',\n // Scrollbars will now appear at the very edge of this div (the modal edge)\n isScrollable === true && 'overflow-auto',\n isScrollable === 'y' && 'overflow-y-auto overflow-x-hidden',\n isScrollable === 'x' && 'overflow-x-auto overflow-y-hidden',\n !isScrollable && 'overflow-visible'\n )}\n >\n {/* CONTENT PADDING WRAPPER */}\n {/* We apply the padding class here, effectively putting content inside the scroll area */}\n <div\n className={cn(\n 'flex size-full flex-1 flex-col',\n contentPaddingClass\n )}\n >\n {children}\n </div>\n </div>\n </MotionModal>\n </m.div>,\n containerElement\n );\n};\n"],"mappings":";;;;;;;;;;;;;;;;AAmDA,MAAM,gBAAgB,IACpB,0DACA;CACE,UAAU,EACR,MAAM;EACJ,IAAI;EACJ,IAAI;EACJ,IAAI;EACJ,IAAI;EACJ,OAAO;CACT,EACF;CACA,iBAAiB,EACf,MAAM,QACR;AACF,CACF;AAGA,MAAM,yBAAyB;CAC7B,MAAM;CACN,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,OAAO;AACT;AAEA,MAAM,cAAcA,OAAE,OAAO,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqEtC,MAAa,SAAyB,EACpC,UACA,QACA,WACA,SACA,iBAAiB,OACjB,OACA,OAAO,MACP,WACA,eAAe,OACf,gBAAgB,MAChB,UAAU,QACV,GAAG,YACC;CACJ,MAAM,mBAAmB,sBAAsB,SAAS;CAExD,kBAAkB;EAAE,KAAK;EAAS,eAAe,UAAU;CAAc,CAAC;CAE1E,gBAAgB;EACd,MAAM,gBAAgB,UAAyB;GAC7C,IAAI,MAAM,QAAQ,YAAY,UAAU,SACtC,QAAQ;EAEZ;EACA,SAAS,iBAAiB,WAAW,YAAY;EACjD,aAAa;GACX,SAAS,oBAAoB,WAAW,YAAY;EACtD;CACF,GAAG,CAAC,QAAQ,OAAO,CAAC;CAEpB,IAAI,CAAC,kBAAkB,OAAO,iCAAI;CAElC,MAAM,WAAW,QAAQ,KAAK;CAG9B,MAAM,sBACJ,uBACG,WAAmD;CAGxD,OAAO,aACL,oBAACA,OAAE,KAAH;EACE,WAAU;EACV,SAAS,SAAS,YAAY;EAC9B,UAAU;GACR,SAAS;IACP,SAAS;IACT,YAAY;IACZ,YAAY;KAAE,UAAU;KAAK,MAAM;IAAiB;GACtD;GACA,WAAW;IACT,SAAS;IACT,YAAY;IACZ,YAAY;KAAE,UAAU;KAAK,MAAM;IAAgB;GACrD;EACF;EACA,UAAU,MAAM;GACd,EAAE,gBAAgB;GAClB,UAAU;EACZ;EACA,eAAa,CAAC;YAEd,qBAAC,aAAD;GACE,UAAU,MAAM,EAAE,gBAAgB;GAClC,SAAS,EAAE,OAAO,SAAS,KAAM,EAAE;GACnC,SAAS,EAAE,OAAO,SAAS,IAAI,GAAI;GACnC,YAAY,EAAE,UAAU,GAAI;GAC5B,WAAW,cAAc;IAAE;IAAM;GAAU,CAAC;GAC5C,MAAK;GACL;GACA,aAAY;GAEZ,SAAQ;GACR,GAAI;aAXN,CAcE,qBAAC,OAAD;IACE,WAAW,GACT,gCACA,kBAAkB,WACd,qBACA,iBACE,qBACA,WACE,iBACA,QACV;cAVF,CAYG,YACC,oBAAC,IAAD;KAAI,WAAU;eACX;IACC,IAEL,kBACC,oBAAC,QAAD;KACE,SAAQ;KACR,OAAM;KACN,OAAM;KACN,WAAU;KACV,UAAU,MAAM;MACd,EAAE,gBAAgB;MAClB,UAAU;KACZ;KACA,MAAM;KACN,MAAK;IACN,EAEA;OAGL,oBAAC,OAAD;IACE,WAAW,GACT,uCAEA,iBAAiB,QAAQ,iBACzB,iBAAiB,OAAO,qCACxB,iBAAiB,OAAO,qCACxB,CAAC,gBAAgB,kBACnB;cAIA,oBAAC,OAAD;KACE,WAAW,GACT,kCACA,mBACF;KAEC;IACE;GACF,EACM;;CACR,IACP,gBACF;AACF"}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { Modal
|
|
1
|
+
import { Modal } from "./Modal.mjs";
|
|
2
2
|
|
|
3
|
-
export { Modal
|
|
3
|
+
export { Modal };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DesktopNavbar.mjs","names":[],"sources":["../../../../src/components/Navbar/DesktopNavbar.tsx"],"sourcesContent":["'use client';\n\nimport type { ReactElement, ReactNode } from 'react';\nimport {
|
|
1
|
+
{"version":3,"file":"DesktopNavbar.mjs","names":[],"sources":["../../../../src/components/Navbar/DesktopNavbar.tsx"],"sourcesContent":["'use client';\n\nimport type { ReactElement, ReactNode } from 'react';\nimport { TabSelector, type TabSelectorItemProps } from '../TabSelector';\n\n/**\n * Props for the DesktopNavbar component\n * @template T - The tab props type extending TabProps\n */\ntype DesktopNavbarProps<T extends TabSelectorItemProps> = {\n /** Logo component or element displayed on the left side */\n logo: ReactNode;\n /** Array of navigation sections as tab elements */\n sections: ReactElement<T>[];\n /** Right-aligned items (e.g., user menu, search, settings) */\n rightItems?: ReactNode;\n /** Currently selected tab key for highlighting active state */\n selectedChoice: T['key'];\n};\n\n/**\n * Desktop Navigation Bar Component\n *\n * A horizontal navigation bar optimized for desktop and tablet viewports.\n * Features a sticky header with backdrop blur, left-aligned logo, center navigation tabs,\n * and right-aligned utility items.\n *\n * Features:\n * - Sticky positioning with z-index layering (z-50)\n * - Semi-transparent backdrop with blur effect for modern glass-morphism design\n * - Responsive spacing that adapts across screen sizes\n * - Horizontal scrollable tabs for overflow content\n * - Left-to-right layout: Logo → Navigation → Utility Items\n * - Integrated with TabSelector for consistent tab behavior\n *\n * Layout Structure:\n * ```\n * [Logo] -------- [Nav Tab 1] [Nav Tab 2] [Nav Tab 3] -------- [Right Items]\n * ```\n *\n * Responsive Behavior:\n * - Base: 2vw margin-left, 3-unit gap between tabs\n * - Large (≥1024px): 5vw margin-left, 3-unit gap between tabs\n * - Extra Large (≥1280px): 10vw margin-left, 6-unit gap between tabs\n * - Right items: 2-unit gap on mobile, 4-unit gap on medium screens\n *\n * Styling Features:\n * - Semi-transparent card background (`bg-card/80`)\n * - Subtle shadow with controlled blur (`shadow-[0_0_10px_-15px_rgba(0,0,0,0.3)]`)\n * - Backdrop blur effect for content behind navbar\n * - Horizontal overflow scrolling for tab content\n *\n * @example\n * Basic usage:\n * ```tsx\n * const navigationTabs = [\n * { key: 'home', label: 'Home', href: '/' },\n * { key: 'products', label: 'Products', href: '/products' },\n * { key: 'about', label: 'About', href: '/about' }\n * ];\n *\n * <DesktopNavbar\n * logo={<CompanyLogo />}\n * sections={navigationTabs}\n * selectedChoice=\"home\"\n * rightItems={<UserProfileMenu />}\n * />\n * ```\n *\n * @example\n * With multiple right items:\n * ```tsx\n * <DesktopNavbar\n * logo={<Logo />}\n * sections={navSections}\n * selectedChoice={currentPage}\n * rightItems={\n * <>\n * <SearchButton />\n * <NotificationBell />\n * <UserMenu />\n * </>\n * }\n * />\n * ```\n *\n * @template T - Tab properties type extending TabProps for type safety\n * @param props - DesktopNavbar component props\n * @returns Horizontal desktop navigation JSX element\n */\nexport const DesktopNavbar = <T extends TabSelectorItemProps>({\n logo,\n sections,\n rightItems,\n selectedChoice,\n}: DesktopNavbarProps<T>) => (\n <nav className=\"sticky top-0 z-50 flex w-full items-center bg-card/80 px-4 py-3 shadow-[0_0_10px_-15px_rgba(0,0,0,0.3)] backdrop-blur\">\n {logo}\n\n <TabSelector\n selectedChoice={selectedChoice}\n className=\"ml-[2vw] h-auto gap-3 overflow-x-auto text-neutral tracking-wide lg:ml-[5vw] lg:gap-3 xl:ml-[10vw] xl:gap-6\"\n tabs={sections}\n hoverable\n color=\"text\"\n />\n\n <div className=\"mr-4 flex items-center justify-end gap-2 md:gap-4\">\n {rightItems}\n </div>\n </nav>\n);\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA0FA,MAAa,iBAAiD,EAC5D,MACA,UACA,YACA,qBAEA,qBAAC,OAAD;CAAK,WAAU;WAAf;EACG;EAED,oBAAC,aAAD;GACkB;GAChB,WAAU;GACV,MAAM;GACN;GACA,OAAM;EACP;EAED,oBAAC,OAAD;GAAK,WAAU;aACZ;EACE;CACF"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import { cn } from "../../utils/cn.mjs";
|
|
4
|
-
import { Button
|
|
4
|
+
import { Button } from "../Button/Button.mjs";
|
|
5
5
|
import { useItemSelector } from "../../hooks/useItemSelector.mjs";
|
|
6
6
|
import { useEffect, useRef } from "react";
|
|
7
7
|
import { cva } from "class-variance-authority";
|
|
@@ -34,18 +34,6 @@ const paginationVariants = cva("flex items-center justify-center gap-1", {
|
|
|
34
34
|
variant: "default"
|
|
35
35
|
}
|
|
36
36
|
});
|
|
37
|
-
let PaginationSize = /* @__PURE__ */ function(PaginationSize) {
|
|
38
|
-
PaginationSize["SM"] = "sm";
|
|
39
|
-
PaginationSize["MD"] = "md";
|
|
40
|
-
PaginationSize["LG"] = "lg";
|
|
41
|
-
return PaginationSize;
|
|
42
|
-
}({});
|
|
43
|
-
let PaginationVariant = /* @__PURE__ */ function(PaginationVariant) {
|
|
44
|
-
PaginationVariant["DEFAULT"] = "default";
|
|
45
|
-
PaginationVariant["BORDERED"] = "bordered";
|
|
46
|
-
PaginationVariant["GHOST"] = "ghost";
|
|
47
|
-
return PaginationVariant;
|
|
48
|
-
}({});
|
|
49
37
|
const generatePageNumbers = (currentPage, totalPages, maxVisiblePages) => {
|
|
50
38
|
if (totalPages <= maxVisiblePages) return Array.from({ length: totalPages }, (_, i) => i + 1);
|
|
51
39
|
const pages = [];
|
|
@@ -174,5 +162,5 @@ const Pagination = ({ currentPage, totalPages, onPageChange, showFirstLast = fal
|
|
|
174
162
|
};
|
|
175
163
|
|
|
176
164
|
//#endregion
|
|
177
|
-
export { Pagination,
|
|
165
|
+
export { Pagination, paginationVariants };
|
|
178
166
|
//# sourceMappingURL=Pagination.mjs.map
|