@cntyclub/ui-react 0.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/dist/chunk-HDGMSYQS.js +26461 -0
- package/dist/chunk-HDGMSYQS.js.map +1 -0
- package/dist/chunk-PR4QN5HX.js +39 -0
- package/dist/chunk-PR4QN5HX.js.map +1 -0
- package/dist/form.d.ts +175 -0
- package/dist/form.js +5207 -0
- package/dist/form.js.map +1 -0
- package/dist/index.d.ts +1462 -0
- package/dist/index.js +81862 -0
- package/dist/index.js.map +1 -0
- package/dist/input-CZvh825j.d.ts +24 -0
- package/dist/qr-code-styling-3Y6LZH6V.js +1123 -0
- package/dist/qr-code-styling-3Y6LZH6V.js.map +1 -0
- package/package.json +79 -0
- package/src/components/form/checkbox-group-field.tsx +101 -0
- package/src/components/form/date-field.tsx +79 -0
- package/src/components/form/date-range-field.tsx +106 -0
- package/src/components/form/form-context.ts +10 -0
- package/src/components/form/form.tsx +54 -0
- package/src/components/form/number-field.tsx +69 -0
- package/src/components/form/select-field.tsx +76 -0
- package/src/components/form/submit-button.tsx +28 -0
- package/src/components/form/text-field.tsx +107 -0
- package/src/components/layout/dashboard-header.tsx +54 -0
- package/src/components/layout/dashboard-panel.tsx +34 -0
- package/src/components/theme-provider.tsx +403 -0
- package/src/components/ui/accordion.tsx +69 -0
- package/src/components/ui/alert-dialog.tsx +169 -0
- package/src/components/ui/alert.tsx +80 -0
- package/src/components/ui/animated-theme-toggler.tsx +265 -0
- package/src/components/ui/app-store-buttons.tsx +182 -0
- package/src/components/ui/aspect-ratio.tsx +23 -0
- package/src/components/ui/autocomplete.tsx +296 -0
- package/src/components/ui/avatar-group.tsx +95 -0
- package/src/components/ui/avatar.tsx +285 -0
- package/src/components/ui/badge-group.tsx +160 -0
- package/src/components/ui/badge.tsx +172 -0
- package/src/components/ui/breadcrumb.tsx +112 -0
- package/src/components/ui/button.tsx +77 -0
- package/src/components/ui/calendar.tsx +137 -0
- package/src/components/ui/card.tsx +244 -0
- package/src/components/ui/carousel.tsx +258 -0
- package/src/components/ui/chart.tsx +379 -0
- package/src/components/ui/checkbox-group.tsx +16 -0
- package/src/components/ui/checkbox.tsx +82 -0
- package/src/components/ui/collapsible.tsx +45 -0
- package/src/components/ui/combobox.tsx +411 -0
- package/src/components/ui/command.tsx +264 -0
- package/src/components/ui/context-menu.tsx +271 -0
- package/src/components/ui/credit-card.tsx +214 -0
- package/src/components/ui/dialog.tsx +196 -0
- package/src/components/ui/drawer.tsx +135 -0
- package/src/components/ui/empty.tsx +127 -0
- package/src/components/ui/featured-icon.tsx +149 -0
- package/src/components/ui/field.tsx +88 -0
- package/src/components/ui/fieldset.tsx +29 -0
- package/src/components/ui/form.tsx +17 -0
- package/src/components/ui/frame.tsx +82 -0
- package/src/components/ui/generic-empty.tsx +142 -0
- package/src/components/ui/group.tsx +97 -0
- package/src/components/ui/horizontal-scroll-fader.tsx +228 -0
- package/src/components/ui/input-group.tsx +102 -0
- package/src/components/ui/input-otp.tsx +96 -0
- package/src/components/ui/input.tsx +66 -0
- package/src/components/ui/item.tsx +198 -0
- package/src/components/ui/kbd.tsx +30 -0
- package/src/components/ui/label.tsx +28 -0
- package/src/components/ui/menu.tsx +312 -0
- package/src/components/ui/menubar.tsx +93 -0
- package/src/components/ui/meter.tsx +67 -0
- package/src/components/ui/multi-select.tsx +308 -0
- package/src/components/ui/navigation-menu.tsx +143 -0
- package/src/components/ui/number-field.tsx +160 -0
- package/src/components/ui/pagination-controls.tsx +74 -0
- package/src/components/ui/pagination.tsx +149 -0
- package/src/components/ui/popover.tsx +119 -0
- package/src/components/ui/preview-card.tsx +55 -0
- package/src/components/ui/progress.tsx +289 -0
- package/src/components/ui/qr-code.tsx +150 -0
- package/src/components/ui/radio-group.tsx +103 -0
- package/src/components/ui/resizable.tsx +56 -0
- package/src/components/ui/scroll-area.tsx +90 -0
- package/src/components/ui/scroller.tsx +38 -0
- package/src/components/ui/section-header.tsx +118 -0
- package/src/components/ui/select.tsx +181 -0
- package/src/components/ui/separator.tsx +23 -0
- package/src/components/ui/sheet.tsx +224 -0
- package/src/components/ui/sidebar.tsx +744 -0
- package/src/components/ui/skeleton.tsx +16 -0
- package/src/components/ui/slider.tsx +108 -0
- package/src/components/ui/smooth-scroll.tsx +143 -0
- package/src/components/ui/social-button.tsx +247 -0
- package/src/components/ui/spinner-on-demand.tsx +32 -0
- package/src/components/ui/spinner.tsx +18 -0
- package/src/components/ui/stat.tsx +187 -0
- package/src/components/ui/stepper.tsx +167 -0
- package/src/components/ui/switch.tsx +56 -0
- package/src/components/ui/table.tsx +126 -0
- package/src/components/ui/tabs.tsx +90 -0
- package/src/components/ui/tag.tsx +229 -0
- package/src/components/ui/target-countdown.tsx +46 -0
- package/src/components/ui/text-editor.tsx +313 -0
- package/src/components/ui/textarea.tsx +51 -0
- package/src/components/ui/timeline.tsx +116 -0
- package/src/components/ui/toast.tsx +268 -0
- package/src/components/ui/toggle-group.tsx +101 -0
- package/src/components/ui/toggle.tsx +45 -0
- package/src/components/ui/toolbar.tsx +89 -0
- package/src/components/ui/tooltip.tsx +102 -0
- package/src/components/ui/vertical-scroll-fader.tsx +250 -0
- package/src/components/ui/video-player.tsx +275 -0
- package/src/components/upload/avatar-upload-base.tsx +131 -0
- package/src/components/upload/image-upload-base.tsx +112 -0
- package/src/form.ts +17 -0
- package/src/index.ts +125 -0
- package/src/lib/hooks/use-callback-ref.ts +15 -0
- package/src/lib/hooks/use-first-render.ts +11 -0
- package/src/lib/hooks/use-hover.ts +53 -0
- package/src/lib/hooks/use-is-tab-active.ts +17 -0
- package/src/lib/hooks/use-media-query.ts +164 -0
- package/src/lib/utils/css.ts +6 -0
- package/src/styles.css +300 -0
- package/src/types/helpers.ts +24 -0
- package/src/types/react.d.ts +7 -0
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { mergeProps } from "@base-ui/react/merge-props";
|
|
4
|
+
import { useRender } from "@base-ui/react/use-render";
|
|
5
|
+
import { cva, type VariantProps } from "class-variance-authority";
|
|
6
|
+
import { TrendingDownIcon, TrendingUpIcon } from "lucide-react";
|
|
7
|
+
import type * as React from "react";
|
|
8
|
+
|
|
9
|
+
import { cn } from "../../lib/utils/css";
|
|
10
|
+
|
|
11
|
+
const statVariants = cva("flex flex-col gap-1.5", {
|
|
12
|
+
defaultVariants: { variant: "default" },
|
|
13
|
+
variants: {
|
|
14
|
+
variant: {
|
|
15
|
+
// Bare — no chrome. Use inside a StatGroup or a Card.
|
|
16
|
+
default: "",
|
|
17
|
+
// A subtle tonal tile.
|
|
18
|
+
muted: "rounded-xl border bg-secondary p-4",
|
|
19
|
+
// A bordered surface tile that reads as its own card.
|
|
20
|
+
card: "rounded-xl border bg-card not-dark:bg-clip-padding p-4 shadow-xs/5",
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
interface StatProps extends useRender.ComponentProps<"div"> {
|
|
26
|
+
variant?: VariantProps<typeof statVariants>["variant"];
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* A single headline metric (KPI). Compose it from `StatLabel`, `StatValue`,
|
|
31
|
+
* `StatDescription` and an optional `StatTrend`. Drop bare `Stat`s into a
|
|
32
|
+
* `StatGroup` for a divided row, or use `variant="muted" | "card"` for a
|
|
33
|
+
* standalone tile.
|
|
34
|
+
*/
|
|
35
|
+
function Stat({ className, variant, render, ...props }: StatProps) {
|
|
36
|
+
const defaultProps = {
|
|
37
|
+
className: cn(statVariants({ className, variant })),
|
|
38
|
+
"data-slot": "stat",
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
return useRender({
|
|
42
|
+
defaultTagName: "div",
|
|
43
|
+
props: mergeProps<"div">(defaultProps, props),
|
|
44
|
+
render,
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** The metric's caption, e.g. "Active members". */
|
|
49
|
+
function StatLabel({
|
|
50
|
+
className,
|
|
51
|
+
render,
|
|
52
|
+
...props
|
|
53
|
+
}: useRender.ComponentProps<"div">) {
|
|
54
|
+
const defaultProps = {
|
|
55
|
+
className: cn("font-medium text-muted-foreground text-sm leading-none", className),
|
|
56
|
+
"data-slot": "stat-label",
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
return useRender({
|
|
60
|
+
defaultTagName: "div",
|
|
61
|
+
props: mergeProps<"div">(defaultProps, props),
|
|
62
|
+
render,
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* The headline number. Sans + tabular so digits stay aligned across a row;
|
|
68
|
+
* drop `font-sans` from `className` to render it in the serif display face.
|
|
69
|
+
*/
|
|
70
|
+
function StatValue({
|
|
71
|
+
className,
|
|
72
|
+
render,
|
|
73
|
+
...props
|
|
74
|
+
}: useRender.ComponentProps<"div">) {
|
|
75
|
+
const defaultProps = {
|
|
76
|
+
className: cn(
|
|
77
|
+
"font-sans font-semibold text-2xl text-foreground leading-none tabular-nums tracking-tight",
|
|
78
|
+
className,
|
|
79
|
+
),
|
|
80
|
+
"data-slot": "stat-value",
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
return useRender({
|
|
84
|
+
defaultTagName: "div",
|
|
85
|
+
props: mergeProps<"div">(defaultProps, props),
|
|
86
|
+
render,
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/** Supporting copy under the value, e.g. "vs. 1,204 last month". */
|
|
91
|
+
function StatDescription({
|
|
92
|
+
className,
|
|
93
|
+
render,
|
|
94
|
+
...props
|
|
95
|
+
}: useRender.ComponentProps<"p">) {
|
|
96
|
+
const defaultProps = {
|
|
97
|
+
className: cn("text-muted-foreground text-sm leading-snug", className),
|
|
98
|
+
"data-slot": "stat-description",
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
return useRender({
|
|
102
|
+
defaultTagName: "p",
|
|
103
|
+
props: mergeProps<"p">(defaultProps, props),
|
|
104
|
+
render,
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const statTrendVariants = cva(
|
|
109
|
+
"inline-flex items-center gap-0.5 font-medium text-sm tabular-nums [&_svg:not([class*='size-'])]:size-3.5 [&_svg]:pointer-events-none [&_svg]:shrink-0",
|
|
110
|
+
{
|
|
111
|
+
defaultVariants: { direction: "up" },
|
|
112
|
+
variants: {
|
|
113
|
+
direction: {
|
|
114
|
+
up: "text-success-foreground",
|
|
115
|
+
down: "text-destructive-foreground",
|
|
116
|
+
neutral: "text-muted-foreground",
|
|
117
|
+
},
|
|
118
|
+
},
|
|
119
|
+
},
|
|
120
|
+
);
|
|
121
|
+
|
|
122
|
+
interface StatTrendProps extends React.ComponentProps<"span"> {
|
|
123
|
+
direction?: VariantProps<typeof statTrendVariants>["direction"];
|
|
124
|
+
/** Show the directional arrow before the children. Defaults to `true`. */
|
|
125
|
+
showIcon?: boolean;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* A small delta chip — e.g. "+12.5%". Picks an up/down arrow from `direction`
|
|
130
|
+
* and colors itself success/destructive/neutral.
|
|
131
|
+
*/
|
|
132
|
+
function StatTrend({
|
|
133
|
+
className,
|
|
134
|
+
direction = "up",
|
|
135
|
+
showIcon = true,
|
|
136
|
+
children,
|
|
137
|
+
...props
|
|
138
|
+
}: StatTrendProps) {
|
|
139
|
+
const Icon = direction === "down" ? TrendingDownIcon : TrendingUpIcon;
|
|
140
|
+
return (
|
|
141
|
+
<span
|
|
142
|
+
className={cn(statTrendVariants({ direction }), className)}
|
|
143
|
+
data-direction={direction}
|
|
144
|
+
data-slot="stat-trend"
|
|
145
|
+
{...props}
|
|
146
|
+
>
|
|
147
|
+
{showIcon && direction !== "neutral" ? <Icon /> : null}
|
|
148
|
+
{children}
|
|
149
|
+
</span>
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Lays a set of bare `Stat`s out as a divided row (stacked on narrow screens),
|
|
155
|
+
* wrapped in a bordered card surface with even padding per metric.
|
|
156
|
+
*/
|
|
157
|
+
function StatGroup({
|
|
158
|
+
className,
|
|
159
|
+
render,
|
|
160
|
+
...props
|
|
161
|
+
}: useRender.ComponentProps<"div">) {
|
|
162
|
+
const defaultProps = {
|
|
163
|
+
className: cn(
|
|
164
|
+
"grid auto-cols-fr grid-flow-row divide-y rounded-xl border bg-card not-dark:bg-clip-padding shadow-xs/5 sm:grid-flow-col sm:divide-x sm:divide-y-0 [&>[data-slot=stat]]:p-4",
|
|
165
|
+
className,
|
|
166
|
+
),
|
|
167
|
+
"data-slot": "stat-group",
|
|
168
|
+
role: "list",
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
return useRender({
|
|
172
|
+
defaultTagName: "div",
|
|
173
|
+
props: mergeProps<"div">(defaultProps, props),
|
|
174
|
+
render,
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
export {
|
|
179
|
+
Stat,
|
|
180
|
+
StatLabel,
|
|
181
|
+
StatValue,
|
|
182
|
+
StatDescription,
|
|
183
|
+
StatTrend,
|
|
184
|
+
StatGroup,
|
|
185
|
+
statVariants,
|
|
186
|
+
statTrendVariants,
|
|
187
|
+
};
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { CheckIcon } from "lucide-react";
|
|
4
|
+
import * as React from "react";
|
|
5
|
+
|
|
6
|
+
import { cn } from "../../lib/utils/css";
|
|
7
|
+
|
|
8
|
+
type Orientation = "horizontal" | "vertical";
|
|
9
|
+
type StepState = "active" | "completed" | "inactive";
|
|
10
|
+
|
|
11
|
+
const StepperContext = React.createContext<{
|
|
12
|
+
value: number;
|
|
13
|
+
orientation: Orientation;
|
|
14
|
+
}>({ orientation: "horizontal", value: 1 });
|
|
15
|
+
|
|
16
|
+
const StepperItemContext = React.createContext<{
|
|
17
|
+
step: number;
|
|
18
|
+
state: StepState;
|
|
19
|
+
}>({ state: "inactive", step: 1 });
|
|
20
|
+
|
|
21
|
+
function Stepper({
|
|
22
|
+
value = 1,
|
|
23
|
+
orientation = "horizontal",
|
|
24
|
+
className,
|
|
25
|
+
...props
|
|
26
|
+
}: React.ComponentProps<"div"> & {
|
|
27
|
+
/** 1-based index of the active step. */
|
|
28
|
+
value?: number;
|
|
29
|
+
orientation?: Orientation;
|
|
30
|
+
}) {
|
|
31
|
+
return (
|
|
32
|
+
<StepperContext.Provider value={{ orientation, value }}>
|
|
33
|
+
<div
|
|
34
|
+
className={cn(
|
|
35
|
+
"group/stepper flex w-full gap-2",
|
|
36
|
+
orientation === "vertical" ? "flex-col" : "items-center",
|
|
37
|
+
className,
|
|
38
|
+
)}
|
|
39
|
+
data-orientation={orientation}
|
|
40
|
+
data-slot="stepper"
|
|
41
|
+
{...props}
|
|
42
|
+
/>
|
|
43
|
+
</StepperContext.Provider>
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function StepperItem({
|
|
48
|
+
step,
|
|
49
|
+
completed,
|
|
50
|
+
className,
|
|
51
|
+
...props
|
|
52
|
+
}: React.ComponentProps<"div"> & { step: number; completed?: boolean }) {
|
|
53
|
+
const { value } = React.useContext(StepperContext);
|
|
54
|
+
const state: StepState =
|
|
55
|
+
completed || value > step
|
|
56
|
+
? "completed"
|
|
57
|
+
: value === step
|
|
58
|
+
? "active"
|
|
59
|
+
: "inactive";
|
|
60
|
+
|
|
61
|
+
return (
|
|
62
|
+
<StepperItemContext.Provider value={{ state, step }}>
|
|
63
|
+
<div
|
|
64
|
+
className={cn(
|
|
65
|
+
"group/step flex gap-2.5",
|
|
66
|
+
"group-data-[orientation=horizontal]/stepper:items-center group-data-[orientation=horizontal]/stepper:not-last:flex-1",
|
|
67
|
+
"group-data-[orientation=vertical]/stepper:flex-col",
|
|
68
|
+
className,
|
|
69
|
+
)}
|
|
70
|
+
data-slot="stepper-item"
|
|
71
|
+
data-state={state}
|
|
72
|
+
{...props}
|
|
73
|
+
/>
|
|
74
|
+
</StepperItemContext.Provider>
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function StepperTrigger({
|
|
79
|
+
className,
|
|
80
|
+
...props
|
|
81
|
+
}: React.ComponentProps<"button">) {
|
|
82
|
+
return (
|
|
83
|
+
<button
|
|
84
|
+
className={cn(
|
|
85
|
+
"flex items-center gap-2.5 rounded-lg text-left outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:pointer-events-none disabled:opacity-64",
|
|
86
|
+
className,
|
|
87
|
+
)}
|
|
88
|
+
data-slot="stepper-trigger"
|
|
89
|
+
type="button"
|
|
90
|
+
{...props}
|
|
91
|
+
/>
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function StepperIndicator({
|
|
96
|
+
className,
|
|
97
|
+
children,
|
|
98
|
+
...props
|
|
99
|
+
}: React.ComponentProps<"span">) {
|
|
100
|
+
const { step } = React.useContext(StepperItemContext);
|
|
101
|
+
return (
|
|
102
|
+
<span
|
|
103
|
+
className={cn(
|
|
104
|
+
"relative flex size-8 shrink-0 items-center justify-center rounded-full border border-transparent bg-muted font-medium text-muted-foreground text-sm transition-colors group-data-[state=active]/step:bg-primary group-data-[state=active]/step:text-primary-foreground group-data-[state=completed]/step:bg-primary group-data-[state=completed]/step:text-primary-foreground",
|
|
105
|
+
className,
|
|
106
|
+
)}
|
|
107
|
+
data-slot="stepper-indicator"
|
|
108
|
+
{...props}
|
|
109
|
+
>
|
|
110
|
+
<span className="group-data-[state=completed]/step:hidden">
|
|
111
|
+
{children ?? step}
|
|
112
|
+
</span>
|
|
113
|
+
<CheckIcon className="hidden size-4 group-data-[state=completed]/step:block" />
|
|
114
|
+
</span>
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function StepperTitle({ className, ...props }: React.ComponentProps<"div">) {
|
|
119
|
+
return (
|
|
120
|
+
<div
|
|
121
|
+
className={cn(
|
|
122
|
+
"font-medium text-sm transition-colors group-data-[state=inactive]/step:text-muted-foreground",
|
|
123
|
+
className,
|
|
124
|
+
)}
|
|
125
|
+
data-slot="stepper-title"
|
|
126
|
+
{...props}
|
|
127
|
+
/>
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function StepperDescription({
|
|
132
|
+
className,
|
|
133
|
+
...props
|
|
134
|
+
}: React.ComponentProps<"div">) {
|
|
135
|
+
return (
|
|
136
|
+
<div
|
|
137
|
+
className={cn("text-muted-foreground text-xs", className)}
|
|
138
|
+
data-slot="stepper-description"
|
|
139
|
+
{...props}
|
|
140
|
+
/>
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function StepperSeparator({ className, ...props }: React.ComponentProps<"div">) {
|
|
145
|
+
return (
|
|
146
|
+
<div
|
|
147
|
+
className={cn(
|
|
148
|
+
"rounded-full bg-border transition-colors group-data-[state=completed]/step:bg-primary",
|
|
149
|
+
"group-data-[orientation=horizontal]/stepper:h-0.5 group-data-[orientation=horizontal]/stepper:flex-1",
|
|
150
|
+
"group-data-[orientation=vertical]/stepper:ms-[calc(--spacing(4)-1px)] group-data-[orientation=vertical]/stepper:h-6 group-data-[orientation=vertical]/stepper:w-0.5",
|
|
151
|
+
className,
|
|
152
|
+
)}
|
|
153
|
+
data-slot="stepper-separator"
|
|
154
|
+
{...props}
|
|
155
|
+
/>
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
export {
|
|
160
|
+
Stepper,
|
|
161
|
+
StepperItem,
|
|
162
|
+
StepperTrigger,
|
|
163
|
+
StepperIndicator,
|
|
164
|
+
StepperTitle,
|
|
165
|
+
StepperDescription,
|
|
166
|
+
StepperSeparator,
|
|
167
|
+
};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { Switch as SwitchPrimitive } from "@base-ui/react/switch";
|
|
4
|
+
|
|
5
|
+
import { cn } from "../../lib/utils/css";
|
|
6
|
+
|
|
7
|
+
type SwitchProps = SwitchPrimitive.Root.Props & {
|
|
8
|
+
size?: "sm" | "md" | "lg";
|
|
9
|
+
slim?: boolean;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
function Switch({ className, size = "md", slim = false, ...props }: SwitchProps) {
|
|
13
|
+
return (
|
|
14
|
+
<SwitchPrimitive.Root
|
|
15
|
+
className={cn(
|
|
16
|
+
"inline-flex shrink-0 items-center rounded-full outline-none transition-[background-color,box-shadow] duration-200",
|
|
17
|
+
"focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background",
|
|
18
|
+
"data-checked:bg-primary data-unchecked:bg-input data-disabled:opacity-64",
|
|
19
|
+
size === "sm" && "[--thumb-size:--spacing(4)] sm:[--thumb-size:--spacing(3.5)]",
|
|
20
|
+
size === "md" && "[--thumb-size:--spacing(5)] sm:[--thumb-size:--spacing(4)]",
|
|
21
|
+
size === "lg" && "[--thumb-size:--spacing(6)] sm:[--thumb-size:--spacing(5)]",
|
|
22
|
+
"w-[calc(var(--thumb-size)*2-2px)]",
|
|
23
|
+
!slim && "h-[calc(var(--thumb-size)+2px)] p-px",
|
|
24
|
+
slim && "relative h-[calc(var(--thumb-size)*0.4)] overflow-visible p-0",
|
|
25
|
+
className,
|
|
26
|
+
)}
|
|
27
|
+
data-slot="switch"
|
|
28
|
+
{...props}
|
|
29
|
+
>
|
|
30
|
+
<SwitchPrimitive.Thumb
|
|
31
|
+
className={cn(
|
|
32
|
+
"pointer-events-none block aspect-square bg-background shadow-sm/5 will-change-transform",
|
|
33
|
+
"[transition:translate_.15s,border-radius_.15s,scale_.1s_.1s,transform-origin_.15s]",
|
|
34
|
+
!slim && [
|
|
35
|
+
"h-full origin-left",
|
|
36
|
+
"in-[[role=switch]:active,[data-slot=label]:active]:not-data-disabled:scale-x-110",
|
|
37
|
+
"in-[[role=switch]:active,[data-slot=label]:active]:rounded-[var(--thumb-size)/calc(var(--thumb-size)*1.1)]",
|
|
38
|
+
"rounded-(--thumb-size)",
|
|
39
|
+
"data-checked:origin-[var(--thumb-size)_50%] data-checked:translate-x-[calc(var(--thumb-size)-4px)]",
|
|
40
|
+
],
|
|
41
|
+
slim && [
|
|
42
|
+
"absolute top-1/2 -translate-y-1/2",
|
|
43
|
+
"h-[var(--thumb-size)] w-[var(--thumb-size)]",
|
|
44
|
+
"rounded-full origin-left",
|
|
45
|
+
"in-[[role=switch]:active,[data-slot=label]:active]:not-data-disabled:scale-x-110",
|
|
46
|
+
"in-[[role=switch]:active,[data-slot=label]:active]:rounded-[var(--thumb-size)/calc(var(--thumb-size)*1.1)]",
|
|
47
|
+
"data-checked:origin-[var(--thumb-size)_50%] data-checked:translate-x-[calc(var(--thumb-size)-2px)]",
|
|
48
|
+
],
|
|
49
|
+
)}
|
|
50
|
+
data-slot="switch-thumb"
|
|
51
|
+
/>
|
|
52
|
+
</SwitchPrimitive.Root>
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export { Switch };
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import type * as React from "react";
|
|
2
|
+
|
|
3
|
+
import { cn } from "../../lib/utils/css";
|
|
4
|
+
|
|
5
|
+
function Table({ className, ...props }: React.ComponentProps<"table">) {
|
|
6
|
+
return (
|
|
7
|
+
<div
|
|
8
|
+
className="relative w-full overflow-x-auto"
|
|
9
|
+
data-slot="table-container"
|
|
10
|
+
>
|
|
11
|
+
<table
|
|
12
|
+
className={cn(
|
|
13
|
+
"w-full caption-bottom in-data-[slot=frame]:border-separate in-data-[slot=frame]:border-spacing-0 text-sm",
|
|
14
|
+
className,
|
|
15
|
+
)}
|
|
16
|
+
data-slot="table"
|
|
17
|
+
{...props}
|
|
18
|
+
/>
|
|
19
|
+
</div>
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function TableHeader({ className, ...props }: React.ComponentProps<"thead">) {
|
|
24
|
+
return (
|
|
25
|
+
<thead
|
|
26
|
+
className={cn(
|
|
27
|
+
"[&_tr]:border-b in-data-[slot=frame]:**:[th]:h-9 in-data-[slot=frame]:*:[tr]:border-none in-data-[slot=frame]:*:[tr]:hover:bg-transparent",
|
|
28
|
+
className,
|
|
29
|
+
)}
|
|
30
|
+
data-slot="table-header"
|
|
31
|
+
{...props}
|
|
32
|
+
/>
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function TableBody({ className, ...props }: React.ComponentProps<"tbody">) {
|
|
37
|
+
return (
|
|
38
|
+
<tbody
|
|
39
|
+
className={cn(
|
|
40
|
+
"relative in-data-[slot=frame]:rounded-xl in-data-[slot=frame]:shadow-xs/5 before:pointer-events-none before:absolute before:inset-px not-in-data-[slot=frame]:before:hidden before:rounded-[calc(var(--radius-xl)-1px)] before:shadow-[0_1px_--theme(--color-black/6%)] dark:before:shadow-[0_-1px_--theme(--color-white/8%)] [&_tr:last-child]:border-0 in-data-[slot=frame]:*:[tr]:border-0 in-data-[slot=frame]:*:[tr]:*:[td]:border-b in-data-[slot=frame]:*:[tr]:*:[td]:bg-background in-data-[slot=frame]:*:[tr]:*:[td]:bg-clip-padding in-data-[slot=frame]:*:[tr]:first:*:[td]:first:rounded-ss-xl in-data-[slot=frame]:*:[tr]:*:[td]:first:border-s in-data-[slot=frame]:*:[tr]:first:*:[td]:border-t in-data-[slot=frame]:*:[tr]:last:*:[td]:last:rounded-ee-xl in-data-[slot=frame]:*:[tr]:*:[td]:last:border-e in-data-[slot=frame]:*:[tr]:first:*:[td]:last:rounded-se-xl in-data-[slot=frame]:*:[tr]:last:*:[td]:first:rounded-es-xl in-data-[slot=frame]:*:[tr]:hover:*:[td]:bg-transparent in-data-[slot=frame]:*:[tr]:data-[state=selected]:*:[td]:bg-muted/72",
|
|
41
|
+
className,
|
|
42
|
+
)}
|
|
43
|
+
data-slot="table-body"
|
|
44
|
+
{...props}
|
|
45
|
+
/>
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function TableFooter({ className, ...props }: React.ComponentProps<"tfoot">) {
|
|
50
|
+
return (
|
|
51
|
+
<tfoot
|
|
52
|
+
className={cn(
|
|
53
|
+
"border-t in-data-[slot=frame]:border-none bg-muted/72 in-data-[slot=frame]:bg-transparent font-medium [&>tr]:last:border-b-0 in-data-[slot=frame]:*:[tr]:hover:bg-transparent",
|
|
54
|
+
className,
|
|
55
|
+
)}
|
|
56
|
+
data-slot="table-footer"
|
|
57
|
+
{...props}
|
|
58
|
+
/>
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function TableRow({ className, ...props }: React.ComponentProps<"tr">) {
|
|
63
|
+
return (
|
|
64
|
+
<tr
|
|
65
|
+
className={cn(
|
|
66
|
+
"border-b transition-colors hover:bg-muted/72 in-data-[slot=frame]:hover:bg-transparent data-[state=selected]:bg-muted/72 in-data-[slot=frame]:data-[state=selected]:bg-transparent",
|
|
67
|
+
className,
|
|
68
|
+
)}
|
|
69
|
+
data-slot="table-row"
|
|
70
|
+
{...props}
|
|
71
|
+
/>
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function TableHead({ className, ...props }: React.ComponentProps<"th">) {
|
|
76
|
+
return (
|
|
77
|
+
<th
|
|
78
|
+
className={cn(
|
|
79
|
+
"h-10 whitespace-nowrap px-2.5 text-left align-middle font-medium text-muted-foreground leading-none has-[[role=checkbox]]:w-px has-[[role=checkbox]]:pe-0",
|
|
80
|
+
className,
|
|
81
|
+
)}
|
|
82
|
+
data-slot="table-head"
|
|
83
|
+
{...props}
|
|
84
|
+
/>
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function TableCell({ className, ...props }: React.ComponentProps<"td">) {
|
|
89
|
+
return (
|
|
90
|
+
<td
|
|
91
|
+
className={cn(
|
|
92
|
+
"whitespace-nowrap p-2.5 align-middle leading-none in-data-[slot=frame]:first:p-[calc(--spacing(2.5)-1px)] in-data-[slot=frame]:last:p-[calc(--spacing(2.5)-1px)] has-[[role=checkbox]]:pe-0",
|
|
93
|
+
className,
|
|
94
|
+
)}
|
|
95
|
+
data-slot="table-cell"
|
|
96
|
+
{...props}
|
|
97
|
+
/>
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function TableCaption({
|
|
102
|
+
className,
|
|
103
|
+
...props
|
|
104
|
+
}: React.ComponentProps<"caption">) {
|
|
105
|
+
return (
|
|
106
|
+
<caption
|
|
107
|
+
className={cn(
|
|
108
|
+
"in-data-[slot=frame]:my-4 mt-4 text-muted-foreground text-sm",
|
|
109
|
+
className,
|
|
110
|
+
)}
|
|
111
|
+
data-slot="table-caption"
|
|
112
|
+
{...props}
|
|
113
|
+
/>
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export {
|
|
118
|
+
Table,
|
|
119
|
+
TableHeader,
|
|
120
|
+
TableBody,
|
|
121
|
+
TableFooter,
|
|
122
|
+
TableHead,
|
|
123
|
+
TableRow,
|
|
124
|
+
TableCell,
|
|
125
|
+
TableCaption,
|
|
126
|
+
};
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { Tabs as TabsPrimitive } from "@base-ui/react/tabs";
|
|
4
|
+
|
|
5
|
+
import { cn } from "../../lib/utils/css";
|
|
6
|
+
|
|
7
|
+
type TabsVariant = "default" | "underline";
|
|
8
|
+
|
|
9
|
+
function Tabs({ className, ...props }: TabsPrimitive.Root.Props) {
|
|
10
|
+
return (
|
|
11
|
+
<TabsPrimitive.Root
|
|
12
|
+
className={cn(
|
|
13
|
+
"flex flex-col gap-2 data-[orientation=vertical]:flex-row",
|
|
14
|
+
className,
|
|
15
|
+
)}
|
|
16
|
+
data-slot="tabs"
|
|
17
|
+
{...props}
|
|
18
|
+
/>
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function TabsList({
|
|
23
|
+
variant = "default",
|
|
24
|
+
className,
|
|
25
|
+
children,
|
|
26
|
+
...props
|
|
27
|
+
}: TabsPrimitive.List.Props & {
|
|
28
|
+
variant?: TabsVariant;
|
|
29
|
+
}) {
|
|
30
|
+
return (
|
|
31
|
+
<TabsPrimitive.List
|
|
32
|
+
className={cn(
|
|
33
|
+
"relative z-0 flex w-fit items-center justify-center gap-x-0.5 text-muted-foreground",
|
|
34
|
+
"data-[orientation=vertical]:flex-col",
|
|
35
|
+
variant === "default"
|
|
36
|
+
? "rounded-lg bg-muted p-0.5 text-muted-foreground/72"
|
|
37
|
+
: "data-[orientation=vertical]:px-1 data-[orientation=horizontal]:py-1 *:data-[slot=tabs-tab]:hover:bg-accent",
|
|
38
|
+
className,
|
|
39
|
+
)}
|
|
40
|
+
data-slot="tabs-list"
|
|
41
|
+
{...props}
|
|
42
|
+
>
|
|
43
|
+
{children}
|
|
44
|
+
<TabsPrimitive.Indicator
|
|
45
|
+
className={cn(
|
|
46
|
+
"-translate-y-(--active-tab-bottom) absolute bottom-0 left-0 h-(--active-tab-height) w-(--active-tab-width) translate-x-(--active-tab-left) transition-[width,translate] duration-200 ease-in-out",
|
|
47
|
+
variant === "underline"
|
|
48
|
+
? "data-[orientation=vertical]:-translate-x-px z-10 bg-primary data-[orientation=horizontal]:h-0.5 data-[orientation=vertical]:w-0.5 data-[orientation=horizontal]:translate-y-px"
|
|
49
|
+
: "-z-1 rounded-md bg-background shadow-sm/5 dark:bg-input",
|
|
50
|
+
)}
|
|
51
|
+
data-slot="tab-indicator"
|
|
52
|
+
/>
|
|
53
|
+
</TabsPrimitive.List>
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function TabsTab({ className, ...props }: TabsPrimitive.Tab.Props) {
|
|
58
|
+
return (
|
|
59
|
+
<TabsPrimitive.Tab
|
|
60
|
+
className={cn(
|
|
61
|
+
"[&_svg]:-mx-0.5 relative flex h-9 shrink-0 grow cursor-pointer items-center justify-center gap-1.5 whitespace-nowrap rounded-md border border-transparent px-[calc(--spacing(2.5)-1px)] font-medium text-base outline-none transition-[color,background-color,box-shadow] hover:text-muted-foreground focus-visible:ring-2 focus-visible:ring-ring data-disabled:pointer-events-none data-[orientation=vertical]:w-full data-[orientation=vertical]:justify-start data-active:text-foreground data-disabled:opacity-64 sm:h-8 sm:text-sm [&_svg:not([class*='size-'])]:size-4.5 sm:[&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0",
|
|
62
|
+
className,
|
|
63
|
+
)}
|
|
64
|
+
data-slot="tabs-tab"
|
|
65
|
+
{...props}
|
|
66
|
+
/>
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function TabsPanel({ className, ...props }: TabsPrimitive.Panel.Props) {
|
|
71
|
+
return (
|
|
72
|
+
<TabsPrimitive.Panel
|
|
73
|
+
className={cn(
|
|
74
|
+
"flex-1 outline-none data-[activation-direction=down]:animate-in data-[activation-direction=left]:animate-in data-[activation-direction=right]:animate-in data-[activation-direction=up]:animate-in fade-in-0 duration-200 ease-out data-[activation-direction=down]:slide-in-from-bottom-1 data-[activation-direction=left]:slide-in-from-left-1 data-[activation-direction=right]:slide-in-from-right-1 data-[activation-direction=up]:slide-in-from-top-1",
|
|
75
|
+
className,
|
|
76
|
+
)}
|
|
77
|
+
data-slot="tabs-content"
|
|
78
|
+
{...props}
|
|
79
|
+
/>
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export {
|
|
84
|
+
Tabs,
|
|
85
|
+
TabsList,
|
|
86
|
+
TabsTab,
|
|
87
|
+
TabsTab as TabsTrigger,
|
|
88
|
+
TabsPanel,
|
|
89
|
+
TabsPanel as TabsContent,
|
|
90
|
+
};
|