@pantoia/ui 0.3.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 +21 -51
- package/alert-dialog/index.tsx +36 -42
- package/badge/index.tsx +1 -1
- package/button/index.tsx +31 -30
- package/callout/index.tsx +4 -4
- package/checkbox/index.tsx +20 -85
- package/combobox/index.tsx +122 -316
- package/command-palette/index.tsx +51 -32
- package/dialog/index.tsx +28 -24
- package/dist/index.js +5 -5
- package/drawer/index.module.css +2 -2
- package/drawer/index.tsx +52 -130
- package/dropdown-menu/index.tsx +87 -95
- package/field/index.tsx +27 -86
- package/input/index.tsx +7 -3
- package/kbd/index.tsx +2 -2
- package/label/index.tsx +6 -8
- package/number-field/index.tsx +122 -173
- package/package.json +2 -6
- package/popover/index.tsx +61 -32
- package/radio-group/index.tsx +35 -38
- package/registry.json +64 -154
- package/select/index.tsx +141 -70
- package/switch/index.tsx +13 -6
- package/table/index.tsx +1 -2
- package/tabs/index.module.css +3 -3
- package/tabs/index.tsx +22 -76
- package/textarea/index.tsx +19 -7
- package/toast/index.module.css +187 -0
- package/toast/index.tsx +141 -46
- package/toggle/index.tsx +4 -3
- package/tokens.css +7 -1
- package/tooltip/index.tsx +61 -30
- package/utilities.css +11 -6
- 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 -37
- package/checkbox/AGENTS.md +0 -54
- package/combobox/AGENTS.md +0 -150
- package/command-palette/AGENTS.md +0 -41
- package/dialog/AGENTS.md +0 -81
- package/drawer/AGENTS.md +0 -66
- package/dropdown-menu/AGENTS.md +0 -133
- package/field/AGENTS.md +0 -92
- package/input/AGENTS.md +0 -35
- package/kbd/AGENTS.md +0 -17
- package/label/AGENTS.md +0 -21
- package/number-field/AGENTS.md +0 -49
- package/popover/AGENTS.md +0 -64
- 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 -61
- 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,77 +1,45 @@
|
|
|
1
1
|
'use client'
|
|
2
2
|
|
|
3
|
-
import { Accordion as AccordionPrimitive } from '
|
|
4
|
-
import type {
|
|
3
|
+
import { Accordion as AccordionPrimitive } from '@base-ui/react/accordion'
|
|
4
|
+
import type { ComponentProps } from 'react'
|
|
5
5
|
|
|
6
6
|
import { tv } from '../tv'
|
|
7
7
|
|
|
8
8
|
import s from './index.module.css'
|
|
9
9
|
|
|
10
|
-
export
|
|
11
|
-
value?: string | string[]
|
|
12
|
-
defaultValue?: string | string[]
|
|
13
|
-
onValueChange?: (value: string & string[]) => void
|
|
14
|
-
multiple?: boolean
|
|
15
|
-
className?: string
|
|
16
|
-
children?: ReactNode
|
|
17
|
-
}
|
|
10
|
+
export type AccordionProps = Omit<AccordionPrimitive.Root.Props<string>, 'className'> & { className?: string }
|
|
18
11
|
|
|
19
12
|
const accordion = tv({ base: 'frame rounded-r12 overflow-hidden divide-y divide-line' })
|
|
20
13
|
|
|
21
|
-
export function Accordion({
|
|
22
|
-
|
|
23
|
-
className: accordion({ className }),
|
|
24
|
-
children,
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
return multiple
|
|
28
|
-
? (
|
|
29
|
-
<AccordionPrimitive.Root
|
|
30
|
-
type="multiple"
|
|
31
|
-
value={value as string[] | undefined}
|
|
32
|
-
defaultValue={defaultValue as string[] | undefined}
|
|
33
|
-
onValueChange={onValueChange}
|
|
34
|
-
{...shared}
|
|
35
|
-
/>
|
|
36
|
-
)
|
|
37
|
-
: (
|
|
38
|
-
<AccordionPrimitive.Root
|
|
39
|
-
type="single"
|
|
40
|
-
collapsible
|
|
41
|
-
value={value as string | undefined}
|
|
42
|
-
defaultValue={defaultValue as string | undefined}
|
|
43
|
-
onValueChange={onValueChange}
|
|
44
|
-
{...shared}
|
|
45
|
-
/>
|
|
46
|
-
)
|
|
14
|
+
export function Accordion({ className, ...rest }: AccordionProps) {
|
|
15
|
+
return <AccordionPrimitive.Root<string> {...rest} className={accordion({ className })} />
|
|
47
16
|
}
|
|
48
17
|
|
|
49
|
-
export
|
|
18
|
+
export type AccordionItemProps = Omit<ComponentProps<typeof AccordionPrimitive.Item>, 'className' | 'value'> & {
|
|
50
19
|
value: string
|
|
51
|
-
disabled?: boolean
|
|
52
20
|
className?: string
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
{children}
|
|
58
|
-
</AccordionPrimitive.Item>
|
|
59
|
-
)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function AccordionItem(props: AccordionItemProps) {
|
|
24
|
+
return <AccordionPrimitive.Item {...props} />
|
|
60
25
|
}
|
|
61
26
|
|
|
62
27
|
const accordionTrigger = tv({
|
|
63
28
|
base: 'text-label text-fg flex h-11 w-full items-center'
|
|
64
29
|
+ ' gap-stack border-b border-transparent px-4 transition-state'
|
|
65
|
-
+ ' press open:border-line
|
|
66
|
-
+ ' disabled:text-fg-disabled disabled:cursor-not-allowed'
|
|
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'
|
|
67
32
|
+ ' focus-visible:outline-2 focus-visible:-outline-offset-2'
|
|
68
33
|
+ ' focus-visible:outline-line-focus-ring',
|
|
69
34
|
})
|
|
70
35
|
|
|
71
|
-
export
|
|
36
|
+
export type AccordionTriggerProps = Omit<ComponentProps<typeof AccordionPrimitive.Trigger>, 'className'> & { className?: string }
|
|
37
|
+
|
|
38
|
+
export function AccordionTrigger({ className, children, ...rest }: AccordionTriggerProps) {
|
|
72
39
|
return (
|
|
73
40
|
<AccordionPrimitive.Header>
|
|
74
41
|
<AccordionPrimitive.Trigger
|
|
42
|
+
{...rest}
|
|
75
43
|
className={accordionTrigger({ className })}
|
|
76
44
|
>
|
|
77
45
|
<span className="flex min-w-0 grow items-center gap-tight">{children}</span>
|
|
@@ -90,12 +58,14 @@ export function AccordionTrigger({ className, children }: { className?: string,
|
|
|
90
58
|
|
|
91
59
|
const accordionContent = tv({ base: 'bg-bg-well text-caption text-fg-muted px-4 py-3' })
|
|
92
60
|
|
|
93
|
-
export
|
|
61
|
+
export type AccordionContentProps = Omit<ComponentProps<typeof AccordionPrimitive.Panel>, 'className'> & { className?: string }
|
|
62
|
+
|
|
63
|
+
export function AccordionContent({ className, children, ...rest }: AccordionContentProps) {
|
|
94
64
|
return (
|
|
95
|
-
<AccordionPrimitive.
|
|
65
|
+
<AccordionPrimitive.Panel {...rest} className={s.panel}>
|
|
96
66
|
<div className={accordionContent({ className })}>
|
|
97
67
|
{children}
|
|
98
68
|
</div>
|
|
99
|
-
</AccordionPrimitive.
|
|
69
|
+
</AccordionPrimitive.Panel>
|
|
100
70
|
)
|
|
101
71
|
}
|
package/alert-dialog/index.tsx
CHANGED
|
@@ -1,28 +1,21 @@
|
|
|
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({
|
|
@@ -33,30 +26,42 @@ const alertDialogContent = tv({
|
|
|
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
58
|
const alertDialogDescription = tv({ base: 'text-prose text-fg-muted' })
|
|
58
59
|
|
|
59
|
-
export
|
|
60
|
+
export type AlertDialogDescriptionProps = Omit<ComponentProps<typeof AlertDialogPrimitive.Description>, 'className'> & {
|
|
61
|
+
className?: string
|
|
62
|
+
}
|
|
63
|
+
|
|
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-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',
|
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-fg-disabled disabled:cursor-not-allowed',
|
|
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-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-fg ring-1 ring-inset ring-line-strong disabled:ring-line'
|
|
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-fg
|
|
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
|
@@ -37,27 +37,27 @@ export const callout = tv({
|
|
|
37
37
|
|
|
38
38
|
const ICONS = {
|
|
39
39
|
info: (
|
|
40
|
-
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={2} strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
|
|
40
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={2} strokeLinecap="round" strokeLinejoin="round" aria-hidden="true" className="size-5">
|
|
41
41
|
<circle cx="12" cy="12" r="10" />
|
|
42
42
|
<path d="M12 16v-4" />
|
|
43
43
|
<path d="M12 8h.01" />
|
|
44
44
|
</svg>
|
|
45
45
|
),
|
|
46
46
|
success: (
|
|
47
|
-
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={2} strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
|
|
47
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={2} strokeLinecap="round" strokeLinejoin="round" aria-hidden="true" className="size-5">
|
|
48
48
|
<circle cx="12" cy="12" r="10" />
|
|
49
49
|
<path d="m16 9-5.5 5.5L8 12" />
|
|
50
50
|
</svg>
|
|
51
51
|
),
|
|
52
52
|
warning: (
|
|
53
|
-
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={2} strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
|
|
53
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={2} strokeLinecap="round" strokeLinejoin="round" aria-hidden="true" className="size-5">
|
|
54
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
55
|
<path d="M12 9v4" />
|
|
56
56
|
<path d="M12 17h.01" />
|
|
57
57
|
</svg>
|
|
58
58
|
),
|
|
59
59
|
danger: (
|
|
60
|
-
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={2} strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
|
|
60
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={2} strokeLinecap="round" strokeLinejoin="round" aria-hidden="true" className="size-5">
|
|
61
61
|
<circle cx="12" cy="12" r="10" />
|
|
62
62
|
<path d="m15 9-6 6" />
|
|
63
63
|
<path d="m9 9 6 6" />
|
package/checkbox/index.tsx
CHANGED
|
@@ -1,15 +1,8 @@
|
|
|
1
1
|
'use client'
|
|
2
2
|
|
|
3
|
-
import { Checkbox as CheckboxPrimitive } from '
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
use,
|
|
7
|
-
useRef,
|
|
8
|
-
useState,
|
|
9
|
-
type ComponentProps,
|
|
10
|
-
type KeyboardEvent as ReactKeyboardEvent,
|
|
11
|
-
type ReactNode,
|
|
12
|
-
} 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'
|
|
13
6
|
|
|
14
7
|
import { tv } from '../tv'
|
|
15
8
|
|
|
@@ -36,52 +29,25 @@ export const checkbox = tv({
|
|
|
36
29
|
defaultVariants: { color: 'neutral' },
|
|
37
30
|
})
|
|
38
31
|
|
|
39
|
-
interface GroupContext {
|
|
40
|
-
value: string[]
|
|
41
|
-
toggle: (item: string, next: boolean) => void
|
|
42
|
-
disabled?: boolean
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
const Group = createContext<GroupContext | null>(null)
|
|
46
|
-
|
|
47
32
|
const ITEMS = '[role="checkbox"]:not([disabled])'
|
|
48
33
|
|
|
49
|
-
export
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
onValueChange?: (value: string[]) => void
|
|
53
|
-
disabled?: boolean
|
|
54
|
-
className?: string
|
|
55
|
-
children?: ReactNode
|
|
56
|
-
}
|
|
34
|
+
export type CheckboxGroupProps = Omit<ComponentProps<typeof CheckboxGroupPrimitive>, 'className'> & { className?: string }
|
|
35
|
+
|
|
36
|
+
type GroupKeyEvent = Parameters<NonNullable<CheckboxGroupProps['onKeyDown']>>[0]
|
|
57
37
|
|
|
58
38
|
const checkboxGroup = tv({ base: 'flex flex-col gap-3' })
|
|
59
39
|
|
|
60
|
-
export function CheckboxGroup({
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
disabled,
|
|
65
|
-
className,
|
|
66
|
-
children,
|
|
67
|
-
}: CheckboxGroupProps) {
|
|
68
|
-
const [own, setOwn] = useState<string[]>(defaultValue ?? [])
|
|
69
|
-
const list = value ?? own
|
|
70
|
-
const root = useRef<HTMLDivElement>(null)
|
|
71
|
-
|
|
72
|
-
const toggle = (item: string, next: boolean) => {
|
|
73
|
-
const after = next ? [...list, item] : list.filter(one => one !== item)
|
|
74
|
-
if (value === undefined) setOwn(after)
|
|
75
|
-
onValueChange?.(after)
|
|
76
|
-
}
|
|
40
|
+
export function CheckboxGroup({ className, onKeyDown, ...rest }: CheckboxGroupProps) {
|
|
41
|
+
const onKeys = (e: GroupKeyEvent) => {
|
|
42
|
+
onKeyDown?.(e)
|
|
43
|
+
if (e.defaultPrevented) return
|
|
77
44
|
|
|
78
|
-
const onKeyDown = (e: ReactKeyboardEvent<HTMLDivElement>) => {
|
|
79
45
|
const step = e.key === 'ArrowDown' || e.key === 'ArrowRight'
|
|
80
46
|
? 1
|
|
81
47
|
: e.key === 'ArrowUp' || e.key === 'ArrowLeft' ? -1 : 0
|
|
82
|
-
if (step === 0
|
|
48
|
+
if (step === 0) return
|
|
83
49
|
|
|
84
|
-
const items = [...
|
|
50
|
+
const items = [...e.currentTarget.querySelectorAll<HTMLElement>(ITEMS)]
|
|
85
51
|
const at = items.indexOf(document.activeElement as HTMLElement)
|
|
86
52
|
if (at === -1) return
|
|
87
53
|
|
|
@@ -89,59 +55,28 @@ export function CheckboxGroup({
|
|
|
89
55
|
items[(at + step + items.length) % items.length]!.focus()
|
|
90
56
|
}
|
|
91
57
|
|
|
92
|
-
return (
|
|
93
|
-
<Group value={{ value: list, toggle, disabled }}>
|
|
94
|
-
<div
|
|
95
|
-
ref={root}
|
|
96
|
-
role="group"
|
|
97
|
-
onKeyDown={onKeyDown}
|
|
98
|
-
className={checkboxGroup({ className })}
|
|
99
|
-
>
|
|
100
|
-
{children}
|
|
101
|
-
</div>
|
|
102
|
-
</Group>
|
|
103
|
-
)
|
|
58
|
+
return <CheckboxGroupPrimitive {...rest} onKeyDown={onKeys} className={checkboxGroup({ className })} />
|
|
104
59
|
}
|
|
105
60
|
|
|
106
|
-
export
|
|
107
|
-
value?: string
|
|
108
|
-
checked?: boolean
|
|
109
|
-
onCheckedChange?: (checked: boolean) => void
|
|
110
|
-
indeterminate?: boolean
|
|
111
|
-
onIndeterminateChange?: (indeterminate: boolean) => void
|
|
61
|
+
export type CheckboxProps = Omit<ComponentProps<typeof CheckboxPrimitive.Root>, 'className'> & {
|
|
112
62
|
color?: 'neutral' | 'info' | 'success' | 'warning' | 'danger'
|
|
63
|
+
className?: string
|
|
113
64
|
}
|
|
114
65
|
|
|
115
66
|
export function Checkbox({
|
|
116
|
-
value,
|
|
117
|
-
checked,
|
|
118
|
-
onCheckedChange,
|
|
119
67
|
indeterminate,
|
|
120
|
-
onIndeterminateChange,
|
|
121
68
|
color,
|
|
122
69
|
className,
|
|
123
|
-
|
|
70
|
+
nativeButton = true,
|
|
71
|
+
render = <button type="button" />,
|
|
124
72
|
...rest
|
|
125
73
|
}: CheckboxProps) {
|
|
126
|
-
const group = use(Group)
|
|
127
|
-
const item = value ?? 'on'
|
|
128
|
-
|
|
129
|
-
const on = group ? group.value.includes(item) : checked ?? false
|
|
130
|
-
const state = indeterminate ? 'indeterminate' as const : on
|
|
131
|
-
|
|
132
|
-
const change = (next: boolean | 'indeterminate') => {
|
|
133
|
-
if (typeof next !== 'boolean') return
|
|
134
|
-
if (group) group.toggle(item, next)
|
|
135
|
-
else onCheckedChange?.(next)
|
|
136
|
-
if (indeterminate) onIndeterminateChange?.(false)
|
|
137
|
-
}
|
|
138
|
-
|
|
139
74
|
return (
|
|
140
75
|
<CheckboxPrimitive.Root
|
|
141
76
|
{...rest}
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
77
|
+
nativeButton={nativeButton}
|
|
78
|
+
render={render}
|
|
79
|
+
indeterminate={indeterminate}
|
|
145
80
|
className={checkbox({ color, className })}
|
|
146
81
|
>
|
|
147
82
|
<CheckboxPrimitive.Indicator className="text-fg-neutral-solid-contrast flex">
|