@meith/ui 0.31.0 → 0.33.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 +4 -1
- package/src/avatar.tsx +2 -5
- package/src/dialog.tsx +2 -0
- package/src/index.ts +4 -2
- package/src/text-link.tsx +12 -0
- package/src/toast.tsx +77 -0
- package/src/tooltip.tsx +50 -0
- package/src/variants.ts +25 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@meith/ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.33.0",
|
|
4
4
|
"description": "Meith's shared UI primitives: buttons, menus and the class utilities themes build with.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -14,10 +14,13 @@
|
|
|
14
14
|
"exports": {
|
|
15
15
|
".": "./src/index.ts",
|
|
16
16
|
"./button": "./src/button.tsx",
|
|
17
|
+
"./dialog": "./src/dialog.tsx",
|
|
17
18
|
"./input-otp": "./src/input-otp.tsx",
|
|
18
19
|
"./menu": "./src/menu.tsx",
|
|
19
20
|
"./popover": "./src/popover.tsx",
|
|
20
21
|
"./tabs": "./src/tabs.tsx",
|
|
22
|
+
"./toast": "./src/toast.tsx",
|
|
23
|
+
"./tooltip": "./src/tooltip.tsx",
|
|
21
24
|
"./utils": "./src/utils.ts",
|
|
22
25
|
"./variants": "./src/variants.ts"
|
|
23
26
|
},
|
package/src/avatar.tsx
CHANGED
|
@@ -14,17 +14,14 @@ function Avatar({ className, src = null, name, size = 40, ...props }: AvatarProp
|
|
|
14
14
|
data-slot="avatar"
|
|
15
15
|
aria-hidden="true"
|
|
16
16
|
className={cn(
|
|
17
|
-
'inline-flex shrink-0 select-none items-center justify-center overflow-hidden rounded-md border border-
|
|
17
|
+
'inline-flex shrink-0 select-none items-center justify-center overflow-hidden rounded-md border border-primary/15 bg-primary/10',
|
|
18
18
|
className,
|
|
19
19
|
)}
|
|
20
20
|
style={{ width: size, height: size }}
|
|
21
21
|
{...props}
|
|
22
22
|
>
|
|
23
23
|
{src === null ? (
|
|
24
|
-
<span
|
|
25
|
-
className="font-medium text-muted-foreground"
|
|
26
|
-
style={{ fontSize: Math.round(size * 0.42) }}
|
|
27
|
-
>
|
|
24
|
+
<span className="font-semibold text-primary" style={{ fontSize: Math.round(size * 0.42) }}>
|
|
28
25
|
{initial}
|
|
29
26
|
</span>
|
|
30
27
|
) : (
|
package/src/dialog.tsx
ADDED
package/src/index.ts
CHANGED
|
@@ -21,6 +21,8 @@ export type { FieldProps } from './field'
|
|
|
21
21
|
export { Field, Input, Label, NativeSelect, Textarea } from './field'
|
|
22
22
|
export type { SeparatorProps } from './separator'
|
|
23
23
|
export { Separator } from './separator'
|
|
24
|
+
export type { TextLinkProps } from './text-link'
|
|
25
|
+
export { TextLink } from './text-link'
|
|
24
26
|
export { cn } from './utils'
|
|
25
|
-
export type { BadgeVariants, ButtonVariants } from './variants'
|
|
26
|
-
export { badgeVariants, buttonVariants } from './variants'
|
|
27
|
+
export type { BadgeVariants, ButtonVariants, TextLinkVariants } from './variants'
|
|
28
|
+
export { badgeVariants, buttonVariants, textLinkVariants } from './variants'
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { VariantProps } from 'class-variance-authority'
|
|
2
|
+
|
|
3
|
+
import { cn } from './utils'
|
|
4
|
+
import { textLinkVariants } from './variants'
|
|
5
|
+
|
|
6
|
+
export interface TextLinkProps
|
|
7
|
+
extends React.ComponentProps<'a'>,
|
|
8
|
+
VariantProps<typeof textLinkVariants> {}
|
|
9
|
+
|
|
10
|
+
export function TextLink({ className, tone, weight, size, ...props }: TextLinkProps) {
|
|
11
|
+
return <a {...props} className={cn(textLinkVariants({ tone, weight, size }), className)} />
|
|
12
|
+
}
|
package/src/toast.tsx
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import { cva, type VariantProps } from 'class-variance-authority'
|
|
4
|
+
import { useCallback, useEffect, useState } from 'react'
|
|
5
|
+
|
|
6
|
+
import { cn } from './utils'
|
|
7
|
+
|
|
8
|
+
export const toastVariants = cva(
|
|
9
|
+
'pointer-events-auto flex w-[min(24rem,calc(100vw-2rem))] items-start justify-between gap-3 rounded-md border border-l-4 px-4 py-3 text-sm shadow-lg',
|
|
10
|
+
{
|
|
11
|
+
variants: {
|
|
12
|
+
tone: {
|
|
13
|
+
info: 'border-border border-l-muted-foreground bg-card text-card-foreground',
|
|
14
|
+
success:
|
|
15
|
+
'border-moderation-approved/30 border-l-moderation-approved bg-card text-card-foreground',
|
|
16
|
+
warning: 'border-border border-l-moderation-pending bg-card text-card-foreground',
|
|
17
|
+
error: 'border-destructive/30 border-l-destructive bg-card text-card-foreground',
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
defaultVariants: { tone: 'info' },
|
|
21
|
+
},
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
export type ToastTone = NonNullable<VariantProps<typeof toastVariants>['tone']>
|
|
25
|
+
|
|
26
|
+
export interface ToastProps {
|
|
27
|
+
readonly children: React.ReactNode
|
|
28
|
+
readonly tone?: ToastTone
|
|
29
|
+
readonly dismissLabel: string
|
|
30
|
+
readonly duration?: number
|
|
31
|
+
readonly className?: string
|
|
32
|
+
readonly onDismiss?: () => void
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function Toast({
|
|
36
|
+
children,
|
|
37
|
+
tone = 'info',
|
|
38
|
+
dismissLabel,
|
|
39
|
+
duration = 6000,
|
|
40
|
+
className,
|
|
41
|
+
onDismiss,
|
|
42
|
+
}: ToastProps) {
|
|
43
|
+
const [open, setOpen] = useState(true)
|
|
44
|
+
|
|
45
|
+
const dismiss = useCallback(() => {
|
|
46
|
+
setOpen(false)
|
|
47
|
+
onDismiss?.()
|
|
48
|
+
}, [onDismiss])
|
|
49
|
+
|
|
50
|
+
useEffect(() => {
|
|
51
|
+
if (duration <= 0) return
|
|
52
|
+
const timer = setTimeout(dismiss, duration)
|
|
53
|
+
return () => clearTimeout(timer)
|
|
54
|
+
}, [duration, dismiss])
|
|
55
|
+
|
|
56
|
+
if (!open) return null
|
|
57
|
+
|
|
58
|
+
const assertive = tone === 'error'
|
|
59
|
+
|
|
60
|
+
return (
|
|
61
|
+
<div
|
|
62
|
+
role={assertive ? 'alert' : 'status'}
|
|
63
|
+
aria-live={assertive ? 'assertive' : 'polite'}
|
|
64
|
+
className={cn(toastVariants({ tone }), className)}
|
|
65
|
+
>
|
|
66
|
+
<div className="min-w-0 flex-1">{children}</div>
|
|
67
|
+
<button
|
|
68
|
+
type="button"
|
|
69
|
+
onClick={dismiss}
|
|
70
|
+
aria-label={dismissLabel}
|
|
71
|
+
className="-mr-1 -mt-1 inline-flex size-6 shrink-0 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-muted hover:text-foreground focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring"
|
|
72
|
+
>
|
|
73
|
+
<span aria-hidden="true">✕</span>
|
|
74
|
+
</button>
|
|
75
|
+
</div>
|
|
76
|
+
)
|
|
77
|
+
}
|
package/src/tooltip.tsx
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import { Tooltip as TooltipPrimitive } from '@base-ui/react/tooltip'
|
|
4
|
+
|
|
5
|
+
import { cn } from './utils'
|
|
6
|
+
|
|
7
|
+
export interface TooltipProps {
|
|
8
|
+
readonly label: React.ReactNode
|
|
9
|
+
readonly children: React.ReactElement
|
|
10
|
+
readonly side?: 'top' | 'bottom' | 'left' | 'right'
|
|
11
|
+
readonly align?: 'start' | 'center' | 'end'
|
|
12
|
+
readonly delay?: number
|
|
13
|
+
readonly className?: string
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function Tooltip({
|
|
17
|
+
label,
|
|
18
|
+
children,
|
|
19
|
+
side = 'top',
|
|
20
|
+
align = 'center',
|
|
21
|
+
delay = 300,
|
|
22
|
+
className,
|
|
23
|
+
}: TooltipProps) {
|
|
24
|
+
return (
|
|
25
|
+
<TooltipPrimitive.Root>
|
|
26
|
+
<TooltipPrimitive.Trigger delay={delay} render={children} />
|
|
27
|
+
<TooltipPrimitive.Portal>
|
|
28
|
+
<TooltipPrimitive.Positioner
|
|
29
|
+
side={side}
|
|
30
|
+
align={align}
|
|
31
|
+
sideOffset={6}
|
|
32
|
+
collisionPadding={8}
|
|
33
|
+
className="z-50"
|
|
34
|
+
>
|
|
35
|
+
<TooltipPrimitive.Popup
|
|
36
|
+
className={cn(
|
|
37
|
+
'max-w-64 origin-[var(--transform-origin)] rounded-md border border-border bg-card px-2 py-1 text-xs text-card-foreground shadow-md',
|
|
38
|
+
'duration-100 ease-out transition-[opacity,transform]',
|
|
39
|
+
'data-[starting-style]:scale-95 data-[starting-style]:opacity-0',
|
|
40
|
+
'data-[ending-style]:scale-95 data-[ending-style]:opacity-0',
|
|
41
|
+
className,
|
|
42
|
+
)}
|
|
43
|
+
>
|
|
44
|
+
{label}
|
|
45
|
+
</TooltipPrimitive.Popup>
|
|
46
|
+
</TooltipPrimitive.Positioner>
|
|
47
|
+
</TooltipPrimitive.Portal>
|
|
48
|
+
</TooltipPrimitive.Root>
|
|
49
|
+
)
|
|
50
|
+
}
|
package/src/variants.ts
CHANGED
|
@@ -68,3 +68,28 @@ export const badgeVariants = cva(
|
|
|
68
68
|
)
|
|
69
69
|
|
|
70
70
|
export type BadgeVariants = VariantProps<typeof badgeVariants>
|
|
71
|
+
|
|
72
|
+
export const textLinkVariants = cva(
|
|
73
|
+
'underline decoration-border underline-offset-2 hover:decoration-foreground',
|
|
74
|
+
{
|
|
75
|
+
variants: {
|
|
76
|
+
tone: {
|
|
77
|
+
default: 'text-foreground',
|
|
78
|
+
muted: 'text-muted-foreground hover:text-foreground',
|
|
79
|
+
inherit: '',
|
|
80
|
+
},
|
|
81
|
+
weight: {
|
|
82
|
+
medium: 'font-medium',
|
|
83
|
+
normal: '',
|
|
84
|
+
},
|
|
85
|
+
size: {
|
|
86
|
+
default: '',
|
|
87
|
+
sm: 'text-sm',
|
|
88
|
+
xs: 'text-xs',
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
defaultVariants: { tone: 'default', weight: 'medium', size: 'default' },
|
|
92
|
+
},
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
export type TextLinkVariants = VariantProps<typeof textLinkVariants>
|