@pantoia/ui 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/accordion/AGENTS.md +60 -0
- package/accordion/index.module.css +10 -0
- package/accordion/index.tsx +91 -0
- package/alert-dialog/AGENTS.md +78 -0
- package/alert-dialog/index.tsx +119 -0
- package/badge/AGENTS.md +35 -0
- package/badge/index.tsx +34 -0
- package/button/AGENTS.md +39 -0
- package/button/index.tsx +98 -0
- package/callout/AGENTS.md +42 -0
- package/callout/index.tsx +70 -0
- package/checkbox/AGENTS.md +54 -0
- package/checkbox/index.tsx +151 -0
- package/code-block/AGENTS.md +60 -0
- package/code-block/index.module.css +46 -0
- package/code-block/index.tsx +127 -0
- package/combobox/AGENTS.md +150 -0
- package/combobox/index.tsx +420 -0
- package/command-palette/AGENTS.md +44 -0
- package/command-palette/index.tsx +108 -0
- package/copy-button/AGENTS.md +43 -0
- package/copy-button/index.tsx +119 -0
- package/dialog/AGENTS.md +81 -0
- package/dialog/index.tsx +108 -0
- package/dist/index.js +189 -0
- package/drawer/AGENTS.md +66 -0
- package/drawer/index.module.css +17 -0
- package/drawer/index.tsx +198 -0
- package/dropdown-menu/AGENTS.md +133 -0
- package/dropdown-menu/index.tsx +223 -0
- package/field/AGENTS.md +96 -0
- package/field/index.tsx +149 -0
- package/input/AGENTS.md +35 -0
- package/input/index.tsx +36 -0
- package/kbd/AGENTS.md +17 -0
- package/kbd/index.tsx +13 -0
- package/label/AGENTS.md +21 -0
- package/label/index.tsx +13 -0
- package/number-field/AGENTS.md +53 -0
- package/number-field/index.tsx +227 -0
- package/package.json +73 -0
- package/popover/AGENTS.md +64 -0
- package/popover/index.tsx +66 -0
- package/press.css +37 -0
- package/radio-group/AGENTS.md +81 -0
- package/radio-group/index.tsx +139 -0
- package/registry.json +726 -0
- package/select/AGENTS.md +90 -0
- package/select/index.tsx +169 -0
- package/styles.css +347 -0
- package/switch/AGENTS.md +37 -0
- package/switch/index.tsx +42 -0
- package/table/AGENTS.md +82 -0
- package/table/index.tsx +120 -0
- package/tabs/AGENTS.md +60 -0
- package/tabs/index.module.css +14 -0
- package/tabs/index.tsx +105 -0
- package/test-utils.ts +10 -0
- package/textarea/AGENTS.md +35 -0
- package/textarea/index.tsx +37 -0
- package/toast/AGENTS.md +42 -0
- package/toast/index.tsx +71 -0
- package/toggle/AGENTS.md +37 -0
- package/toggle/index.tsx +36 -0
- package/tooltip/AGENTS.md +50 -0
- package/tooltip/index.tsx +57 -0
- package/tv.ts +23 -0
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# Popover
|
|
2
|
+
|
|
3
|
+
```
|
|
4
|
+
받기 npx @pantoia/ui add popover
|
|
5
|
+
층 ui
|
|
6
|
+
파일 popover/index.tsx · popover/AGENTS.md
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## 부위
|
|
10
|
+
|
|
11
|
+
| 이름 | props |
|
|
12
|
+
|---|---|
|
|
13
|
+
| `Popover` | `PopoverProps` |
|
|
14
|
+
| `PopoverTrigger` | — |
|
|
15
|
+
| `PopoverAnchor` | — |
|
|
16
|
+
| `PopoverClose` | — |
|
|
17
|
+
| `PopoverContent` | `PopoverContentProps` |
|
|
18
|
+
|
|
19
|
+
### `PopoverTrigger`
|
|
20
|
+
|
|
21
|
+
| 이름 | 타입 | 필수 |
|
|
22
|
+
|---|---|---|
|
|
23
|
+
| `children` | `ReactNode` | 예 |
|
|
24
|
+
|
|
25
|
+
### `PopoverAnchor`
|
|
26
|
+
|
|
27
|
+
| 이름 | 타입 | 필수 |
|
|
28
|
+
|---|---|---|
|
|
29
|
+
| `children` | `ReactNode` | 예 |
|
|
30
|
+
|
|
31
|
+
### `PopoverClose`
|
|
32
|
+
|
|
33
|
+
| 이름 | 타입 | 필수 |
|
|
34
|
+
|---|---|---|
|
|
35
|
+
| `children` | `ReactNode` | 예 |
|
|
36
|
+
|
|
37
|
+
## props
|
|
38
|
+
|
|
39
|
+
### `PopoverProps`
|
|
40
|
+
|
|
41
|
+
| 이름 | 타입 | 필수 |
|
|
42
|
+
|---|---|---|
|
|
43
|
+
| `open` | `boolean` | |
|
|
44
|
+
| `defaultOpen` | `boolean` | |
|
|
45
|
+
| `onOpenChange` | `(open: boolean) => void` | |
|
|
46
|
+
| `children` | `ReactNode` | |
|
|
47
|
+
|
|
48
|
+
### `PopoverContentProps`
|
|
49
|
+
|
|
50
|
+
`Omit<ComponentProps<typeof PopoverPrimitive.Content>, 'side' | 'align'>` 를 확장한다.
|
|
51
|
+
|
|
52
|
+
| 이름 | 타입 | 필수 |
|
|
53
|
+
|---|---|---|
|
|
54
|
+
| `side` | `'top' \| 'right' \| 'bottom' \| 'left'` | |
|
|
55
|
+
| `align` | `'start' \| 'center' \| 'end'` | |
|
|
56
|
+
| `arrow` | `boolean` | |
|
|
57
|
+
|
|
58
|
+
## 함께 받는 것
|
|
59
|
+
|
|
60
|
+
`tv`
|
|
61
|
+
|
|
62
|
+
## npm 의존
|
|
63
|
+
|
|
64
|
+
`radix-ui`
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import { Popover as PopoverPrimitive } from 'radix-ui'
|
|
4
|
+
import type { ComponentProps, ReactNode } from 'react'
|
|
5
|
+
|
|
6
|
+
import { tv } from '../tv'
|
|
7
|
+
|
|
8
|
+
export interface PopoverProps {
|
|
9
|
+
open?: boolean
|
|
10
|
+
defaultOpen?: boolean
|
|
11
|
+
onOpenChange?: (open: boolean) => void
|
|
12
|
+
children?: ReactNode
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function Popover({ open, defaultOpen, onOpenChange, children }: PopoverProps) {
|
|
16
|
+
return (
|
|
17
|
+
<PopoverPrimitive.Root open={open} defaultOpen={defaultOpen} onOpenChange={onOpenChange}>
|
|
18
|
+
{children}
|
|
19
|
+
</PopoverPrimitive.Root>
|
|
20
|
+
)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function PopoverTrigger({ children }: { children: ReactNode }) {
|
|
24
|
+
return <PopoverPrimitive.Trigger asChild>{children}</PopoverPrimitive.Trigger>
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function PopoverAnchor({ children }: { children: ReactNode }) {
|
|
28
|
+
return <PopoverPrimitive.Anchor asChild>{children}</PopoverPrimitive.Anchor>
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function PopoverClose({ children }: { children: ReactNode }) {
|
|
32
|
+
return <PopoverPrimitive.Close asChild>{children}</PopoverPrimitive.Close>
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface PopoverContentProps extends Omit<ComponentProps<typeof PopoverPrimitive.Content>, 'side' | 'align'> {
|
|
36
|
+
side?: 'top' | 'right' | 'bottom' | 'left'
|
|
37
|
+
align?: 'start' | 'center' | 'end'
|
|
38
|
+
arrow?: boolean
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function PopoverContent({
|
|
42
|
+
side = 'bottom',
|
|
43
|
+
align = 'center',
|
|
44
|
+
arrow = true,
|
|
45
|
+
className,
|
|
46
|
+
children,
|
|
47
|
+
...rest
|
|
48
|
+
}: PopoverContentProps) {
|
|
49
|
+
return (
|
|
50
|
+
<PopoverPrimitive.Portal>
|
|
51
|
+
<PopoverPrimitive.Content
|
|
52
|
+
{...rest}
|
|
53
|
+
side={side}
|
|
54
|
+
align={align}
|
|
55
|
+
sideOffset={8}
|
|
56
|
+
arrowPadding={16}
|
|
57
|
+
className={tv({ base: 'bg-float text-fg rounded-float shadow-s3 z-overlay p-4'
|
|
58
|
+
+ ' open:animate-enter closed:animate-exit'
|
|
59
|
+
+ ' focus-visible:outline-none' })({ className })}
|
|
60
|
+
>
|
|
61
|
+
{children}
|
|
62
|
+
{arrow && <PopoverPrimitive.Arrow className="fill-float" width={12} height={6} />}
|
|
63
|
+
</PopoverPrimitive.Content>
|
|
64
|
+
</PopoverPrimitive.Portal>
|
|
65
|
+
)
|
|
66
|
+
}
|
package/press.css
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
:root, .light { --pressed-dim: rgba(0,23,51,0.12); }
|
|
2
|
+
.dark { --pressed-dim: rgba(209,209,253,0.14); }
|
|
3
|
+
|
|
4
|
+
:root { --scale-press: 0.97; }
|
|
5
|
+
|
|
6
|
+
@media (prefers-reduced-motion: reduce) {
|
|
7
|
+
:root { --scale-press: 1; }
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
@utility press {
|
|
11
|
+
position: relative;
|
|
12
|
+
|
|
13
|
+
&::after {
|
|
14
|
+
content: "";
|
|
15
|
+
position: absolute;
|
|
16
|
+
inset: 0;
|
|
17
|
+
border-radius: inherit;
|
|
18
|
+
background: var(--pressed-dim);
|
|
19
|
+
opacity: 0;
|
|
20
|
+
pointer-events: none;
|
|
21
|
+
transition: opacity var(--dur-state) var(--ease-state);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
&:active:not(:disabled)::after,
|
|
25
|
+
&[data-pressed]:not(:disabled)::after {
|
|
26
|
+
opacity: 1;
|
|
27
|
+
transition-duration: 0s;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
@utility press-shrink {
|
|
32
|
+
&:active:not(:disabled),
|
|
33
|
+
&[data-pressed]:not(:disabled) {
|
|
34
|
+
scale: var(--scale-press);
|
|
35
|
+
transition-duration: 0s;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# RadioGroup
|
|
2
|
+
|
|
3
|
+
```
|
|
4
|
+
받기 npx @pantoia/ui add radio-group
|
|
5
|
+
층 ui
|
|
6
|
+
파일 radio-group/index.tsx · radio-group/AGENTS.md
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## 부위
|
|
10
|
+
|
|
11
|
+
| 이름 | props |
|
|
12
|
+
|---|---|
|
|
13
|
+
| `RadioGroup` | `RadioGroupProps` |
|
|
14
|
+
| `RadioGroupItem` | `RadioGroupItemProps` |
|
|
15
|
+
| `RadioGroupItemLabel` | — |
|
|
16
|
+
| `RadioGroupItemDescription` | — |
|
|
17
|
+
|
|
18
|
+
### `RadioGroupItemLabel`
|
|
19
|
+
|
|
20
|
+
| 이름 | 타입 | 필수 |
|
|
21
|
+
|---|---|---|
|
|
22
|
+
| `className` | `string` | |
|
|
23
|
+
| `children` | `ReactNode` | |
|
|
24
|
+
|
|
25
|
+
### `RadioGroupItemDescription`
|
|
26
|
+
|
|
27
|
+
| 이름 | 타입 | 필수 |
|
|
28
|
+
|---|---|---|
|
|
29
|
+
| `className` | `string` | |
|
|
30
|
+
| `children` | `ReactNode` | |
|
|
31
|
+
|
|
32
|
+
## props
|
|
33
|
+
|
|
34
|
+
### `RadioColor`
|
|
35
|
+
|
|
36
|
+
`'control' | 'info' | 'success' | 'warning' | 'danger'`
|
|
37
|
+
|
|
38
|
+
### `RadioItemContext`
|
|
39
|
+
|
|
40
|
+
| 이름 | 타입 | 필수 |
|
|
41
|
+
|---|---|---|
|
|
42
|
+
| `id` | `string` | 예 |
|
|
43
|
+
| `labelId` | `string` | 예 |
|
|
44
|
+
| `descriptionId` | `string` | 예 |
|
|
45
|
+
|
|
46
|
+
### `RadioGroupProps`
|
|
47
|
+
|
|
48
|
+
| 이름 | 타입 | 필수 |
|
|
49
|
+
|---|---|---|
|
|
50
|
+
| `value` | `string` | |
|
|
51
|
+
| `defaultValue` | `string` | |
|
|
52
|
+
| `onValueChange` | `(value: string) => void` | |
|
|
53
|
+
| `color` | `RadioColor` | |
|
|
54
|
+
| `disabled` | `boolean` | |
|
|
55
|
+
| `className` | `string` | |
|
|
56
|
+
| `children` | `ReactNode` | |
|
|
57
|
+
|
|
58
|
+
### `RadioGroupItemProps`
|
|
59
|
+
|
|
60
|
+
| 이름 | 타입 | 필수 |
|
|
61
|
+
|---|---|---|
|
|
62
|
+
| `value` | `string` | 예 |
|
|
63
|
+
| `disabled` | `boolean` | |
|
|
64
|
+
| `className` | `string` | |
|
|
65
|
+
| `children` | `ReactNode` | |
|
|
66
|
+
|
|
67
|
+
## 변형 — `radioGroupItem`
|
|
68
|
+
|
|
69
|
+
슬롯 `root` · `control`
|
|
70
|
+
|
|
71
|
+
| 축 | 값 | 기본 |
|
|
72
|
+
|---|---|---|
|
|
73
|
+
| `color` | `control` · `info` · `success` · `warning` · `danger` | `control` |
|
|
74
|
+
|
|
75
|
+
## 함께 받는 것
|
|
76
|
+
|
|
77
|
+
`label` · `tv`
|
|
78
|
+
|
|
79
|
+
## npm 의존
|
|
80
|
+
|
|
81
|
+
`radix-ui`
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import { RadioGroup as RadioGroupPrimitive } from 'radix-ui'
|
|
4
|
+
import { createContext, use, useId, type ReactNode } from 'react'
|
|
5
|
+
|
|
6
|
+
import { Label } from '../label'
|
|
7
|
+
import { tv } from '../tv'
|
|
8
|
+
|
|
9
|
+
export type RadioColor = 'control' | 'info' | 'success' | 'warning' | 'danger'
|
|
10
|
+
|
|
11
|
+
const ColorContext = createContext<RadioColor>('control')
|
|
12
|
+
|
|
13
|
+
export interface RadioItemContext {
|
|
14
|
+
id: string
|
|
15
|
+
labelId: string
|
|
16
|
+
descriptionId: string
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const ItemContext = createContext<RadioItemContext | null>(null)
|
|
20
|
+
|
|
21
|
+
export const radioGroupItem = tv({
|
|
22
|
+
slots: {
|
|
23
|
+
root: 'flex gap-2 items-center described:items-start described:[&_.radio-mark]:mt-0.5',
|
|
24
|
+
control: 'radio-mark size-5 shrink-0 rounded-full ring-1 ring-inset ring-line-strong'
|
|
25
|
+
+ ' bg-transparent transition-state press press-shrink'
|
|
26
|
+
+ ' inline-flex items-center justify-center'
|
|
27
|
+
+ ' checked:ring-2'
|
|
28
|
+
+ ' in-invalid:ring-2 in-invalid:ring-danger'
|
|
29
|
+
+ ' focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring'
|
|
30
|
+
+ ' disabled:ring-line disabled:bg-disabled disabled:cursor-not-allowed'
|
|
31
|
+
+ ' checked:disabled:bg-control-on-disabled checked:disabled:ring-control-on-disabled',
|
|
32
|
+
},
|
|
33
|
+
|
|
34
|
+
variants: {
|
|
35
|
+
color: {
|
|
36
|
+
control: { control: 'checked:bg-control-on checked:ring-control-on' },
|
|
37
|
+
info: { control: 'checked:bg-info checked:ring-info' },
|
|
38
|
+
success: { control: 'checked:bg-success checked:ring-success' },
|
|
39
|
+
warning: { control: 'checked:bg-warning checked:ring-warning' },
|
|
40
|
+
danger: { control: 'checked:bg-danger checked:ring-danger' },
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
|
|
44
|
+
defaultVariants: { color: 'control' },
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
export interface RadioGroupProps {
|
|
48
|
+
value?: string
|
|
49
|
+
defaultValue?: string
|
|
50
|
+
onValueChange?: (value: string) => void
|
|
51
|
+
color?: RadioColor
|
|
52
|
+
disabled?: boolean
|
|
53
|
+
className?: string
|
|
54
|
+
children?: ReactNode
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function RadioGroup({
|
|
58
|
+
value,
|
|
59
|
+
defaultValue,
|
|
60
|
+
onValueChange,
|
|
61
|
+
color = 'control',
|
|
62
|
+
disabled = false,
|
|
63
|
+
className,
|
|
64
|
+
children,
|
|
65
|
+
...rest
|
|
66
|
+
}: RadioGroupProps) {
|
|
67
|
+
return (
|
|
68
|
+
<ColorContext value={color}>
|
|
69
|
+
<RadioGroupPrimitive.Root
|
|
70
|
+
{...rest}
|
|
71
|
+
value={value}
|
|
72
|
+
defaultValue={defaultValue}
|
|
73
|
+
onValueChange={onValueChange}
|
|
74
|
+
disabled={disabled}
|
|
75
|
+
className={tv({ base: 'flex flex-col gap-3' })({ className })}
|
|
76
|
+
>
|
|
77
|
+
{children}
|
|
78
|
+
</RadioGroupPrimitive.Root>
|
|
79
|
+
</ColorContext>
|
|
80
|
+
)
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export interface RadioGroupItemProps {
|
|
84
|
+
value: string
|
|
85
|
+
disabled?: boolean
|
|
86
|
+
className?: string
|
|
87
|
+
children?: ReactNode
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export function RadioGroupItem({ value, disabled, className, children }: RadioGroupItemProps) {
|
|
91
|
+
const id = useId()
|
|
92
|
+
const color = use(ColorContext)
|
|
93
|
+
const ui = radioGroupItem({ color })
|
|
94
|
+
|
|
95
|
+
return (
|
|
96
|
+
<ItemContext value={{ id, labelId: `${id}-label`, descriptionId: `${id}-description` }}>
|
|
97
|
+
<div className={ui.root({ className })}>
|
|
98
|
+
<RadioGroupPrimitive.Item
|
|
99
|
+
id={id}
|
|
100
|
+
value={value}
|
|
101
|
+
disabled={disabled}
|
|
102
|
+
aria-labelledby={`${id}-label`}
|
|
103
|
+
aria-describedby={`${id}-description`}
|
|
104
|
+
className={ui.control()}
|
|
105
|
+
>
|
|
106
|
+
<RadioGroupPrimitive.Indicator className="text-fg-on-control size-2.5 rounded-full bg-current" />
|
|
107
|
+
</RadioGroupPrimitive.Item>
|
|
108
|
+
|
|
109
|
+
<div className="flex min-w-0 flex-col gap-0.5">
|
|
110
|
+
{children}
|
|
111
|
+
</div>
|
|
112
|
+
</div>
|
|
113
|
+
</ItemContext>
|
|
114
|
+
)
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export function RadioGroupItemLabel({ className, children }: { className?: string, children?: ReactNode }) {
|
|
118
|
+
const ctx = use(ItemContext)
|
|
119
|
+
|
|
120
|
+
return (
|
|
121
|
+
<Label id={ctx?.labelId} htmlFor={ctx?.id} className={className}>
|
|
122
|
+
{children}
|
|
123
|
+
</Label>
|
|
124
|
+
)
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export function RadioGroupItemDescription({ className, children }: { className?: string, children?: ReactNode }) {
|
|
128
|
+
const ctx = use(ItemContext)
|
|
129
|
+
|
|
130
|
+
return (
|
|
131
|
+
<p
|
|
132
|
+
id={ctx?.descriptionId}
|
|
133
|
+
data-description
|
|
134
|
+
className={tv({ base: 'text-caption text-fg-subtle' })({ className })}
|
|
135
|
+
>
|
|
136
|
+
{children}
|
|
137
|
+
</p>
|
|
138
|
+
)
|
|
139
|
+
}
|