@timmbr/ui 1.0.0-beta → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +20 -16
- package/dist/components/Avatar/Avatar.styles.d.ts +1 -1
- package/dist/components/Badge/Badge.styles.d.ts +1 -1
- package/dist/components/Button/Button.styles.d.ts +2 -2
- package/dist/components/Chip/Chip.styles.d.ts +1 -1
- package/dist/components/CrossZoneLink/CrossZoneLink.d.ts +10 -0
- package/dist/components/CrossZoneLink/CrossZoneLink.d.ts.map +1 -0
- package/dist/components/CrossZoneLink/CrossZoneLink.js +111 -0
- package/dist/components/CrossZoneLink/CrossZoneLink.styles.d.ts +8 -0
- package/dist/components/CrossZoneLink/CrossZoneLink.styles.d.ts.map +1 -0
- package/dist/components/CrossZoneLink/CrossZoneLink.styles.js +33 -0
- package/dist/components/CrossZoneLink/CrossZoneLink.types.d.ts +31 -0
- package/dist/components/CrossZoneLink/CrossZoneLink.types.d.ts.map +1 -0
- package/dist/components/CrossZoneLink/index.d.ts +4 -0
- package/dist/components/CrossZoneLink/index.d.ts.map +1 -0
- package/dist/components/Divider/Divider.styles.d.ts +1 -1
- package/dist/components/FormField/FormField.js +3 -3
- package/dist/components/Heading/Heading.styles.d.ts +2 -2
- package/dist/components/Icon/Icon.styles.d.ts +1 -1
- package/dist/components/Inline/Inline.styles.d.ts +2 -2
- package/dist/components/Input/Input.js +3 -3
- package/dist/components/Input/Input.styles.d.ts +1 -1
- package/dist/components/Input/Input.styles.js +1 -1
- package/dist/components/Input/Input.types.d.ts +1 -1
- package/dist/components/Input/Input.types.d.ts.map +1 -1
- package/dist/components/LinkButton/LinkButton.d.ts +13 -0
- package/dist/components/LinkButton/LinkButton.d.ts.map +1 -0
- package/dist/components/LinkButton/LinkButton.js +179 -0
- package/dist/components/LinkButton/LinkButton.styles.d.ts +8 -0
- package/dist/components/LinkButton/LinkButton.styles.d.ts.map +1 -0
- package/dist/components/LinkButton/LinkButton.styles.js +61 -0
- package/dist/components/LinkButton/LinkButton.types.d.ts +60 -0
- package/dist/components/LinkButton/LinkButton.types.d.ts.map +1 -0
- package/dist/components/LinkButton/index.d.ts +4 -0
- package/dist/components/LinkButton/index.d.ts.map +1 -0
- package/dist/components/Progress/Progress.styles.d.ts +1 -1
- package/dist/components/Radio/Radio.js +3 -3
- package/dist/components/Select/Select.js +3 -3
- package/dist/components/Select/Select.styles.d.ts +1 -1
- package/dist/components/SideBarNavigation/SideBarNavigation.context.d.ts +15 -0
- package/dist/components/SideBarNavigation/SideBarNavigation.context.d.ts.map +1 -0
- package/dist/components/SideBarNavigation/SideBarNavigation.context.js +10 -0
- package/dist/components/SideBarNavigation/SideBarNavigation.d.ts +4 -0
- package/dist/components/SideBarNavigation/SideBarNavigation.d.ts.map +1 -0
- package/dist/components/SideBarNavigation/SideBarNavigation.helpers.d.ts +19 -0
- package/dist/components/SideBarNavigation/SideBarNavigation.helpers.d.ts.map +1 -0
- package/dist/components/SideBarNavigation/SideBarNavigation.helpers.js +48 -0
- package/dist/components/SideBarNavigation/SideBarNavigation.js +132 -0
- package/dist/components/SideBarNavigation/SideBarNavigation.styles.d.ts +18 -0
- package/dist/components/SideBarNavigation/SideBarNavigation.styles.d.ts.map +1 -0
- package/dist/components/SideBarNavigation/SideBarNavigation.styles.js +85 -0
- package/dist/components/SideBarNavigation/SideBarNavigation.types.d.ts +69 -0
- package/dist/components/SideBarNavigation/SideBarNavigation.types.d.ts.map +1 -0
- package/dist/components/SideBarNavigation/index.d.ts +13 -0
- package/dist/components/SideBarNavigation/index.d.ts.map +1 -0
- package/dist/components/SideBarNavigation/subcomponents/SidebarBranding.d.ts +13 -0
- package/dist/components/SideBarNavigation/subcomponents/SidebarBranding.d.ts.map +1 -0
- package/dist/components/SideBarNavigation/subcomponents/SidebarBranding.js +58 -0
- package/dist/components/SideBarNavigation/subcomponents/SidebarFooter.d.ts +10 -0
- package/dist/components/SideBarNavigation/subcomponents/SidebarFooter.d.ts.map +1 -0
- package/dist/components/SideBarNavigation/subcomponents/SidebarFooter.js +27 -0
- package/dist/components/SideBarNavigation/subcomponents/SidebarNavItem.d.ts +14 -0
- package/dist/components/SideBarNavigation/subcomponents/SidebarNavItem.d.ts.map +1 -0
- package/dist/components/SideBarNavigation/subcomponents/SidebarNavItem.js +147 -0
- package/dist/components/SideBarNavigation/subcomponents/SidebarPopoverMenu.d.ts +13 -0
- package/dist/components/SideBarNavigation/subcomponents/SidebarPopoverMenu.d.ts.map +1 -0
- package/dist/components/SideBarNavigation/subcomponents/SidebarPopoverMenu.js +106 -0
- package/dist/components/SideBarNavigation/subcomponents/SidebarProfile.d.ts +13 -0
- package/dist/components/SideBarNavigation/subcomponents/SidebarProfile.d.ts.map +1 -0
- package/dist/components/SideBarNavigation/subcomponents/SidebarProfile.js +118 -0
- package/dist/components/SideBarNavigation/subcomponents/SidebarSubItem.d.ts +13 -0
- package/dist/components/SideBarNavigation/subcomponents/SidebarSubItem.d.ts.map +1 -0
- package/dist/components/SideBarNavigation/subcomponents/SidebarSubItem.js +34 -0
- package/dist/components/SideBarNavigation/subcomponents/SidebarToggle.d.ts +8 -0
- package/dist/components/SideBarNavigation/subcomponents/SidebarToggle.d.ts.map +1 -0
- package/dist/components/SideBarNavigation/subcomponents/SidebarToggle.js +40 -0
- package/dist/components/Stack/Stack.styles.d.ts +2 -2
- package/dist/components/Tabs/Tabs.styles.d.ts +2 -2
- package/dist/components/Text/Text.styles.d.ts +2 -2
- package/dist/components/Textarea/Textarea.js +3 -3
- package/dist/components/Textarea/Textarea.styles.d.ts +1 -1
- package/dist/components/Toast/Toast.d.ts.map +1 -1
- package/dist/components/Toast/Toast.js +12 -3
- package/dist/components/Toast/Toast.types.d.ts +34 -0
- package/dist/components/Toast/Toast.types.d.ts.map +1 -1
- package/dist/components/Toast/ToastContainer.d.ts +7 -0
- package/dist/components/Toast/ToastContainer.d.ts.map +1 -0
- package/dist/components/Toast/ToastContainer.js +104 -0
- package/dist/components/Toast/index.d.ts +2 -0
- package/dist/components/Toast/index.d.ts.map +1 -1
- package/dist/components/Toast/toastStore.d.ts +31 -0
- package/dist/components/Toast/toastStore.d.ts.map +1 -0
- package/dist/components/Toast/toastStore.js +104 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +16 -1
- package/dist/providers/TimmbrConfigProvider.d.ts +20 -2
- package/dist/providers/TimmbrConfigProvider.d.ts.map +1 -1
- package/dist/providers/TimmbrConfigProvider.js +38 -3
- package/package.json +14 -6
package/README.md
CHANGED
|
@@ -67,12 +67,12 @@ export default function RootLayout({ children }: { children: React.ReactNode })
|
|
|
67
67
|
|
|
68
68
|
| Category | Components | Description |
|
|
69
69
|
| :--- | :--- | :--- |
|
|
70
|
-
| **Actions** | `Button` | Accessible
|
|
70
|
+
| **Actions** | `Button`, `LinkButton` | Accessible buttons and anchor links with `next/link` default SPA routing, adornment icons, loading spinners, and cross-zone delegation. |
|
|
71
71
|
| **Typography** | `Text`, `Heading` | Typography primitives restricted to semantic elements (`<p>`, `<span>`, `<h1>`–`<h6>`) with design token scaling. |
|
|
72
72
|
| **Surfaces** | `Card`, `Avatar`, `Badge`, `Chip`, `Divider` | Display primitives including user avatars, status pills, elevated cards, interactive chips, and separators. |
|
|
73
73
|
| **Layout** | `Container`, `Stack`, `Inline`, `Grid`, `Center` | Responsive breakpoint containers, flex distribution, responsive CSS grid, and centered wrappers. |
|
|
74
74
|
| **Form Controls** | `Input`, `Textarea`, `Select`, `Checkbox`, `Radio`, `Switch`, `RangeSlider`, `FormField`, `Label` | Comprehensive form primitives with labels, helper text, validation error states, and dual-thumb sliders. |
|
|
75
|
-
| **Navigation** | `Tabs`, `Pagination` |
|
|
75
|
+
| **Navigation** | `Tabs`, `Pagination`, `SideBarNavigation` | Accessible tabs, multi-page pagination, and responsive collapsable sidebar navigation. |
|
|
76
76
|
| **Feedback** | `Alert`, `Progress`, `Skeleton`, `Spinner`, `Toast` | Status banners, determinate/indeterminate progress, shimmer loaders, and card-deck multi-toasts with hover-spread. |
|
|
77
77
|
| **Overlays** | `Dialog`, `Drawer`, `Dropdown`, `Popover`, `Tooltip` | Centered dialogs, off-canvas sliding drawers, contextual dropdowns, interactive popovers, and accessible tooltips. |
|
|
78
78
|
| **Data Display** | `Table`, `DataList`, `Stat`, `EmptyState` | Structured data tables with pagination, key-value data lists, KPI metrics, and empty state placeholders. |
|
|
@@ -82,24 +82,28 @@ export default function RootLayout({ children }: { children: React.ReactNode })
|
|
|
82
82
|
## Component Usage
|
|
83
83
|
|
|
84
84
|
|
|
85
|
-
### Button
|
|
85
|
+
### Button & LinkButton
|
|
86
86
|
|
|
87
87
|
```tsx
|
|
88
|
-
import { Button } from '@timmbr/ui';
|
|
89
|
-
import Link from 'next/link';
|
|
88
|
+
import { Button, LinkButton } from '@timmbr/ui';
|
|
90
89
|
|
|
91
|
-
export function
|
|
90
|
+
export function NavigationExample() {
|
|
92
91
|
return (
|
|
93
|
-
<div className="flex gap-4">
|
|
94
|
-
{/*
|
|
95
|
-
<
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
{/*
|
|
100
|
-
<
|
|
101
|
-
|
|
102
|
-
</
|
|
92
|
+
<div className="flex gap-4 items-center">
|
|
93
|
+
{/* 1. Internal same-zone navigation: uses next/link by default, styled as a link */}
|
|
94
|
+
<LinkButton href="/dashboard">
|
|
95
|
+
Go to Dashboard
|
|
96
|
+
</LinkButton>
|
|
97
|
+
|
|
98
|
+
{/* 2. Button visual appearance if desired */}
|
|
99
|
+
<LinkButton href="/signup" variant="primary">
|
|
100
|
+
Sign Up
|
|
101
|
+
</LinkButton>
|
|
102
|
+
|
|
103
|
+
{/* 3. Cross-zone boundary: NEVER use next/link across zones. Always use crossZone */}
|
|
104
|
+
<LinkButton href="/docs" crossZone>
|
|
105
|
+
Documentation (Cross-Zone)
|
|
106
|
+
</LinkButton>
|
|
103
107
|
</div>
|
|
104
108
|
);
|
|
105
109
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type VariantProps } from 'class-variance-authority';
|
|
2
2
|
export declare const avatarRootVariants: (props?: ({
|
|
3
3
|
size?: "sm" | "lg" | "md" | "xl" | "2xl" | "xs" | null | undefined;
|
|
4
|
-
variant?: "
|
|
4
|
+
variant?: "grey" | "outline" | "subtle" | "primary" | "secondary" | null | undefined;
|
|
5
5
|
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
6
6
|
export declare const avatarStatusVariants: (props?: ({
|
|
7
7
|
status?: "online" | "offline" | "busy" | "away" | null | undefined;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type VariantProps } from 'class-variance-authority';
|
|
2
2
|
export declare const badgeVariants: (props?: ({
|
|
3
|
-
variant?: "default" | "
|
|
3
|
+
variant?: "default" | "destructive" | "success" | "outline" | "subtle" | "primary" | "secondary" | "brand" | null | undefined;
|
|
4
4
|
size?: "sm" | "lg" | "md" | null | undefined;
|
|
5
5
|
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
6
6
|
export type BadgeVariants = VariantProps<typeof badgeVariants>;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type VariantProps } from 'class-variance-authority';
|
|
2
2
|
export declare const buttonVariants: (props?: ({
|
|
3
|
-
variant?: "link" | "default" | "
|
|
4
|
-
size?: "default" | "
|
|
3
|
+
variant?: "link" | "default" | "destructive" | "outline" | "ghost" | "primary" | "secondary" | null | undefined;
|
|
4
|
+
size?: "default" | "icon" | "sm" | "lg" | "md" | null | undefined;
|
|
5
5
|
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
6
6
|
export type ButtonVariants = VariantProps<typeof buttonVariants>;
|
|
7
7
|
//# sourceMappingURL=Button.styles.d.ts.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type VariantProps } from 'class-variance-authority';
|
|
2
2
|
export declare const chipVariants: (props?: ({
|
|
3
3
|
variant?: "filled" | "subtle" | "outlined" | null | undefined;
|
|
4
|
-
color?: "default" | "
|
|
4
|
+
color?: "default" | "destructive" | "success" | "warning" | "primary" | null | undefined;
|
|
5
5
|
size?: "default" | "sm" | "lg" | null | undefined;
|
|
6
6
|
clickable?: boolean | null | undefined;
|
|
7
7
|
selected?: boolean | null | undefined;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import type { CrossZoneLinkProps } from './CrossZoneLink.types';
|
|
3
|
+
/**
|
|
4
|
+
* CrossZoneLink forces hard browser-level navigation across Next.js multi-zone / microfrontend boundaries.
|
|
5
|
+
*
|
|
6
|
+
* ARCHITECTURAL RULE:
|
|
7
|
+
* NEVER use `next/link` for navigation across zone boundaries. Always use `CrossZoneLink` from `@timmbr/ui`.
|
|
8
|
+
*/
|
|
9
|
+
export declare const CrossZoneLink: React.ForwardRefExoticComponent<CrossZoneLinkProps & React.RefAttributes<HTMLAnchorElement>>;
|
|
10
|
+
//# sourceMappingURL=CrossZoneLink.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CrossZoneLink.d.ts","sourceRoot":"","sources":["../../../src/components/CrossZoneLink/CrossZoneLink.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAK/B,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAEhE;;;;;GAKG;AACH,eAAO,MAAM,aAAa,8FA4GzB,CAAC"}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import { Slot } from '@radix-ui/react-slot';
|
|
5
|
+
import { cn } from '@timmbr/utils';
|
|
6
|
+
import { crossZoneLinkVariants } from './CrossZoneLink.styles.js';
|
|
7
|
+
import { useTimmbrConfig, resolveZoneHref } from '../../providers/TimmbrConfigProvider.js';
|
|
8
|
+
|
|
9
|
+
const CrossZoneLink = React.forwardRef(
|
|
10
|
+
({
|
|
11
|
+
className,
|
|
12
|
+
style,
|
|
13
|
+
variant,
|
|
14
|
+
size,
|
|
15
|
+
asChild = false,
|
|
16
|
+
href,
|
|
17
|
+
zone,
|
|
18
|
+
disabled = false,
|
|
19
|
+
leftIcon,
|
|
20
|
+
rightIcon,
|
|
21
|
+
target,
|
|
22
|
+
rel,
|
|
23
|
+
onClick,
|
|
24
|
+
children,
|
|
25
|
+
...props
|
|
26
|
+
}, ref) => {
|
|
27
|
+
const config = useTimmbrConfig();
|
|
28
|
+
const resolvedHref = resolveZoneHref(href, zone, config.zones?.zones);
|
|
29
|
+
const isExternal = resolvedHref.startsWith("http://") || resolvedHref.startsWith("https://") || target === "_blank";
|
|
30
|
+
const resolvedRel = rel ?? (isExternal ? "noopener noreferrer" : void 0);
|
|
31
|
+
const handleClick = (e) => {
|
|
32
|
+
if (disabled) {
|
|
33
|
+
e.preventDefault();
|
|
34
|
+
e.stopPropagation();
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
onClick?.(e);
|
|
38
|
+
};
|
|
39
|
+
if (asChild) {
|
|
40
|
+
return /* @__PURE__ */ jsx(
|
|
41
|
+
Slot,
|
|
42
|
+
{
|
|
43
|
+
ref,
|
|
44
|
+
"data-slot": "cross-zone-link",
|
|
45
|
+
"data-cross-zone": "true",
|
|
46
|
+
"aria-disabled": disabled ? "true" : void 0,
|
|
47
|
+
tabIndex: disabled ? -1 : props.tabIndex,
|
|
48
|
+
className: cn(
|
|
49
|
+
crossZoneLinkVariants({
|
|
50
|
+
variant,
|
|
51
|
+
size,
|
|
52
|
+
disabled,
|
|
53
|
+
className
|
|
54
|
+
})
|
|
55
|
+
),
|
|
56
|
+
style,
|
|
57
|
+
onClick: handleClick,
|
|
58
|
+
...props,
|
|
59
|
+
children
|
|
60
|
+
}
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
return /* @__PURE__ */ jsxs(
|
|
64
|
+
"a",
|
|
65
|
+
{
|
|
66
|
+
ref,
|
|
67
|
+
href: disabled ? void 0 : resolvedHref,
|
|
68
|
+
target,
|
|
69
|
+
rel: resolvedRel,
|
|
70
|
+
"data-slot": "cross-zone-link",
|
|
71
|
+
"data-cross-zone": "true",
|
|
72
|
+
"data-testid": "timmbr-cross-zone-link",
|
|
73
|
+
"aria-disabled": disabled ? "true" : void 0,
|
|
74
|
+
tabIndex: disabled ? -1 : props.tabIndex,
|
|
75
|
+
style,
|
|
76
|
+
onClick: handleClick,
|
|
77
|
+
className: cn(
|
|
78
|
+
crossZoneLinkVariants({
|
|
79
|
+
variant,
|
|
80
|
+
size,
|
|
81
|
+
disabled,
|
|
82
|
+
className
|
|
83
|
+
})
|
|
84
|
+
),
|
|
85
|
+
...props,
|
|
86
|
+
children: [
|
|
87
|
+
leftIcon && /* @__PURE__ */ jsx(
|
|
88
|
+
"span",
|
|
89
|
+
{
|
|
90
|
+
className: "inline-flex shrink-0 items-center justify-center pointer-events-none",
|
|
91
|
+
"data-slot": "cross-zone-link-left-icon",
|
|
92
|
+
children: leftIcon
|
|
93
|
+
}
|
|
94
|
+
),
|
|
95
|
+
children && /* @__PURE__ */ jsx("span", { children }),
|
|
96
|
+
rightIcon && /* @__PURE__ */ jsx(
|
|
97
|
+
"span",
|
|
98
|
+
{
|
|
99
|
+
className: "inline-flex shrink-0 items-center justify-center pointer-events-none",
|
|
100
|
+
"data-slot": "cross-zone-link-right-icon",
|
|
101
|
+
children: rightIcon
|
|
102
|
+
}
|
|
103
|
+
)
|
|
104
|
+
]
|
|
105
|
+
}
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
);
|
|
109
|
+
CrossZoneLink.displayName = "CrossZoneLink";
|
|
110
|
+
|
|
111
|
+
export { CrossZoneLink };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type VariantProps } from 'class-variance-authority';
|
|
2
|
+
export declare const crossZoneLinkVariants: (props?: ({
|
|
3
|
+
variant?: "default" | "inline" | "subtle" | "primary" | "secondary" | "muted" | null | undefined;
|
|
4
|
+
size?: "default" | "sm" | "lg" | null | undefined;
|
|
5
|
+
disabled?: boolean | null | undefined;
|
|
6
|
+
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
7
|
+
export type CrossZoneLinkVariants = VariantProps<typeof crossZoneLinkVariants>;
|
|
8
|
+
//# sourceMappingURL=CrossZoneLink.styles.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CrossZoneLink.styles.d.ts","sourceRoot":"","sources":["../../../src/components/CrossZoneLink/CrossZoneLink.styles.ts"],"names":[],"mappings":"AAAA,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAElE,eAAO,MAAM,qBAAqB;;;;8EA4BjC,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG,YAAY,CAAC,OAAO,qBAAqB,CAAC,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { cva } from 'class-variance-authority';
|
|
2
|
+
|
|
3
|
+
const crossZoneLinkVariants = cva(
|
|
4
|
+
"inline-flex items-center no-underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-2 rounded-[2px] transition-all duration-150 select-none",
|
|
5
|
+
{
|
|
6
|
+
variants: {
|
|
7
|
+
variant: {
|
|
8
|
+
default: "text-primary hover:underline underline-offset-4 font-medium",
|
|
9
|
+
primary: "text-primary font-semibold hover:brightness-110 active:brightness-95",
|
|
10
|
+
secondary: "text-secondary-foreground hover:text-foreground font-medium",
|
|
11
|
+
muted: "text-grey-600 dark:text-grey-400 hover:text-foreground font-normal",
|
|
12
|
+
subtle: "text-foreground/80 hover:text-foreground font-normal",
|
|
13
|
+
inline: "text-primary underline underline-offset-4 hover:opacity-80 inline font-medium"
|
|
14
|
+
},
|
|
15
|
+
size: {
|
|
16
|
+
sm: "text-xs gap-1",
|
|
17
|
+
default: "text-sm gap-1.5",
|
|
18
|
+
lg: "text-base gap-2"
|
|
19
|
+
},
|
|
20
|
+
disabled: {
|
|
21
|
+
true: "pointer-events-none opacity-50 cursor-not-allowed",
|
|
22
|
+
false: "cursor-pointer"
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
defaultVariants: {
|
|
26
|
+
variant: "default",
|
|
27
|
+
size: "default",
|
|
28
|
+
disabled: false
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
export { crossZoneLinkVariants };
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type * as React from 'react';
|
|
2
|
+
import type { VariantProps } from 'class-variance-authority';
|
|
3
|
+
import type { crossZoneLinkVariants } from './CrossZoneLink.styles';
|
|
4
|
+
export interface CrossZoneLinkProps extends React.AnchorHTMLAttributes<HTMLAnchorElement>, VariantProps<typeof crossZoneLinkVariants> {
|
|
5
|
+
/**
|
|
6
|
+
* The destination URL or relative path.
|
|
7
|
+
*/
|
|
8
|
+
href: string;
|
|
9
|
+
/**
|
|
10
|
+
* Optional zone key corresponding to configured zones in TimmbrConfigProvider.
|
|
11
|
+
* If provided and configured, resolves against the zone's base URL.
|
|
12
|
+
*/
|
|
13
|
+
zone?: string;
|
|
14
|
+
/**
|
|
15
|
+
* Merges props onto an immediate child element using Radix UI Slot.
|
|
16
|
+
*/
|
|
17
|
+
asChild?: boolean;
|
|
18
|
+
/**
|
|
19
|
+
* Leading icon element rendered before link text.
|
|
20
|
+
*/
|
|
21
|
+
leftIcon?: React.ReactNode;
|
|
22
|
+
/**
|
|
23
|
+
* Trailing icon element rendered after link text.
|
|
24
|
+
*/
|
|
25
|
+
rightIcon?: React.ReactNode;
|
|
26
|
+
/**
|
|
27
|
+
* Disables user interaction and navigation.
|
|
28
|
+
*/
|
|
29
|
+
disabled?: boolean;
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=CrossZoneLink.types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CrossZoneLink.types.d.ts","sourceRoot":"","sources":["../../../src/components/CrossZoneLink/CrossZoneLink.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,KAAK,MAAM,OAAO,CAAC;AACpC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAEpE,MAAM,WAAW,kBACf,SAAQ,KAAK,CAAC,oBAAoB,CAAC,iBAAiB,CAAC,EACnD,YAAY,CAAC,OAAO,qBAAqB,CAAC;IAC5C;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IACb;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;OAEG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;OAEG;IACH,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B;;OAEG;IACH,SAAS,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC5B;;OAEG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/CrossZoneLink/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,qBAAqB,EAAE,KAAK,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAC3F,YAAY,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC"}
|
|
@@ -3,7 +3,7 @@ export declare const dividerVariants: (props?: ({
|
|
|
3
3
|
orientation?: "horizontal" | "vertical" | null | undefined;
|
|
4
4
|
variant?: "dashed" | "dotted" | "solid" | null | undefined;
|
|
5
5
|
thickness?: "default" | "thick" | "thin" | null | undefined;
|
|
6
|
-
color?: "default" | "primary" | "
|
|
6
|
+
color?: "default" | "primary" | "muted" | "brand" | null | undefined;
|
|
7
7
|
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
8
8
|
export type DividerVariants = VariantProps<typeof dividerVariants>;
|
|
9
9
|
//# sourceMappingURL=Divider.styles.d.ts.map
|
|
@@ -39,12 +39,12 @@ const FormField = React.forwardRef(
|
|
|
39
39
|
{
|
|
40
40
|
id: `${id}-desc`,
|
|
41
41
|
className: cn(
|
|
42
|
-
"text-xs mt-0.5 flex items-
|
|
42
|
+
"text-xs mt-0.5 flex items-start gap-1.5",
|
|
43
43
|
isError ? "text-destructive font-medium" : "text-muted"
|
|
44
44
|
),
|
|
45
45
|
children: [
|
|
46
|
-
isError ? /* @__PURE__ */ jsx(AlertCircle, { className: "w-3.5 h-3.5 shrink-0", "aria-hidden": "true" }) : /* @__PURE__ */ jsx(Info, { className: "w-3.5 h-3.5 shrink-0", "aria-hidden": "true" }),
|
|
47
|
-
/* @__PURE__ */ jsx("span", { children: errorMessage || helperText })
|
|
46
|
+
isError ? /* @__PURE__ */ jsx(AlertCircle, { className: "w-3.5 h-3.5 shrink-0 mt-0.5", "aria-hidden": "true" }) : /* @__PURE__ */ jsx(Info, { className: "w-3.5 h-3.5 shrink-0 mt-0.5", "aria-hidden": "true" }),
|
|
47
|
+
/* @__PURE__ */ jsx("span", { className: "leading-tight", children: errorMessage || helperText })
|
|
48
48
|
]
|
|
49
49
|
}
|
|
50
50
|
)
|
|
@@ -2,8 +2,8 @@ import { type VariantProps } from 'class-variance-authority';
|
|
|
2
2
|
export declare const headingVariants: (props?: ({
|
|
3
3
|
level?: 1 | 2 | 3 | 4 | 5 | 6 | null | undefined;
|
|
4
4
|
font?: "title" | "display" | null | undefined;
|
|
5
|
-
foreground?: "default" | "inherit" | "white" | "subtle" | "primary" | "secondary" | "
|
|
6
|
-
weight?: "bold" | "
|
|
5
|
+
foreground?: "default" | "destructive" | "inherit" | "white" | "subtle" | "primary" | "secondary" | "muted" | null | undefined;
|
|
6
|
+
weight?: "bold" | "normal" | "medium" | "light" | "semibold" | null | undefined;
|
|
7
7
|
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
8
8
|
export type HeadingVariants = VariantProps<typeof headingVariants>;
|
|
9
9
|
//# sourceMappingURL=Heading.styles.d.ts.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type VariantProps } from 'class-variance-authority';
|
|
2
2
|
export declare const iconVariants: (props?: ({
|
|
3
3
|
size?: "sm" | "lg" | "md" | "xl" | "xs" | null | undefined;
|
|
4
|
-
foreground?: "default" | "inherit" | "white" | "subtle" | "primary" | "secondary" | "
|
|
4
|
+
foreground?: "default" | "destructive" | "inherit" | "white" | "subtle" | "primary" | "secondary" | "muted" | null | undefined;
|
|
5
5
|
clickable?: boolean | null | undefined;
|
|
6
6
|
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
7
7
|
export type IconVariants = VariantProps<typeof iconVariants>;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type VariantProps } from 'class-variance-authority';
|
|
2
2
|
export declare const inlineVariants: (props?: ({
|
|
3
|
-
align?: "center" | "
|
|
4
|
-
justify?: "center" | "
|
|
3
|
+
align?: "center" | "start" | "end" | "baseline" | null | undefined;
|
|
4
|
+
justify?: "center" | "start" | "end" | "between" | "around" | "evenly" | null | undefined;
|
|
5
5
|
wrap?: boolean | null | undefined;
|
|
6
6
|
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
7
7
|
export type InlineVariants = VariantProps<typeof inlineVariants>;
|
|
@@ -175,12 +175,12 @@ const Input = React.forwardRef(
|
|
|
175
175
|
{
|
|
176
176
|
id: `${id}-desc`,
|
|
177
177
|
className: cn(
|
|
178
|
-
"text-xs mt-0.5 flex items-
|
|
178
|
+
"text-xs mt-0.5 flex items-start gap-1.5 text-left",
|
|
179
179
|
isError ? "text-destructive font-medium" : "text-muted-foreground"
|
|
180
180
|
),
|
|
181
181
|
children: [
|
|
182
|
-
isError ? /* @__PURE__ */ jsx(AlertCircle, { className: "w-3.5 h-3.5 shrink-0 text-destructive", "aria-hidden": "true" }) : /* @__PURE__ */ jsx(Info, { className: "w-3.5 h-3.5 shrink-0 text-muted-foreground", "aria-hidden": "true" }),
|
|
183
|
-
/* @__PURE__ */ jsx("span", { children: errorMessage || helperText })
|
|
182
|
+
isError ? /* @__PURE__ */ jsx(AlertCircle, { className: "w-3.5 h-3.5 shrink-0 mt-0.5 text-destructive", "aria-hidden": "true" }) : /* @__PURE__ */ jsx(Info, { className: "w-3.5 h-3.5 shrink-0 mt-0.5 text-muted-foreground", "aria-hidden": "true" }),
|
|
183
|
+
/* @__PURE__ */ jsx("span", { className: "leading-tight", children: errorMessage || helperText })
|
|
184
184
|
]
|
|
185
185
|
}
|
|
186
186
|
)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type VariantProps } from 'class-variance-authority';
|
|
2
2
|
export declare const inputWrapperVariants: (props?: ({
|
|
3
|
-
variant?: "
|
|
3
|
+
variant?: "filled" | "outline" | "subtle" | null | undefined;
|
|
4
4
|
size?: "default" | "sm" | "lg" | "md" | null | undefined;
|
|
5
5
|
isError?: boolean | null | undefined;
|
|
6
6
|
isDisabled?: boolean | null | undefined;
|
|
@@ -33,7 +33,7 @@ const inputWrapperVariants = cva(
|
|
|
33
33
|
}
|
|
34
34
|
);
|
|
35
35
|
const inputFieldVariants = cva(
|
|
36
|
-
"w-full h-full bg-transparent font-sans border-0 p-0 text-foreground placeholder:text-muted focus:outline-none focus:ring-0 focus-visible:outline-none disabled:cursor-not-allowed"
|
|
36
|
+
"w-full h-full bg-transparent font-sans border-0 p-0 text-foreground placeholder:text-muted focus:outline-none focus:ring-0 focus-visible:outline-none disabled:cursor-not-allowed [box-shadow:none] [&:-webkit-autofill]:[-webkit-background-clip:text] [&:-webkit-autofill]:[background-clip:text] [&:-webkit-autofill]:[-webkit-text-fill-color:currentColor] [&:-webkit-autofill]:[caret-color:currentColor] [&:-webkit-autofill]:[transition:background-color_5000000s_ease-in-out_0s] [&:-webkit-autofill]:[box-shadow:none] [&:autofill]:[-webkit-background-clip:text] [&:autofill]:[background-clip:text] [&:autofill]:[-webkit-text-fill-color:currentColor] [&:autofill]:[caret-color:currentColor] [&:autofill]:[transition:background-color_5000000s_ease-in-out_0s] [&:autofill]:[box-shadow:none]"
|
|
37
37
|
);
|
|
38
38
|
|
|
39
39
|
export { inputFieldVariants, inputWrapperVariants };
|
|
@@ -41,7 +41,7 @@ export interface InputProps extends Omit<React.InputHTMLAttributes<HTMLInputElem
|
|
|
41
41
|
/**
|
|
42
42
|
* HTML input type (text, password, email, number, search, tel, url, date, etc.).
|
|
43
43
|
*/
|
|
44
|
-
type?: 'text' | 'password' | 'email' | 'number' | 'search' | 'tel' | 'url' | 'date' | 'time' | (string &
|
|
44
|
+
type?: 'text' | 'password' | 'email' | 'number' | 'search' | 'tel' | 'url' | 'date' | 'time' | (string & Record<never, never>);
|
|
45
45
|
/**
|
|
46
46
|
* Whether to display an interactive show/hide password toggle button when type="password".
|
|
47
47
|
* Defaults to true.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Input.types.d.ts","sourceRoot":"","sources":["../../../src/components/Input/Input.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,KAAK,MAAM,OAAO,CAAC;AACpC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AACpD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAErD,MAAM,WAAW,UACf,SAAQ,IAAI,CAAC,KAAK,CAAC,mBAAmB,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC,EAC/D,aAAa;IACf;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;OAEG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;OAEG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B;;OAEG;IACH,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IACzB;;OAEG;IACH,aAAa,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAChC;;OAEG;IACH,cAAc,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACjC;;OAEG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;OAEG;IACH,IAAI,CAAC,EACD,MAAM,GACN,UAAU,GACV,OAAO,GACP,QAAQ,GACR,QAAQ,GACR,KAAK,GACL,KAAK,GACL,MAAM,GACN,MAAM,GACN,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"Input.types.d.ts","sourceRoot":"","sources":["../../../src/components/Input/Input.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,KAAK,MAAM,OAAO,CAAC;AACpC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AACpD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAErD,MAAM,WAAW,UACf,SAAQ,IAAI,CAAC,KAAK,CAAC,mBAAmB,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC,EAC/D,aAAa;IACf;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;OAEG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;OAEG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B;;OAEG;IACH,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IACzB;;OAEG;IACH,aAAa,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAChC;;OAEG;IACH,cAAc,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACjC;;OAEG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;OAEG;IACH,IAAI,CAAC,EACD,MAAM,GACN,UAAU,GACV,OAAO,GACP,QAAQ,GACR,QAAQ,GACR,KAAK,GACL,KAAK,GACL,MAAM,GACN,MAAM,GACN,CAAC,MAAM,GAAG,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC;IACpC;;;OAGG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import type { LinkButtonProps } from './LinkButton.types';
|
|
3
|
+
/**
|
|
4
|
+
* LinkButton is a unified navigation component for internal, cross-zone, and external links.
|
|
5
|
+
*
|
|
6
|
+
* NAVIGATION RULES:
|
|
7
|
+
* 1. Internal same-zone navigation: Uses Next.js `next/link` by default for client-side SPA routing and prefetching.
|
|
8
|
+
* 2. Cross-zone boundary navigation: Uses native HTML `<a>` navigation when `crossZone={true}` or when `zone` points
|
|
9
|
+
* to an external zone. NEVER use `next/link` across zone boundaries.
|
|
10
|
+
* 3. Default variant: Styled as a link by default, with button visual styling available via variant props.
|
|
11
|
+
*/
|
|
12
|
+
export declare const LinkButton: React.ForwardRefExoticComponent<LinkButtonProps & React.RefAttributes<HTMLAnchorElement>>;
|
|
13
|
+
//# sourceMappingURL=LinkButton.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LinkButton.d.ts","sourceRoot":"","sources":["../../../src/components/LinkButton/LinkButton.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAQ/B,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAE1D;;;;;;;;GAQG;AACH,eAAO,MAAM,UAAU,2FAyMtB,CAAC"}
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import NextLink from 'next/link';
|
|
5
|
+
import { Slot } from '@radix-ui/react-slot';
|
|
6
|
+
import { cn } from '@timmbr/utils';
|
|
7
|
+
import { SpinnerIcon } from '@timmbr/icons';
|
|
8
|
+
import { resolveMotion } from '../../types/motion.js';
|
|
9
|
+
import { linkButtonVariants } from './LinkButton.styles.js';
|
|
10
|
+
import { useTimmbrConfig, resolveZoneHref } from '../../providers/TimmbrConfigProvider.js';
|
|
11
|
+
import { useGlobalAnimation } from '../../providers/AnimationProvider.js';
|
|
12
|
+
|
|
13
|
+
const LinkButton = React.forwardRef(
|
|
14
|
+
({
|
|
15
|
+
className,
|
|
16
|
+
style,
|
|
17
|
+
variant,
|
|
18
|
+
size,
|
|
19
|
+
asChild = false,
|
|
20
|
+
motion,
|
|
21
|
+
leftIcon,
|
|
22
|
+
rightIcon,
|
|
23
|
+
loading = false,
|
|
24
|
+
loadingText,
|
|
25
|
+
disabled = false,
|
|
26
|
+
href,
|
|
27
|
+
zone,
|
|
28
|
+
crossZone = false,
|
|
29
|
+
prefetch,
|
|
30
|
+
replace,
|
|
31
|
+
scroll,
|
|
32
|
+
target,
|
|
33
|
+
rel,
|
|
34
|
+
onClick,
|
|
35
|
+
children,
|
|
36
|
+
...props
|
|
37
|
+
}, ref) => {
|
|
38
|
+
const config = useTimmbrConfig();
|
|
39
|
+
const globalMotion = useGlobalAnimation();
|
|
40
|
+
const resolvedVariant = variant ?? config.components?.button?.defaultVariant ?? "default";
|
|
41
|
+
const resolvedSize = size ?? config.components?.button?.defaultSize ?? "default";
|
|
42
|
+
const { shouldAnimate, motionClass } = resolveMotion(motion, globalMotion);
|
|
43
|
+
const isDisabled = disabled || loading;
|
|
44
|
+
const resolvedHref = href ? resolveZoneHref(href, zone, config.zones?.zones) : void 0;
|
|
45
|
+
const handleClick = (e) => {
|
|
46
|
+
if (isDisabled) {
|
|
47
|
+
e.preventDefault();
|
|
48
|
+
e.stopPropagation();
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
onClick?.(e);
|
|
52
|
+
};
|
|
53
|
+
const buttonClassName = cn(
|
|
54
|
+
linkButtonVariants({
|
|
55
|
+
variant: resolvedVariant,
|
|
56
|
+
size: resolvedSize,
|
|
57
|
+
disabled: isDisabled,
|
|
58
|
+
className
|
|
59
|
+
}),
|
|
60
|
+
!shouldAnimate && "transition-none active:scale-100",
|
|
61
|
+
motionClass
|
|
62
|
+
);
|
|
63
|
+
if (asChild) {
|
|
64
|
+
return /* @__PURE__ */ jsx(
|
|
65
|
+
Slot,
|
|
66
|
+
{
|
|
67
|
+
ref,
|
|
68
|
+
className: buttonClassName,
|
|
69
|
+
style,
|
|
70
|
+
"data-slot": "link-button",
|
|
71
|
+
"aria-disabled": isDisabled ? "true" : void 0,
|
|
72
|
+
tabIndex: isDisabled ? -1 : props.tabIndex,
|
|
73
|
+
onClick: handleClick,
|
|
74
|
+
...props,
|
|
75
|
+
children
|
|
76
|
+
}
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
const content = loading ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
80
|
+
/* @__PURE__ */ jsx(SpinnerIcon, { size: resolvedSize === "sm" ? 14 : 18 }),
|
|
81
|
+
loadingText ? /* @__PURE__ */ jsx("span", { children: loadingText }) : children
|
|
82
|
+
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
83
|
+
leftIcon && /* @__PURE__ */ jsx(
|
|
84
|
+
"span",
|
|
85
|
+
{
|
|
86
|
+
className: "inline-flex shrink-0 items-center justify-center pointer-events-none",
|
|
87
|
+
"data-slot": "link-button-left-icon",
|
|
88
|
+
children: leftIcon
|
|
89
|
+
}
|
|
90
|
+
),
|
|
91
|
+
children && /* @__PURE__ */ jsx("span", { children }),
|
|
92
|
+
rightIcon && /* @__PURE__ */ jsx(
|
|
93
|
+
"span",
|
|
94
|
+
{
|
|
95
|
+
className: "inline-flex shrink-0 items-center justify-center pointer-events-none",
|
|
96
|
+
"data-slot": "link-button-right-icon",
|
|
97
|
+
children: rightIcon
|
|
98
|
+
}
|
|
99
|
+
)
|
|
100
|
+
] });
|
|
101
|
+
if (isDisabled) {
|
|
102
|
+
return /* @__PURE__ */ jsx(
|
|
103
|
+
"a",
|
|
104
|
+
{
|
|
105
|
+
ref,
|
|
106
|
+
"data-slot": "link-button",
|
|
107
|
+
"data-testid": "timmbr-link-button",
|
|
108
|
+
"aria-disabled": "true",
|
|
109
|
+
tabIndex: -1,
|
|
110
|
+
style,
|
|
111
|
+
onClick: handleClick,
|
|
112
|
+
className: buttonClassName,
|
|
113
|
+
...props,
|
|
114
|
+
children: content
|
|
115
|
+
}
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
const isExternal = Boolean(resolvedHref) && (resolvedHref.startsWith("http://") || resolvedHref.startsWith("https://") || resolvedHref.startsWith("mailto:") || resolvedHref.startsWith("tel:") || target === "_blank");
|
|
119
|
+
const isDifferentZone = Boolean(zone) && Boolean(config.zones?.currentZone) && zone !== config.zones?.currentZone;
|
|
120
|
+
const requiresCrossZone = crossZone || isDifferentZone || Boolean(zone && !config.zones?.currentZone);
|
|
121
|
+
const resolvedRel = rel ?? (isExternal ? "noopener noreferrer" : void 0);
|
|
122
|
+
if (requiresCrossZone || isExternal) {
|
|
123
|
+
return /* @__PURE__ */ jsx(
|
|
124
|
+
"a",
|
|
125
|
+
{
|
|
126
|
+
ref,
|
|
127
|
+
href: resolvedHref ?? "#",
|
|
128
|
+
target,
|
|
129
|
+
rel: resolvedRel,
|
|
130
|
+
"data-slot": "link-button",
|
|
131
|
+
"data-cross-zone": requiresCrossZone ? "true" : void 0,
|
|
132
|
+
"data-testid": "timmbr-link-button",
|
|
133
|
+
style,
|
|
134
|
+
onClick: handleClick,
|
|
135
|
+
className: buttonClassName,
|
|
136
|
+
...props,
|
|
137
|
+
children: content
|
|
138
|
+
}
|
|
139
|
+
);
|
|
140
|
+
}
|
|
141
|
+
if (resolvedHref) {
|
|
142
|
+
return /* @__PURE__ */ jsx(
|
|
143
|
+
NextLink,
|
|
144
|
+
{
|
|
145
|
+
ref,
|
|
146
|
+
href: resolvedHref,
|
|
147
|
+
prefetch,
|
|
148
|
+
replace,
|
|
149
|
+
scroll,
|
|
150
|
+
target,
|
|
151
|
+
rel: resolvedRel,
|
|
152
|
+
"data-slot": "link-button",
|
|
153
|
+
"data-testid": "timmbr-link-button",
|
|
154
|
+
style,
|
|
155
|
+
onClick: handleClick,
|
|
156
|
+
className: buttonClassName,
|
|
157
|
+
...props,
|
|
158
|
+
children: content
|
|
159
|
+
}
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
return /* @__PURE__ */ jsx(
|
|
163
|
+
"a",
|
|
164
|
+
{
|
|
165
|
+
ref,
|
|
166
|
+
"data-slot": "link-button",
|
|
167
|
+
"data-testid": "timmbr-link-button",
|
|
168
|
+
style,
|
|
169
|
+
onClick: handleClick,
|
|
170
|
+
className: buttonClassName,
|
|
171
|
+
...props,
|
|
172
|
+
children: content
|
|
173
|
+
}
|
|
174
|
+
);
|
|
175
|
+
}
|
|
176
|
+
);
|
|
177
|
+
LinkButton.displayName = "LinkButton";
|
|
178
|
+
|
|
179
|
+
export { LinkButton };
|