@strategicos/ui 0.0.0-stage → 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/README.md +33 -2
- package/THIRD_PARTY_NOTICES.md +27 -0
- package/dist/components/alert-dialog.d.ts +15 -0
- package/dist/components/alert-dialog.d.ts.map +1 -0
- package/dist/components/alert-dialog.js +40 -0
- package/dist/components/alert-dialog.js.map +1 -0
- package/dist/components/alert.d.ts +11 -0
- package/dist/components/alert.d.ts.map +1 -0
- package/dist/components/alert.js +28 -0
- package/dist/components/alert.js.map +1 -0
- package/dist/components/avatar.d.ts +12 -0
- package/dist/components/avatar.d.ts.map +1 -0
- package/dist/components/avatar.js +24 -0
- package/dist/components/avatar.js.map +1 -0
- package/dist/components/badge.d.ts +10 -0
- package/dist/components/badge.d.ts.map +1 -0
- package/dist/components/badge.js +33 -0
- package/dist/components/badge.js.map +1 -0
- package/dist/components/button.d.ts +11 -0
- package/dist/components/button.d.ts.map +1 -0
- package/dist/components/button.js +36 -0
- package/dist/components/button.js.map +1 -0
- package/dist/components/card.d.ts +12 -0
- package/dist/components/card.d.ts.map +1 -0
- package/dist/components/card.js +25 -0
- package/dist/components/card.js.map +1 -0
- package/dist/components/dialog.d.ts +18 -0
- package/dist/components/dialog.d.ts.map +1 -0
- package/dist/components/dialog.js +38 -0
- package/dist/components/dialog.js.map +1 -0
- package/dist/components/dropdown-menu.d.ts +30 -0
- package/dist/components/dropdown-menu.d.ts.map +1 -0
- package/dist/components/dropdown-menu.js +52 -0
- package/dist/components/dropdown-menu.js.map +1 -0
- package/dist/components/input.d.ts +4 -0
- package/dist/components/input.d.ts.map +1 -0
- package/dist/components/input.js +7 -0
- package/dist/components/input.js.map +1 -0
- package/dist/components/label.d.ts +5 -0
- package/dist/components/label.d.ts.map +1 -0
- package/dist/components/label.js +9 -0
- package/dist/components/label.js.map +1 -0
- package/dist/components/pagination.d.ts +12 -0
- package/dist/components/pagination.d.ts.map +1 -0
- package/dist/components/pagination.js +12 -0
- package/dist/components/pagination.js.map +1 -0
- package/dist/components/select.d.ts +18 -0
- package/dist/components/select.d.ts.map +1 -0
- package/dist/components/select.js +37 -0
- package/dist/components/select.js.map +1 -0
- package/dist/components/separator.d.ts +5 -0
- package/dist/components/separator.d.ts.map +1 -0
- package/dist/components/separator.js +9 -0
- package/dist/components/separator.js.map +1 -0
- package/dist/components/sheet.d.ts +15 -0
- package/dist/components/sheet.d.ts.map +1 -0
- package/dist/components/sheet.js +38 -0
- package/dist/components/sheet.js.map +1 -0
- package/dist/components/sidebar.d.ts +70 -0
- package/dist/components/sidebar.d.ts.map +1 -0
- package/dist/components/sidebar.js +207 -0
- package/dist/components/sidebar.js.map +1 -0
- package/dist/components/skeleton.d.ts +3 -0
- package/dist/components/skeleton.d.ts.map +1 -0
- package/dist/components/skeleton.js +7 -0
- package/dist/components/skeleton.js.map +1 -0
- package/dist/components/sonner.d.ts +4 -0
- package/dist/components/sonner.d.ts.map +1 -0
- package/dist/components/sonner.js +26 -0
- package/dist/components/sonner.js.map +1 -0
- package/dist/components/table.d.ts +11 -0
- package/dist/components/table.d.ts.map +1 -0
- package/dist/components/table.js +29 -0
- package/dist/components/table.js.map +1 -0
- package/dist/components/tabs.d.ts +13 -0
- package/dist/components/tabs.d.ts.map +1 -0
- package/dist/components/tabs.js +69 -0
- package/dist/components/tabs.js.map +1 -0
- package/dist/components/textarea.d.ts +15 -0
- package/dist/components/textarea.d.ts.map +1 -0
- package/dist/components/textarea.js +18 -0
- package/dist/components/textarea.js.map +1 -0
- package/dist/components/tooltip.d.ts +8 -0
- package/dist/components/tooltip.d.ts.map +1 -0
- package/dist/components/tooltip.js +18 -0
- package/dist/components/tooltip.js.map +1 -0
- package/dist/hooks/use-mobile.d.ts +2 -0
- package/dist/hooks/use-mobile.d.ts.map +1 -0
- package/dist/hooks/use-mobile.js +14 -0
- package/dist/hooks/use-mobile.js.map +1 -0
- package/dist/lib/utils.d.ts +4 -0
- package/dist/lib/utils.d.ts.map +1 -0
- package/dist/lib/utils.js +7 -0
- package/dist/lib/utils.js.map +1 -0
- package/package.json +76 -4
- package/src/components/alert-dialog.tsx +152 -0
- package/src/components/alert.tsx +76 -0
- package/src/components/avatar.tsx +112 -0
- package/src/components/badge.tsx +57 -0
- package/src/components/button.tsx +67 -0
- package/src/components/card.tsx +103 -0
- package/src/components/dialog.tsx +168 -0
- package/src/components/dropdown-menu.tsx +269 -0
- package/src/components/input.tsx +19 -0
- package/src/components/label.tsx +24 -0
- package/src/components/pagination.tsx +62 -0
- package/src/components/select.tsx +208 -0
- package/src/components/separator.tsx +28 -0
- package/src/components/sheet.tsx +147 -0
- package/src/components/sidebar.tsx +702 -0
- package/src/components/skeleton.tsx +13 -0
- package/src/components/sonner.tsx +49 -0
- package/src/components/table.tsx +116 -0
- package/src/components/tabs.tsx +153 -0
- package/src/components/textarea.tsx +29 -0
- package/src/components/tooltip.tsx +57 -0
- package/src/hooks/use-mobile.ts +20 -0
- package/src/lib/utils.ts +7 -0
- package/styles.css +112 -0
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import { useTheme } from "next-themes"
|
|
4
|
+
import { Toaster as Sonner, type ToasterProps } from "sonner"
|
|
5
|
+
import { CircleCheckIcon, InfoIcon, TriangleAlertIcon, OctagonXIcon, Loader2Icon } from "lucide-react"
|
|
6
|
+
|
|
7
|
+
const Toaster = ({ ...props }: ToasterProps) => {
|
|
8
|
+
const { theme = "system" } = useTheme()
|
|
9
|
+
|
|
10
|
+
return (
|
|
11
|
+
<Sonner
|
|
12
|
+
theme={theme as ToasterProps["theme"]}
|
|
13
|
+
className="toaster group"
|
|
14
|
+
icons={{
|
|
15
|
+
success: (
|
|
16
|
+
<CircleCheckIcon className="size-4" />
|
|
17
|
+
),
|
|
18
|
+
info: (
|
|
19
|
+
<InfoIcon className="size-4" />
|
|
20
|
+
),
|
|
21
|
+
warning: (
|
|
22
|
+
<TriangleAlertIcon className="size-4" />
|
|
23
|
+
),
|
|
24
|
+
error: (
|
|
25
|
+
<OctagonXIcon className="size-4" />
|
|
26
|
+
),
|
|
27
|
+
loading: (
|
|
28
|
+
<Loader2Icon className="size-4 animate-spin" />
|
|
29
|
+
),
|
|
30
|
+
}}
|
|
31
|
+
style={
|
|
32
|
+
{
|
|
33
|
+
"--normal-bg": "var(--popover)",
|
|
34
|
+
"--normal-text": "var(--popover-foreground)",
|
|
35
|
+
"--normal-border": "var(--border)",
|
|
36
|
+
"--border-radius": "var(--radius)",
|
|
37
|
+
} as React.CSSProperties
|
|
38
|
+
}
|
|
39
|
+
toastOptions={{
|
|
40
|
+
classNames: {
|
|
41
|
+
toast: "cn-toast",
|
|
42
|
+
},
|
|
43
|
+
}}
|
|
44
|
+
{...props}
|
|
45
|
+
/>
|
|
46
|
+
)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export { Toaster }
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import * as React from "react"
|
|
4
|
+
|
|
5
|
+
import { cn } from "../lib/utils.js"
|
|
6
|
+
|
|
7
|
+
function Table({ className, ...props }: React.ComponentProps<"table">) {
|
|
8
|
+
return (
|
|
9
|
+
<div
|
|
10
|
+
data-slot="table-container"
|
|
11
|
+
className="relative w-full overflow-x-auto"
|
|
12
|
+
>
|
|
13
|
+
<table
|
|
14
|
+
data-slot="table"
|
|
15
|
+
className={cn("w-full caption-bottom text-sm", className)}
|
|
16
|
+
{...props}
|
|
17
|
+
/>
|
|
18
|
+
</div>
|
|
19
|
+
)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function TableHeader({ className, ...props }: React.ComponentProps<"thead">) {
|
|
23
|
+
return (
|
|
24
|
+
<thead
|
|
25
|
+
data-slot="table-header"
|
|
26
|
+
className={cn("[&_tr]:border-b", className)}
|
|
27
|
+
{...props}
|
|
28
|
+
/>
|
|
29
|
+
)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function TableBody({ className, ...props }: React.ComponentProps<"tbody">) {
|
|
33
|
+
return (
|
|
34
|
+
<tbody
|
|
35
|
+
data-slot="table-body"
|
|
36
|
+
className={cn("[&_tr:last-child]:border-0", className)}
|
|
37
|
+
{...props}
|
|
38
|
+
/>
|
|
39
|
+
)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function TableFooter({ className, ...props }: React.ComponentProps<"tfoot">) {
|
|
43
|
+
return (
|
|
44
|
+
<tfoot
|
|
45
|
+
data-slot="table-footer"
|
|
46
|
+
className={cn(
|
|
47
|
+
"border-t bg-muted/50 font-medium [&>tr]:last:border-b-0",
|
|
48
|
+
className
|
|
49
|
+
)}
|
|
50
|
+
{...props}
|
|
51
|
+
/>
|
|
52
|
+
)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function TableRow({ className, ...props }: React.ComponentProps<"tr">) {
|
|
56
|
+
return (
|
|
57
|
+
<tr
|
|
58
|
+
data-slot="table-row"
|
|
59
|
+
className={cn(
|
|
60
|
+
"border-b transition-colors hover:bg-muted/50 has-aria-expanded:bg-muted/50 data-[state=selected]:bg-muted",
|
|
61
|
+
className
|
|
62
|
+
)}
|
|
63
|
+
{...props}
|
|
64
|
+
/>
|
|
65
|
+
)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function TableHead({ className, ...props }: React.ComponentProps<"th">) {
|
|
69
|
+
return (
|
|
70
|
+
<th
|
|
71
|
+
data-slot="table-head"
|
|
72
|
+
className={cn(
|
|
73
|
+
"h-10 px-2 text-left align-middle font-medium whitespace-nowrap text-foreground [&:has([role=checkbox])]:pr-0",
|
|
74
|
+
className
|
|
75
|
+
)}
|
|
76
|
+
{...props}
|
|
77
|
+
/>
|
|
78
|
+
)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function TableCell({ className, ...props }: React.ComponentProps<"td">) {
|
|
82
|
+
return (
|
|
83
|
+
<td
|
|
84
|
+
data-slot="table-cell"
|
|
85
|
+
className={cn(
|
|
86
|
+
"p-2 align-middle whitespace-nowrap [&:has([role=checkbox])]:pr-0",
|
|
87
|
+
className
|
|
88
|
+
)}
|
|
89
|
+
{...props}
|
|
90
|
+
/>
|
|
91
|
+
)
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function TableCaption({
|
|
95
|
+
className,
|
|
96
|
+
...props
|
|
97
|
+
}: React.ComponentProps<"caption">) {
|
|
98
|
+
return (
|
|
99
|
+
<caption
|
|
100
|
+
data-slot="table-caption"
|
|
101
|
+
className={cn("mt-4 text-sm text-muted-foreground", className)}
|
|
102
|
+
{...props}
|
|
103
|
+
/>
|
|
104
|
+
)
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export {
|
|
108
|
+
Table,
|
|
109
|
+
TableHeader,
|
|
110
|
+
TableBody,
|
|
111
|
+
TableFooter,
|
|
112
|
+
TableHead,
|
|
113
|
+
TableRow,
|
|
114
|
+
TableCell,
|
|
115
|
+
TableCaption,
|
|
116
|
+
}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import * as React from "react"
|
|
4
|
+
import { cva, type VariantProps } from "class-variance-authority"
|
|
5
|
+
import { Tabs as TabsPrimitive } from "radix-ui"
|
|
6
|
+
|
|
7
|
+
import { cn } from "../lib/utils.js"
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Abas do app — shadcn/Radix, com o visual do app. O Radix dá o comportamento de
|
|
11
|
+
* tablist: `role`/`aria-selected`/`aria-controls`, setas (← → na horizontal,
|
|
12
|
+
* ↑ ↓ na vertical) e tabIndex roving (só a aba ativa entra no Tab).
|
|
13
|
+
*
|
|
14
|
+
* Variantes da lista (`<TabsList variant>`):
|
|
15
|
+
* - `line` — sublinhada. O padrão para NAVEGAR entre painéis de conteúdo
|
|
16
|
+
* distintos (Comentários | Histórico, Meus imports | Acervo). Na orientação
|
|
17
|
+
* vertical vira uma lista lateral (configurações).
|
|
18
|
+
* - `default` — seletor segmentado (pill sobre fundo cinza), para escolher um
|
|
19
|
+
* MODO que transforma o mesmo conteúdo (Ações | Tarefas no kanban). Evite-o
|
|
20
|
+
* dentro de diálogo: o item ativo usa a cor de fundo da página, que sobre a
|
|
21
|
+
* superfície do diálogo (branca) fica mais escura — elevação invertida.
|
|
22
|
+
*
|
|
23
|
+
* Para esconder o rótulo das abas inativas no mobile, use no rótulo:
|
|
24
|
+
* `className="hidden group-data-active/tabs-trigger:inline sm:inline"`.
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
type Orientation = "horizontal" | "vertical"
|
|
28
|
+
type Variant = "default" | "line"
|
|
29
|
+
|
|
30
|
+
const OrientationContext = React.createContext<Orientation>("horizontal")
|
|
31
|
+
const VariantContext = React.createContext<Variant>("default")
|
|
32
|
+
|
|
33
|
+
function Tabs({
|
|
34
|
+
className,
|
|
35
|
+
orientation = "horizontal",
|
|
36
|
+
...props
|
|
37
|
+
}: React.ComponentProps<typeof TabsPrimitive.Root>) {
|
|
38
|
+
return (
|
|
39
|
+
<OrientationContext.Provider value={orientation}>
|
|
40
|
+
<TabsPrimitive.Root
|
|
41
|
+
data-slot="tabs"
|
|
42
|
+
orientation={orientation}
|
|
43
|
+
className={cn(
|
|
44
|
+
"flex gap-2",
|
|
45
|
+
orientation === "horizontal" ? "flex-col" : "flex-row",
|
|
46
|
+
className
|
|
47
|
+
)}
|
|
48
|
+
{...props}
|
|
49
|
+
/>
|
|
50
|
+
</OrientationContext.Provider>
|
|
51
|
+
)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const tabsListVariants = cva("flex text-muted-foreground", {
|
|
55
|
+
variants: {
|
|
56
|
+
variant: {
|
|
57
|
+
default: "w-fit items-center rounded-lg bg-muted p-[3px]",
|
|
58
|
+
line: "gap-1",
|
|
59
|
+
},
|
|
60
|
+
orientation: {
|
|
61
|
+
horizontal: "",
|
|
62
|
+
vertical: "flex-col items-stretch",
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
compoundVariants: [
|
|
66
|
+
{ variant: "default", orientation: "horizontal", className: "h-8" },
|
|
67
|
+
{ variant: "line", orientation: "horizontal", className: "border-b border-border" },
|
|
68
|
+
{ variant: "line", orientation: "vertical", className: "gap-0.5" },
|
|
69
|
+
],
|
|
70
|
+
defaultVariants: { variant: "default", orientation: "horizontal" },
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
function TabsList({
|
|
74
|
+
className,
|
|
75
|
+
variant = "default",
|
|
76
|
+
...props
|
|
77
|
+
}: React.ComponentProps<typeof TabsPrimitive.List> &
|
|
78
|
+
Omit<VariantProps<typeof tabsListVariants>, "orientation">) {
|
|
79
|
+
const orientation = React.useContext(OrientationContext)
|
|
80
|
+
const v = variant ?? "default"
|
|
81
|
+
return (
|
|
82
|
+
<VariantContext.Provider value={v}>
|
|
83
|
+
<TabsPrimitive.List
|
|
84
|
+
data-slot="tabs-list"
|
|
85
|
+
data-variant={v}
|
|
86
|
+
className={cn(tabsListVariants({ variant: v, orientation }), className)}
|
|
87
|
+
{...props}
|
|
88
|
+
/>
|
|
89
|
+
</VariantContext.Provider>
|
|
90
|
+
)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const tabsTriggerVariants = cva(
|
|
94
|
+
"group/tabs-trigger relative inline-flex cursor-pointer items-center gap-2 text-sm font-medium whitespace-nowrap transition-colors outline-none focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
95
|
+
{
|
|
96
|
+
variants: {
|
|
97
|
+
variant: {
|
|
98
|
+
default:
|
|
99
|
+
"h-full flex-1 justify-center rounded-md border border-transparent px-2 py-0.5 text-foreground/60 hover:text-foreground data-active:bg-background data-active:text-foreground data-active:shadow-sm dark:text-muted-foreground dark:data-active:border-input dark:data-active:bg-input/30",
|
|
100
|
+
line: "text-muted-foreground hover:text-foreground data-active:text-primary-strong",
|
|
101
|
+
},
|
|
102
|
+
orientation: {
|
|
103
|
+
horizontal: "",
|
|
104
|
+
vertical: "",
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
compoundVariants: [
|
|
108
|
+
{
|
|
109
|
+
variant: "line",
|
|
110
|
+
orientation: "horizontal",
|
|
111
|
+
className:
|
|
112
|
+
"-mb-px justify-center border-b-2 border-transparent px-3 py-2.5 data-active:border-primary-strong sm:px-4",
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
variant: "line",
|
|
116
|
+
orientation: "vertical",
|
|
117
|
+
className:
|
|
118
|
+
"w-full justify-start rounded-md px-2.5 py-1.5 text-left font-normal text-foreground/80 hover:bg-accent/60 hover:text-foreground data-active:bg-accent data-active:font-medium data-active:text-foreground",
|
|
119
|
+
},
|
|
120
|
+
],
|
|
121
|
+
defaultVariants: { variant: "default", orientation: "horizontal" },
|
|
122
|
+
}
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
function TabsTrigger({
|
|
126
|
+
className,
|
|
127
|
+
...props
|
|
128
|
+
}: React.ComponentProps<typeof TabsPrimitive.Trigger>) {
|
|
129
|
+
const orientation = React.useContext(OrientationContext)
|
|
130
|
+
const variant = React.useContext(VariantContext)
|
|
131
|
+
return (
|
|
132
|
+
<TabsPrimitive.Trigger
|
|
133
|
+
data-slot="tabs-trigger"
|
|
134
|
+
className={cn(tabsTriggerVariants({ variant, orientation }), className)}
|
|
135
|
+
{...props}
|
|
136
|
+
/>
|
|
137
|
+
)
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function TabsContent({
|
|
141
|
+
className,
|
|
142
|
+
...props
|
|
143
|
+
}: React.ComponentProps<typeof TabsPrimitive.Content>) {
|
|
144
|
+
return (
|
|
145
|
+
<TabsPrimitive.Content
|
|
146
|
+
data-slot="tabs-content"
|
|
147
|
+
className={cn("min-w-0 flex-1 outline-none", className)}
|
|
148
|
+
{...props}
|
|
149
|
+
/>
|
|
150
|
+
)
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
export { Tabs, TabsList, TabsTrigger, TabsContent, tabsListVariants }
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import * as React from "react"
|
|
2
|
+
|
|
3
|
+
import { cn } from "../lib/utils.js"
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Campo multilinha. Espelha os tokens do <Input> — mesma borda, mesmo raio,
|
|
7
|
+
* mesmo anel de foco, mesmo tratamento de desabilitado e de aria-invalid — para
|
|
8
|
+
* que um campo de texto longo não pareça de outro sistema ao lado de um curto.
|
|
9
|
+
*
|
|
10
|
+
* Difere do Input só no que a multilinha exige: sem altura fixa, com padding
|
|
11
|
+
* vertical maior e `leading-relaxed`.
|
|
12
|
+
*
|
|
13
|
+
* Não confundir com o InlineTextarea do gerenciador: aquele é um editor inline
|
|
14
|
+
* (sem borda até o hover, salva no blur), um padrão deliberadamente diferente.
|
|
15
|
+
*/
|
|
16
|
+
function Textarea({ className, ...props }: React.ComponentProps<"textarea">) {
|
|
17
|
+
return (
|
|
18
|
+
<textarea
|
|
19
|
+
data-slot="textarea"
|
|
20
|
+
className={cn(
|
|
21
|
+
"w-full min-w-0 resize-none rounded-lg border border-input bg-transparent px-3 py-2 text-base leading-relaxed transition-colors outline-none placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-1 focus-visible:ring-ring/50 disabled:pointer-events-none disabled:cursor-not-allowed disabled:bg-input/50 disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-1 aria-invalid:ring-destructive/20 md:text-sm dark:bg-input/30 dark:disabled:bg-input/80 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40",
|
|
22
|
+
className
|
|
23
|
+
)}
|
|
24
|
+
{...props}
|
|
25
|
+
/>
|
|
26
|
+
)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export { Textarea }
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import * as React from "react"
|
|
4
|
+
import { Tooltip as TooltipPrimitive } from "radix-ui"
|
|
5
|
+
|
|
6
|
+
import { cn } from "../lib/utils.js"
|
|
7
|
+
|
|
8
|
+
function TooltipProvider({
|
|
9
|
+
delayDuration = 0,
|
|
10
|
+
...props
|
|
11
|
+
}: React.ComponentProps<typeof TooltipPrimitive.Provider>) {
|
|
12
|
+
return (
|
|
13
|
+
<TooltipPrimitive.Provider
|
|
14
|
+
data-slot="tooltip-provider"
|
|
15
|
+
delayDuration={delayDuration}
|
|
16
|
+
{...props}
|
|
17
|
+
/>
|
|
18
|
+
)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function Tooltip({
|
|
22
|
+
...props
|
|
23
|
+
}: React.ComponentProps<typeof TooltipPrimitive.Root>) {
|
|
24
|
+
return <TooltipPrimitive.Root data-slot="tooltip" {...props} />
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function TooltipTrigger({
|
|
28
|
+
...props
|
|
29
|
+
}: React.ComponentProps<typeof TooltipPrimitive.Trigger>) {
|
|
30
|
+
return <TooltipPrimitive.Trigger data-slot="tooltip-trigger" {...props} />
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function TooltipContent({
|
|
34
|
+
className,
|
|
35
|
+
sideOffset = 0,
|
|
36
|
+
children,
|
|
37
|
+
...props
|
|
38
|
+
}: React.ComponentProps<typeof TooltipPrimitive.Content>) {
|
|
39
|
+
return (
|
|
40
|
+
<TooltipPrimitive.Portal>
|
|
41
|
+
<TooltipPrimitive.Content
|
|
42
|
+
data-slot="tooltip-content"
|
|
43
|
+
sideOffset={sideOffset}
|
|
44
|
+
className={cn(
|
|
45
|
+
"z-50 inline-flex w-fit max-w-xs origin-(--radix-tooltip-content-transform-origin) items-center gap-1.5 rounded-md bg-foreground px-3 py-1.5 text-xs text-background has-data-[slot=kbd]:pr-1.5 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 **:data-[slot=kbd]:relative **:data-[slot=kbd]:isolate **:data-[slot=kbd]:z-50 **:data-[slot=kbd]:rounded-sm data-[state=delayed-open]:animate-in data-[state=delayed-open]:fade-in-0 data-[state=delayed-open]:zoom-in-95 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95",
|
|
46
|
+
className
|
|
47
|
+
)}
|
|
48
|
+
{...props}
|
|
49
|
+
>
|
|
50
|
+
{children}
|
|
51
|
+
<TooltipPrimitive.Arrow className="z-50 size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-[2px] bg-foreground fill-foreground" />
|
|
52
|
+
</TooltipPrimitive.Content>
|
|
53
|
+
</TooltipPrimitive.Portal>
|
|
54
|
+
)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger }
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import * as React from "react"
|
|
2
|
+
|
|
3
|
+
const MOBILE_BREAKPOINT = 768
|
|
4
|
+
|
|
5
|
+
function subscribe(callback: () => void) {
|
|
6
|
+
const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`)
|
|
7
|
+
mql.addEventListener("change", callback)
|
|
8
|
+
return () => mql.removeEventListener("change", callback)
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function useIsMobile() {
|
|
12
|
+
// Assina a media query como um "external store" — sem setState em effect
|
|
13
|
+
// (evita o cascading render que o react-hooks/set-state-in-effect alerta) e
|
|
14
|
+
// com snapshot de servidor (false) para não quebrar o SSR/hidratação.
|
|
15
|
+
return React.useSyncExternalStore(
|
|
16
|
+
subscribe,
|
|
17
|
+
() => window.innerWidth < MOBILE_BREAKPOINT,
|
|
18
|
+
() => false,
|
|
19
|
+
)
|
|
20
|
+
}
|
package/src/lib/utils.ts
ADDED
package/styles.css
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/* @strategicos/ui — estilos que os componentes precisam.
|
|
2
|
+
*
|
|
3
|
+
* Importe DEPOIS do tailwindcss e dos tokens:
|
|
4
|
+
* @import "tailwindcss";
|
|
5
|
+
* @import "@strategicos/tokens/theme.css";
|
|
6
|
+
* @import "@strategicos/ui/styles.css";
|
|
7
|
+
*
|
|
8
|
+
* O @source abaixo faz o Tailwind do app escanear o JS compilado deste pacote.
|
|
9
|
+
* Sem ele, as classes usadas só aqui dentro (h-7.5, data-active:…) não são
|
|
10
|
+
* geradas, porque o Tailwind ignora node_modules por padrão. */
|
|
11
|
+
|
|
12
|
+
@import "tw-animate-css";
|
|
13
|
+
|
|
14
|
+
@source "./dist";
|
|
15
|
+
|
|
16
|
+
/* Variantes de estado do Radix e utilitário no-scrollbar. Copiado do
|
|
17
|
+
* shadcn/tailwind.css para não depender do pacote `shadcn` (que é a CLI). */
|
|
18
|
+
@theme inline {
|
|
19
|
+
@keyframes accordion-down {
|
|
20
|
+
from {
|
|
21
|
+
height: 0;
|
|
22
|
+
}
|
|
23
|
+
to {
|
|
24
|
+
height: var(
|
|
25
|
+
--radix-accordion-content-height,
|
|
26
|
+
var(--accordion-panel-height, auto)
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
@keyframes accordion-up {
|
|
32
|
+
from {
|
|
33
|
+
height: var(
|
|
34
|
+
--radix-accordion-content-height,
|
|
35
|
+
var(--accordion-panel-height, auto)
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
to {
|
|
39
|
+
height: 0;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/* Custom variants */
|
|
45
|
+
@custom-variant data-open {
|
|
46
|
+
&:where([data-state="open"]),
|
|
47
|
+
&:where([data-open]:not([data-open="false"])) {
|
|
48
|
+
@slot;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
@custom-variant data-closed {
|
|
53
|
+
&:where([data-state="closed"]),
|
|
54
|
+
&:where([data-closed]:not([data-closed="false"])) {
|
|
55
|
+
@slot;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
@custom-variant data-checked {
|
|
60
|
+
&:where([data-state="checked"]),
|
|
61
|
+
&:where([data-checked]:not([data-checked="false"])) {
|
|
62
|
+
@slot;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
@custom-variant data-unchecked {
|
|
67
|
+
&:where([data-state="unchecked"]),
|
|
68
|
+
&:where([data-unchecked]:not([data-unchecked="false"])) {
|
|
69
|
+
@slot;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
@custom-variant data-selected {
|
|
74
|
+
&:where([data-selected="true"]) {
|
|
75
|
+
@slot;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
@custom-variant data-disabled {
|
|
80
|
+
&:where([data-disabled="true"]),
|
|
81
|
+
&:where([data-disabled]:not([data-disabled="false"])) {
|
|
82
|
+
@slot;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
@custom-variant data-active {
|
|
87
|
+
&:where([data-state="active"]),
|
|
88
|
+
&:where([data-active]:not([data-active="false"])) {
|
|
89
|
+
@slot;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
@custom-variant data-horizontal {
|
|
94
|
+
&:where([data-orientation="horizontal"]) {
|
|
95
|
+
@slot;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
@custom-variant data-vertical {
|
|
100
|
+
&:where([data-orientation="vertical"]) {
|
|
101
|
+
@slot;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
@utility no-scrollbar {
|
|
106
|
+
-ms-overflow-style: none;
|
|
107
|
+
scrollbar-width: none;
|
|
108
|
+
|
|
109
|
+
&::-webkit-scrollbar {
|
|
110
|
+
display: none;
|
|
111
|
+
}
|
|
112
|
+
}
|