@boyernick/standard-ui-react 0.1.1-canary.9 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +5 -3
- package/src/accordion.tsx +5 -2
- package/src/alert-dialog.tsx +1 -1
- package/src/attachment.tsx +5 -2
- package/src/autocomplete.tsx +4 -3
- package/src/block-editor.tsx +1747 -0
- package/src/brand.tsx +2 -2
- package/src/breadcrumb.tsx +14 -7
- package/src/button.tsx +22 -11
- package/src/calendar.tsx +6 -3
- package/src/carousel.tsx +220 -53
- package/src/checkbox.tsx +3 -2
- package/src/code-block.tsx +66 -5
- package/src/collapsible.tsx +4 -2
- package/src/combobox.tsx +4 -3
- package/src/command.tsx +27 -12
- package/src/dialog.tsx +33 -10
- package/src/empty.tsx +4 -4
- package/src/field.tsx +4 -3
- package/src/filter-group.tsx +143 -0
- package/src/icons.tsx +28 -1
- package/src/illustrations.tsx +219 -141
- package/src/index.ts +238 -18
- package/src/input.tsx +8 -5
- package/src/kbd.tsx +10 -4
- package/src/lib/focus.ts +41 -0
- package/src/lib/popup.ts +1 -1
- package/src/lifeline/company-icon.tsx +71 -0
- package/src/lifeline/index.ts +42 -0
- package/src/lifeline/lifeline-data.ts +97 -0
- package/src/lifeline/lifeline-desktop.tsx +204 -0
- package/src/lifeline/lifeline-event.tsx +108 -0
- package/src/lifeline/lifeline-fireworks.tsx +302 -0
- package/src/lifeline/lifeline-hover-image.tsx +269 -0
- package/src/lifeline/lifeline-icons.tsx +39 -0
- package/src/lifeline/lifeline-intro-timing.ts +105 -0
- package/src/lifeline/lifeline-labels.tsx +24 -0
- package/src/lifeline/lifeline-layout.ts +1 -0
- package/src/lifeline/lifeline-legend.tsx +31 -0
- package/src/lifeline/lifeline-lightbox.tsx +309 -0
- package/src/lifeline/lifeline-marker.tsx +183 -0
- package/src/lifeline/lifeline-people.tsx +99 -0
- package/src/lifeline/lifeline-photos.tsx +366 -0
- package/src/lifeline/lifeline-shell.tsx +135 -0
- package/src/lifeline/lifeline-utils.ts +83 -0
- package/src/lifeline/lifeline-vertical.tsx +482 -0
- package/src/lifeline/lifeline.tsx +69 -0
- package/src/lifeline/types.ts +112 -0
- package/src/lifeline/use-lifeline-intro.ts +130 -0
- package/src/lifeline/use-lifeline-scroll.ts +1011 -0
- package/src/lifeline/use-lifeline-vertical-scroll.ts +271 -0
- package/src/menubar.tsx +9 -2
- package/src/minimap.tsx +296 -0
- package/src/modal.tsx +608 -0
- package/src/navigation-menu.tsx +338 -67
- package/src/number-field.tsx +336 -61
- package/src/otp-field.tsx +4 -3
- package/src/pagination.tsx +262 -42
- package/src/password-protection.tsx +345 -0
- package/src/popover.tsx +1 -1
- package/src/progress.tsx +5 -0
- package/src/questionnaire.tsx +284 -0
- package/src/radio.tsx +4 -2
- package/src/scroll-area.tsx +4 -1
- package/src/select.tsx +5 -2
- package/src/sidebar.tsx +113 -28
- package/src/slider.tsx +66 -6
- package/src/sounds.tsx +6 -10
- package/src/spinner.tsx +105 -32
- package/src/switch.tsx +4 -1
- package/src/table.tsx +82 -15
- package/src/tabs.tsx +189 -38
- package/src/text-animate.tsx +71 -28
- package/src/textarea.tsx +6 -1
- package/src/timeline.tsx +378 -0
- package/src/toast.tsx +214 -35
- package/src/toggle.tsx +4 -2
- package/src/toolbar.tsx +12 -7
- package/src/tooltip.tsx +43 -3
- package/src/video-player.tsx +396 -127
- package/src/image-modal.tsx +0 -110
- package/src/markdown-editor.tsx +0 -302
package/src/sounds.tsx
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use client"
|
|
2
2
|
|
|
3
|
+
import { IconPlay } from "@central-icons-react/round-filled-radius-2-stroke-2/IconPlay"
|
|
3
4
|
import {
|
|
4
5
|
createContext,
|
|
5
6
|
useCallback,
|
|
@@ -28,7 +29,7 @@ const SOUND_PRESETS: SoundPreset[] = [
|
|
|
28
29
|
{
|
|
29
30
|
id: "click",
|
|
30
31
|
label: "Click",
|
|
31
|
-
description: "
|
|
32
|
+
description: "Confirmation for toggles and secondary actions.",
|
|
32
33
|
play: (ctx, when, destination) => {
|
|
33
34
|
const osc = ctx.createOscillator()
|
|
34
35
|
const gain = ctx.createGain()
|
|
@@ -219,14 +220,15 @@ export const Sound = ({
|
|
|
219
220
|
>
|
|
220
221
|
<Button
|
|
221
222
|
type="button"
|
|
222
|
-
variant="
|
|
223
|
-
size="
|
|
223
|
+
variant="secondary"
|
|
224
|
+
size="md"
|
|
224
225
|
iconOnly
|
|
225
226
|
rounded
|
|
227
|
+
className="shrink-0 hover:scale-[1.04] active:scale-95"
|
|
226
228
|
aria-label={`Play ${resolvedLabel}`}
|
|
227
229
|
onClick={handlePlay}
|
|
228
230
|
>
|
|
229
|
-
<
|
|
231
|
+
<IconPlay size={12} mode="raw" className="size-3" aria-hidden />
|
|
230
232
|
</Button>
|
|
231
233
|
<div className="min-w-0 flex-1">
|
|
232
234
|
<p className="text-sm-strong text-fg-primary">{resolvedLabel}</p>
|
|
@@ -262,9 +264,3 @@ export const SoundToggle = ({
|
|
|
262
264
|
</Button>
|
|
263
265
|
)
|
|
264
266
|
}
|
|
265
|
-
|
|
266
|
-
const PlayIcon = () => (
|
|
267
|
-
<svg viewBox="0 0 24 24" fill="none" className="size-4" aria-hidden>
|
|
268
|
-
<path d="M9 7.5v9l8-4.5-8-4.5Z" fill="currentColor" />
|
|
269
|
-
</svg>
|
|
270
|
-
)
|
package/src/spinner.tsx
CHANGED
|
@@ -2,44 +2,117 @@ import { cva, type VariantProps } from "class-variance-authority";
|
|
|
2
2
|
import type { ComponentProps } from "react";
|
|
3
3
|
import { cn } from "./lib/cn";
|
|
4
4
|
|
|
5
|
+
const SPINNER_SPOKES = Array.from({ length: 12 }, (_, index) => index);
|
|
6
|
+
|
|
5
7
|
const spinnerVariants = cva(
|
|
6
|
-
"
|
|
7
|
-
{
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
"text-current motion-reduce:animate-none",
|
|
9
|
+
{
|
|
10
|
+
variants: {
|
|
11
|
+
variant: {
|
|
12
|
+
ring: "animate-spin",
|
|
13
|
+
arc: "animate-spin",
|
|
14
|
+
dots: "",
|
|
15
|
+
spokes: "",
|
|
16
|
+
},
|
|
17
|
+
size: {
|
|
18
|
+
sm: "size-3.5",
|
|
19
|
+
md: "size-4",
|
|
20
|
+
lg: "size-5",
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
defaultVariants: {
|
|
24
|
+
variant: "ring",
|
|
25
|
+
size: "md",
|
|
12
26
|
},
|
|
13
27
|
},
|
|
14
|
-
|
|
15
|
-
size: "md",
|
|
16
|
-
},
|
|
17
|
-
});
|
|
28
|
+
);
|
|
18
29
|
|
|
19
30
|
export type SpinnerProps = ComponentProps<"svg"> &
|
|
20
31
|
VariantProps<typeof spinnerVariants>;
|
|
21
32
|
|
|
22
|
-
export const Spinner = ({
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
<
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
33
|
+
export const Spinner = ({
|
|
34
|
+
className,
|
|
35
|
+
variant,
|
|
36
|
+
size,
|
|
37
|
+
...props
|
|
38
|
+
}: SpinnerProps) => {
|
|
39
|
+
const resolvedVariant = variant ?? "ring";
|
|
40
|
+
|
|
41
|
+
return (
|
|
42
|
+
<svg
|
|
43
|
+
role="status"
|
|
44
|
+
aria-label="Loading"
|
|
45
|
+
className={cn(
|
|
46
|
+
spinnerVariants({ variant: resolvedVariant, size }),
|
|
47
|
+
className,
|
|
48
|
+
)}
|
|
49
|
+
viewBox="0 0 24 24"
|
|
50
|
+
fill="none"
|
|
51
|
+
{...props}
|
|
52
|
+
>
|
|
53
|
+
{resolvedVariant === "spokes" ? (
|
|
54
|
+
<g stroke="currentColor" strokeWidth="2.25" strokeLinecap="round">
|
|
55
|
+
{SPINNER_SPOKES.map((spoke) => (
|
|
56
|
+
<line
|
|
57
|
+
key={spoke}
|
|
58
|
+
x1="12"
|
|
59
|
+
y1="3"
|
|
60
|
+
x2="12"
|
|
61
|
+
y2="6.25"
|
|
62
|
+
transform={`rotate(${spoke * 30} 12 12)`}
|
|
63
|
+
className="animate-[spinner-spoke_1.2s_linear_infinite] motion-reduce:animate-none motion-reduce:opacity-40"
|
|
64
|
+
style={{ animationDelay: `${spoke * -0.1}s` }}
|
|
65
|
+
/>
|
|
66
|
+
))}
|
|
67
|
+
</g>
|
|
68
|
+
) : resolvedVariant === "dots" ? (
|
|
69
|
+
<g fill="currentColor">
|
|
70
|
+
<circle
|
|
71
|
+
cx="5"
|
|
72
|
+
cy="12"
|
|
73
|
+
r="2.25"
|
|
74
|
+
className="animate-[spinner-dot_1.2s_var(--ease-passive)_infinite] [animation-delay:-0.32s] motion-reduce:animate-none"
|
|
75
|
+
/>
|
|
76
|
+
<circle
|
|
77
|
+
cx="12"
|
|
78
|
+
cy="12"
|
|
79
|
+
r="2.25"
|
|
80
|
+
className="animate-[spinner-dot_1.2s_var(--ease-passive)_infinite] [animation-delay:-0.16s] motion-reduce:animate-none"
|
|
81
|
+
/>
|
|
82
|
+
<circle
|
|
83
|
+
cx="19"
|
|
84
|
+
cy="12"
|
|
85
|
+
r="2.25"
|
|
86
|
+
className="animate-[spinner-dot_1.2s_var(--ease-passive)_infinite] motion-reduce:animate-none"
|
|
87
|
+
/>
|
|
88
|
+
</g>
|
|
89
|
+
) : resolvedVariant === "arc" ? (
|
|
90
|
+
<circle
|
|
91
|
+
cx="12"
|
|
92
|
+
cy="12"
|
|
93
|
+
r="9"
|
|
94
|
+
stroke="currentColor"
|
|
95
|
+
strokeWidth="2.5"
|
|
96
|
+
strokeLinecap="round"
|
|
97
|
+
strokeDasharray="42 15"
|
|
98
|
+
/>
|
|
99
|
+
) : (
|
|
100
|
+
<>
|
|
101
|
+
<path
|
|
102
|
+
d="M21 12C21 16.9706 16.9706 21 12 21C7.02944 21 3 16.9706 3 12C3 7.02944 7.02944 3 12 3C16.9706 3 21 7.02944 21 12Z"
|
|
103
|
+
stroke="currentColor"
|
|
104
|
+
strokeOpacity="0.3"
|
|
105
|
+
strokeWidth="2"
|
|
106
|
+
/>
|
|
107
|
+
<path
|
|
108
|
+
d="M21 12C21 16.9706 16.9706 21 12 21"
|
|
109
|
+
stroke="currentColor"
|
|
110
|
+
strokeWidth="2"
|
|
111
|
+
/>
|
|
112
|
+
</>
|
|
113
|
+
)}
|
|
114
|
+
</svg>
|
|
115
|
+
);
|
|
116
|
+
};
|
|
44
117
|
|
|
45
118
|
export { spinnerVariants };
|
package/src/switch.tsx
CHANGED
|
@@ -3,13 +3,16 @@
|
|
|
3
3
|
import { Switch as BaseSwitch } from "@base-ui/react/switch"
|
|
4
4
|
import type { ComponentProps } from "react"
|
|
5
5
|
import { cn } from "./lib/cn"
|
|
6
|
+
import { focusRing, focusRingBorder } from "./lib/focus"
|
|
6
7
|
|
|
7
8
|
export type SwitchProps = ComponentProps<typeof BaseSwitch.Root>
|
|
8
9
|
|
|
9
10
|
export const Switch = ({ className, ...props }: SwitchProps) => (
|
|
10
11
|
<BaseSwitch.Root
|
|
11
12
|
className={cn(
|
|
12
|
-
"relative inline-flex h-6 w-10 shrink-0 items-center rounded-full bg-background-quaternary transition-colors duration-[var(--duration-sm)] ease-enter motion-reduce:transition-none
|
|
13
|
+
"relative inline-flex h-6 w-10 shrink-0 items-center rounded-full bg-background-quaternary transition-colors duration-[var(--duration-sm)] ease-enter motion-reduce:transition-none data-checked:bg-brand-primary data-disabled:cursor-not-allowed data-disabled:opacity-50",
|
|
14
|
+
focusRingBorder,
|
|
15
|
+
focusRing,
|
|
13
16
|
className,
|
|
14
17
|
)}
|
|
15
18
|
{...props}
|
package/src/table.tsx
CHANGED
|
@@ -1,8 +1,60 @@
|
|
|
1
|
+
import { cva, type VariantProps } from "class-variance-authority";
|
|
1
2
|
import type { ComponentProps } from "react";
|
|
2
3
|
import { cn } from "./lib/cn";
|
|
3
4
|
|
|
4
|
-
|
|
5
|
-
|
|
5
|
+
const tableVariants = cva(
|
|
6
|
+
"group/table w-full text-sm text-fg-primary",
|
|
7
|
+
{
|
|
8
|
+
variants: {
|
|
9
|
+
variant: {
|
|
10
|
+
default: "border-collapse",
|
|
11
|
+
grid: [
|
|
12
|
+
"border-separate border-spacing-0",
|
|
13
|
+
"[&_tr]:border-b-0",
|
|
14
|
+
"[&_tr>*]:border-r [&_tr>*]:border-b [&_tr>*]:border-border-primary",
|
|
15
|
+
"[&_tr>*:last-child]:border-r-0",
|
|
16
|
+
"[&_tbody_tr:last-child>*]:border-b-0 [&_tfoot_tr:last-child>*]:border-b-0",
|
|
17
|
+
],
|
|
18
|
+
},
|
|
19
|
+
density: {
|
|
20
|
+
default: "",
|
|
21
|
+
compact: "[&_th]:h-8 [&_th]:px-3 [&_td]:px-3 [&_td]:py-2",
|
|
22
|
+
},
|
|
23
|
+
striped: {
|
|
24
|
+
true: "[&_tbody_tr:nth-child(even)]:bg-background-secondary",
|
|
25
|
+
false: "",
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
defaultVariants: {
|
|
29
|
+
variant: "default",
|
|
30
|
+
density: "default",
|
|
31
|
+
striped: false,
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
const tableHeaderVariants = cva(
|
|
37
|
+
"bg-background-secondary [&_tr]:border-b [&_tr]:border-border-primary",
|
|
38
|
+
{
|
|
39
|
+
variants: {
|
|
40
|
+
sticky: {
|
|
41
|
+
true: "[&_th]:sticky [&_th]:top-0 [&_th]:z-10 [&_th]:bg-background-secondary [&_th]:py-2.5",
|
|
42
|
+
false: "",
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
defaultVariants: {
|
|
46
|
+
sticky: false,
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
export type TableProps = ComponentProps<"table"> &
|
|
52
|
+
VariantProps<typeof tableVariants> & {
|
|
53
|
+
/** Classes for the bordered horizontal-scroll container. */
|
|
54
|
+
containerClassName?: string;
|
|
55
|
+
};
|
|
56
|
+
export type TableHeaderProps = ComponentProps<"thead"> &
|
|
57
|
+
VariantProps<typeof tableHeaderVariants>;
|
|
6
58
|
export type TableBodyProps = ComponentProps<"tbody">;
|
|
7
59
|
export type TableFooterProps = ComponentProps<"tfoot">;
|
|
8
60
|
export type TableRowProps = ComponentProps<"tr">;
|
|
@@ -10,24 +62,37 @@ export type TableHeadProps = ComponentProps<"th">;
|
|
|
10
62
|
export type TableCellProps = ComponentProps<"td">;
|
|
11
63
|
export type TableCaptionProps = ComponentProps<"caption">;
|
|
12
64
|
|
|
13
|
-
export const Table = ({
|
|
14
|
-
|
|
65
|
+
export const Table = ({
|
|
66
|
+
className,
|
|
67
|
+
containerClassName,
|
|
68
|
+
variant,
|
|
69
|
+
density,
|
|
70
|
+
striped,
|
|
71
|
+
...props
|
|
72
|
+
}: TableProps) => (
|
|
73
|
+
<div
|
|
74
|
+
className={cn(
|
|
75
|
+
"w-full overflow-auto rounded-lg border border-border-primary bg-surface",
|
|
76
|
+
containerClassName,
|
|
77
|
+
)}
|
|
78
|
+
>
|
|
15
79
|
<table
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
)}
|
|
80
|
+
data-variant={variant ?? "default"}
|
|
81
|
+
data-density={density ?? "default"}
|
|
82
|
+
data-striped={striped || undefined}
|
|
83
|
+
className={cn(tableVariants({ variant, density, striped }), className)}
|
|
20
84
|
{...props}
|
|
21
85
|
/>
|
|
22
86
|
</div>
|
|
23
87
|
);
|
|
24
88
|
|
|
25
|
-
export const TableHeader = ({
|
|
89
|
+
export const TableHeader = ({
|
|
90
|
+
className,
|
|
91
|
+
sticky,
|
|
92
|
+
...props
|
|
93
|
+
}: TableHeaderProps) => (
|
|
26
94
|
<thead
|
|
27
|
-
className={cn(
|
|
28
|
-
"bg-background-secondary [&_tr]:border-b [&_tr]:border-border-primary",
|
|
29
|
-
className,
|
|
30
|
-
)}
|
|
95
|
+
className={cn(tableHeaderVariants({ sticky }), className)}
|
|
31
96
|
{...props}
|
|
32
97
|
/>
|
|
33
98
|
);
|
|
@@ -39,7 +104,7 @@ export const TableBody = ({ className, ...props }: TableBodyProps) => (
|
|
|
39
104
|
export const TableFooter = ({ className, ...props }: TableFooterProps) => (
|
|
40
105
|
<tfoot
|
|
41
106
|
className={cn(
|
|
42
|
-
"border-t border-border-primary bg-background-secondary font-medium",
|
|
107
|
+
"border-t border-border-primary bg-background-secondary font-medium [&_tr]:hover:bg-transparent",
|
|
43
108
|
className,
|
|
44
109
|
)}
|
|
45
110
|
{...props}
|
|
@@ -49,7 +114,7 @@ export const TableFooter = ({ className, ...props }: TableFooterProps) => (
|
|
|
49
114
|
export const TableRow = ({ className, ...props }: TableRowProps) => (
|
|
50
115
|
<tr
|
|
51
116
|
className={cn(
|
|
52
|
-
"border-b border-border-primary hover:bg-background-secondary",
|
|
117
|
+
"border-b border-border-primary transition-colors duration-[var(--duration-sm)] ease-enter hover:bg-background-secondary aria-selected:bg-background-tertiary data-[selected]:bg-background-tertiary data-[state=selected]:bg-background-tertiary",
|
|
53
118
|
className,
|
|
54
119
|
)}
|
|
55
120
|
{...props}
|
|
@@ -79,3 +144,5 @@ export const TableCaption = ({ className, ...props }: TableCaptionProps) => (
|
|
|
79
144
|
{...props}
|
|
80
145
|
/>
|
|
81
146
|
);
|
|
147
|
+
|
|
148
|
+
export { tableHeaderVariants, tableVariants };
|
package/src/tabs.tsx
CHANGED
|
@@ -1,62 +1,213 @@
|
|
|
1
1
|
"use client"
|
|
2
2
|
|
|
3
3
|
import { Tabs as BaseTabs } from "@base-ui/react/tabs"
|
|
4
|
-
import type
|
|
4
|
+
import { cva, type VariantProps } from "class-variance-authority"
|
|
5
|
+
import { createContext, type ComponentProps, useContext } from "react"
|
|
5
6
|
import { cn } from "./lib/cn"
|
|
7
|
+
import { focusRing, focusRingBorder } from "./lib/focus"
|
|
6
8
|
import { motion } from "./lib/motion"
|
|
7
9
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
const tabsListVariants = cva("relative flex items-center", {
|
|
11
|
+
variants: {
|
|
12
|
+
variant: {
|
|
13
|
+
underline:
|
|
14
|
+
"w-full gap-0.5 border-b border-border-primary data-[orientation=vertical]:w-40 data-[orientation=vertical]:shrink-0 data-[orientation=vertical]:flex-col data-[orientation=vertical]:items-stretch data-[orientation=vertical]:gap-0 data-[orientation=vertical]:border-r data-[orientation=vertical]:border-b-0",
|
|
15
|
+
segmented:
|
|
16
|
+
"w-fit rounded-lg bg-background-tertiary p-0.5 data-[orientation=vertical]:flex-col data-[orientation=vertical]:items-stretch",
|
|
17
|
+
pill: "w-fit gap-1 data-[orientation=vertical]:flex-col data-[orientation=vertical]:items-stretch",
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
defaultVariants: {
|
|
21
|
+
variant: "underline",
|
|
22
|
+
},
|
|
23
|
+
})
|
|
13
24
|
|
|
14
|
-
|
|
15
|
-
|
|
25
|
+
const tabsTabVariants = cva(
|
|
26
|
+
cn(
|
|
27
|
+
"relative z-10 inline-flex shrink-0 cursor-pointer items-center justify-center gap-1.5 whitespace-nowrap text-fg-tertiary select-none hover:text-fg-primary data-active:text-fg-primary data-disabled:cursor-not-allowed data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0",
|
|
28
|
+
focusRingBorder,
|
|
29
|
+
focusRing,
|
|
30
|
+
),
|
|
31
|
+
{
|
|
32
|
+
variants: {
|
|
33
|
+
variant: {
|
|
34
|
+
underline:
|
|
35
|
+
"data-[orientation=horizontal]:pb-1 data-[orientation=vertical]:w-full data-[orientation=vertical]:justify-start",
|
|
36
|
+
segmented: "rounded-md",
|
|
37
|
+
pill: "rounded-full bg-background-tertiary data-active:bg-transparent",
|
|
38
|
+
},
|
|
39
|
+
size: {
|
|
40
|
+
sm: "text-xs [&_svg]:size-3.5",
|
|
41
|
+
md: "text-sm [&_svg]:size-4",
|
|
42
|
+
lg: "text-md [&_svg]:size-4",
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
compoundVariants: [
|
|
46
|
+
{
|
|
47
|
+
variant: "underline",
|
|
48
|
+
size: "sm",
|
|
49
|
+
class: "h-8 px-2.5 data-[orientation=horizontal]:h-9",
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
variant: "underline",
|
|
53
|
+
size: "md",
|
|
54
|
+
class: "h-10 px-3 data-[orientation=horizontal]:h-11",
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
variant: "underline",
|
|
58
|
+
size: "lg",
|
|
59
|
+
class: "h-12 px-3.5 data-[orientation=horizontal]:h-13",
|
|
60
|
+
},
|
|
61
|
+
{ variant: "segmented", size: "sm", class: "h-7 px-2.5" },
|
|
62
|
+
{ variant: "segmented", size: "md", class: "h-8 px-3" },
|
|
63
|
+
{ variant: "segmented", size: "lg", class: "h-9 px-3.5" },
|
|
64
|
+
{ variant: "pill", size: "sm", class: "h-7 px-2.5" },
|
|
65
|
+
{ variant: "pill", size: "md", class: "h-8 px-3" },
|
|
66
|
+
{ variant: "pill", size: "lg", class: "h-9 px-3.5" },
|
|
67
|
+
],
|
|
68
|
+
defaultVariants: {
|
|
69
|
+
variant: "underline",
|
|
70
|
+
size: "md",
|
|
71
|
+
},
|
|
72
|
+
},
|
|
16
73
|
)
|
|
17
74
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
75
|
+
const tabsIndicatorVariants = cva("absolute z-0", {
|
|
76
|
+
variants: {
|
|
77
|
+
variant: {
|
|
78
|
+
underline:
|
|
79
|
+
"bottom-0 left-0 h-0.5 w-(--active-tab-width) translate-x-(--active-tab-left) rounded-full bg-brand-primary data-[orientation=vertical]:top-0 data-[orientation=vertical]:right-0 data-[orientation=vertical]:bottom-auto data-[orientation=vertical]:left-auto data-[orientation=vertical]:h-(--active-tab-height) data-[orientation=vertical]:w-0.5 data-[orientation=vertical]:translate-x-0 data-[orientation=vertical]:translate-y-(--active-tab-top)",
|
|
80
|
+
segmented:
|
|
81
|
+
"inset-y-0.5 left-0 w-(--active-tab-width) translate-x-(--active-tab-left) rounded-md bg-surface-raised shadow-hairline data-[orientation=vertical]:inset-x-0.5 data-[orientation=vertical]:top-0 data-[orientation=vertical]:bottom-auto data-[orientation=vertical]:h-(--active-tab-height) data-[orientation=vertical]:w-auto data-[orientation=vertical]:translate-x-0 data-[orientation=vertical]:translate-y-(--active-tab-top)",
|
|
82
|
+
pill: "inset-y-0 left-0 w-(--active-tab-width) translate-x-(--active-tab-left) rounded-full bg-surface-raised shadow-hairline data-[orientation=vertical]:inset-x-0 data-[orientation=vertical]:top-0 data-[orientation=vertical]:bottom-auto data-[orientation=vertical]:h-(--active-tab-height) data-[orientation=vertical]:w-auto data-[orientation=vertical]:translate-x-0 data-[orientation=vertical]:translate-y-(--active-tab-top)",
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
defaultVariants: {
|
|
86
|
+
variant: "underline",
|
|
87
|
+
},
|
|
88
|
+
})
|
|
27
89
|
|
|
28
|
-
export
|
|
29
|
-
<
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
90
|
+
export type TabsVariant = NonNullable<
|
|
91
|
+
VariantProps<typeof tabsListVariants>["variant"]
|
|
92
|
+
>
|
|
93
|
+
export type TabsSize = NonNullable<
|
|
94
|
+
VariantProps<typeof tabsTabVariants>["size"]
|
|
95
|
+
>
|
|
96
|
+
|
|
97
|
+
type TabsStyleContextValue = {
|
|
98
|
+
variant: TabsVariant
|
|
99
|
+
size: TabsSize
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const TabsStyleContext = createContext<TabsStyleContextValue>({
|
|
103
|
+
variant: "underline",
|
|
104
|
+
size: "md",
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
export type TabsProps = ComponentProps<typeof BaseTabs.Root> & {
|
|
108
|
+
/** Visual treatment shared by the list, tabs, and indicator. */
|
|
109
|
+
variant?: TabsVariant
|
|
110
|
+
/** Height and typography shared by every tab. */
|
|
111
|
+
size?: TabsSize
|
|
112
|
+
}
|
|
113
|
+
export type TabsListProps = ComponentProps<typeof BaseTabs.List> &
|
|
114
|
+
VariantProps<typeof tabsListVariants>
|
|
115
|
+
export type TabsTabProps = ComponentProps<typeof BaseTabs.Tab> &
|
|
116
|
+
VariantProps<typeof tabsTabVariants>
|
|
117
|
+
export type TabsIndicatorProps = ComponentProps<typeof BaseTabs.Indicator> &
|
|
118
|
+
VariantProps<typeof tabsIndicatorVariants>
|
|
119
|
+
export type TabsPanelProps = ComponentProps<typeof BaseTabs.Panel>
|
|
120
|
+
|
|
121
|
+
export const Tabs = ({
|
|
122
|
+
className,
|
|
123
|
+
variant = "underline",
|
|
124
|
+
size = "md",
|
|
125
|
+
...props
|
|
126
|
+
}: TabsProps) => (
|
|
127
|
+
<TabsStyleContext.Provider value={{ variant, size }}>
|
|
128
|
+
<BaseTabs.Root
|
|
129
|
+
data-slot="tabs"
|
|
130
|
+
className={cn(
|
|
131
|
+
"flex w-full flex-col data-[orientation=vertical]:flex-row data-[orientation=vertical]:gap-6",
|
|
132
|
+
className,
|
|
133
|
+
)}
|
|
134
|
+
{...props}
|
|
135
|
+
/>
|
|
136
|
+
</TabsStyleContext.Provider>
|
|
38
137
|
)
|
|
39
138
|
|
|
139
|
+
export const TabsList = ({
|
|
140
|
+
className,
|
|
141
|
+
variant,
|
|
142
|
+
...props
|
|
143
|
+
}: TabsListProps) => {
|
|
144
|
+
const styles = useContext(TabsStyleContext)
|
|
145
|
+
|
|
146
|
+
return (
|
|
147
|
+
<BaseTabs.List
|
|
148
|
+
data-slot="tabs-list"
|
|
149
|
+
className={cn(
|
|
150
|
+
tabsListVariants({ variant: variant ?? styles.variant }),
|
|
151
|
+
className,
|
|
152
|
+
)}
|
|
153
|
+
{...props}
|
|
154
|
+
/>
|
|
155
|
+
)
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
export const TabsTab = ({
|
|
159
|
+
className,
|
|
160
|
+
variant,
|
|
161
|
+
size,
|
|
162
|
+
...props
|
|
163
|
+
}: TabsTabProps) => {
|
|
164
|
+
const styles = useContext(TabsStyleContext)
|
|
165
|
+
|
|
166
|
+
return (
|
|
167
|
+
<BaseTabs.Tab
|
|
168
|
+
data-slot="tabs-tab"
|
|
169
|
+
className={cn(
|
|
170
|
+
tabsTabVariants({
|
|
171
|
+
variant: variant ?? styles.variant,
|
|
172
|
+
size: size ?? styles.size,
|
|
173
|
+
}),
|
|
174
|
+
motion.colors,
|
|
175
|
+
className,
|
|
176
|
+
)}
|
|
177
|
+
{...props}
|
|
178
|
+
/>
|
|
179
|
+
)
|
|
180
|
+
}
|
|
181
|
+
|
|
40
182
|
export const TabsIndicator = ({
|
|
41
183
|
className,
|
|
184
|
+
variant,
|
|
42
185
|
...props
|
|
43
|
-
}: TabsIndicatorProps) =>
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
186
|
+
}: TabsIndicatorProps) => {
|
|
187
|
+
const styles = useContext(TabsStyleContext)
|
|
188
|
+
|
|
189
|
+
return (
|
|
190
|
+
<BaseTabs.Indicator
|
|
191
|
+
data-slot="tabs-indicator"
|
|
192
|
+
className={cn(
|
|
193
|
+
tabsIndicatorVariants({ variant: variant ?? styles.variant }),
|
|
194
|
+
motion.tabsIndicator,
|
|
195
|
+
className,
|
|
196
|
+
)}
|
|
197
|
+
{...props}
|
|
198
|
+
/>
|
|
199
|
+
)
|
|
200
|
+
}
|
|
53
201
|
|
|
54
202
|
export const TabsPanel = ({ className, ...props }: TabsPanelProps) => (
|
|
55
203
|
<BaseTabs.Panel
|
|
204
|
+
data-slot="tabs-panel"
|
|
56
205
|
className={cn(
|
|
57
|
-
"pt-4 text-sm leading-relaxed text-fg-secondary outline-none focus-visible:outline-none",
|
|
206
|
+
"pt-4 text-sm leading-relaxed text-fg-secondary outline-none focus-visible:outline-none data-[orientation=vertical]:pt-0",
|
|
58
207
|
className,
|
|
59
208
|
)}
|
|
60
209
|
{...props}
|
|
61
210
|
/>
|
|
62
211
|
)
|
|
212
|
+
|
|
213
|
+
export { tabsIndicatorVariants, tabsListVariants, tabsTabVariants }
|