@pantoia/ui 0.2.0 → 0.4.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/accordion/index.module.css +4 -4
- package/accordion/index.tsx +30 -58
- package/alert-dialog/index.tsx +38 -44
- package/badge/index.tsx +2 -2
- package/button/index.tsx +31 -30
- package/callout/index.tsx +29 -8
- package/checkbox/index.tsx +24 -88
- package/combobox/index.tsx +133 -323
- package/command-palette/index.tsx +55 -34
- package/dialog/index.tsx +30 -26
- package/dist/index.js +155 -27
- package/drawer/index.module.css +2 -2
- package/drawer/index.tsx +54 -132
- package/dropdown-menu/index.tsx +95 -100
- package/field/index.tsx +43 -94
- package/input/index.tsx +13 -9
- package/kbd/index.tsx +2 -2
- package/label/index.tsx +7 -9
- package/number-field/index.tsx +129 -176
- package/package.json +12 -15
- package/palette.css +114 -0
- package/popover/index.tsx +62 -33
- package/radio-group/index.tsx +36 -39
- package/registry.json +65 -169
- package/select/index.tsx +154 -76
- package/switch/index.tsx +13 -6
- package/table/index.tsx +5 -6
- package/tabs/index.module.css +5 -3
- package/tabs/index.tsx +26 -77
- package/tailwind.css +3 -0
- package/textarea/index.tsx +25 -13
- package/toast/index.module.css +187 -0
- package/toast/index.tsx +141 -46
- package/toggle/index.tsx +8 -7
- package/{styles.css → tokens.css} +82 -303
- package/tooltip/index.tsx +62 -31
- package/tv.ts +0 -1
- package/utilities.css +124 -0
- package/accordion/AGENTS.md +0 -60
- package/alert-dialog/AGENTS.md +0 -78
- package/badge/AGENTS.md +0 -35
- package/button/AGENTS.md +0 -39
- package/callout/AGENTS.md +0 -41
- package/checkbox/AGENTS.md +0 -54
- package/combobox/AGENTS.md +0 -150
- package/command-palette/AGENTS.md +0 -45
- package/dialog/AGENTS.md +0 -81
- package/drawer/AGENTS.md +0 -66
- package/dropdown-menu/AGENTS.md +0 -133
- package/field/AGENTS.md +0 -96
- package/input/AGENTS.md +0 -35
- package/kbd/AGENTS.md +0 -17
- package/label/AGENTS.md +0 -21
- package/number-field/AGENTS.md +0 -53
- package/popover/AGENTS.md +0 -64
- package/press.css +0 -37
- package/radio-group/AGENTS.md +0 -81
- package/select/AGENTS.md +0 -90
- package/switch/AGENTS.md +0 -37
- package/table/AGENTS.md +0 -82
- package/tabs/AGENTS.md +0 -60
- package/test-utils.ts +0 -10
- package/textarea/AGENTS.md +0 -35
- package/toast/AGENTS.md +0 -34
- package/toggle/AGENTS.md +0 -37
- package/tooltip/AGENTS.md +0 -50
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
@keyframes acc-open { from { height: 0; } to { height: var(--
|
|
2
|
-
@keyframes acc-close { from { height: var(--
|
|
1
|
+
@keyframes acc-open { from { height: 0; } to { height: var(--accordion-panel-height); } }
|
|
2
|
+
@keyframes acc-close { from { height: var(--accordion-panel-height); } to { height: 0; } }
|
|
3
3
|
|
|
4
4
|
.panel { overflow: hidden; }
|
|
5
|
-
.panel[data-
|
|
6
|
-
.panel[data-
|
|
5
|
+
.panel[data-open] { animation: acc-open var(--dur-enter) var(--ease-enter); }
|
|
6
|
+
.panel[data-closed] { animation: acc-close var(--dur-exit) var(--ease-exit); }
|
|
7
7
|
|
|
8
8
|
@media (prefers-reduced-motion: reduce) {
|
|
9
9
|
.panel { animation: none; }
|
package/accordion/index.tsx
CHANGED
|
@@ -1,99 +1,71 @@
|
|
|
1
1
|
'use client'
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import type { ReactNode } from 'react'
|
|
3
|
+
import { Accordion as AccordionPrimitive } from '@base-ui/react/accordion'
|
|
4
|
+
import type { ComponentProps } from 'react'
|
|
6
5
|
|
|
7
6
|
import { tv } from '../tv'
|
|
8
7
|
|
|
9
8
|
import s from './index.module.css'
|
|
10
9
|
|
|
11
|
-
export
|
|
12
|
-
value?: string | string[]
|
|
13
|
-
defaultValue?: string | string[]
|
|
14
|
-
onValueChange?: (value: string & string[]) => void
|
|
15
|
-
multiple?: boolean
|
|
16
|
-
className?: string
|
|
17
|
-
children?: ReactNode
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
const accordion = tv({ base: 'frame rounded-panel overflow-hidden divide-y divide-line' })
|
|
10
|
+
export type AccordionProps = Omit<AccordionPrimitive.Root.Props<string>, 'className'> & { className?: string }
|
|
21
11
|
|
|
22
|
-
|
|
23
|
-
const shared = {
|
|
24
|
-
className: accordion({ className }),
|
|
25
|
-
children,
|
|
26
|
-
}
|
|
12
|
+
const accordion = tv({ base: 'frame rounded-r12 overflow-hidden divide-y divide-line' })
|
|
27
13
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
<AccordionPrimitive.Root
|
|
31
|
-
type="multiple"
|
|
32
|
-
value={value as string[] | undefined}
|
|
33
|
-
defaultValue={defaultValue as string[] | undefined}
|
|
34
|
-
onValueChange={onValueChange}
|
|
35
|
-
{...shared}
|
|
36
|
-
/>
|
|
37
|
-
)
|
|
38
|
-
: (
|
|
39
|
-
<AccordionPrimitive.Root
|
|
40
|
-
type="single"
|
|
41
|
-
collapsible
|
|
42
|
-
value={value as string | undefined}
|
|
43
|
-
defaultValue={defaultValue as string | undefined}
|
|
44
|
-
onValueChange={onValueChange}
|
|
45
|
-
{...shared}
|
|
46
|
-
/>
|
|
47
|
-
)
|
|
14
|
+
export function Accordion({ className, ...rest }: AccordionProps) {
|
|
15
|
+
return <AccordionPrimitive.Root<string> {...rest} className={accordion({ className })} />
|
|
48
16
|
}
|
|
49
17
|
|
|
50
|
-
export
|
|
18
|
+
export type AccordionItemProps = Omit<ComponentProps<typeof AccordionPrimitive.Item>, 'className' | 'value'> & {
|
|
51
19
|
value: string
|
|
52
|
-
disabled?: boolean
|
|
53
20
|
className?: string
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
{children}
|
|
59
|
-
</AccordionPrimitive.Item>
|
|
60
|
-
)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function AccordionItem(props: AccordionItemProps) {
|
|
24
|
+
return <AccordionPrimitive.Item {...props} />
|
|
61
25
|
}
|
|
62
26
|
|
|
63
27
|
const accordionTrigger = tv({
|
|
64
|
-
base: 'text-label text-
|
|
28
|
+
base: 'text-label text-fg flex h-11 w-full items-center'
|
|
65
29
|
+ ' gap-stack border-b border-transparent px-4 transition-state'
|
|
66
|
-
+ ' press open:border-line
|
|
67
|
-
+ ' disabled:text-
|
|
30
|
+
+ ' press data-panel-open:border-line not-data-disabled:hover:bg-bg-neutral-hover'
|
|
31
|
+
+ ' data-disabled:text-fg-disabled data-disabled:cursor-not-allowed'
|
|
68
32
|
+ ' focus-visible:outline-2 focus-visible:-outline-offset-2'
|
|
69
33
|
+ ' focus-visible:outline-line-focus-ring',
|
|
70
34
|
})
|
|
71
35
|
|
|
72
|
-
export
|
|
36
|
+
export type AccordionTriggerProps = Omit<ComponentProps<typeof AccordionPrimitive.Trigger>, 'className'> & { className?: string }
|
|
37
|
+
|
|
38
|
+
export function AccordionTrigger({ className, children, ...rest }: AccordionTriggerProps) {
|
|
73
39
|
return (
|
|
74
40
|
<AccordionPrimitive.Header>
|
|
75
41
|
<AccordionPrimitive.Trigger
|
|
42
|
+
{...rest}
|
|
76
43
|
className={accordionTrigger({ className })}
|
|
77
44
|
>
|
|
78
45
|
<span className="flex min-w-0 grow items-center gap-tight">{children}</span>
|
|
79
46
|
|
|
80
|
-
<
|
|
81
|
-
|
|
47
|
+
<svg
|
|
48
|
+
viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={2} strokeLinecap="round" strokeLinejoin="round" aria-hidden="true"
|
|
49
|
+
className="text-fg-subtle size-4 shrink-0 transition-transform open:rotate-180
|
|
82
50
|
motion-reduce:transition-none"
|
|
83
|
-
|
|
51
|
+
>
|
|
52
|
+
<path d="m6 9 6 6 6-6" />
|
|
53
|
+
</svg>
|
|
84
54
|
</AccordionPrimitive.Trigger>
|
|
85
55
|
</AccordionPrimitive.Header>
|
|
86
56
|
)
|
|
87
57
|
}
|
|
88
58
|
|
|
89
|
-
const accordionContent = tv({ base: 'bg-
|
|
59
|
+
const accordionContent = tv({ base: 'bg-bg-well text-caption text-fg-muted px-4 py-3' })
|
|
60
|
+
|
|
61
|
+
export type AccordionContentProps = Omit<ComponentProps<typeof AccordionPrimitive.Panel>, 'className'> & { className?: string }
|
|
90
62
|
|
|
91
|
-
export function AccordionContent({ className, children }:
|
|
63
|
+
export function AccordionContent({ className, children, ...rest }: AccordionContentProps) {
|
|
92
64
|
return (
|
|
93
|
-
<AccordionPrimitive.
|
|
65
|
+
<AccordionPrimitive.Panel {...rest} className={s.panel}>
|
|
94
66
|
<div className={accordionContent({ className })}>
|
|
95
67
|
{children}
|
|
96
68
|
</div>
|
|
97
|
-
</AccordionPrimitive.
|
|
69
|
+
</AccordionPrimitive.Panel>
|
|
98
70
|
)
|
|
99
71
|
}
|
package/alert-dialog/index.tsx
CHANGED
|
@@ -1,62 +1,67 @@
|
|
|
1
1
|
'use client'
|
|
2
2
|
|
|
3
|
-
import { AlertDialog as AlertDialogPrimitive } from '
|
|
3
|
+
import { AlertDialog as AlertDialogPrimitive } from '@base-ui/react/alert-dialog'
|
|
4
4
|
import type { ComponentProps, ReactNode } from 'react'
|
|
5
5
|
|
|
6
6
|
import { Button } from '../button'
|
|
7
7
|
import { tv } from '../tv'
|
|
8
8
|
|
|
9
|
-
export
|
|
10
|
-
open?: boolean
|
|
11
|
-
defaultOpen?: boolean
|
|
12
|
-
onOpenChange?: (open: boolean) => void
|
|
13
|
-
children?: ReactNode
|
|
14
|
-
}
|
|
9
|
+
export type AlertDialogProps = ComponentProps<typeof AlertDialogPrimitive.Root>
|
|
15
10
|
|
|
16
|
-
export function AlertDialog(
|
|
17
|
-
return
|
|
18
|
-
<AlertDialogPrimitive.Root open={open} defaultOpen={defaultOpen} onOpenChange={onOpenChange}>
|
|
19
|
-
{children}
|
|
20
|
-
</AlertDialogPrimitive.Root>
|
|
21
|
-
)
|
|
11
|
+
export function AlertDialog(props: AlertDialogProps) {
|
|
12
|
+
return <AlertDialogPrimitive.Root {...props} />
|
|
22
13
|
}
|
|
23
14
|
|
|
24
|
-
export
|
|
25
|
-
|
|
15
|
+
export type AlertDialogTriggerProps = ComponentProps<typeof AlertDialogPrimitive.Trigger>
|
|
16
|
+
|
|
17
|
+
export function AlertDialogTrigger(props: AlertDialogTriggerProps) {
|
|
18
|
+
return <AlertDialogPrimitive.Trigger {...props} />
|
|
26
19
|
}
|
|
27
20
|
|
|
28
21
|
const alertDialogContent = tv({
|
|
29
|
-
base: 'sheet text-
|
|
22
|
+
base: 'sheet text-fg z-overlay fixed left-1/2 top-1/2'
|
|
30
23
|
+ ' w-full max-w-112 -translate-x-1/2 -translate-y-1/2'
|
|
31
24
|
+ ' rounded-r20 p-6 flex flex-col gap-stack overflow-y-auto'
|
|
32
25
|
+ ' open:animate-fade-in closed:animate-fade-out'
|
|
33
26
|
+ ' focus-visible:outline-none',
|
|
34
27
|
})
|
|
35
28
|
|
|
36
|
-
export
|
|
29
|
+
export type AlertDialogContentProps = Omit<ComponentProps<typeof AlertDialogPrimitive.Popup>, 'className'> & {
|
|
30
|
+
className?: string
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function AlertDialogContent({ className, children, ...rest }: AlertDialogContentProps) {
|
|
37
34
|
return (
|
|
38
35
|
<AlertDialogPrimitive.Portal>
|
|
39
|
-
<AlertDialogPrimitive.
|
|
36
|
+
<AlertDialogPrimitive.Backdrop className="bg-bg-overlay z-overlay fixed inset-0 open:animate-fade-in closed:animate-fade-out" />
|
|
40
37
|
|
|
41
|
-
<AlertDialogPrimitive.
|
|
38
|
+
<AlertDialogPrimitive.Popup
|
|
42
39
|
{...rest}
|
|
43
40
|
className={alertDialogContent({ className })}
|
|
44
41
|
>
|
|
45
42
|
{children}
|
|
46
|
-
</AlertDialogPrimitive.
|
|
43
|
+
</AlertDialogPrimitive.Popup>
|
|
47
44
|
</AlertDialogPrimitive.Portal>
|
|
48
45
|
)
|
|
49
46
|
}
|
|
50
47
|
|
|
51
48
|
const alertDialogTitle = tv({ base: 'text-section' })
|
|
52
49
|
|
|
53
|
-
export
|
|
50
|
+
export type AlertDialogTitleProps = Omit<ComponentProps<typeof AlertDialogPrimitive.Title>, 'className'> & {
|
|
51
|
+
className?: string
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function AlertDialogTitle({ className, ...rest }: AlertDialogTitleProps) {
|
|
54
55
|
return <AlertDialogPrimitive.Title {...rest} className={alertDialogTitle({ className })} />
|
|
55
56
|
}
|
|
56
57
|
|
|
57
|
-
const alertDialogDescription = tv({ base: 'text-prose text-
|
|
58
|
+
const alertDialogDescription = tv({ base: 'text-prose text-fg-muted' })
|
|
59
|
+
|
|
60
|
+
export type AlertDialogDescriptionProps = Omit<ComponentProps<typeof AlertDialogPrimitive.Description>, 'className'> & {
|
|
61
|
+
className?: string
|
|
62
|
+
}
|
|
58
63
|
|
|
59
|
-
export function AlertDialogDescription({ className, ...rest }:
|
|
64
|
+
export function AlertDialogDescription({ className, ...rest }: AlertDialogDescriptionProps) {
|
|
60
65
|
return (
|
|
61
66
|
<AlertDialogPrimitive.Description
|
|
62
67
|
{...rest}
|
|
@@ -93,7 +98,7 @@ export function AlertDialogHeader({ lead, trail, className, children }: AlertDia
|
|
|
93
98
|
)
|
|
94
99
|
}
|
|
95
100
|
|
|
96
|
-
const alertDialogFooter = tv({ base: 'flex justify-end gap-2' })
|
|
101
|
+
const alertDialogFooter = tv({ base: 'mt-auto flex justify-end gap-2' })
|
|
97
102
|
|
|
98
103
|
export function AlertDialogFooter({ className, children }: { className?: string, children?: ReactNode }) {
|
|
99
104
|
return (
|
|
@@ -103,27 +108,16 @@ export function AlertDialogFooter({ className, children }: { className?: string,
|
|
|
103
108
|
)
|
|
104
109
|
}
|
|
105
110
|
|
|
106
|
-
export
|
|
111
|
+
export type AlertDialogActionProps = Omit<ComponentProps<typeof AlertDialogPrimitive.Close>, 'color'> & {
|
|
107
112
|
color?: 'neutral' | 'brand' | 'danger'
|
|
108
|
-
onClick?: () => void
|
|
109
|
-
className?: string
|
|
110
|
-
children?: ReactNode
|
|
111
|
-
}) {
|
|
112
|
-
return (
|
|
113
|
-
<AlertDialogPrimitive.Action asChild>
|
|
114
|
-
<Button emphasis="solid" color={color} onClick={onClick} className={className}>
|
|
115
|
-
{children}
|
|
116
|
-
</Button>
|
|
117
|
-
</AlertDialogPrimitive.Action>
|
|
118
|
-
)
|
|
119
113
|
}
|
|
120
114
|
|
|
121
|
-
export function
|
|
122
|
-
return
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
115
|
+
export function AlertDialogAction({ color = 'neutral', render, ...rest }: AlertDialogActionProps) {
|
|
116
|
+
return <AlertDialogPrimitive.Close {...rest} render={render ?? <Button emphasis="solid" color={color} />} />
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export type AlertDialogCancelProps = ComponentProps<typeof AlertDialogPrimitive.Close>
|
|
120
|
+
|
|
121
|
+
export function AlertDialogCancel({ render, ...rest }: AlertDialogCancelProps) {
|
|
122
|
+
return <AlertDialogPrimitive.Close {...rest} render={render ?? <Button color="neutral" emphasis="outline" />} />
|
|
129
123
|
}
|
package/badge/index.tsx
CHANGED
|
@@ -8,7 +8,7 @@ export const badge = tv({
|
|
|
8
8
|
|
|
9
9
|
variants: {
|
|
10
10
|
color: {
|
|
11
|
-
neutral: 'bg-
|
|
11
|
+
neutral: 'bg-bg-neutral-solid/10 text-fg',
|
|
12
12
|
brand: 'bg-bg-brand-weak text-fg-brand-contrast',
|
|
13
13
|
info: 'bg-bg-info-weak text-fg-info-contrast',
|
|
14
14
|
success: 'bg-bg-success-weak text-fg-success-contrast',
|
|
@@ -16,7 +16,7 @@ export const badge = tv({
|
|
|
16
16
|
danger: 'bg-bg-danger-weak text-fg-danger-contrast',
|
|
17
17
|
},
|
|
18
18
|
shape: {
|
|
19
|
-
square: 'rounded-
|
|
19
|
+
square: 'rounded-r4',
|
|
20
20
|
pill: 'rounded-full',
|
|
21
21
|
},
|
|
22
22
|
},
|
package/button/index.tsx
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { Button as ButtonPrimitive } from '@base-ui/react/button'
|
|
2
|
+
import type { ComponentProps } from 'react'
|
|
2
3
|
|
|
3
4
|
import { tv } from '../tv'
|
|
4
5
|
|
|
@@ -7,7 +8,7 @@ export const button = tv({
|
|
|
7
8
|
+ ' rounded-r8 text-label'
|
|
8
9
|
+ ' transition-state press press-shrink'
|
|
9
10
|
+ ' focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-line-focus-ring'
|
|
10
|
-
+ ' disabled:text-
|
|
11
|
+
+ ' data-disabled:text-fg-disabled data-disabled:cursor-not-allowed',
|
|
11
12
|
|
|
12
13
|
variants: {
|
|
13
14
|
color: { brand: '', neutral: '', danger: '' },
|
|
@@ -28,46 +29,46 @@ export const button = tv({
|
|
|
28
29
|
compoundVariants: [
|
|
29
30
|
{ color: 'brand', emphasis: 'solid',
|
|
30
31
|
class: 'bg-bg-brand-solid text-fg-brand-solid-contrast'
|
|
31
|
-
+ '
|
|
32
|
-
+ ' disabled:bg-bg-brand-solid/20' },
|
|
32
|
+
+ ' not-data-disabled:hover:bg-bg-brand-solid-hover'
|
|
33
|
+
+ ' data-disabled:bg-bg-brand-solid/20' },
|
|
33
34
|
{ color: 'brand', emphasis: 'weak',
|
|
34
|
-
class: 'bg-bg-brand-weak text-fg-brand-contrast disabled:text-fg-brand-contrast/40'
|
|
35
|
-
+ '
|
|
35
|
+
class: 'bg-bg-brand-weak text-fg-brand-contrast data-disabled:text-fg-brand-contrast/40'
|
|
36
|
+
+ ' not-data-disabled:hover:bg-bg-brand-solid/10' },
|
|
36
37
|
{ color: 'brand', emphasis: 'outline',
|
|
37
|
-
class: 'text-fg-brand-contrast disabled:text-fg-brand-contrast/40'
|
|
38
|
-
+ ' ring-1 ring-inset ring-line-brand-weak disabled:ring-line'
|
|
39
|
-
+ '
|
|
38
|
+
class: 'text-fg-brand-contrast data-disabled:text-fg-brand-contrast/40'
|
|
39
|
+
+ ' ring-1 ring-inset ring-line-brand-weak data-disabled:ring-line'
|
|
40
|
+
+ ' not-data-disabled:hover:bg-bg-brand-solid/10' },
|
|
40
41
|
{ color: 'brand', emphasis: 'ghost',
|
|
41
|
-
class: 'text-fg-brand-contrast disabled:text-fg-brand-contrast/40'
|
|
42
|
-
+ '
|
|
42
|
+
class: 'text-fg-brand-contrast data-disabled:text-fg-brand-contrast/40'
|
|
43
|
+
+ ' not-data-disabled:hover:bg-bg-brand-solid/10' },
|
|
43
44
|
|
|
44
45
|
{ color: 'neutral', emphasis: 'solid',
|
|
45
46
|
class: 'bg-bg-neutral-solid text-fg-neutral-solid-contrast'
|
|
46
|
-
+ '
|
|
47
|
-
+ ' disabled:bg-bg-neutral-solid/20' },
|
|
47
|
+
+ ' not-data-disabled:hover:bg-bg-neutral-solid-hover'
|
|
48
|
+
+ ' data-disabled:bg-bg-neutral-solid/20' },
|
|
48
49
|
{ color: 'neutral', emphasis: 'weak',
|
|
49
|
-
class: 'bg-
|
|
50
|
-
+ '
|
|
50
|
+
class: 'bg-bg-neutral-solid/8 text-fg'
|
|
51
|
+
+ ' not-data-disabled:hover:bg-bg-neutral-solid/16' },
|
|
51
52
|
{ color: 'neutral', emphasis: 'outline',
|
|
52
|
-
class: 'text-
|
|
53
|
-
+ '
|
|
53
|
+
class: 'text-fg ring-1 ring-inset ring-line-strong data-disabled:ring-line'
|
|
54
|
+
+ ' not-data-disabled:hover:bg-bg-neutral-hover' },
|
|
54
55
|
{ color: 'neutral', emphasis: 'ghost',
|
|
55
|
-
class: 'text-
|
|
56
|
+
class: 'text-fg not-data-disabled:hover:bg-bg-neutral-hover' },
|
|
56
57
|
|
|
57
58
|
{ color: 'danger', emphasis: 'solid',
|
|
58
59
|
class: 'bg-bg-danger-solid text-white'
|
|
59
|
-
+ '
|
|
60
|
-
+ ' disabled:bg-bg-danger-solid/20' },
|
|
60
|
+
+ ' not-data-disabled:hover:bg-bg-danger-solid-hover'
|
|
61
|
+
+ ' data-disabled:bg-bg-danger-solid/20' },
|
|
61
62
|
{ color: 'danger', emphasis: 'weak',
|
|
62
|
-
class: 'bg-bg-danger-weak text-fg-danger-contrast disabled:text-fg-danger-contrast/40'
|
|
63
|
-
+ '
|
|
63
|
+
class: 'bg-bg-danger-weak text-fg-danger-contrast data-disabled:text-fg-danger-contrast/40'
|
|
64
|
+
+ ' not-data-disabled:hover:bg-bg-danger-solid/10' },
|
|
64
65
|
{ color: 'danger', emphasis: 'outline',
|
|
65
|
-
class: 'text-fg-danger-contrast disabled:text-fg-danger-contrast/40'
|
|
66
|
-
+ ' ring-1 ring-inset ring-line-danger-weak disabled:ring-line'
|
|
67
|
-
+ '
|
|
66
|
+
class: 'text-fg-danger-contrast data-disabled:text-fg-danger-contrast/40'
|
|
67
|
+
+ ' ring-1 ring-inset ring-line-danger-weak data-disabled:ring-line'
|
|
68
|
+
+ ' not-data-disabled:hover:bg-bg-danger-solid/10' },
|
|
68
69
|
{ color: 'danger', emphasis: 'ghost',
|
|
69
|
-
class: 'text-fg-danger-contrast disabled:text-fg-danger-contrast/40'
|
|
70
|
-
+ '
|
|
70
|
+
class: 'text-fg-danger-contrast data-disabled:text-fg-danger-contrast/40'
|
|
71
|
+
+ ' not-data-disabled:hover:bg-bg-danger-solid/10' },
|
|
71
72
|
|
|
72
73
|
{ shape: ['rect', 'pill'], size: 'sm', class: 'px-3' },
|
|
73
74
|
{ shape: ['rect', 'pill'], size: 'md', class: 'px-3.5' },
|
|
@@ -80,7 +81,8 @@ export const button = tv({
|
|
|
80
81
|
defaultVariants: { size: 'md', shape: 'rect' },
|
|
81
82
|
})
|
|
82
83
|
|
|
83
|
-
export interface ButtonProps extends Omit<
|
|
84
|
+
export interface ButtonProps extends Omit<ComponentProps<typeof ButtonPrimitive>, 'className' | 'color'> {
|
|
85
|
+
className?: string
|
|
84
86
|
color: 'brand' | 'neutral' | 'danger'
|
|
85
87
|
emphasis: 'solid' | 'weak' | 'outline' | 'ghost'
|
|
86
88
|
size?: 'sm' | 'md' | 'lg'
|
|
@@ -89,8 +91,7 @@ export interface ButtonProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement
|
|
|
89
91
|
|
|
90
92
|
export function Button({ color, emphasis, size, shape, className, ...rest }: ButtonProps) {
|
|
91
93
|
return (
|
|
92
|
-
<
|
|
93
|
-
type="button"
|
|
94
|
+
<ButtonPrimitive
|
|
94
95
|
{...rest}
|
|
95
96
|
className={button({ color, emphasis, size, shape, className })}
|
|
96
97
|
/>
|
package/callout/index.tsx
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
import { CircleCheck, CircleX, Info, TriangleAlert } from 'lucide-react'
|
|
2
1
|
import type { ReactNode } from 'react'
|
|
3
2
|
|
|
4
3
|
import { tv } from '../tv'
|
|
5
4
|
|
|
6
5
|
export const callout = tv({
|
|
7
6
|
slots: {
|
|
8
|
-
root: 'flex gap-stack rounded-
|
|
7
|
+
root: 'flex gap-stack rounded-r12 border p-4 text-prose',
|
|
9
8
|
icon: 'flex shrink-0 mt-0.5 [&_svg]:size-5',
|
|
10
9
|
title: 'font-bold',
|
|
11
10
|
body: 'flex min-w-0 flex-1 flex-col gap-tight',
|
|
@@ -37,10 +36,33 @@ export const callout = tv({
|
|
|
37
36
|
})
|
|
38
37
|
|
|
39
38
|
const ICONS = {
|
|
40
|
-
info:
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
39
|
+
info: (
|
|
40
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={2} strokeLinecap="round" strokeLinejoin="round" aria-hidden="true" className="size-5">
|
|
41
|
+
<circle cx="12" cy="12" r="10" />
|
|
42
|
+
<path d="M12 16v-4" />
|
|
43
|
+
<path d="M12 8h.01" />
|
|
44
|
+
</svg>
|
|
45
|
+
),
|
|
46
|
+
success: (
|
|
47
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={2} strokeLinecap="round" strokeLinejoin="round" aria-hidden="true" className="size-5">
|
|
48
|
+
<circle cx="12" cy="12" r="10" />
|
|
49
|
+
<path d="m16 9-5.5 5.5L8 12" />
|
|
50
|
+
</svg>
|
|
51
|
+
),
|
|
52
|
+
warning: (
|
|
53
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={2} strokeLinecap="round" strokeLinejoin="round" aria-hidden="true" className="size-5">
|
|
54
|
+
<path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3" />
|
|
55
|
+
<path d="M12 9v4" />
|
|
56
|
+
<path d="M12 17h.01" />
|
|
57
|
+
</svg>
|
|
58
|
+
),
|
|
59
|
+
danger: (
|
|
60
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={2} strokeLinecap="round" strokeLinejoin="round" aria-hidden="true" className="size-5">
|
|
61
|
+
<circle cx="12" cy="12" r="10" />
|
|
62
|
+
<path d="m15 9-6 6" />
|
|
63
|
+
<path d="m9 9 6 6" />
|
|
64
|
+
</svg>
|
|
65
|
+
),
|
|
44
66
|
} as const
|
|
45
67
|
|
|
46
68
|
export interface CalloutProps {
|
|
@@ -53,12 +75,11 @@ export interface CalloutProps {
|
|
|
53
75
|
|
|
54
76
|
export function Callout({ color, icon, title, className, children }: CalloutProps) {
|
|
55
77
|
const ui = callout({ color })
|
|
56
|
-
const Fallback = ICONS[color ?? 'info']
|
|
57
78
|
|
|
58
79
|
return (
|
|
59
80
|
<div className={ui.root({ className })} role="alert">
|
|
60
81
|
<span className={ui.icon()}>
|
|
61
|
-
{icon ??
|
|
82
|
+
{icon ?? ICONS[color ?? 'info']}
|
|
62
83
|
</span>
|
|
63
84
|
<div className={ui.body()}>
|
|
64
85
|
{title && <span className={ui.title()}>{title}</span>}
|
package/checkbox/index.tsx
CHANGED
|
@@ -1,21 +1,13 @@
|
|
|
1
1
|
'use client'
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
createContext,
|
|
7
|
-
use,
|
|
8
|
-
useRef,
|
|
9
|
-
useState,
|
|
10
|
-
type ComponentProps,
|
|
11
|
-
type KeyboardEvent as ReactKeyboardEvent,
|
|
12
|
-
type ReactNode,
|
|
13
|
-
} from 'react'
|
|
3
|
+
import { Checkbox as CheckboxPrimitive } from '@base-ui/react/checkbox'
|
|
4
|
+
import { CheckboxGroup as CheckboxGroupPrimitive } from '@base-ui/react/checkbox-group'
|
|
5
|
+
import type { ComponentProps } from 'react'
|
|
14
6
|
|
|
15
7
|
import { tv } from '../tv'
|
|
16
8
|
|
|
17
9
|
export const checkbox = tv({
|
|
18
|
-
base: 'size-5 shrink-0 rounded-
|
|
10
|
+
base: 'size-5 shrink-0 rounded-r4 inline-flex items-center justify-center'
|
|
19
11
|
+ ' bg-transparent ring-1 ring-inset ring-line-strong'
|
|
20
12
|
+ ' transition-state press press-shrink'
|
|
21
13
|
+ ' checked:ring-2'
|
|
@@ -37,52 +29,25 @@ export const checkbox = tv({
|
|
|
37
29
|
defaultVariants: { color: 'neutral' },
|
|
38
30
|
})
|
|
39
31
|
|
|
40
|
-
interface GroupContext {
|
|
41
|
-
value: string[]
|
|
42
|
-
toggle: (item: string, next: boolean) => void
|
|
43
|
-
disabled?: boolean
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
const Group = createContext<GroupContext | null>(null)
|
|
47
|
-
|
|
48
32
|
const ITEMS = '[role="checkbox"]:not([disabled])'
|
|
49
33
|
|
|
50
|
-
export
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
onValueChange?: (value: string[]) => void
|
|
54
|
-
disabled?: boolean
|
|
55
|
-
className?: string
|
|
56
|
-
children?: ReactNode
|
|
57
|
-
}
|
|
34
|
+
export type CheckboxGroupProps = Omit<ComponentProps<typeof CheckboxGroupPrimitive>, 'className'> & { className?: string }
|
|
35
|
+
|
|
36
|
+
type GroupKeyEvent = Parameters<NonNullable<CheckboxGroupProps['onKeyDown']>>[0]
|
|
58
37
|
|
|
59
38
|
const checkboxGroup = tv({ base: 'flex flex-col gap-3' })
|
|
60
39
|
|
|
61
|
-
export function CheckboxGroup({
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
disabled,
|
|
66
|
-
className,
|
|
67
|
-
children,
|
|
68
|
-
}: CheckboxGroupProps) {
|
|
69
|
-
const [own, setOwn] = useState<string[]>(defaultValue ?? [])
|
|
70
|
-
const list = value ?? own
|
|
71
|
-
const root = useRef<HTMLDivElement>(null)
|
|
72
|
-
|
|
73
|
-
const toggle = (item: string, next: boolean) => {
|
|
74
|
-
const after = next ? [...list, item] : list.filter(one => one !== item)
|
|
75
|
-
if (value === undefined) setOwn(after)
|
|
76
|
-
onValueChange?.(after)
|
|
77
|
-
}
|
|
40
|
+
export function CheckboxGroup({ className, onKeyDown, ...rest }: CheckboxGroupProps) {
|
|
41
|
+
const onKeys = (e: GroupKeyEvent) => {
|
|
42
|
+
onKeyDown?.(e)
|
|
43
|
+
if (e.defaultPrevented) return
|
|
78
44
|
|
|
79
|
-
const onKeyDown = (e: ReactKeyboardEvent<HTMLDivElement>) => {
|
|
80
45
|
const step = e.key === 'ArrowDown' || e.key === 'ArrowRight'
|
|
81
46
|
? 1
|
|
82
47
|
: e.key === 'ArrowUp' || e.key === 'ArrowLeft' ? -1 : 0
|
|
83
|
-
if (step === 0
|
|
48
|
+
if (step === 0) return
|
|
84
49
|
|
|
85
|
-
const items = [...
|
|
50
|
+
const items = [...e.currentTarget.querySelectorAll<HTMLElement>(ITEMS)]
|
|
86
51
|
const at = items.indexOf(document.activeElement as HTMLElement)
|
|
87
52
|
if (at === -1) return
|
|
88
53
|
|
|
@@ -90,63 +55,34 @@ export function CheckboxGroup({
|
|
|
90
55
|
items[(at + step + items.length) % items.length]!.focus()
|
|
91
56
|
}
|
|
92
57
|
|
|
93
|
-
return (
|
|
94
|
-
<Group value={{ value: list, toggle, disabled }}>
|
|
95
|
-
<div
|
|
96
|
-
ref={root}
|
|
97
|
-
role="group"
|
|
98
|
-
onKeyDown={onKeyDown}
|
|
99
|
-
className={checkboxGroup({ className })}
|
|
100
|
-
>
|
|
101
|
-
{children}
|
|
102
|
-
</div>
|
|
103
|
-
</Group>
|
|
104
|
-
)
|
|
58
|
+
return <CheckboxGroupPrimitive {...rest} onKeyDown={onKeys} className={checkboxGroup({ className })} />
|
|
105
59
|
}
|
|
106
60
|
|
|
107
|
-
export
|
|
108
|
-
value?: string
|
|
109
|
-
checked?: boolean
|
|
110
|
-
onCheckedChange?: (checked: boolean) => void
|
|
111
|
-
indeterminate?: boolean
|
|
112
|
-
onIndeterminateChange?: (indeterminate: boolean) => void
|
|
61
|
+
export type CheckboxProps = Omit<ComponentProps<typeof CheckboxPrimitive.Root>, 'className'> & {
|
|
113
62
|
color?: 'neutral' | 'info' | 'success' | 'warning' | 'danger'
|
|
63
|
+
className?: string
|
|
114
64
|
}
|
|
115
65
|
|
|
116
66
|
export function Checkbox({
|
|
117
|
-
value,
|
|
118
|
-
checked,
|
|
119
|
-
onCheckedChange,
|
|
120
67
|
indeterminate,
|
|
121
|
-
onIndeterminateChange,
|
|
122
68
|
color,
|
|
123
69
|
className,
|
|
124
|
-
|
|
70
|
+
nativeButton = true,
|
|
71
|
+
render = <button type="button" />,
|
|
125
72
|
...rest
|
|
126
73
|
}: CheckboxProps) {
|
|
127
|
-
const group = use(Group)
|
|
128
|
-
const item = value ?? 'on'
|
|
129
|
-
|
|
130
|
-
const on = group ? group.value.includes(item) : checked ?? false
|
|
131
|
-
const state = indeterminate ? 'indeterminate' as const : on
|
|
132
|
-
|
|
133
|
-
const change = (next: boolean | 'indeterminate') => {
|
|
134
|
-
if (typeof next !== 'boolean') return
|
|
135
|
-
if (group) group.toggle(item, next)
|
|
136
|
-
else onCheckedChange?.(next)
|
|
137
|
-
if (indeterminate) onIndeterminateChange?.(false)
|
|
138
|
-
}
|
|
139
|
-
|
|
140
74
|
return (
|
|
141
75
|
<CheckboxPrimitive.Root
|
|
142
76
|
{...rest}
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
77
|
+
nativeButton={nativeButton}
|
|
78
|
+
render={render}
|
|
79
|
+
indeterminate={indeterminate}
|
|
146
80
|
className={checkbox({ color, className })}
|
|
147
81
|
>
|
|
148
82
|
<CheckboxPrimitive.Indicator className="text-fg-neutral-solid-contrast flex">
|
|
149
|
-
|
|
83
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={2} strokeLinecap="round" strokeLinejoin="round" aria-hidden="true" className="size-4">
|
|
84
|
+
{indeterminate ? <path d="M5 12h14" /> : <path d="M20 6 9 17l-5-5" />}
|
|
85
|
+
</svg>
|
|
150
86
|
</CheckboxPrimitive.Indicator>
|
|
151
87
|
</CheckboxPrimitive.Root>
|
|
152
88
|
)
|