@meith/ui 0.31.0 → 0.32.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@meith/ui",
3
- "version": "0.31.0",
3
+ "version": "0.32.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/dialog.tsx ADDED
@@ -0,0 +1,2 @@
1
+ export { AlertDialog } from '@base-ui/react/alert-dialog'
2
+ export { Dialog } from '@base-ui/react/dialog'
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
+ }
@@ -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>