@intlayer/design-system 7.5.0-canary.0 → 7.5.0-canary.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/components/Avatar/index.mjs +5 -28
- package/dist/esm/components/Avatar/index.mjs.map +1 -1
- package/dist/esm/components/Badge/index.mjs +1 -1
- package/dist/esm/components/Badge/index.mjs.map +1 -1
- package/dist/esm/components/Breadcrumb/index.mjs +1 -0
- package/dist/esm/components/Breadcrumb/index.mjs.map +1 -1
- package/dist/esm/components/Button/Button.mjs +15 -11
- package/dist/esm/components/Button/Button.mjs.map +1 -1
- package/dist/esm/components/Container/index.mjs +7 -4
- package/dist/esm/components/Container/index.mjs.map +1 -1
- package/dist/esm/components/DictionaryFieldEditor/DictionaryFieldEditor.mjs +2 -4
- package/dist/esm/components/DictionaryFieldEditor/DictionaryFieldEditor.mjs.map +1 -1
- package/dist/esm/components/DropDown/index.mjs +6 -2
- package/dist/esm/components/DropDown/index.mjs.map +1 -1
- package/dist/esm/components/Form/elements/CheckboxElement.mjs +8 -4
- package/dist/esm/components/Form/elements/CheckboxElement.mjs.map +1 -1
- package/dist/esm/components/Form/elements/OTPElement.mjs +1 -5
- package/dist/esm/components/Form/elements/OTPElement.mjs.map +1 -1
- package/dist/esm/components/Input/Input.mjs.map +1 -1
- package/dist/esm/components/Input/OTPInput.mjs +1 -2
- package/dist/esm/components/Input/OTPInput.mjs.map +1 -1
- package/dist/esm/components/KeyboardShortcut/KeyboardShortcut.mjs +225 -0
- package/dist/esm/components/KeyboardShortcut/KeyboardShortcut.mjs.map +1 -0
- package/dist/esm/components/KeyboardShortcut/index.mjs +3 -0
- package/dist/esm/components/Link/Link.mjs +5 -10
- package/dist/esm/components/Link/Link.mjs.map +1 -1
- 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 +83 -43
- package/dist/esm/components/Pagination/Pagination.mjs.map +1 -1
- package/dist/esm/components/Popover/static.mjs +3 -6
- package/dist/esm/components/Popover/static.mjs.map +1 -1
- package/dist/esm/components/SwitchSelector/index.mjs +2 -2
- package/dist/esm/components/SwitchSelector/index.mjs.map +1 -1
- package/dist/esm/components/Tag/index.mjs +2 -2
- package/dist/esm/components/Tag/index.mjs.map +1 -1
- package/dist/esm/components/Terminal/Terminal.mjs +4 -1
- package/dist/esm/components/Terminal/Terminal.mjs.map +1 -1
- package/dist/esm/components/Terminal/terminal.content.mjs +51 -0
- package/dist/esm/components/Terminal/terminal.content.mjs.map +1 -0
- package/dist/esm/components/index.mjs +2 -1
- package/dist/esm/hooks/index.mjs +2 -2
- package/dist/esm/hooks/reactQuery.mjs +8 -1
- package/dist/esm/hooks/reactQuery.mjs.map +1 -1
- package/dist/esm/hooks/useItemSelector.mjs +51 -28
- package/dist/esm/hooks/useItemSelector.mjs.map +1 -1
- package/dist/esm/libs/auth.mjs +9 -3
- package/dist/esm/libs/auth.mjs.map +1 -1
- package/dist/types/components/Avatar/index.d.ts.map +1 -1
- package/dist/types/components/Badge/index.d.ts.map +1 -1
- package/dist/types/components/Breadcrumb/breadcrumb.content.d.ts +3 -3
- package/dist/types/components/Breadcrumb/index.d.ts.map +1 -1
- package/dist/types/components/Browser/Browser.content.d.ts +5 -5
- package/dist/types/components/Button/Button.d.ts +1 -1
- package/dist/types/components/Button/Button.d.ts.map +1 -1
- package/dist/types/components/CollapsibleTable/CollapsibleTable.d.ts +2 -2
- package/dist/types/components/CollapsibleTable/CollapsibleTable.d.ts.map +1 -1
- package/dist/types/components/Command/index.d.ts +17 -17
- package/dist/types/components/Command/index.d.ts.map +1 -1
- package/dist/types/components/Container/index.d.ts +12 -10
- package/dist/types/components/Container/index.d.ts.map +1 -1
- package/dist/types/components/CopyButton/CopyButton.content.d.ts +3 -3
- package/dist/types/components/DictionaryFieldEditor/DictionaryCreationForm/dictionaryCreationForm.content.d.ts +25 -25
- package/dist/types/components/DictionaryFieldEditor/DictionaryCreationForm/useDictionaryFormSchema.content.d.ts +9 -9
- package/dist/types/components/DictionaryFieldEditor/DictionaryCreationForm/useDictionaryFormSchema.content.d.ts.map +1 -1
- package/dist/types/components/DictionaryFieldEditor/DictionaryDetails/dictionaryDetails.content.d.ts +33 -33
- package/dist/types/components/DictionaryFieldEditor/DictionaryDetails/useDictionaryDetailsSchema.content.d.ts +25 -25
- package/dist/types/components/DictionaryFieldEditor/DictionaryFieldEditor.d.ts.map +1 -1
- package/dist/types/components/DictionaryFieldEditor/NavigationView/navigationViewNode.content.d.ts +25 -25
- package/dist/types/components/DictionaryFieldEditor/SaveForm/saveForm.content.d.ts +33 -33
- package/dist/types/components/DictionaryFieldEditor/StructureView/structureView.content.d.ts +9 -9
- package/dist/types/components/DictionaryFieldEditor/VersionSwitcherDropDown/versionSwitcherDropDown.content.d.ts +7 -7
- package/dist/types/components/DictionaryFieldEditor/VersionSwitcherDropDown/versionSwitcherDropDown.content.d.ts.map +1 -1
- package/dist/types/components/DictionaryFieldEditor/dictionaryFieldEditor.content.d.ts +5 -5
- package/dist/types/components/DictionaryFieldEditor/nodeTypeSelector.content.d.ts +31 -31
- package/dist/types/components/ExpandCollapse/expandCollapse.content.d.ts +3 -3
- package/dist/types/components/Form/FormBase.d.ts +2 -2
- package/dist/types/components/Form/FormBase.d.ts.map +1 -1
- package/dist/types/components/Form/FormField.d.ts +2 -2
- package/dist/types/components/Form/FormField.d.ts.map +1 -1
- package/dist/types/components/Form/FormItem.d.ts +2 -2
- package/dist/types/components/Form/FormItem.d.ts.map +1 -1
- package/dist/types/components/Form/elements/CheckboxElement.d.ts.map +1 -1
- package/dist/types/components/Form/elements/EditableFieldTextAreaElement.d.ts +2 -2
- package/dist/types/components/Form/elements/FormElement.d.ts +2 -2
- package/dist/types/components/Form/elements/MultiselectElement.d.ts +2 -2
- package/dist/types/components/Form/elements/OTPElement.d.ts +2 -2
- package/dist/types/components/Form/elements/OTPElement.d.ts.map +1 -1
- package/dist/types/components/Form/elements/SelectElement.d.ts +2 -2
- package/dist/types/components/Form/elements/SwitchSelectorElement.d.ts +2 -2
- package/dist/types/components/IDE/CodeContext.d.ts +2 -2
- package/dist/types/components/IDE/FileTree.d.ts.map +1 -1
- package/dist/types/components/IDE/code.content.d.ts +5 -5
- package/dist/types/components/IDE/copyCode.content.d.ts +5 -5
- package/dist/types/components/Input/Checkbox.d.ts +3 -3
- package/dist/types/components/Input/Checkbox.d.ts.map +1 -1
- package/dist/types/components/Input/Input.d.ts +3 -3
- package/dist/types/components/Input/Input.d.ts.map +1 -1
- package/dist/types/components/Input/OTPInput.d.ts +7 -9
- package/dist/types/components/Input/OTPInput.d.ts.map +1 -1
- package/dist/types/components/Input/SearchInput.d.ts +2 -2
- package/dist/types/components/Input/SearchInput.d.ts.map +1 -1
- package/dist/types/components/KeyboardShortcut/KeyboardShortcut.d.ts +90 -0
- package/dist/types/components/KeyboardShortcut/KeyboardShortcut.d.ts.map +1 -0
- package/dist/types/components/KeyboardShortcut/index.d.ts +2 -0
- package/dist/types/components/Link/Link.d.ts +3 -3
- package/dist/types/components/Loader/index.content.d.ts +3 -3
- package/dist/types/components/Loader/index.content.d.ts.map +1 -1
- package/dist/types/components/Loader/spinner.d.ts +2 -2
- package/dist/types/components/Loader/spinner.d.ts.map +1 -1
- package/dist/types/components/LocaleSwitcherContentDropDown/localeSwitcher.content.d.ts +17 -17
- package/dist/types/components/LocaleSwitcherContentDropDown/localeSwitcher.content.d.ts.map +1 -1
- package/dist/types/components/LocaleSwitcherDropDown/localeSwitcher.content.d.ts +13 -13
- package/dist/types/components/LocaleSwitcherDropDown/localeSwitcher.content.d.ts.map +1 -1
- package/dist/types/components/MaxWidthSmoother/index.d.ts +2 -2
- package/dist/types/components/Navbar/Burger.d.ts.map +1 -1
- package/dist/types/components/Navbar/DesktopNavbar.d.ts +2 -2
- package/dist/types/components/Navbar/MobileNavbar.d.ts +2 -2
- package/dist/types/components/Navbar/index.d.ts +2 -2
- package/dist/types/components/Pagination/Pagination.d.ts +3 -3
- package/dist/types/components/Pagination/Pagination.d.ts.map +1 -1
- package/dist/types/components/Pagination/pagination.content.d.ts +11 -11
- package/dist/types/components/Popover/static.d.ts +1 -17
- package/dist/types/components/Popover/static.d.ts.map +1 -1
- package/dist/types/components/Select/Select.d.ts +3 -3
- package/dist/types/components/SocialNetworks/index.d.ts +2 -2
- package/dist/types/components/SocialNetworks/index.d.ts.map +1 -1
- package/dist/types/components/SwitchSelector/index.d.ts +5 -5
- package/dist/types/components/SwitchSelector/index.d.ts.map +1 -1
- package/dist/types/components/Tab/Tab.d.ts +6 -6
- package/dist/types/components/Tab/Tab.d.ts.map +1 -1
- package/dist/types/components/Tab/TabContext.d.ts +2 -2
- package/dist/types/components/TabSelector/TabSelector.d.ts +4 -4
- package/dist/types/components/TabSelector/TabSelector.d.ts.map +1 -1
- package/dist/types/components/Table/table.content.d.ts +3 -3
- package/dist/types/components/Table/table.content.d.ts.map +1 -1
- package/dist/types/components/Tag/index.d.ts +4 -4
- package/dist/types/components/Tag/index.d.ts.map +1 -1
- package/dist/types/components/Terminal/Terminal.d.ts.map +1 -1
- package/dist/types/components/Terminal/terminal.content.d.ts +93 -0
- package/dist/types/components/Terminal/terminal.content.d.ts.map +1 -0
- package/dist/types/components/Toaster/Toast.d.ts +2 -2
- package/dist/types/components/Toaster/Toast.d.ts.map +1 -1
- package/dist/types/components/Toaster/Toaster.d.ts +2 -2
- package/dist/types/components/index.d.ts +3 -1
- package/dist/types/hooks/index.d.ts +2 -2
- package/dist/types/hooks/reactQuery.d.ts +2 -1
- package/dist/types/hooks/reactQuery.d.ts.map +1 -1
- package/dist/types/hooks/useDevice.d.ts.map +1 -1
- package/dist/types/libs/auth.d.ts +1 -0
- package/dist/types/libs/auth.d.ts.map +1 -1
- package/package.json +40 -34
|
@@ -96,8 +96,8 @@ const linkVariants = cva("gap-3 transition-all duration-300 focus-visible:outlin
|
|
|
96
96
|
variant: {
|
|
97
97
|
[`${LinkVariant.DEFAULT}`]: "h-auto justify-start border-inherit bg-current/0 px-1 underline-offset-4 hover:bg-current/0 hover:underline",
|
|
98
98
|
[`${LinkVariant.INVISIBLE_LINK}`]: "h-auto justify-start border-inherit bg-current/0 px-1 underline-offset-4 hover:bg-current/0",
|
|
99
|
-
[`${LinkVariant.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-
|
|
100
|
-
[`${LinkVariant.BUTTON_OUTLINED}`]: "relative flex cursor-pointer flex-row items-center justify-center gap-2 rounded-full border-[1.
|
|
99
|
+
[`${LinkVariant.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",
|
|
100
|
+
[`${LinkVariant.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",
|
|
101
101
|
[`${LinkVariant.HOVERABLE}`]: "block rounded-lg border-none bg-current/0 hover:bg-current/10 aria-[current]:bg-current/5"
|
|
102
102
|
},
|
|
103
103
|
roundedSize: {
|
|
@@ -247,10 +247,8 @@ const Link = (props) => {
|
|
|
247
247
|
const isChildrenString = typeof children === "string";
|
|
248
248
|
const rel = isExternalLink ? "noopener noreferrer nofollow" : void 0;
|
|
249
249
|
const target = isExternalLink ? "_blank" : "_self";
|
|
250
|
-
const href = locale && hrefProp && !isExternalLink && !isPageSection ? getLocalizedUrl(hrefProp, locale) : hrefProp;
|
|
251
|
-
const isButton = variant === "button" || variant === "button-outlined";
|
|
252
250
|
return /* @__PURE__ */ jsxs("a", {
|
|
253
|
-
href,
|
|
251
|
+
href: locale && hrefProp && !isExternalLink && !isPageSection ? getLocalizedUrl(hrefProp, locale) : hrefProp,
|
|
254
252
|
"aria-label": label,
|
|
255
253
|
rel,
|
|
256
254
|
target,
|
|
@@ -261,14 +259,11 @@ const Link = (props) => {
|
|
|
261
259
|
roundedSize,
|
|
262
260
|
underlined,
|
|
263
261
|
size,
|
|
264
|
-
className
|
|
262
|
+
className
|
|
265
263
|
})),
|
|
266
264
|
...otherProps,
|
|
267
265
|
children: [
|
|
268
|
-
|
|
269
|
-
className,
|
|
270
|
-
children
|
|
271
|
-
}) : children,
|
|
266
|
+
children,
|
|
272
267
|
isExternalLink && isChildrenString && /* @__PURE__ */ jsx(ExternalLink, { className: "ml-2 inline-block size-4" }),
|
|
273
268
|
isPageSection && /* @__PURE__ */ jsx(MoveRight, { className: "ml-2 inline-block size-4" })
|
|
274
269
|
]
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Link.mjs","names":["Link: FC<LinkProps>"],"sources":["../../../../src/components/Link/Link.tsx"],"sourcesContent":["import { getLocalizedUrl } from '@intlayer/core';\nimport type { LocalesValues } from '@intlayer/types';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { ExternalLink, MoveRight } from 'lucide-react';\nimport type { AnchorHTMLAttributes, DetailedHTMLProps, FC } from 'react';\nimport { cn } from '../../utils/cn';\n\n/**\n * Visual style variants for Link component\n *\n * @enum {string}\n */\nexport enum LinkVariant {\n /** Default underlined link with hover effects */\n DEFAULT = 'default',\n /** Link without visible underline or hover effects */\n INVISIBLE_LINK = 'invisible-link',\n /** Button-styled link with solid background */\n BUTTON = 'button',\n /** Button-styled link with outlined border */\n BUTTON_OUTLINED = 'button-outlined',\n /** Link with subtle hover background effect */\n HOVERABLE = 'hoverable',\n}\n\n/**\n * Color theme variants for Link component\n *\n * @enum {string}\n */\nexport enum LinkColor {\n /** Primary brand color */\n PRIMARY = 'primary',\n /** Secondary brand color */\n SECONDARY = 'secondary',\n /** Destructive/danger color for critical actions */\n DESTRUCTIVE = 'destructive',\n /** Neutral/muted color for less prominent links */\n NEUTRAL = 'neutral',\n /** Light color for dark backgrounds */\n LIGHT = 'light',\n /** Dark color for light backgrounds */\n DARK = 'dark',\n /** Default text color */\n TEXT = 'text',\n /** Inverse text color for opposite backgrounds */\n TEXT_INVERSE = 'text-inverse',\n /** Error/red color for error states */\n ERROR = 'error',\n /** Success/green color for positive actions */\n SUCCESS = 'success',\n /** Custom color - no default styling applied */\n CUSTOM = 'custom',\n}\n\n/** Available rounded corner sizes for the container */\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\n/**\n * Underline style options for Link component\n *\n * @enum {string}\n */\nexport enum LinkUnderlined {\n /** Default underline behavior based on variant */\n DEFAULT = 'default',\n /** Always show underline */\n TRUE = 'true',\n /** Never show underline */\n FALSE = 'false',\n}\n\n/**\n * Class variance authority configuration for Link component styling\n * Defines the visual appearance based on variant, color, and underline options\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 underline-offset-4 hover:bg-current/0 hover:underline',\n [`${LinkVariant.INVISIBLE_LINK}`]:\n 'h-auto justify-start border-inherit bg-current/0 px-1 underline-offset-4 hover:bg-current/0',\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-6 aria-selected:ring-6',\n\n [`${LinkVariant.BUTTON_OUTLINED}`]:\n 'relative flex cursor-pointer flex-row items-center justify-center gap-2 rounded-full border-[1.5px] border-current text-center font-medium text-text ring-0 *:text-text hover:bg-current/20 hover:ring-6 aria-selected:ring-6',\n\n [`${LinkVariant.HOVERABLE}`]:\n 'block rounded-lg border-none bg-current/0 hover:bg-current/10 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.DESTRUCTIVE}`]: 'text-destructive',\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 // 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 for button (Chrome bug fix: ring-current/20 doesn't work properly)\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.DESTRUCTIVE,\n class: 'ring-destructive/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 color: LinkColor.PRIMARY,\n roundedSize: LinkRoundedSize.MD,\n underlined: LinkUnderlined.DEFAULT,\n size: LinkSize.MD,\n },\n }\n);\n\n/**\n * Props interface for the Link component\n *\n * @interface LinkProps\n * @extends {DetailedHTMLProps<AnchorHTMLAttributes<HTMLAnchorElement>, HTMLAnchorElement>}\n * @extends {VariantProps<typeof linkVariants>}\n */\nexport type LinkProps = DetailedHTMLProps<\n AnchorHTMLAttributes<HTMLAnchorElement>,\n HTMLAnchorElement\n> &\n VariantProps<typeof linkVariants> & {\n /**\n * Accessible label for screen readers (required)\n * Provides context about what the link does or where it leads\n * @example \"Navigate to home page\"\n */\n label: string;\n\n /**\n * Whether this link opens in a new tab/window\n * When true, adds target=\"_blank\" and security attributes\n * Auto-detected for URLs starting with http/https when undefined\n * @default undefined (auto-detect based on href)\n */\n isExternalLink?: boolean;\n\n /**\n * If a link is a page section as '#id'\n * @default false\n */\n isPageSection?: boolean;\n\n /**\n * Whether this link represents the current page/active state\n * Adds aria-current=\"page\" for accessibility\n * @default false\n */\n isActive?: boolean;\n\n /**\n * Locale for internationalized URLs\n * When provided, URLs are automatically localized using Intlayer\n * @example 'fr', 'es', 'en'\n */\n locale?: LocalesValues;\n };\n\n/**\n * Utility function to determine if a link should be treated as external\n *\n * @param props - Link component props containing href and isExternalLink\n * @returns {boolean} True if the link should open externally\n *\n * @example\n * ```tsx\n * checkIsExternalLink({ href: '[https://example.com](https://example.com)' }) // true\n * checkIsExternalLink({ href: '/internal-page' }) // false\n * checkIsExternalLink({ href: '/page', isExternalLink: true }) // true\n * ```\n */\nexport const checkIsExternalLink = ({\n href,\n isExternalLink: isExternalLinkProp,\n}: LinkProps): boolean => {\n const isValidHref = typeof href === 'string' && href.trim() !== '';\n const isExternalLink =\n isExternalLinkProp === true ||\n (typeof isExternalLinkProp === 'undefined' &&\n isValidHref &&\n /^https?:\\/\\//.test(href));\n\n return isExternalLink;\n};\n\n/**\n * Link Component\n *\n * A versatile link component that handles both internal and external navigation\n * with comprehensive internationalization support and multiple visual variants.\n * ...\n */\nexport const Link: FC<LinkProps> = (props) => {\n const {\n variant = LinkVariant.DEFAULT,\n color = LinkColor.PRIMARY,\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 = typeof children === 'string';\n\n const rel = isExternalLink ? 'noopener noreferrer nofollow' : undefined;\n\n const target = isExternalLink ? '_blank' : '_self';\n\n const href =\n locale && hrefProp && !isExternalLink && !isPageSection\n ? getLocalizedUrl(hrefProp, locale)\n : hrefProp;\n\n const isButton = variant === 'button' || variant === 'button-outlined';\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 className={cn(\n linkVariants({\n variant,\n color,\n roundedSize,\n underlined,\n size,\n className: isButton ? undefined : className,\n })\n )}\n {...otherProps}\n >\n {isButton ? <span className={className}>{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
|
+
{"version":3,"file":"Link.mjs","names":["Link: FC<LinkProps>"],"sources":["../../../../src/components/Link/Link.tsx"],"sourcesContent":["import { getLocalizedUrl } from '@intlayer/core';\nimport type { LocalesValues } from '@intlayer/types';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { ExternalLink, MoveRight } from 'lucide-react';\nimport type { AnchorHTMLAttributes, DetailedHTMLProps, FC } from 'react';\nimport { cn } from '../../utils/cn';\n\n/**\n * Visual style variants for Link component\n *\n * @enum {string}\n */\nexport enum LinkVariant {\n /** Default underlined link with hover effects */\n DEFAULT = 'default',\n /** Link without visible underline or hover effects */\n INVISIBLE_LINK = 'invisible-link',\n /** Button-styled link with solid background */\n BUTTON = 'button',\n /** Button-styled link with outlined border */\n BUTTON_OUTLINED = 'button-outlined',\n /** Link with subtle hover background effect */\n HOVERABLE = 'hoverable',\n}\n\n/**\n * Color theme variants for Link component\n *\n * @enum {string}\n */\nexport enum LinkColor {\n /** Primary brand color */\n PRIMARY = 'primary',\n /** Secondary brand color */\n SECONDARY = 'secondary',\n /** Destructive/danger color for critical actions */\n DESTRUCTIVE = 'destructive',\n /** Neutral/muted color for less prominent links */\n NEUTRAL = 'neutral',\n /** Light color for dark backgrounds */\n LIGHT = 'light',\n /** Dark color for light backgrounds */\n DARK = 'dark',\n /** Default text color */\n TEXT = 'text',\n /** Inverse text color for opposite backgrounds */\n TEXT_INVERSE = 'text-inverse',\n /** Error/red color for error states */\n ERROR = 'error',\n /** Success/green color for positive actions */\n SUCCESS = 'success',\n /** Custom color - no default styling applied */\n CUSTOM = 'custom',\n}\n\n/** Available rounded corner sizes for the container */\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\n/**\n * Underline style options for Link component\n *\n * @enum {string}\n */\nexport enum LinkUnderlined {\n /** Default underline behavior based on variant */\n DEFAULT = 'default',\n /** Always show underline */\n TRUE = 'true',\n /** Never show underline */\n FALSE = 'false',\n}\n\n/**\n * Class variance authority configuration for Link component styling\n * Defines the visual appearance based on variant, color, and underline options\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 underline-offset-4 hover:bg-current/0 hover:underline',\n [`${LinkVariant.INVISIBLE_LINK}`]:\n 'h-auto justify-start border-inherit bg-current/0 px-1 underline-offset-4 hover:bg-current/0',\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',\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',\n\n [`${LinkVariant.HOVERABLE}`]:\n 'block rounded-lg border-none bg-current/0 hover:bg-current/10 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.DESTRUCTIVE}`]: 'text-destructive',\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 // 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 for button (Chrome bug fix: ring-current/20 doesn't work properly)\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.DESTRUCTIVE,\n class: 'ring-destructive/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 color: LinkColor.PRIMARY,\n roundedSize: LinkRoundedSize.MD,\n underlined: LinkUnderlined.DEFAULT,\n size: LinkSize.MD,\n },\n }\n);\n\n/**\n * Props interface for the Link component\n *\n * @interface LinkProps\n * @extends {DetailedHTMLProps<AnchorHTMLAttributes<HTMLAnchorElement>, HTMLAnchorElement>}\n * @extends {VariantProps<typeof linkVariants>}\n */\nexport type LinkProps = DetailedHTMLProps<\n AnchorHTMLAttributes<HTMLAnchorElement>,\n HTMLAnchorElement\n> &\n VariantProps<typeof linkVariants> & {\n /**\n * Accessible label for screen readers (required)\n * Provides context about what the link does or where it leads\n * @example \"Navigate to home page\"\n */\n label: string;\n\n /**\n * Whether this link opens in a new tab/window\n * When true, adds target=\"_blank\" and security attributes\n * Auto-detected for URLs starting with http/https when undefined\n * @default undefined (auto-detect based on href)\n */\n isExternalLink?: boolean;\n\n /**\n * If a link is a page section as '#id'\n * @default false\n */\n isPageSection?: boolean;\n\n /**\n * Whether this link represents the current page/active state\n * Adds aria-current=\"page\" for accessibility\n * @default false\n */\n isActive?: boolean;\n\n /**\n * Locale for internationalized URLs\n * When provided, URLs are automatically localized using Intlayer\n * @example 'fr', 'es', 'en'\n */\n locale?: LocalesValues;\n };\n\n/**\n * Utility function to determine if a link should be treated as external\n *\n * @param props - Link component props containing href and isExternalLink\n * @returns {boolean} True if the link should open externally\n *\n * @example\n * ```tsx\n * checkIsExternalLink({ href: '[https://example.com](https://example.com)' }) // true\n * checkIsExternalLink({ href: '/internal-page' }) // false\n * checkIsExternalLink({ href: '/page', isExternalLink: true }) // true\n * ```\n */\nexport const checkIsExternalLink = ({\n href,\n isExternalLink: isExternalLinkProp,\n}: LinkProps): boolean => {\n const isValidHref = typeof href === 'string' && href.trim() !== '';\n const isExternalLink =\n isExternalLinkProp === true ||\n (typeof isExternalLinkProp === 'undefined' &&\n isValidHref &&\n /^https?:\\/\\//.test(href));\n\n return isExternalLink;\n};\n\n/**\n * Link Component\n *\n * A versatile link component that handles both internal and external navigation\n * with comprehensive internationalization support and multiple visual variants.\n * ...\n */\nexport const Link: FC<LinkProps> = (props) => {\n const {\n variant = LinkVariant.DEFAULT,\n color = LinkColor.PRIMARY,\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 = typeof children === 'string';\n\n const rel = isExternalLink ? 'noopener noreferrer nofollow' : undefined;\n\n const target = isExternalLink ? '_blank' : '_self';\n\n const href =\n locale && hrefProp && !isExternalLink && !isPageSection\n ? getLocalizedUrl(hrefProp, locale)\n : hrefProp;\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 className={cn(\n linkVariants({\n variant,\n color,\n roundedSize,\n underlined,\n size,\n className,\n })\n )}\n {...otherProps}\n >\n {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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"}
|
|
@@ -80,7 +80,7 @@ const DesktopNavbar = ({ logo, sections, rightItems, selectedChoice }) => /* @__
|
|
|
80
80
|
logo,
|
|
81
81
|
/* @__PURE__ */ jsx(TabSelector, {
|
|
82
82
|
selectedChoice,
|
|
83
|
-
className: "ml-[2vw] gap-3 overflow-x-auto text-neutral tracking-wide lg:ml-[5vw] lg:gap-3 xl:ml-[10vw] xl:gap-6",
|
|
83
|
+
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",
|
|
84
84
|
tabs: sections,
|
|
85
85
|
hoverable: true,
|
|
86
86
|
color: TabSelectorColor.TEXT
|
|
@@ -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 {\n TabSelector,\n TabSelectorColor,\n type TabSelectorItemProps,\n} 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] 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={TabSelectorColor.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":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8FA,MAAa,iBAAiD,EAC5D,MACA,UACA,YACA,qBAEA,qBAAC;CAAI,WAAU;;EACZ;EAED,oBAAC;GACiB;GAChB,WAAU;GACV,MAAM;GACN;GACA,OAAO,iBAAiB;IACxB;EAEF,oBAAC;GAAI,WAAU;aACZ;IACG;;EACF"}
|
|
1
|
+
{"version":3,"file":"DesktopNavbar.mjs","names":[],"sources":["../../../../src/components/Navbar/DesktopNavbar.tsx"],"sourcesContent":["'use client';\n\nimport type { ReactElement, ReactNode } from 'react';\nimport {\n TabSelector,\n TabSelectorColor,\n type TabSelectorItemProps,\n} 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={TabSelectorColor.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":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8FA,MAAa,iBAAiD,EAC5D,MACA,UACA,YACA,qBAEA,qBAAC;CAAI,WAAU;;EACZ;EAED,oBAAC;GACiB;GAChB,WAAU;GACV,MAAM;GACN;GACA,OAAO,iBAAiB;IACxB;EAEF,oBAAC;GAAI,WAAU;aACZ;IACG;;EACF"}
|
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
import { cn } from "../../utils/cn.mjs";
|
|
4
4
|
import { Button, ButtonColor, ButtonSize, ButtonVariant } from "../Button/Button.mjs";
|
|
5
|
+
import { useItemSelector } from "../../hooks/useItemSelector.mjs";
|
|
5
6
|
import { ChevronLeft, ChevronRight, MoreHorizontal } from "lucide-react";
|
|
7
|
+
import { useEffect, useRef } from "react";
|
|
6
8
|
import { cva } from "class-variance-authority";
|
|
7
9
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
8
10
|
|
|
@@ -66,66 +68,104 @@ const generatePageNumbers = (currentPage, totalPages, maxVisiblePages) => {
|
|
|
66
68
|
}
|
|
67
69
|
return pages;
|
|
68
70
|
};
|
|
71
|
+
const selector = (option) => option?.getAttribute("aria-current") === "true";
|
|
69
72
|
const getButtonSize = (size) => {
|
|
70
|
-
|
|
73
|
+
if (size === PaginationSize.SM) return ButtonSize.ICON_SM;
|
|
74
|
+
else if (size === PaginationSize.LG) return ButtonSize.ICON_LG;
|
|
75
|
+
else return ButtonSize.ICON_MD;
|
|
71
76
|
};
|
|
77
|
+
const InputIndicator = (props) => /* @__PURE__ */ jsx("div", {
|
|
78
|
+
className: "absolute top-0 z-0 h-full w-auto rounded-xl bg-text/20 ring-4 ring-text/10 transition-[left,width] duration-300 ease-in-out [corner-shape:squircle] supports-[corner-shape:squircle]:rounded-2xl motion-reduce:transition-none",
|
|
79
|
+
...props
|
|
80
|
+
});
|
|
72
81
|
const Pagination = ({ currentPage, totalPages, onPageChange, showFirstLast = false, showPrevNext = true, maxVisiblePages = 5, disabled = false, size = PaginationSize.MD, variant = PaginationVariant.DEFAULT, color = ButtonColor.TEXT, className, ...props }) => {
|
|
73
82
|
const pageNumbers = generatePageNumbers(currentPage, totalPages, maxVisiblePages);
|
|
74
83
|
const buttonSize = getButtonSize(size);
|
|
75
84
|
const isFirstPage = currentPage === 1;
|
|
76
85
|
const isLastPage = currentPage === totalPages;
|
|
86
|
+
const optionsRefs = useRef([]);
|
|
87
|
+
const indicatorRef = useRef(null);
|
|
88
|
+
const { choiceIndicatorPosition, calculatePosition } = useItemSelector(optionsRefs, {
|
|
89
|
+
selector,
|
|
90
|
+
isHoverable: true
|
|
91
|
+
});
|
|
92
|
+
useEffect(() => {
|
|
93
|
+
const timer = setTimeout(() => {
|
|
94
|
+
calculatePosition();
|
|
95
|
+
}, 300);
|
|
96
|
+
return () => clearTimeout(timer);
|
|
97
|
+
}, [currentPage, calculatePosition]);
|
|
77
98
|
if (totalPages <= 1) return null;
|
|
78
99
|
const handlePageChange = (page) => {
|
|
79
100
|
if (!disabled && page >= 1 && page <= totalPages && page !== currentPage) onPageChange(page);
|
|
80
101
|
};
|
|
81
|
-
return /* @__PURE__ */
|
|
102
|
+
return /* @__PURE__ */ jsx("div", {
|
|
82
103
|
className: cn(paginationVariants({
|
|
83
104
|
size,
|
|
84
105
|
variant
|
|
85
106
|
}), className),
|
|
86
107
|
...props,
|
|
87
|
-
children:
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
},
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
108
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
109
|
+
className: "relative flex items-center gap-1",
|
|
110
|
+
children: [
|
|
111
|
+
choiceIndicatorPosition && /* @__PURE__ */ jsx(InputIndicator, {
|
|
112
|
+
style: choiceIndicatorPosition,
|
|
113
|
+
ref: indicatorRef
|
|
114
|
+
}),
|
|
115
|
+
showPrevNext && /* @__PURE__ */ jsx(Button, {
|
|
116
|
+
variant: ButtonVariant.OUTLINE,
|
|
117
|
+
size: buttonSize,
|
|
118
|
+
color: ButtonColor.TEXT,
|
|
119
|
+
onClick: () => handlePageChange(currentPage - 1),
|
|
120
|
+
disabled: disabled || isFirstPage,
|
|
121
|
+
label: "Go to previous page",
|
|
122
|
+
Icon: ChevronLeft,
|
|
123
|
+
ref: (el) => {
|
|
124
|
+
if (el) optionsRefs.current[0] = el;
|
|
125
|
+
},
|
|
126
|
+
className: "min-w-0 px-2"
|
|
127
|
+
}),
|
|
128
|
+
/* @__PURE__ */ jsx("div", {
|
|
129
|
+
className: "flex items-center gap-1 max-md:gap-0.5",
|
|
130
|
+
children: pageNumbers.map((page, index) => {
|
|
131
|
+
if (page === "ellipsis") return /* @__PURE__ */ jsx("div", {
|
|
132
|
+
className: "flex h-8 min-w-8 items-center justify-center px-1",
|
|
133
|
+
children: /* @__PURE__ */ jsx(MoreHorizontal, { className: "h-4 w-4 text-muted-foreground" })
|
|
134
|
+
}, `ellipsis-${page}-${index}`);
|
|
135
|
+
const isActive = page === currentPage;
|
|
136
|
+
const refIndex = (showPrevNext ? 1 : 0) + pageNumbers.slice(0, index).filter((p) => p !== "ellipsis").length;
|
|
137
|
+
return /* @__PURE__ */ jsx(Button, {
|
|
138
|
+
variant: isActive ? ButtonVariant.DEFAULT : ButtonVariant.OUTLINE,
|
|
139
|
+
size: buttonSize,
|
|
140
|
+
color: ButtonColor.TEXT,
|
|
141
|
+
onClick: () => handlePageChange(page),
|
|
142
|
+
disabled,
|
|
143
|
+
label: `Go to page ${page}`,
|
|
144
|
+
"aria-current": isActive ? "true" : "false",
|
|
145
|
+
ref: (el) => {
|
|
146
|
+
if (el) optionsRefs.current[refIndex] = el;
|
|
147
|
+
},
|
|
148
|
+
className: cn("flex aspect-square h-8 w-8 min-w-0 items-center justify-center p-0 text-sm", size === "sm" && "h-6 w-6 text-xs", size === "lg" && "h-10 w-10 text-base", isActive && "font-semibold"),
|
|
149
|
+
children: page
|
|
150
|
+
}, page);
|
|
151
|
+
})
|
|
152
|
+
}),
|
|
153
|
+
showPrevNext && /* @__PURE__ */ jsx(Button, {
|
|
154
|
+
variant: ButtonVariant.OUTLINE,
|
|
155
|
+
size: buttonSize,
|
|
156
|
+
color: ButtonColor.TEXT,
|
|
157
|
+
onClick: () => handlePageChange(currentPage + 1),
|
|
158
|
+
disabled: disabled || isLastPage,
|
|
159
|
+
label: "Go to next page",
|
|
160
|
+
Icon: ChevronRight,
|
|
161
|
+
ref: (el) => {
|
|
162
|
+
const lastRefIndex = (showPrevNext ? 1 : 0) + pageNumbers.filter((p) => p !== "ellipsis").length;
|
|
163
|
+
if (el) optionsRefs.current[lastRefIndex] = el;
|
|
164
|
+
},
|
|
165
|
+
className: "min-w-0 px-2"
|
|
116
166
|
})
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
variant: ButtonVariant.OUTLINE,
|
|
120
|
-
size: buttonSize,
|
|
121
|
-
color: ButtonColor.TEXT,
|
|
122
|
-
onClick: () => handlePageChange(currentPage + 1),
|
|
123
|
-
disabled: disabled || isLastPage,
|
|
124
|
-
label: "Go to next page",
|
|
125
|
-
Icon: ChevronRight,
|
|
126
|
-
className: "min-w-0 px-2"
|
|
127
|
-
})
|
|
128
|
-
]
|
|
167
|
+
]
|
|
168
|
+
})
|
|
129
169
|
});
|
|
130
170
|
};
|
|
131
171
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Pagination.mjs","names":["pages: (number | 'ellipsis')[]","Pagination: FC<PaginationProps>"],"sources":["../../../../src/components/Pagination/Pagination.tsx"],"sourcesContent":["'use client';\n\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { ChevronLeft, ChevronRight, MoreHorizontal } from 'lucide-react';\nimport type { FC, HTMLAttributes } from 'react';\nimport { cn } from '../../utils/cn';\nimport { Button, ButtonColor, ButtonSize, ButtonVariant } from '../Button';\n\nexport const paginationVariants = cva(\n 'flex items-center justify-center gap-1',\n {\n variants: {\n size: {\n sm: 'gap-1',\n md: 'gap-2',\n lg: 'gap-3',\n },\n color: {\n text: 'background-text',\n primary: 'background-primary',\n secondary: 'background-secondary',\n neutral: 'background-neutral',\n destructive: 'background-destructive',\n },\n variant: {\n default: '',\n bordered: 'rounded-lg border border-border p-2',\n ghost: 'bg-transparent',\n },\n },\n defaultVariants: {\n size: 'md',\n variant: 'default',\n },\n }\n);\n\nexport enum PaginationSize {\n SM = 'sm',\n MD = 'md',\n LG = 'lg',\n}\n\nexport enum PaginationVariant {\n DEFAULT = 'default',\n BORDERED = 'bordered',\n GHOST = 'ghost',\n}\n\nexport type PaginationProps = HTMLAttributes<HTMLDivElement> &\n VariantProps<typeof paginationVariants> & {\n currentPage: number;\n totalPages: number;\n onPageChange: (page: number) => void;\n showFirstLast?: boolean;\n showPrevNext?: boolean;\n maxVisiblePages?: number;\n disabled?: boolean;\n };\n\nconst generatePageNumbers = (\n currentPage: number,\n totalPages: number,\n maxVisiblePages: number\n): (number | 'ellipsis')[] => {\n if (totalPages <= maxVisiblePages) {\n return Array.from({ length: totalPages }, (_, i) => i + 1);\n }\n\n const pages: (number | 'ellipsis')[] = [];\n const halfVisible = Math.floor(maxVisiblePages / 2);\n\n pages.push(1);\n\n if (currentPage <= halfVisible + 2) {\n for (let i = 2; i <= Math.min(maxVisiblePages - 1, totalPages - 1); i++) {\n pages.push(i);\n }\n if (totalPages > maxVisiblePages) {\n pages.push('ellipsis');\n }\n if (totalPages > 1) {\n pages.push(totalPages);\n }\n } else if (currentPage >= totalPages - halfVisible - 1) {\n if (totalPages > maxVisiblePages) {\n pages.push('ellipsis');\n }\n for (\n let i = Math.max(2, totalPages - maxVisiblePages + 2);\n i <= totalPages;\n i++\n ) {\n pages.push(i);\n }\n } else {\n pages.push('ellipsis');\n const start = currentPage - halfVisible;\n const end = currentPage + halfVisible;\n for (let i = start; i <= end; i++) {\n pages.push(i);\n }\n pages.push('ellipsis');\n pages.push(totalPages);\n }\n\n return pages;\n};\n\nconst getButtonSize = (size?: PaginationSize | `${PaginationSize}` | null) => {\n return size === PaginationSize.SM\n ? ButtonSize.ICON_SM\n : size === PaginationSize.LG\n ? ButtonSize.ICON_LG\n : ButtonSize.ICON_MD;\n};\n\nexport const Pagination: FC<PaginationProps> = ({\n currentPage,\n totalPages,\n onPageChange,\n showFirstLast = false,\n showPrevNext = true,\n maxVisiblePages = 5,\n disabled = false,\n size = PaginationSize.MD,\n variant = PaginationVariant.DEFAULT,\n color = ButtonColor.TEXT,\n className,\n ...props\n}) => {\n const pageNumbers = generatePageNumbers(\n currentPage,\n totalPages,\n maxVisiblePages\n );\n\n const buttonSize = getButtonSize(size);\n const isFirstPage = currentPage === 1;\n const isLastPage = currentPage === totalPages;\n\n if (totalPages <= 1) return null;\n\n const handlePageChange = (page: number) => {\n if (!disabled && page >= 1 && page <= totalPages && page !== currentPage) {\n onPageChange(page);\n }\n };\n\n return (\n <div\n className={cn(paginationVariants({ size, variant }), className)}\n {...props}\n >\n {showPrevNext && (\n <Button\n variant={ButtonVariant.OUTLINE}\n size={buttonSize}\n color={ButtonColor.TEXT}\n onClick={() => handlePageChange(currentPage - 1)}\n disabled={disabled || isFirstPage}\n label=\"Go to previous page\"\n Icon={ChevronLeft}\n className=\"min-w-0 px-2\"\n />\n )}\n\n <div className=\"flex items-center gap-1 max-md:gap-0.5\">\n {pageNumbers.map((page) => {\n if (page === 'ellipsis') {\n return (\n <div\n key={`ellipsis-${page}`}\n className=\"flex h-8 min-w-8 items-center justify-center px-1\"\n >\n <MoreHorizontal className=\"h-4 w-4 text-muted-foreground\" />\n </div>\n );\n }\n\n const isActive = page === currentPage;\n return (\n <Button\n key={page}\n variant={isActive ? ButtonVariant.DEFAULT : ButtonVariant.OUTLINE}\n size={buttonSize}\n color={ButtonColor.TEXT}\n onClick={() => handlePageChange(page)}\n disabled={disabled}\n label={`Go to page ${page}`}\n className={cn(\n 'flex aspect-square h-8 w-8 min-w-0 items-center justify-center p-0 text-sm',\n size === 'sm' && 'h-6 w-6 text-xs',\n size === 'lg' && 'h-10 w-10 text-base',\n isActive && 'font-semibold'\n )}\n >\n {page}\n </Button>\n );\n })}\n </div>\n\n {showPrevNext && (\n <Button\n variant={ButtonVariant.OUTLINE}\n size={buttonSize}\n color={ButtonColor.TEXT}\n onClick={() => handlePageChange(currentPage + 1)}\n disabled={disabled || isLastPage}\n label=\"Go to next page\"\n Icon={ChevronRight}\n className=\"min-w-0 px-2\"\n />\n )}\n </div>\n );\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Pagination.mjs","names":["pages: (number | 'ellipsis')[]","InputIndicator: FC<ComponentProps<'div'>>","Pagination: FC<PaginationProps>"],"sources":["../../../../src/components/Pagination/Pagination.tsx"],"sourcesContent":["'use client';\n\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { ChevronLeft, ChevronRight, MoreHorizontal } from 'lucide-react';\nimport {\n type ComponentProps,\n type FC,\n type HTMLAttributes,\n type RefObject,\n useEffect,\n useRef,\n} from 'react';\nimport { useItemSelector } from '../../hooks';\nimport { cn } from '../../utils/cn';\nimport { Button, ButtonColor, ButtonSize, ButtonVariant } from '../Button';\n\nexport const paginationVariants = cva(\n 'flex items-center justify-center gap-1',\n {\n variants: {\n size: {\n sm: 'gap-1',\n md: 'gap-2',\n lg: 'gap-3',\n },\n color: {\n text: 'background-text',\n primary: 'background-primary',\n secondary: 'background-secondary',\n neutral: 'background-neutral',\n destructive: 'background-destructive',\n },\n variant: {\n default: '',\n bordered: 'rounded-lg border border-border p-2',\n ghost: 'bg-transparent',\n },\n },\n defaultVariants: {\n size: 'md',\n variant: 'default',\n },\n }\n);\n\nexport enum PaginationSize {\n SM = 'sm',\n MD = 'md',\n LG = 'lg',\n}\n\nexport enum PaginationVariant {\n DEFAULT = 'default',\n BORDERED = 'bordered',\n GHOST = 'ghost',\n}\n\nexport type PaginationProps = HTMLAttributes<HTMLDivElement> &\n VariantProps<typeof paginationVariants> & {\n currentPage: number;\n totalPages: number;\n onPageChange: (page: number) => void;\n showFirstLast?: boolean;\n showPrevNext?: boolean;\n maxVisiblePages?: number;\n disabled?: boolean;\n };\n\nconst generatePageNumbers = (\n currentPage: number,\n totalPages: number,\n maxVisiblePages: number\n): (number | 'ellipsis')[] => {\n if (totalPages <= maxVisiblePages) {\n return Array.from({ length: totalPages }, (_, i) => i + 1);\n }\n\n const pages: (number | 'ellipsis')[] = [];\n const halfVisible = Math.floor(maxVisiblePages / 2);\n\n pages.push(1);\n\n if (currentPage <= halfVisible + 2) {\n for (let i = 2; i <= Math.min(maxVisiblePages - 1, totalPages - 1); i++) {\n pages.push(i);\n }\n if (totalPages > maxVisiblePages) {\n pages.push('ellipsis');\n }\n if (totalPages > 1) {\n pages.push(totalPages);\n }\n } else if (currentPage >= totalPages - halfVisible - 1) {\n if (totalPages > maxVisiblePages) {\n pages.push('ellipsis');\n }\n for (\n let i = Math.max(2, totalPages - maxVisiblePages + 2);\n i <= totalPages;\n i++\n ) {\n pages.push(i);\n }\n } else {\n pages.push('ellipsis');\n const start = currentPage - halfVisible;\n const end = currentPage + halfVisible;\n for (let i = start; i <= end; i++) {\n pages.push(i);\n }\n pages.push('ellipsis');\n pages.push(totalPages);\n }\n\n return pages;\n};\n\nconst selector = (option: HTMLElement) =>\n option?.getAttribute('aria-current') === 'true';\n\nconst getButtonSize = (size?: PaginationSize | `${PaginationSize}` | null) => {\n if (size === PaginationSize.SM) {\n return ButtonSize.ICON_SM;\n } else if (size === PaginationSize.LG) {\n return ButtonSize.ICON_LG;\n } else {\n return ButtonSize.ICON_MD;\n }\n};\n\nconst InputIndicator: FC<ComponentProps<'div'>> = (props) => (\n <div\n className=\"absolute top-0 z-0 h-full w-auto rounded-xl bg-text/20 ring-4 ring-text/10 transition-[left,width] duration-300 ease-in-out [corner-shape:squircle] supports-[corner-shape:squircle]:rounded-2xl motion-reduce:transition-none\"\n {...props}\n />\n);\n\nexport const Pagination: FC<PaginationProps> = ({\n currentPage,\n totalPages,\n onPageChange,\n showFirstLast = false,\n showPrevNext = true,\n maxVisiblePages = 5,\n disabled = false,\n size = PaginationSize.MD,\n variant = PaginationVariant.DEFAULT,\n color = ButtonColor.TEXT,\n className,\n ...props\n}) => {\n const pageNumbers = generatePageNumbers(\n currentPage,\n totalPages,\n maxVisiblePages\n );\n\n const buttonSize = getButtonSize(size);\n const isFirstPage = currentPage === 1;\n const isLastPage = currentPage === totalPages;\n\n const optionsRefs = useRef<HTMLElement[]>([]);\n const indicatorRef = useRef<HTMLDivElement | null>(null);\n const { choiceIndicatorPosition, calculatePosition } = useItemSelector(\n optionsRefs,\n {\n selector,\n isHoverable: true,\n }\n );\n\n useEffect(() => {\n const timer = setTimeout(() => {\n calculatePosition();\n }, 300);\n\n return () => clearTimeout(timer);\n }, [currentPage, calculatePosition]);\n\n if (totalPages <= 1) return null;\n\n const handlePageChange = (page: number) => {\n if (!disabled && page >= 1 && page <= totalPages && page !== currentPage) {\n onPageChange(page);\n }\n };\n\n return (\n <div\n className={cn(paginationVariants({ size, variant }), className)}\n {...props}\n >\n <div className=\"relative flex items-center gap-1\">\n {choiceIndicatorPosition && (\n <InputIndicator style={choiceIndicatorPosition} ref={indicatorRef} />\n )}\n\n {showPrevNext && (\n <Button\n variant={ButtonVariant.OUTLINE}\n size={buttonSize}\n color={ButtonColor.TEXT}\n onClick={() => handlePageChange(currentPage - 1)}\n disabled={disabled || isFirstPage}\n label=\"Go to previous page\"\n Icon={ChevronLeft}\n ref={(el) => {\n if (el) optionsRefs.current[0] = el;\n }}\n className=\"min-w-0 px-2\"\n />\n )}\n\n <div className=\"flex items-center gap-1 max-md:gap-0.5\">\n {pageNumbers.map((page, index) => {\n if (page === 'ellipsis') {\n return (\n <div\n key={`ellipsis-${page}-${index}`}\n className=\"flex h-8 min-w-8 items-center justify-center px-1\"\n >\n <MoreHorizontal className=\"h-4 w-4 text-muted-foreground\" />\n </div>\n );\n }\n\n const isActive = page === currentPage;\n // Calculate ref index: offset by 1 if showPrevNext, then count only non-ellipsis items\n const refIndex =\n (showPrevNext ? 1 : 0) +\n pageNumbers.slice(0, index).filter((p) => p !== 'ellipsis')\n .length;\n\n return (\n <Button\n key={page}\n variant={\n isActive ? ButtonVariant.DEFAULT : ButtonVariant.OUTLINE\n }\n size={buttonSize}\n color={ButtonColor.TEXT}\n onClick={() => handlePageChange(page)}\n disabled={disabled}\n label={`Go to page ${page}`}\n aria-current={isActive ? 'true' : 'false'}\n ref={(el) => {\n if (el) optionsRefs.current[refIndex] = el;\n }}\n className={cn(\n 'flex aspect-square h-8 w-8 min-w-0 items-center justify-center p-0 text-sm',\n size === 'sm' && 'h-6 w-6 text-xs',\n size === 'lg' && 'h-10 w-10 text-base',\n isActive && 'font-semibold'\n )}\n >\n {page}\n </Button>\n );\n })}\n </div>\n\n {showPrevNext && (\n <Button\n variant={ButtonVariant.OUTLINE}\n size={buttonSize}\n color={ButtonColor.TEXT}\n onClick={() => handlePageChange(currentPage + 1)}\n disabled={disabled || isLastPage}\n label=\"Go to next page\"\n Icon={ChevronRight}\n ref={(el) => {\n const lastRefIndex =\n (showPrevNext ? 1 : 0) +\n pageNumbers.filter((p) => p !== 'ellipsis').length;\n if (el) optionsRefs.current[lastRefIndex] = el;\n }}\n className=\"min-w-0 px-2\"\n />\n )}\n </div>\n </div>\n );\n};\n"],"mappings":"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"}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { cn } from "../../utils/cn.mjs";
|
|
2
2
|
import { Container } from "../Container/index.mjs";
|
|
3
|
-
import { forwardRef } from "react";
|
|
4
3
|
import { jsx } from "react/jsx-runtime";
|
|
5
4
|
|
|
6
5
|
//#region src/components/Popover/static.tsx
|
|
@@ -175,18 +174,16 @@ const PopoverStatic = ({ children, className, identifier, ...props }) => /* @__P
|
|
|
175
174
|
* @param props - Popover Detail component props
|
|
176
175
|
* @returns Positioned popover content with animations and accessibility
|
|
177
176
|
*/
|
|
178
|
-
const Detail =
|
|
179
|
-
ref,
|
|
177
|
+
const Detail = ({ children, isHidden = void 0, isOverable = true, isFocusable = false, xAlign = PopoverXAlign.START, yAlign = PopoverYAlign.BELOW, identifier, className, displayArrow = true, ...props }) => /* @__PURE__ */ jsx(Container, {
|
|
180
178
|
transparency: "sm",
|
|
181
179
|
role: "group",
|
|
182
180
|
"aria-hidden": isHidden,
|
|
183
181
|
"aria-labelledby": `unrollable-panel-button-${identifier}`,
|
|
184
182
|
id: `unrollable-panel-${identifier}`,
|
|
185
|
-
className: cn("absolute z-
|
|
183
|
+
className: cn("absolute z-50 min-w-full rounded-md ring-1 ring-neutral", xAlign === "start" && "left-0", xAlign === "end" && "right-0", yAlign === "bellow" && "top-[calc(100%+1rem)]", yAlign === "above" && "bottom-[calc(100%+1rem)]", displayArrow && "before:absolute before:z-[999] before:h-0 before:w-0 before:content-[\"\"]", displayArrow && xAlign === "start" && "before:left-2", displayArrow && xAlign === "end" && "before:right-2", displayArrow && yAlign === "bellow" && "before:-top-[10px] before:border-r-[10px] before:border-r-transparent before:border-b-[10px] before:border-b-neutral before:border-l-[10px] before:border-l-transparent", displayArrow && yAlign === "above" && "before:-bottom-[10px] before:border-t-[10px] before:border-t-neutral before:border-r-[10px] before:border-r-transparent before:border-l-[10px] before:border-l-transparent", "overflow-x-visible opacity-0 transition-all duration-400 ease-in-out", isHidden !== false ? "invisible" : "visible opacity-100 delay-800", isOverable && "group-hover/popover:visible group-hover/popover:opacity-100 group-hover/popover:delay-800", isFocusable && "group-focus-within/popover:visible group-focus-within/popover:opacity-100 group-focus-within/popover:delay-800", className),
|
|
186
184
|
...props,
|
|
187
185
|
children
|
|
188
|
-
})
|
|
189
|
-
Detail.displayName = "Popover.Detail";
|
|
186
|
+
});
|
|
190
187
|
PopoverStatic.Detail = Detail;
|
|
191
188
|
|
|
192
189
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"static.mjs","names":["PopoverStatic: PopoverType"],"sources":["../../../../src/components/Popover/static.tsx"],"sourcesContent":["import type { DetailedHTMLProps, FC, HTMLAttributes } from 'react';\nimport { forwardRef } from 'react';\nimport { cn } from '../../utils/cn';\nimport { Container } from '../Container';\n\n/**\n * Props for the main Popover component\n * Extends HTMLDivElement attributes for full DOM compatibility\n */\nexport type PopoverProps = DetailedHTMLProps<\n HTMLAttributes<HTMLDivElement>,\n HTMLDivElement\n> & {\n /** Unique identifier linking the trigger to its popover content for accessibility */\n identifier: string;\n};\n\n/**\n * Composite type for the Popover component with Detail subcomponent\n * Allows for Popover.Detail usage pattern\n */\nexport type PopoverType = FC<PopoverProps> & {\n Detail: FC<DetailProps>;\n};\n\n/**\n * Horizontal alignment options for popover positioning\n */\nexport enum PopoverXAlign {\n /** Align popover to start (left) of trigger */\n START = 'start',\n /** Align popover to end (right) of trigger */\n END = 'end',\n}\n\n/**\n * Vertical alignment options for popover positioning\n */\nexport enum PopoverYAlign {\n /** Position popover below the trigger */\n BELOW = 'bellow',\n /** Position popover above the trigger */\n ABOVE = 'above',\n}\n\n/**\n * Popover Component\n *\n * A versatile popover container that displays contextual content when triggered by hover\n * or focus interactions. Built with accessibility in mind and supports multiple positioning\n * options with smooth animations.\n *\n * Features:\n * - Hover and focus-based triggering\n * - Multiple positioning options (above/below, start/end)\n * - Accessibility compliant with ARIA attributes\n * - Smooth animations with configurable delays\n * - Optional directional arrows\n * - Automatic z-index management\n * - Responsive design support\n *\n * Architecture:\n * - Main Popover acts as trigger container\n * - Popover.Detail renders the actual popover content\n * - Uses CSS groups for coordinated hover/focus states\n * - Unique identifier system prevents conflicts\n *\n * @example\n * Basic hover popover:\n * ```jsx\n * <Popover identifier=\"help-tooltip\">\n * <button>Need Help?</button>\n *\n * <Popover.Detail identifier=\"help-tooltip\">\n * <div>This is helpful information!</div>\n * </Popover.Detail>\n * </Popover>\n * ```\n *\n * @example\n * Focus-triggered popover:\n * ```jsx\n * <Popover identifier=\"focus-menu\">\n * <input placeholder=\"Focus me\" />\n *\n * <Popover.Detail\n * identifier=\"focus-menu\"\n * isFocusable\n * isOverable={false}\n * >\n * <div>Focus-only menu content</div>\n * </Popover.Detail>\n * </Popover>\n * ```\n *\n * @example\n * Positioned popover with custom alignment:\n * ```jsx\n * <Popover identifier=\"positioned\">\n * <span>Hover me</span>\n *\n * <Popover.Detail\n * identifier=\"positioned\"\n * xAlign={PopoverXAlign.END}\n * yAlign={PopoverYAlign.ABOVE}\n * displayArrow={false}\n * >\n * <div>Above and right-aligned</div>\n * </Popover.Detail>\n * </Popover>\n * ```\n *\n * Accessibility Features:\n * - Proper ARIA labeling and relationships\n * - Keyboard navigation support\n * - Screen reader compatibility\n * - Focus management\n *\n * Performance Considerations:\n * - CSS-only animations for smooth transitions\n * - Efficient group-based state management\n * - Minimal DOM updates during interactions\n *\n * @param props - Popover component props\n * @returns Trigger container with popover functionality\n */\nexport const PopoverStatic: PopoverType = ({\n children,\n className,\n identifier,\n ...props\n}) => (\n <div\n className={cn('group/popover relative flex cursor-pointer', className)}\n id={`unrollable-panel-button-${identifier}`}\n aria-haspopup\n {...props}\n >\n {children}\n </div>\n);\n\n/**\n * Props for the Popover.Detail component\n * Extends HTMLDivElement attributes for styling flexibility\n */\nexport type DetailProps = HTMLAttributes<HTMLDivElement> & {\n /** Whether the popover responds to focus events on the trigger */\n isFocusable?: boolean;\n /** Controls visibility state - undefined allows automatic hover/focus control */\n isHidden?: boolean;\n /** Whether the popover responds to hover events on the trigger */\n isOverable?: boolean;\n /** Unique identifier matching the trigger's identifier for accessibility */\n identifier: string;\n /** Horizontal positioning relative to trigger */\n xAlign?: PopoverXAlign | `${PopoverXAlign}`;\n /** Vertical positioning relative to trigger */\n yAlign?: PopoverYAlign | `${PopoverYAlign}`;\n /** Whether to display the directional arrow indicator */\n displayArrow?: boolean;\n};\n\n/**\n * Popover Detail Component\n *\n * The actual popover content container with advanced positioning, animation, and\n * accessibility features. Automatically manages visibility based on trigger interactions.\n *\n * Features:\n * - Precise positioning with alignment options\n * - Smooth fade and slide animations\n * - Configurable directional arrows\n * - Hover and focus interaction support\n * - Accessibility-compliant ARIA attributes\n * - High z-index for overlay behavior\n * - Automatic visibility management\n *\n * Positioning System:\n * - X-axis: START (left-aligned) or END (right-aligned)\n * - Y-axis: BELOW (underneath) or ABOVE (on top)\n * - Automatic spacing with 1rem gap from trigger\n * - Responsive minimum width matching trigger\n *\n * Arrow Indicators:\n * - CSS-generated triangular arrows\n * - Positioned based on alignment settings\n * - Points toward trigger for visual connection\n * - Can be disabled for clean, minimal appearance\n *\n * Animation Behavior:\n * - Starts invisible with opacity: 0\n * - Smooth 400ms transitions with easing\n * - 800ms delay for hover states (prevents flicker)\n * - Immediate hiding when trigger loses focus/hover\n *\n * @example\n * Rich content popover:\n * ```jsx\n * <Popover.Detail identifier=\"rich-content\">\n * <div className=\"p-4\">\n * <h3>Popover Title</h3>\n * <p>Detailed information with multiple paragraphs.</p>\n * <button>Action Button</button>\n * </div>\n * </Popover.Detail>\n * ```\n *\n * @example\n * Menu-style popover:\n * ```jsx\n * <Popover.Detail\n * identifier=\"context-menu\"\n * displayArrow={false}\n * xAlign={PopoverXAlign.END}\n * >\n * <ul className=\"py-2\">\n * <li><button className=\"w-full px-4 py-2\">Edit</button></li>\n * <li><button className=\"w-full px-4 py-2\">Delete</button></li>\n * </ul>\n * </Popover.Detail>\n * ```\n *\n * @param props - Popover Detail component props\n * @returns Positioned popover content with animations and accessibility\n */\nconst Detail = forwardRef<HTMLDivElement, DetailProps>(\n (\n {\n children,\n isHidden = undefined,\n isOverable = true,\n isFocusable = false,\n xAlign = PopoverXAlign.START,\n yAlign = PopoverYAlign.BELOW,\n identifier,\n className,\n displayArrow = true,\n ...props\n },\n ref\n ) => (\n <Container\n ref={ref}\n transparency=\"sm\"\n role=\"group\"\n aria-hidden={isHidden}\n aria-labelledby={`unrollable-panel-button-${identifier}`}\n id={`unrollable-panel-${identifier}`}\n className={cn(\n 'absolute z-[1000] min-w-full rounded-md ring-1 ring-neutral',\n\n /* Positioning */\n xAlign === 'start' && 'left-0',\n xAlign === 'end' && 'right-0',\n yAlign === 'bellow' && 'top-[calc(100%+1rem)]',\n yAlign === 'above' && 'bottom-[calc(100%+1rem)]',\n\n /* Arrow indicator */\n displayArrow &&\n 'before:absolute before:z-[999] before:h-0 before:w-0 before:content-[\"\"]',\n\n /* Horizontal positioning */\n displayArrow && xAlign === 'start' && 'before:left-2',\n displayArrow && xAlign === 'end' && 'before:right-2',\n\n /* Arrow pointing up (when popover is below trigger) */\n displayArrow &&\n yAlign === 'bellow' &&\n 'before:-top-[10px] before:border-r-[10px] before:border-r-transparent before:border-b-[10px] before:border-b-neutral before:border-l-[10px] before:border-l-transparent',\n\n /* Arrow pointing down (when popover is above trigger) */\n displayArrow &&\n yAlign === 'above' &&\n 'before:-bottom-[10px] before:border-t-[10px] before:border-t-neutral before:border-r-[10px] before:border-r-transparent before:border-l-[10px] before:border-l-transparent',\n\n /* Visibility management */\n 'overflow-x-visible opacity-0 transition-all duration-400 ease-in-out',\n isHidden !== false ? 'invisible' : 'visible opacity-100 delay-800',\n isOverable &&\n 'group-hover/popover:visible group-hover/popover:opacity-100 group-hover/popover:delay-800',\n isFocusable &&\n 'group-focus-within/popover:visible group-focus-within/popover:opacity-100 group-focus-within/popover:delay-800',\n className\n )}\n {...props}\n >\n {children}\n </Container>\n )\n);\n\nDetail.displayName = 'Popover.Detail';\n\nPopoverStatic.Detail = Detail;\n\n// Export Detail for use in dynamic version\nexport { Detail };\n"],"mappings":";;;;;;;;;AA4BA,IAAY,0DAAL;;AAEL;;AAEA;;;;;;AAMF,IAAY,0DAAL;;AAEL;;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAoFF,MAAaA,iBAA8B,EACzC,UACA,WACA,YACA,GAAG,YAEH,oBAAC;CACC,WAAW,GAAG,8CAA8C,UAAU;CACtE,IAAI,2BAA2B;CAC/B;CACA,GAAI;CAEH;EACG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuFR,MAAM,SAAS,YAEX,EACE,UACA,WAAW,QACX,aAAa,MACb,cAAc,OACd,SAAS,cAAc,OACvB,SAAS,cAAc,OACvB,YACA,WACA,eAAe,MACf,GAAG,SAEL,QAEA,oBAAC;CACM;CACL,cAAa;CACb,MAAK;CACL,eAAa;CACb,mBAAiB,2BAA2B;CAC5C,IAAI,oBAAoB;CACxB,WAAW,GACT,+DAGA,WAAW,WAAW,UACtB,WAAW,SAAS,WACpB,WAAW,YAAY,yBACvB,WAAW,WAAW,4BAGtB,gBACE,8EAGF,gBAAgB,WAAW,WAAW,iBACtC,gBAAgB,WAAW,SAAS,kBAGpC,gBACE,WAAW,YACX,2KAGF,gBACE,WAAW,WACX,8KAGF,wEACA,aAAa,QAAQ,cAAc,iCACnC,cACE,6FACF,eACE,kHACF,UACD;CACD,GAAI;CAEH;EACS,CAEf;AAED,OAAO,cAAc;AAErB,cAAc,SAAS"}
|
|
1
|
+
{"version":3,"file":"static.mjs","names":["PopoverStatic: PopoverType","Detail: FC<DetailProps>"],"sources":["../../../../src/components/Popover/static.tsx"],"sourcesContent":["import type { DetailedHTMLProps, FC, HTMLAttributes } from 'react';\nimport { cn } from '../../utils/cn';\nimport { Container } from '../Container';\n\n/**\n * Props for the main Popover component\n * Extends HTMLDivElement attributes for full DOM compatibility\n */\nexport type PopoverProps = DetailedHTMLProps<\n HTMLAttributes<HTMLDivElement>,\n HTMLDivElement\n> & {\n /** Unique identifier linking the trigger to its popover content for accessibility */\n identifier: string;\n};\n\n/**\n * Composite type for the Popover component with Detail subcomponent\n * Allows for Popover.Detail usage pattern\n */\nexport type PopoverType = FC<PopoverProps> & {\n Detail: FC<DetailProps>;\n};\n\n/**\n * Horizontal alignment options for popover positioning\n */\nexport enum PopoverXAlign {\n /** Align popover to start (left) of trigger */\n START = 'start',\n /** Align popover to end (right) of trigger */\n END = 'end',\n}\n\n/**\n * Vertical alignment options for popover positioning\n */\nexport enum PopoverYAlign {\n /** Position popover below the trigger */\n BELOW = 'bellow',\n /** Position popover above the trigger */\n ABOVE = 'above',\n}\n\n/**\n * Popover Component\n *\n * A versatile popover container that displays contextual content when triggered by hover\n * or focus interactions. Built with accessibility in mind and supports multiple positioning\n * options with smooth animations.\n *\n * Features:\n * - Hover and focus-based triggering\n * - Multiple positioning options (above/below, start/end)\n * - Accessibility compliant with ARIA attributes\n * - Smooth animations with configurable delays\n * - Optional directional arrows\n * - Automatic z-index management\n * - Responsive design support\n *\n * Architecture:\n * - Main Popover acts as trigger container\n * - Popover.Detail renders the actual popover content\n * - Uses CSS groups for coordinated hover/focus states\n * - Unique identifier system prevents conflicts\n *\n * @example\n * Basic hover popover:\n * ```jsx\n * <Popover identifier=\"help-tooltip\">\n * <button>Need Help?</button>\n *\n * <Popover.Detail identifier=\"help-tooltip\">\n * <div>This is helpful information!</div>\n * </Popover.Detail>\n * </Popover>\n * ```\n *\n * @example\n * Focus-triggered popover:\n * ```jsx\n * <Popover identifier=\"focus-menu\">\n * <input placeholder=\"Focus me\" />\n *\n * <Popover.Detail\n * identifier=\"focus-menu\"\n * isFocusable\n * isOverable={false}\n * >\n * <div>Focus-only menu content</div>\n * </Popover.Detail>\n * </Popover>\n * ```\n *\n * @example\n * Positioned popover with custom alignment:\n * ```jsx\n * <Popover identifier=\"positioned\">\n * <span>Hover me</span>\n *\n * <Popover.Detail\n * identifier=\"positioned\"\n * xAlign={PopoverXAlign.END}\n * yAlign={PopoverYAlign.ABOVE}\n * displayArrow={false}\n * >\n * <div>Above and right-aligned</div>\n * </Popover.Detail>\n * </Popover>\n * ```\n *\n * Accessibility Features:\n * - Proper ARIA labeling and relationships\n * - Keyboard navigation support\n * - Screen reader compatibility\n * - Focus management\n *\n * Performance Considerations:\n * - CSS-only animations for smooth transitions\n * - Efficient group-based state management\n * - Minimal DOM updates during interactions\n *\n * @param props - Popover component props\n * @returns Trigger container with popover functionality\n */\nexport const PopoverStatic: PopoverType = ({\n children,\n className,\n identifier,\n ...props\n}) => (\n <div\n className={cn('group/popover relative flex cursor-pointer', className)}\n id={`unrollable-panel-button-${identifier}`}\n aria-haspopup\n {...props}\n >\n {children}\n </div>\n);\n\n/**\n * Props for the Popover.Detail component\n * Extends HTMLDivElement attributes for styling flexibility\n */\nexport type DetailProps = HTMLAttributes<HTMLDivElement> & {\n /** Whether the popover responds to focus events on the trigger */\n isFocusable?: boolean;\n /** Controls visibility state - undefined allows automatic hover/focus control */\n isHidden?: boolean;\n /** Whether the popover responds to hover events on the trigger */\n isOverable?: boolean;\n /** Unique identifier matching the trigger's identifier for accessibility */\n identifier: string;\n /** Horizontal positioning relative to trigger */\n xAlign?: PopoverXAlign | `${PopoverXAlign}`;\n /** Vertical positioning relative to trigger */\n yAlign?: PopoverYAlign | `${PopoverYAlign}`;\n /** Whether to display the directional arrow indicator */\n displayArrow?: boolean;\n};\n\n/**\n * Popover Detail Component\n *\n * The actual popover content container with advanced positioning, animation, and\n * accessibility features. Automatically manages visibility based on trigger interactions.\n *\n * Features:\n * - Precise positioning with alignment options\n * - Smooth fade and slide animations\n * - Configurable directional arrows\n * - Hover and focus interaction support\n * - Accessibility-compliant ARIA attributes\n * - High z-index for overlay behavior\n * - Automatic visibility management\n *\n * Positioning System:\n * - X-axis: START (left-aligned) or END (right-aligned)\n * - Y-axis: BELOW (underneath) or ABOVE (on top)\n * - Automatic spacing with 1rem gap from trigger\n * - Responsive minimum width matching trigger\n *\n * Arrow Indicators:\n * - CSS-generated triangular arrows\n * - Positioned based on alignment settings\n * - Points toward trigger for visual connection\n * - Can be disabled for clean, minimal appearance\n *\n * Animation Behavior:\n * - Starts invisible with opacity: 0\n * - Smooth 400ms transitions with easing\n * - 800ms delay for hover states (prevents flicker)\n * - Immediate hiding when trigger loses focus/hover\n *\n * @example\n * Rich content popover:\n * ```jsx\n * <Popover.Detail identifier=\"rich-content\">\n * <div className=\"p-4\">\n * <h3>Popover Title</h3>\n * <p>Detailed information with multiple paragraphs.</p>\n * <button>Action Button</button>\n * </div>\n * </Popover.Detail>\n * ```\n *\n * @example\n * Menu-style popover:\n * ```jsx\n * <Popover.Detail\n * identifier=\"context-menu\"\n * displayArrow={false}\n * xAlign={PopoverXAlign.END}\n * >\n * <ul className=\"py-2\">\n * <li><button className=\"w-full px-4 py-2\">Edit</button></li>\n * <li><button className=\"w-full px-4 py-2\">Delete</button></li>\n * </ul>\n * </Popover.Detail>\n * ```\n *\n * @param props - Popover Detail component props\n * @returns Positioned popover content with animations and accessibility\n */\nconst Detail: FC<DetailProps> = ({\n children,\n isHidden = undefined,\n isOverable = true,\n isFocusable = false,\n xAlign = PopoverXAlign.START,\n yAlign = PopoverYAlign.BELOW,\n identifier,\n className,\n displayArrow = true,\n ...props\n}) => (\n <Container\n transparency=\"sm\"\n role=\"group\"\n aria-hidden={isHidden}\n aria-labelledby={`unrollable-panel-button-${identifier}`}\n id={`unrollable-panel-${identifier}`}\n className={cn(\n 'absolute z-50 min-w-full rounded-md ring-1 ring-neutral',\n\n /* Positioning */\n xAlign === 'start' && 'left-0',\n xAlign === 'end' && 'right-0',\n yAlign === 'bellow' && 'top-[calc(100%+1rem)]',\n yAlign === 'above' && 'bottom-[calc(100%+1rem)]',\n\n /* Arrow indicator */\n displayArrow &&\n 'before:absolute before:z-[999] before:h-0 before:w-0 before:content-[\"\"]',\n\n /* Horizontal positioning */\n displayArrow && xAlign === 'start' && 'before:left-2',\n displayArrow && xAlign === 'end' && 'before:right-2',\n\n /* Arrow pointing up (when popover is below trigger) */\n displayArrow &&\n yAlign === 'bellow' &&\n 'before:-top-[10px] before:border-r-[10px] before:border-r-transparent before:border-b-[10px] before:border-b-neutral before:border-l-[10px] before:border-l-transparent',\n\n /* Arrow pointing down (when popover is above trigger) */\n displayArrow &&\n yAlign === 'above' &&\n 'before:-bottom-[10px] before:border-t-[10px] before:border-t-neutral before:border-r-[10px] before:border-r-transparent before:border-l-[10px] before:border-l-transparent',\n\n /* Visibility management */\n 'overflow-x-visible opacity-0 transition-all duration-400 ease-in-out',\n isHidden !== false ? 'invisible' : 'visible opacity-100 delay-800',\n isOverable &&\n 'group-hover/popover:visible group-hover/popover:opacity-100 group-hover/popover:delay-800',\n isFocusable &&\n 'group-focus-within/popover:visible group-focus-within/popover:opacity-100 group-focus-within/popover:delay-800',\n className\n )}\n {...props}\n >\n {children}\n </Container>\n);\n\nPopoverStatic.Detail = Detail;\n\n// Export Detail for use in dynamic version\nexport { Detail };\n"],"mappings":";;;;;;;;AA2BA,IAAY,0DAAL;;AAEL;;AAEA;;;;;;AAMF,IAAY,0DAAL;;AAEL;;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAoFF,MAAaA,iBAA8B,EACzC,UACA,WACA,YACA,GAAG,YAEH,oBAAC;CACC,WAAW,GAAG,8CAA8C,UAAU;CACtE,IAAI,2BAA2B;CAC/B;CACA,GAAI;CAEH;EACG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuFR,MAAMC,UAA2B,EAC/B,UACA,WAAW,QACX,aAAa,MACb,cAAc,OACd,SAAS,cAAc,OACvB,SAAS,cAAc,OACvB,YACA,WACA,eAAe,MACf,GAAG,YAEH,oBAAC;CACC,cAAa;CACb,MAAK;CACL,eAAa;CACb,mBAAiB,2BAA2B;CAC5C,IAAI,oBAAoB;CACxB,WAAW,GACT,2DAGA,WAAW,WAAW,UACtB,WAAW,SAAS,WACpB,WAAW,YAAY,yBACvB,WAAW,WAAW,4BAGtB,gBACE,8EAGF,gBAAgB,WAAW,WAAW,iBACtC,gBAAgB,WAAW,SAAS,kBAGpC,gBACE,WAAW,YACX,2KAGF,gBACE,WAAW,WACX,8KAGF,wEACA,aAAa,QAAQ,cAAc,iCACnC,cACE,6FACF,eACE,kHACF,UACD;CACD,GAAI;CAEH;EACS;AAGd,cAAc,SAAS"}
|
|
@@ -24,7 +24,7 @@ let SwitchSelectorColor = /* @__PURE__ */ function(SwitchSelectorColor$1) {
|
|
|
24
24
|
SwitchSelectorColor$1["TEXT"] = "text";
|
|
25
25
|
return SwitchSelectorColor$1;
|
|
26
26
|
}({});
|
|
27
|
-
const switchSelectorVariant = cva("flex w-fit cursor-pointer flex-row gap-2 rounded-full border-[1.
|
|
27
|
+
const switchSelectorVariant = cva("flex w-fit cursor-pointer flex-row gap-2 rounded-full border-[1.3px] p-[1.5px]", {
|
|
28
28
|
variants: { color: {
|
|
29
29
|
[`${SwitchSelectorColor.PRIMARY}`]: "border-primary text-primary",
|
|
30
30
|
[`${SwitchSelectorColor.SECONDARY}`]: "border-secondary text-secondary",
|
|
@@ -50,7 +50,7 @@ const choiceVariant = cva("z-1 w-full flex-1 cursor-pointer font-medium text-sm
|
|
|
50
50
|
} },
|
|
51
51
|
defaultVariants: { size: `${SwitchSelectorSize.MD}` }
|
|
52
52
|
});
|
|
53
|
-
const indicatorVariant = cva("absolute top-0 z-
|
|
53
|
+
const indicatorVariant = cva("absolute top-0 z-0 h-full w-auto rounded-full transition-[left,width] duration-300 ease-in-out motion-reduce:transition-none", { variants: { color: {
|
|
54
54
|
[`${SwitchSelectorColor.PRIMARY}`]: "bg-primary data-[indicator=true]:text-text",
|
|
55
55
|
[`${SwitchSelectorColor.SECONDARY}`]: "bg-secondary data-[indicator=true]:text-text",
|
|
56
56
|
[`${SwitchSelectorColor.DESTRUCTIVE}`]: "bg-destructive data-[indicator=true]:text-text",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["defaultChoices: SwitchSelectorChoices<boolean>","value"],"sources":["../../../../src/components/SwitchSelector/index.tsx"],"sourcesContent":["'use client';\n\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport {\n type HTMLAttributes,\n type ReactNode,\n useEffect,\n useRef,\n useState,\n} from 'react';\nimport { useItemSelector } from '../../hooks';\nimport { cn } from '../../utils/cn';\n\nexport type SwitchSelectorChoice<T = boolean> = {\n content: ReactNode;\n value: T;\n} & HTMLAttributes<HTMLButtonElement>;\nexport type SwitchSelectorChoices<T> = SwitchSelectorChoice<T>[];\n\nconst defaultChoices: SwitchSelectorChoices<boolean> = [\n { content: 'Off', value: false },\n { content: 'On', value: true },\n];\n\nexport type SwitchSelectorProps<T = boolean> = {\n choices?: SwitchSelectorChoices<T>;\n value?: T;\n defaultValue?: T;\n onChange?: (choice: T) => void;\n className?: string;\n hoverable?: boolean;\n} & VariantProps<typeof switchSelectorVariant> &\n VariantProps<typeof choiceVariant>;\n\nexport enum SwitchSelectorColor {\n PRIMARY = 'primary',\n SECONDARY = 'secondary',\n DESTRUCTIVE = 'destructive',\n NEUTRAL = 'neutral',\n LIGHT = 'light',\n DARK = 'dark',\n TEXT = 'text',\n}\n\nconst switchSelectorVariant = cva(\n 'flex w-fit cursor-pointer flex-row gap-2 rounded-full border-[1.
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["defaultChoices: SwitchSelectorChoices<boolean>","value"],"sources":["../../../../src/components/SwitchSelector/index.tsx"],"sourcesContent":["'use client';\n\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport {\n type HTMLAttributes,\n type ReactNode,\n useEffect,\n useRef,\n useState,\n} from 'react';\nimport { useItemSelector } from '../../hooks';\nimport { cn } from '../../utils/cn';\n\nexport type SwitchSelectorChoice<T = boolean> = {\n content: ReactNode;\n value: T;\n} & HTMLAttributes<HTMLButtonElement>;\nexport type SwitchSelectorChoices<T> = SwitchSelectorChoice<T>[];\n\nconst defaultChoices: SwitchSelectorChoices<boolean> = [\n { content: 'Off', value: false },\n { content: 'On', value: true },\n];\n\nexport type SwitchSelectorProps<T = boolean> = {\n choices?: SwitchSelectorChoices<T>;\n value?: T;\n defaultValue?: T;\n onChange?: (choice: T) => void;\n className?: string;\n hoverable?: boolean;\n} & VariantProps<typeof switchSelectorVariant> &\n VariantProps<typeof choiceVariant>;\n\nexport enum SwitchSelectorColor {\n PRIMARY = 'primary',\n SECONDARY = 'secondary',\n DESTRUCTIVE = 'destructive',\n NEUTRAL = 'neutral',\n LIGHT = 'light',\n DARK = 'dark',\n TEXT = 'text',\n}\n\nconst switchSelectorVariant = cva(\n 'flex w-fit cursor-pointer flex-row gap-2 rounded-full border-[1.3px] p-[1.5px]',\n {\n variants: {\n color: {\n [`${SwitchSelectorColor.PRIMARY}`]: 'border-primary text-primary',\n [`${SwitchSelectorColor.SECONDARY}`]: 'border-secondary text-secondary',\n [`${SwitchSelectorColor.DESTRUCTIVE}`]:\n 'border-destructive bg-destructive text-destructive',\n [`${SwitchSelectorColor.NEUTRAL}`]: 'border-neutral text-neutral',\n [`${SwitchSelectorColor.LIGHT}`]: 'border-white text-white',\n [`${SwitchSelectorColor.DARK}`]: 'border-neutral-800 text-neutral-800',\n [`${SwitchSelectorColor.TEXT}`]: 'border-text text-text',\n },\n },\n defaultVariants: {\n color: `${SwitchSelectorColor.PRIMARY}`,\n },\n }\n);\n\nexport enum SwitchSelectorSize {\n SM = 'sm',\n MD = 'md',\n LG = 'lg',\n}\n\nconst choiceVariant = cva(\n 'z-1 w-full flex-1 cursor-pointer font-medium text-sm transition-all duration-300 ease-in-out aria-selected:cursor-default data-[indicator=true]:text-text-opposite motion-reduce:transition-none',\n {\n variants: {\n size: {\n [`${SwitchSelectorSize.SM}`]: 'px-2 py-1 text-xs',\n [`${SwitchSelectorSize.MD}`]: 'p-2 text-sm',\n [`${SwitchSelectorSize.LG}`]: 'p-4 text-base',\n },\n },\n defaultVariants: {\n size: `${SwitchSelectorSize.MD}`,\n },\n }\n);\n\nconst indicatorVariant = cva(\n 'absolute top-0 z-0 h-full w-auto rounded-full transition-[left,width] duration-300 ease-in-out motion-reduce:transition-none',\n {\n variants: {\n color: {\n [`${SwitchSelectorColor.PRIMARY}`]:\n 'bg-primary data-[indicator=true]:text-text',\n [`${SwitchSelectorColor.SECONDARY}`]:\n 'bg-secondary data-[indicator=true]:text-text',\n [`${SwitchSelectorColor.DESTRUCTIVE}`]:\n 'bg-destructive data-[indicator=true]:text-text',\n [`${SwitchSelectorColor.NEUTRAL}`]:\n 'bg-neutral data-[indicator=true]:text-white',\n [`${SwitchSelectorColor.LIGHT}`]:\n 'bg-white data-[indicator=true]:text-black',\n [`${SwitchSelectorColor.DARK}`]:\n 'bg-neutral-800 data-[indicator=true]:text-white',\n [`${SwitchSelectorColor.TEXT}`]:\n 'bg-text data-[indicator=true]:text-text-opposite',\n },\n },\n }\n);\n\n/**\n *\n * Component that allows the user to select one of the provided choices.\n *\n * Example:\n * ```jsx\n * <SwitchSelector\n * choices={[\n * { content: 'Option 1', value: 'option1' },\n * { content: 'Option 2', value: 'option2' },\n * { content: 'Option 3', value: 'option3' },\n * ]}\n * value=\"option1\"\n * onChange={(choice) => console.log(choice)}\n * />\n * ```\n */\nexport const SwitchSelector = <T,>({\n choices = defaultChoices as SwitchSelectorChoices<T>,\n value,\n defaultValue,\n onChange,\n color = SwitchSelectorColor.PRIMARY,\n size = SwitchSelectorSize.MD,\n className,\n hoverable = true,\n}: SwitchSelectorProps<T>) => {\n const [valueState, setValue] = useState<T>(\n value ?? defaultValue ?? choices[0].value\n );\n const [hoveredIndex, setHoveredIndex] = useState<number | null>(null);\n\n const optionsRefs = useRef<HTMLButtonElement[]>([]);\n const indicatorRef = useRef<HTMLDivElement | null>(null);\n const { choiceIndicatorPosition } = useItemSelector(optionsRefs, {\n isHoverable: hoverable,\n });\n\n const selectedIndex = choices.findIndex(\n (choice) => choice.value === valueState\n );\n\n // The indicator follows hover if hoverable, otherwise the selected option\n const indicatorIndex =\n hoverable && hoveredIndex !== null ? hoveredIndex : selectedIndex;\n\n const handleChange = (newValue: T) => {\n setValue(newValue);\n onChange?.(newValue);\n };\n\n useEffect(() => {\n if (value === undefined) return;\n setValue(value);\n }, [value]);\n\n return (\n <div\n className={switchSelectorVariant({\n color,\n className,\n })}\n role=\"tablist\"\n >\n <div className=\"relative flex size-full flex-row items-center justify-center\">\n {choices.map((choice, index) => {\n const { content, value, ...buttonProps } = choice;\n\n const isKeyOfKey =\n typeof value === 'string' || typeof value === 'number';\n\n const isSelected = index === selectedIndex;\n const isIndicatorOwner = index === indicatorIndex;\n\n return (\n <button\n {...buttonProps}\n className={cn(\n choiceVariant({\n size,\n })\n )}\n key={isKeyOfKey ? value : index}\n role=\"tab\"\n onClick={() => handleChange(value)}\n aria-selected={isSelected ? 'true' : undefined}\n data-indicator={isIndicatorOwner ? 'true' : undefined}\n disabled={isSelected}\n tabIndex={isSelected ? 0 : -1}\n ref={(el) => {\n optionsRefs.current[index] = el!;\n }}\n onMouseEnter={() => setHoveredIndex(index)}\n onMouseLeave={() => setHoveredIndex(null)}\n >\n {content}\n </button>\n );\n })}\n\n {choiceIndicatorPosition && (\n <div\n className={cn(\n indicatorVariant({\n color,\n })\n )}\n style={choiceIndicatorPosition}\n ref={indicatorRef}\n />\n )}\n </div>\n </div>\n );\n};\n"],"mappings":"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"}
|
|
@@ -187,14 +187,14 @@ const containerVariants = cva("w-fit backdrop-blur", {
|
|
|
187
187
|
},
|
|
188
188
|
size: {
|
|
189
189
|
[`${TagSize.XS}`]: "border-[1.2px] px-2 py-0.5 text-xs",
|
|
190
|
-
[`${TagSize.SM}`]: "border-[1.
|
|
190
|
+
[`${TagSize.SM}`]: "border-[1.3px] px-2 py-0.5 text-sm",
|
|
191
191
|
[`${TagSize.MD}`]: "border-2 px-2 py-1 text-base",
|
|
192
192
|
[`${TagSize.LG}`]: "border-2 px-3 py-2 text-lg",
|
|
193
193
|
[`${TagSize.XL}`]: "border-2 px-3 py-2 text-xl"
|
|
194
194
|
},
|
|
195
195
|
border: {
|
|
196
196
|
[`${TagBorder.NONE}`]: "border-none",
|
|
197
|
-
[`${TagBorder.WITH}`]: "border-[1.
|
|
197
|
+
[`${TagBorder.WITH}`]: "border-[1.3px] border-text"
|
|
198
198
|
},
|
|
199
199
|
background: {
|
|
200
200
|
[`${TagBackground.NONE}`]: "bg-none",
|