@pantoia/ui 0.1.0 → 0.3.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 +5 -5
- package/accordion/index.tsx +21 -11
- package/alert-dialog/AGENTS.md +7 -7
- package/alert-dialog/index.tsx +20 -10
- package/badge/AGENTS.md +5 -5
- package/badge/index.tsx +8 -8
- package/button/AGENTS.md +7 -7
- package/button/index.tsx +34 -34
- package/callout/AGENTS.md +4 -9
- package/callout/index.tsx +42 -22
- package/checkbox/AGENTS.md +5 -5
- package/checkbox/index.tsx +19 -16
- package/combobox/AGENTS.md +13 -13
- package/combobox/index.tsx +90 -42
- package/command-palette/AGENTS.md +3 -6
- package/command-palette/index.tsx +7 -3
- package/dialog/AGENTS.md +6 -6
- package/dialog/index.tsx +11 -5
- package/dist/index.js +200 -43
- package/drawer/AGENTS.md +5 -5
- package/drawer/index.tsx +8 -4
- package/dropdown-menu/AGENTS.md +12 -12
- package/dropdown-menu/index.tsx +27 -12
- package/field/AGENTS.md +8 -12
- package/field/index.tsx +39 -13
- package/input/AGENTS.md +4 -4
- package/input/index.tsx +5 -5
- package/kbd/AGENTS.md +1 -1
- package/kbd/index.tsx +6 -2
- package/label/AGENTS.md +1 -1
- package/label/index.tsx +3 -1
- package/number-field/AGENTS.md +6 -10
- package/number-field/index.tsx +26 -16
- package/package.json +13 -15
- package/palette.css +114 -0
- package/popover/AGENTS.md +4 -4
- package/popover/index.tsx +14 -4
- package/radio-group/AGENTS.md +8 -8
- package/radio-group/index.tsx +20 -16
- package/registry.json +9 -71
- package/select/AGENTS.md +10 -10
- package/select/index.tsx +46 -21
- package/switch/AGENTS.md +4 -4
- package/switch/index.tsx +13 -13
- package/table/AGENTS.md +9 -9
- package/table/index.tsx +16 -6
- package/tabs/AGENTS.md +5 -4
- package/tabs/index.module.css +2 -0
- package/tabs/index.tsx +22 -11
- package/tailwind.css +3 -0
- package/textarea/AGENTS.md +4 -4
- package/textarea/index.tsx +5 -5
- package/toast/AGENTS.md +5 -13
- package/toast/index.tsx +27 -33
- package/toggle/AGENTS.md +4 -4
- package/toggle/index.tsx +8 -7
- package/tokens.css +272 -0
- package/tooltip/AGENTS.md +2 -2
- package/tooltip/index.tsx +14 -4
- package/tv.ts +0 -1
- package/utilities.css +119 -0
- package/code-block/AGENTS.md +0 -60
- package/code-block/index.module.css +0 -46
- package/code-block/index.tsx +0 -127
- package/copy-button/AGENTS.md +0 -43
- package/copy-button/index.tsx +0 -119
- package/press.css +0 -37
- package/styles.css +0 -347
package/field/index.tsx
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
'use client'
|
|
2
2
|
|
|
3
|
-
import { CircleAlert, CircleCheck, LoaderCircle } from 'lucide-react'
|
|
4
3
|
import { createContext, use, useId, type ReactNode } from 'react'
|
|
5
4
|
|
|
6
5
|
import { Label } from '../label'
|
|
@@ -66,6 +65,8 @@ export function Field({ invalid = false, layout, className, children }: FieldPro
|
|
|
66
65
|
)
|
|
67
66
|
}
|
|
68
67
|
|
|
68
|
+
const fieldLabel = tv({ base: 'group-has-disabled:text-fg-disabled' })
|
|
69
|
+
|
|
69
70
|
export function FieldLabel({ className, children }: { className?: string, children?: ReactNode }) {
|
|
70
71
|
const ctx = use(Context)
|
|
71
72
|
|
|
@@ -73,21 +74,25 @@ export function FieldLabel({ className, children }: { className?: string, childr
|
|
|
73
74
|
<Label
|
|
74
75
|
id={ctx?.labelId}
|
|
75
76
|
htmlFor={ctx?.id}
|
|
76
|
-
className={
|
|
77
|
+
className={fieldLabel({ className })}
|
|
77
78
|
>
|
|
78
79
|
{children}
|
|
79
80
|
</Label>
|
|
80
81
|
)
|
|
81
82
|
}
|
|
82
83
|
|
|
84
|
+
const fieldHelp = tv({
|
|
85
|
+
base: 'basis-full text-caption text-fg-subtle'
|
|
86
|
+
+ ' group-has-disabled:text-fg-disabled',
|
|
87
|
+
})
|
|
88
|
+
|
|
83
89
|
export function FieldHelp({ className, children }: { className?: string, children?: ReactNode }) {
|
|
84
90
|
const ctx = use(Context)
|
|
85
91
|
|
|
86
92
|
return (
|
|
87
93
|
<p
|
|
88
94
|
id={ctx?.messageId}
|
|
89
|
-
className={
|
|
90
|
-
+ ' group-has-disabled:text-fg-disabled' })({ className })}
|
|
95
|
+
className={fieldHelp({ className })}
|
|
91
96
|
>
|
|
92
97
|
{children}
|
|
93
98
|
</p>
|
|
@@ -100,6 +105,11 @@ export interface FieldErrorProps {
|
|
|
100
105
|
children?: ReactNode
|
|
101
106
|
}
|
|
102
107
|
|
|
108
|
+
const fieldError = tv({
|
|
109
|
+
base: 'basis-full text-caption text-fg-danger'
|
|
110
|
+
+ ' flex items-start gap-tight',
|
|
111
|
+
})
|
|
112
|
+
|
|
103
113
|
export function FieldError({ items, className, children }: FieldErrorProps) {
|
|
104
114
|
const ctx = use(Context)
|
|
105
115
|
const list = items == null ? [] : Array.isArray(items) ? items : [items]
|
|
@@ -107,10 +117,13 @@ export function FieldError({ items, className, children }: FieldErrorProps) {
|
|
|
107
117
|
return (
|
|
108
118
|
<p
|
|
109
119
|
id={ctx?.messageId}
|
|
110
|
-
className={
|
|
111
|
-
+ ' flex items-start gap-tight' })({ className })}
|
|
120
|
+
className={fieldError({ className })}
|
|
112
121
|
>
|
|
113
|
-
<
|
|
122
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={2} strokeLinecap="round" strokeLinejoin="round" aria-hidden="true" className="mt-0.5 size-4 shrink-0">
|
|
123
|
+
<circle cx="12" cy="12" r="10" />
|
|
124
|
+
<line x1="12" x2="12" y1="8" y2="12" />
|
|
125
|
+
<line x1="12" x2="12.01" y1="16" y2="16" />
|
|
126
|
+
</svg>
|
|
114
127
|
<span className="flex min-w-0 flex-col gap-0.5">
|
|
115
128
|
{children ?? list.map(t => <span key={t}>{t}</span>)}
|
|
116
129
|
</span>
|
|
@@ -118,31 +131,44 @@ export function FieldError({ items, className, children }: FieldErrorProps) {
|
|
|
118
131
|
)
|
|
119
132
|
}
|
|
120
133
|
|
|
134
|
+
const fieldPending = tv({
|
|
135
|
+
base: 'basis-full text-caption text-fg-subtle'
|
|
136
|
+
+ ' flex items-start gap-tight',
|
|
137
|
+
})
|
|
138
|
+
|
|
121
139
|
export function FieldPending({ className, children }: { className?: string, children?: ReactNode }) {
|
|
122
140
|
const ctx = use(Context)
|
|
123
141
|
|
|
124
142
|
return (
|
|
125
143
|
<p
|
|
126
144
|
id={ctx?.messageId}
|
|
127
|
-
className={
|
|
128
|
-
+ ' flex items-start gap-tight' })({ className })}
|
|
145
|
+
className={fieldPending({ className })}
|
|
129
146
|
>
|
|
130
|
-
<
|
|
147
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={2} strokeLinecap="round" strokeLinejoin="round" aria-hidden="true" className="mt-0.5 size-4 shrink-0 animate-spin motion-reduce:animate-none">
|
|
148
|
+
<path d="M21 12a9 9 0 1 1-6.219-8.56" />
|
|
149
|
+
</svg>
|
|
131
150
|
<span className="min-w-0">{children}</span>
|
|
132
151
|
</p>
|
|
133
152
|
)
|
|
134
153
|
}
|
|
135
154
|
|
|
155
|
+
const fieldSuccess = tv({
|
|
156
|
+
base: 'basis-full text-caption text-fg-success'
|
|
157
|
+
+ ' flex items-start gap-tight',
|
|
158
|
+
})
|
|
159
|
+
|
|
136
160
|
export function FieldSuccess({ className, children }: { className?: string, children?: ReactNode }) {
|
|
137
161
|
const ctx = use(Context)
|
|
138
162
|
|
|
139
163
|
return (
|
|
140
164
|
<p
|
|
141
165
|
id={ctx?.messageId}
|
|
142
|
-
className={
|
|
143
|
-
+ ' flex items-start gap-tight' })({ className })}
|
|
166
|
+
className={fieldSuccess({ className })}
|
|
144
167
|
>
|
|
145
|
-
<
|
|
168
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={2} strokeLinecap="round" strokeLinejoin="round" aria-hidden="true" className="mt-0.5 size-4 shrink-0">
|
|
169
|
+
<circle cx="12" cy="12" r="10" />
|
|
170
|
+
<path d="m16 9-5.5 5.5L8 12" />
|
|
171
|
+
</svg>
|
|
146
172
|
<span className="min-w-0">{children}</span>
|
|
147
173
|
</p>
|
|
148
174
|
)
|
package/input/AGENTS.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
```
|
|
4
4
|
받기 npx @pantoia/ui add input
|
|
5
5
|
층 ui
|
|
6
|
-
파일 input/index.tsx
|
|
6
|
+
파일 input/index.tsx, input/AGENTS.md
|
|
7
7
|
```
|
|
8
8
|
|
|
9
9
|
## 부위
|
|
@@ -23,12 +23,12 @@
|
|
|
23
23
|
| `surface` | `'bare' \| 'well'` | |
|
|
24
24
|
| `size` | `'sm' \| 'md' \| 'lg'` | |
|
|
25
25
|
|
|
26
|
-
## 변형
|
|
26
|
+
## 변형 - `input`
|
|
27
27
|
|
|
28
28
|
| 축 | 값 | 기본 |
|
|
29
29
|
|---|---|---|
|
|
30
|
-
| `surface` | `bare
|
|
31
|
-
| `size` | `sm
|
|
30
|
+
| `surface` | `bare`, `well` | `bare` |
|
|
31
|
+
| `size` | `sm`, `md`, `lg` | `md` |
|
|
32
32
|
|
|
33
33
|
## 함께 받는 것
|
|
34
34
|
|
package/input/index.tsx
CHANGED
|
@@ -5,16 +5,16 @@ import { tv } from '../tv'
|
|
|
5
5
|
export const input = tv({
|
|
6
6
|
base: 'w-full rounded-r8 text-value text-fg'
|
|
7
7
|
+ ' placeholder:text-fg-placeholder'
|
|
8
|
-
+ ' invalid:ring-2 invalid:ring-danger'
|
|
8
|
+
+ ' invalid:ring-2 invalid:ring-line-danger'
|
|
9
9
|
+ ' read-only:text-fg-muted'
|
|
10
10
|
+ ' transition-state'
|
|
11
|
-
+ ' focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring'
|
|
12
|
-
+ ' disabled:bg-disabled disabled:text-fg-disabled disabled:cursor-not-allowed',
|
|
11
|
+
+ ' focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-line-focus-ring'
|
|
12
|
+
+ ' disabled:bg-bg-neutral-disabled disabled:text-fg-disabled disabled:cursor-not-allowed',
|
|
13
13
|
|
|
14
14
|
variants: {
|
|
15
15
|
surface: {
|
|
16
|
-
bare: 'bg-transparent ring-1 ring-inset ring-line-strong read-only:bg-well',
|
|
17
|
-
well: 'bg-well',
|
|
16
|
+
bare: 'bg-transparent ring-1 ring-inset ring-line-strong read-only:bg-bg-well',
|
|
17
|
+
well: 'bg-bg-well',
|
|
18
18
|
},
|
|
19
19
|
size: {
|
|
20
20
|
sm: 'h-8 px-3',
|
package/kbd/AGENTS.md
CHANGED
package/kbd/index.tsx
CHANGED
|
@@ -2,12 +2,16 @@ import type { HTMLAttributes } from 'react'
|
|
|
2
2
|
|
|
3
3
|
import { tv } from '../tv'
|
|
4
4
|
|
|
5
|
+
const kbd = tv({
|
|
6
|
+
base: 'bg-bg-well text-fg-muted text-micro rounded-r4 inline-flex items-center'
|
|
7
|
+
+ ' border border-line px-1.5 py-0.5 font-mono',
|
|
8
|
+
})
|
|
9
|
+
|
|
5
10
|
export function Kbd({ className, ...rest }: HTMLAttributes<HTMLElement>) {
|
|
6
11
|
return (
|
|
7
12
|
<kbd
|
|
8
13
|
{...rest}
|
|
9
|
-
className={
|
|
10
|
-
+ ' border border-line px-1.5 py-0.5 font-mono' })({ className })}
|
|
14
|
+
className={kbd({ className })}
|
|
11
15
|
/>
|
|
12
16
|
)
|
|
13
17
|
}
|
package/label/AGENTS.md
CHANGED
package/label/index.tsx
CHANGED
|
@@ -3,11 +3,13 @@ import type { ComponentProps } from 'react'
|
|
|
3
3
|
|
|
4
4
|
import { tv } from '../tv'
|
|
5
5
|
|
|
6
|
+
const labelText = tv({ base: 'text-label text-fg' })
|
|
7
|
+
|
|
6
8
|
export function Label({ className, ...rest }: ComponentProps<typeof LabelPrimitive.Root>) {
|
|
7
9
|
return (
|
|
8
10
|
<LabelPrimitive.Root
|
|
9
11
|
{...rest}
|
|
10
|
-
className={
|
|
12
|
+
className={labelText({ className })}
|
|
11
13
|
/>
|
|
12
14
|
)
|
|
13
15
|
}
|
package/number-field/AGENTS.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
```
|
|
4
4
|
받기 npx @pantoia/ui add number-field
|
|
5
5
|
층 ui
|
|
6
|
-
파일 number-field/index.tsx
|
|
6
|
+
파일 number-field/index.tsx, number-field/AGENTS.md
|
|
7
7
|
```
|
|
8
8
|
|
|
9
9
|
## 부위
|
|
@@ -34,20 +34,16 @@
|
|
|
34
34
|
| `readOnly` | `boolean` | |
|
|
35
35
|
| `className` | `string` | |
|
|
36
36
|
|
|
37
|
-
## 변형
|
|
37
|
+
## 변형 - `numberField`
|
|
38
38
|
|
|
39
|
-
슬롯 `root
|
|
39
|
+
슬롯 `root`, `step`, `input`
|
|
40
40
|
|
|
41
41
|
| 축 | 값 | 기본 |
|
|
42
42
|
|---|---|---|
|
|
43
|
-
| `surface` | `bare
|
|
44
|
-
| `size` | `sm
|
|
45
|
-
| `readonly` | `true` |
|
|
43
|
+
| `surface` | `bare`, `well` | `bare` |
|
|
44
|
+
| `size` | `sm`, `md`, `lg` | `md` |
|
|
45
|
+
| `readonly` | `true` | - |
|
|
46
46
|
|
|
47
47
|
## 함께 받는 것
|
|
48
48
|
|
|
49
49
|
`tv`
|
|
50
|
-
|
|
51
|
-
## npm 의존
|
|
52
|
-
|
|
53
|
-
`lucide-react`
|
package/number-field/index.tsx
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
'use client'
|
|
2
2
|
|
|
3
|
-
import { Minus, Plus } from 'lucide-react'
|
|
4
3
|
import { useEffect, useRef, useState, type InputHTMLAttributes, type PointerEvent as ReactPointerEvent, type KeyboardEvent as ReactKeyboardEvent } from 'react'
|
|
5
4
|
|
|
6
5
|
import { tv } from '../tv'
|
|
@@ -9,13 +8,14 @@ export const numberField = tv({
|
|
|
9
8
|
slots: {
|
|
10
9
|
root: 'flex items-center rounded-r8'
|
|
11
10
|
+ ' transition-state'
|
|
12
|
-
+ ' invalid-within:ring-2 invalid-within:ring-danger'
|
|
13
|
-
+ ' has-disabled:bg-disabled has-disabled:cursor-not-allowed'
|
|
11
|
+
+ ' invalid-within:ring-2 invalid-within:ring-line-danger'
|
|
12
|
+
+ ' has-disabled:bg-bg-neutral-disabled has-disabled:cursor-not-allowed'
|
|
14
13
|
+ ' has-focus-visible:outline-2 has-focus-visible:outline-offset-2'
|
|
15
|
-
+ ' has-focus-visible:outline-ring',
|
|
14
|
+
+ ' has-focus-visible:outline-line-focus-ring',
|
|
16
15
|
step: 'text-fg-muted grid shrink-0 place-items-center rounded-r8'
|
|
17
|
-
+ ' transition-state press press-shrink enabled:hover:bg-hover'
|
|
18
|
-
+ ' disabled:text-fg-disabled disabled:cursor-not-allowed'
|
|
16
|
+
+ ' transition-state press press-shrink enabled:not-aria-disabled:hover:bg-bg-neutral-hover'
|
|
17
|
+
+ ' disabled:text-fg-disabled disabled:cursor-not-allowed'
|
|
18
|
+
+ ' aria-disabled:text-fg-disabled aria-disabled:cursor-not-allowed',
|
|
19
19
|
input: 'text-value text-fg w-full min-w-0 bg-transparent text-center outline-none'
|
|
20
20
|
+ ' disabled:text-fg-disabled disabled:cursor-not-allowed',
|
|
21
21
|
},
|
|
@@ -23,7 +23,7 @@ export const numberField = tv({
|
|
|
23
23
|
variants: {
|
|
24
24
|
surface: {
|
|
25
25
|
bare: { root: 'bg-transparent ring-1 ring-inset ring-line-strong' },
|
|
26
|
-
well: { root: 'bg-well' },
|
|
26
|
+
well: { root: 'bg-bg-well' },
|
|
27
27
|
},
|
|
28
28
|
size: {
|
|
29
29
|
sm: { root: 'h-8', step: 'size-8' },
|
|
@@ -31,7 +31,7 @@ export const numberField = tv({
|
|
|
31
31
|
lg: { root: 'h-10', step: 'size-10', input: 'text-t16' },
|
|
32
32
|
},
|
|
33
33
|
readonly: {
|
|
34
|
-
true: { root: 'bg-well', input: 'text-fg-muted' },
|
|
34
|
+
true: { root: 'bg-bg-well', input: 'text-fg-muted' },
|
|
35
35
|
},
|
|
36
36
|
},
|
|
37
37
|
|
|
@@ -55,8 +55,11 @@ function snap(n: number, min: number, step: number) {
|
|
|
55
55
|
function useHold(step: () => void, blocked: boolean) {
|
|
56
56
|
const timer = useRef<ReturnType<typeof setTimeout> | undefined>(undefined)
|
|
57
57
|
const beat = useRef<ReturnType<typeof setInterval> | undefined>(undefined)
|
|
58
|
+
const latest = useRef(step)
|
|
58
59
|
const [pressed, setPressed] = useState(false)
|
|
59
60
|
|
|
61
|
+
useEffect(() => { latest.current = step })
|
|
62
|
+
|
|
60
63
|
const stop = () => {
|
|
61
64
|
clearTimeout(timer.current)
|
|
62
65
|
clearInterval(beat.current)
|
|
@@ -68,12 +71,12 @@ function useHold(step: () => void, blocked: boolean) {
|
|
|
68
71
|
const onPointerDown = (e: ReactPointerEvent<HTMLButtonElement>) => {
|
|
69
72
|
if (e.button !== 0 || blocked) return
|
|
70
73
|
|
|
71
|
-
|
|
74
|
+
latest.current()
|
|
72
75
|
setPressed(true)
|
|
73
76
|
e.currentTarget.setPointerCapture(e.pointerId)
|
|
74
77
|
|
|
75
78
|
timer.current = setTimeout(() => {
|
|
76
|
-
beat.current = setInterval(
|
|
79
|
+
beat.current = setInterval(() => { latest.current() }, HOLD_EVERY)
|
|
77
80
|
}, HOLD_DELAY)
|
|
78
81
|
}
|
|
79
82
|
|
|
@@ -132,8 +135,8 @@ export function NumberField(props: NumberFieldProps) {
|
|
|
132
135
|
const atMin = current !== undefined && current <= min
|
|
133
136
|
const atMax = current !== undefined && current >= max
|
|
134
137
|
|
|
135
|
-
const down = useHold(() => { setTyping(null); set(from - step) }, blocked)
|
|
136
|
-
const up = useHold(() => { setTyping(null); set(from + step) }, blocked)
|
|
138
|
+
const down = useHold(() => { setTyping(null); set(from - step) }, blocked || atMin)
|
|
139
|
+
const up = useHold(() => { setTyping(null); set(from + step) }, blocked || atMax)
|
|
137
140
|
|
|
138
141
|
const onKeyDown = (e: ReactKeyboardEvent<HTMLInputElement>) => {
|
|
139
142
|
if (blocked) return
|
|
@@ -180,7 +183,8 @@ export function NumberField(props: NumberFieldProps) {
|
|
|
180
183
|
<button
|
|
181
184
|
type="button"
|
|
182
185
|
aria-label={decrementLabel}
|
|
183
|
-
disabled={blocked
|
|
186
|
+
disabled={blocked}
|
|
187
|
+
aria-disabled={atMin || undefined}
|
|
184
188
|
data-pressed={down.pressed ? '' : undefined}
|
|
185
189
|
className={ui.step()}
|
|
186
190
|
onPointerDown={down.onPointerDown}
|
|
@@ -188,7 +192,9 @@ export function NumberField(props: NumberFieldProps) {
|
|
|
188
192
|
onPointerCancel={down.onPointerCancel}
|
|
189
193
|
onLostPointerCapture={down.onLostPointerCapture}
|
|
190
194
|
>
|
|
191
|
-
<
|
|
195
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={2} strokeLinecap="round" strokeLinejoin="round" aria-hidden="true" className="size-4">
|
|
196
|
+
<path d="M5 12h14" />
|
|
197
|
+
</svg>
|
|
192
198
|
</button>
|
|
193
199
|
|
|
194
200
|
<input
|
|
@@ -212,7 +218,8 @@ export function NumberField(props: NumberFieldProps) {
|
|
|
212
218
|
<button
|
|
213
219
|
type="button"
|
|
214
220
|
aria-label={incrementLabel}
|
|
215
|
-
disabled={blocked
|
|
221
|
+
disabled={blocked}
|
|
222
|
+
aria-disabled={atMax || undefined}
|
|
216
223
|
data-pressed={up.pressed ? '' : undefined}
|
|
217
224
|
className={ui.step()}
|
|
218
225
|
onPointerDown={up.onPointerDown}
|
|
@@ -220,7 +227,10 @@ export function NumberField(props: NumberFieldProps) {
|
|
|
220
227
|
onPointerCancel={up.onPointerCancel}
|
|
221
228
|
onLostPointerCapture={up.onLostPointerCapture}
|
|
222
229
|
>
|
|
223
|
-
<
|
|
230
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={2} strokeLinecap="round" strokeLinejoin="round" aria-hidden="true" className="size-4">
|
|
231
|
+
<path d="M5 12h14" />
|
|
232
|
+
<path d="M12 5v14" />
|
|
233
|
+
</svg>
|
|
224
234
|
</button>
|
|
225
235
|
</div>
|
|
226
236
|
)
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pantoia/ui",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Pantoia
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"description": "Pantoia Design System",
|
|
5
5
|
"homepage": "https://design.pantoia.com",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
@@ -20,14 +20,18 @@
|
|
|
20
20
|
"dist",
|
|
21
21
|
"tv.ts",
|
|
22
22
|
"test-utils.ts",
|
|
23
|
-
"
|
|
24
|
-
"
|
|
23
|
+
"tailwind.css",
|
|
24
|
+
"palette.css",
|
|
25
|
+
"tokens.css",
|
|
26
|
+
"utilities.css",
|
|
25
27
|
"registry.json"
|
|
26
28
|
],
|
|
27
29
|
"exports": {
|
|
28
30
|
"./tv": "./tv.ts",
|
|
29
|
-
"./
|
|
30
|
-
"./
|
|
31
|
+
"./tailwind.css": "./tailwind.css",
|
|
32
|
+
"./palette.css": "./palette.css",
|
|
33
|
+
"./tokens.css": "./tokens.css",
|
|
34
|
+
"./utilities.css": "./utilities.css",
|
|
31
35
|
"./registry.json": "./registry.json",
|
|
32
36
|
"./test-utils": "./test-utils.ts",
|
|
33
37
|
"./*": "./*/index.tsx"
|
|
@@ -39,17 +43,13 @@
|
|
|
39
43
|
"access": "public"
|
|
40
44
|
},
|
|
41
45
|
"engines": {
|
|
42
|
-
"node": ">=
|
|
46
|
+
"node": ">=20.11"
|
|
43
47
|
},
|
|
44
48
|
"scripts": {
|
|
45
49
|
"prepack": "tsc cli/index.ts --ignoreConfig --outDir dist --target es2022 --module esnext --moduleResolution bundler --skipLibCheck --types node",
|
|
46
|
-
"lint": "eslint . --max-warnings 0",
|
|
47
50
|
"typecheck": "tsc --noEmit"
|
|
48
51
|
},
|
|
49
52
|
"dependencies": {
|
|
50
|
-
"@fontsource/jetbrains-mono": "5.3.0",
|
|
51
|
-
"lucide-react": "^1.39.0",
|
|
52
|
-
"pretendard": "1.3.9",
|
|
53
53
|
"radix-ui": "^1.6.7",
|
|
54
54
|
"sonner": "^2.0.8",
|
|
55
55
|
"tailwind-variants": "^3.3.1"
|
|
@@ -57,17 +57,15 @@
|
|
|
57
57
|
"peerDependencies": {
|
|
58
58
|
"react": "^19",
|
|
59
59
|
"react-dom": "^19",
|
|
60
|
-
"tailwindcss": "^4.
|
|
60
|
+
"tailwindcss": "^4.0.0"
|
|
61
61
|
},
|
|
62
62
|
"devDependencies": {
|
|
63
|
-
"@pantoia/eslint-config": "*",
|
|
64
63
|
"@pantoia/typescript-config": "*",
|
|
65
64
|
"@types/node": "26.4.0",
|
|
66
65
|
"@types/react": "19.2.18",
|
|
67
66
|
"@types/react-dom": "19.2.5",
|
|
68
|
-
"eslint": "10.9.1",
|
|
69
67
|
"react": "19.2.8",
|
|
70
68
|
"react-dom": "19.2.8",
|
|
71
|
-
"typescript": "
|
|
69
|
+
"typescript": "7.0.2"
|
|
72
70
|
}
|
|
73
71
|
}
|
package/palette.css
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
:root, .light {
|
|
2
|
+
--pds-gray-50:#f9fafb; --pds-gray-100:#f2f4f6; --pds-gray-200:#e5e8eb; --pds-gray-300:#d1d6db;
|
|
3
|
+
--pds-gray-400:#b0b8c1; --pds-gray-500:#8b95a1; --pds-gray-600:#6b7684; --pds-gray-700:#4e5968;
|
|
4
|
+
--pds-gray-800:#333d4b; --pds-gray-900:#191f28;
|
|
5
|
+
|
|
6
|
+
--pds-brand-50:#f5f1fd; --pds-brand-100:#e4d6ff; --pds-brand-200:#ceb0ff; --pds-brand-300:#bb8ffa;
|
|
7
|
+
--pds-brand-400:#aa74f2; --pds-brand-500:#9c63e4; --pds-brand-600:#8750c9; --pds-brand-700:#7543b0;
|
|
8
|
+
--pds-brand-800:#633997; --pds-brand-900:#54317f;
|
|
9
|
+
|
|
10
|
+
--pds-blue-50:#e8f3ff; --pds-blue-100:#c9e2ff; --pds-blue-200:#90c2ff; --pds-blue-300:#64a8ff;
|
|
11
|
+
--pds-blue-400:#4593fc; --pds-blue-500:#3182f6; --pds-blue-600:#2272eb; --pds-blue-700:#1b64da;
|
|
12
|
+
--pds-blue-800:#1957c2; --pds-blue-900:#194aa6;
|
|
13
|
+
|
|
14
|
+
--pds-green-50:#f0faf6; --pds-green-100:#aeefd5; --pds-green-200:#76e4b8; --pds-green-300:#3fd599;
|
|
15
|
+
--pds-green-400:#15c47e; --pds-green-500:#03b26c; --pds-green-600:#02a262; --pds-green-700:#029359;
|
|
16
|
+
--pds-green-800:#028450; --pds-green-900:#027648;
|
|
17
|
+
|
|
18
|
+
--pds-orange-50:#fff3e0; --pds-orange-100:#ffe0b0; --pds-orange-200:#ffcd80; --pds-orange-300:#ffbd51;
|
|
19
|
+
--pds-orange-400:#ffa927; --pds-orange-500:#fe9800; --pds-orange-600:#fb8800; --pds-orange-700:#f57800;
|
|
20
|
+
--pds-orange-800:#ed6700; --pds-orange-900:#e45600;
|
|
21
|
+
|
|
22
|
+
--pds-red-50:#ffeeee; --pds-red-100:#ffd4d6; --pds-red-200:#feafb4; --pds-red-300:#fb8890;
|
|
23
|
+
--pds-red-400:#f66570; --pds-red-500:#f04452; --pds-red-600:#e42939; --pds-red-700:#d22030;
|
|
24
|
+
--pds-red-800:#bc1b2a; --pds-red-900:#a51926;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.dark {
|
|
28
|
+
--pds-gray-50:#202027; --pds-gray-100:#2c2c35; --pds-gray-200:#3c3c47; --pds-gray-300:#4d4d59;
|
|
29
|
+
--pds-gray-400:#62626d; --pds-gray-500:#7e7e87; --pds-gray-600:#9e9ea4; --pds-gray-700:#c3c3c6;
|
|
30
|
+
--pds-gray-800:#e4e4e5; --pds-gray-900:#ffffff;
|
|
31
|
+
|
|
32
|
+
--pds-brand-50:#362949; --pds-brand-100:#462e66; --pds-brand-200:#583682; --pds-brand-300:#6b3fa0;
|
|
33
|
+
--pds-brand-400:#8451c4; --pds-brand-500:#9c63e4; --pds-brand-600:#ad75f7; --pds-brand-700:#c094ff;
|
|
34
|
+
--pds-brand-800:#d6baff; --pds-brand-900:#eadeff;
|
|
35
|
+
|
|
36
|
+
--pds-blue-50:#202c4d; --pds-blue-100:#23386a; --pds-blue-200:#25478c; --pds-blue-300:#265ab3;
|
|
37
|
+
--pds-blue-400:#2970d9; --pds-blue-500:#3485fa; --pds-blue-600:#449bff; --pds-blue-700:#61b0ff;
|
|
38
|
+
--pds-blue-800:#8fcdff; --pds-blue-900:#c8e7ff;
|
|
39
|
+
|
|
40
|
+
--pds-green-50:#153729; --pds-green-100:#135338; --pds-green-200:#136d47; --pds-green-300:#138a59;
|
|
41
|
+
--pds-green-400:#13a065; --pds-green-500:#16bb76; --pds-green-600:#26cf88; --pds-green-700:#4ee4a6;
|
|
42
|
+
--pds-green-800:#82f6c5; --pds-green-900:#ccffea;
|
|
43
|
+
|
|
44
|
+
--pds-orange-50:#3d2500; --pds-orange-100:#563200; --pds-orange-200:#804600; --pds-orange-300:#a85f00;
|
|
45
|
+
--pds-orange-400:#cf7200; --pds-orange-500:#f18600; --pds-orange-600:#fd9528; --pds-orange-700:#ffa861;
|
|
46
|
+
--pds-orange-800:#ffc39e; --pds-orange-900:#ffe4d6;
|
|
47
|
+
|
|
48
|
+
--pds-red-50:#3c2020; --pds-red-100:#562025; --pds-red-200:#7a242d; --pds-red-300:#9e2733;
|
|
49
|
+
--pds-red-400:#ca2f3d; --pds-red-500:#f04251; --pds-red-600:#fa616d; --pds-red-700:#fe818b;
|
|
50
|
+
--pds-red-800:#ffa8ad; --pds-red-900:#ffd1d3;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
@theme inline {
|
|
54
|
+
--color-pds-gray-50: var(--pds-gray-50);
|
|
55
|
+
--color-pds-gray-100: var(--pds-gray-100);
|
|
56
|
+
--color-pds-gray-200: var(--pds-gray-200);
|
|
57
|
+
--color-pds-gray-300: var(--pds-gray-300);
|
|
58
|
+
--color-pds-gray-400: var(--pds-gray-400);
|
|
59
|
+
--color-pds-gray-500: var(--pds-gray-500);
|
|
60
|
+
--color-pds-gray-600: var(--pds-gray-600);
|
|
61
|
+
--color-pds-gray-700: var(--pds-gray-700);
|
|
62
|
+
--color-pds-gray-800: var(--pds-gray-800);
|
|
63
|
+
--color-pds-gray-900: var(--pds-gray-900);
|
|
64
|
+
--color-pds-brand-50: var(--pds-brand-50);
|
|
65
|
+
--color-pds-brand-100: var(--pds-brand-100);
|
|
66
|
+
--color-pds-brand-200: var(--pds-brand-200);
|
|
67
|
+
--color-pds-brand-300: var(--pds-brand-300);
|
|
68
|
+
--color-pds-brand-400: var(--pds-brand-400);
|
|
69
|
+
--color-pds-brand-500: var(--pds-brand-500);
|
|
70
|
+
--color-pds-brand-600: var(--pds-brand-600);
|
|
71
|
+
--color-pds-brand-700: var(--pds-brand-700);
|
|
72
|
+
--color-pds-brand-800: var(--pds-brand-800);
|
|
73
|
+
--color-pds-brand-900: var(--pds-brand-900);
|
|
74
|
+
--color-pds-blue-50: var(--pds-blue-50);
|
|
75
|
+
--color-pds-blue-100: var(--pds-blue-100);
|
|
76
|
+
--color-pds-blue-200: var(--pds-blue-200);
|
|
77
|
+
--color-pds-blue-300: var(--pds-blue-300);
|
|
78
|
+
--color-pds-blue-400: var(--pds-blue-400);
|
|
79
|
+
--color-pds-blue-500: var(--pds-blue-500);
|
|
80
|
+
--color-pds-blue-600: var(--pds-blue-600);
|
|
81
|
+
--color-pds-blue-700: var(--pds-blue-700);
|
|
82
|
+
--color-pds-blue-800: var(--pds-blue-800);
|
|
83
|
+
--color-pds-blue-900: var(--pds-blue-900);
|
|
84
|
+
--color-pds-green-50: var(--pds-green-50);
|
|
85
|
+
--color-pds-green-100: var(--pds-green-100);
|
|
86
|
+
--color-pds-green-200: var(--pds-green-200);
|
|
87
|
+
--color-pds-green-300: var(--pds-green-300);
|
|
88
|
+
--color-pds-green-400: var(--pds-green-400);
|
|
89
|
+
--color-pds-green-500: var(--pds-green-500);
|
|
90
|
+
--color-pds-green-600: var(--pds-green-600);
|
|
91
|
+
--color-pds-green-700: var(--pds-green-700);
|
|
92
|
+
--color-pds-green-800: var(--pds-green-800);
|
|
93
|
+
--color-pds-green-900: var(--pds-green-900);
|
|
94
|
+
--color-pds-orange-50: var(--pds-orange-50);
|
|
95
|
+
--color-pds-orange-100: var(--pds-orange-100);
|
|
96
|
+
--color-pds-orange-200: var(--pds-orange-200);
|
|
97
|
+
--color-pds-orange-300: var(--pds-orange-300);
|
|
98
|
+
--color-pds-orange-400: var(--pds-orange-400);
|
|
99
|
+
--color-pds-orange-500: var(--pds-orange-500);
|
|
100
|
+
--color-pds-orange-600: var(--pds-orange-600);
|
|
101
|
+
--color-pds-orange-700: var(--pds-orange-700);
|
|
102
|
+
--color-pds-orange-800: var(--pds-orange-800);
|
|
103
|
+
--color-pds-orange-900: var(--pds-orange-900);
|
|
104
|
+
--color-pds-red-50: var(--pds-red-50);
|
|
105
|
+
--color-pds-red-100: var(--pds-red-100);
|
|
106
|
+
--color-pds-red-200: var(--pds-red-200);
|
|
107
|
+
--color-pds-red-300: var(--pds-red-300);
|
|
108
|
+
--color-pds-red-400: var(--pds-red-400);
|
|
109
|
+
--color-pds-red-500: var(--pds-red-500);
|
|
110
|
+
--color-pds-red-600: var(--pds-red-600);
|
|
111
|
+
--color-pds-red-700: var(--pds-red-700);
|
|
112
|
+
--color-pds-red-800: var(--pds-red-800);
|
|
113
|
+
--color-pds-red-900: var(--pds-red-900);
|
|
114
|
+
}
|
package/popover/AGENTS.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
```
|
|
4
4
|
받기 npx @pantoia/ui add popover
|
|
5
5
|
층 ui
|
|
6
|
-
파일 popover/index.tsx
|
|
6
|
+
파일 popover/index.tsx, popover/AGENTS.md
|
|
7
7
|
```
|
|
8
8
|
|
|
9
9
|
## 부위
|
|
@@ -11,9 +11,9 @@
|
|
|
11
11
|
| 이름 | props |
|
|
12
12
|
|---|---|
|
|
13
13
|
| `Popover` | `PopoverProps` |
|
|
14
|
-
| `PopoverTrigger` |
|
|
15
|
-
| `PopoverAnchor` |
|
|
16
|
-
| `PopoverClose` |
|
|
14
|
+
| `PopoverTrigger` | - |
|
|
15
|
+
| `PopoverAnchor` | - |
|
|
16
|
+
| `PopoverClose` | - |
|
|
17
17
|
| `PopoverContent` | `PopoverContentProps` |
|
|
18
18
|
|
|
19
19
|
### `PopoverTrigger`
|
package/popover/index.tsx
CHANGED
|
@@ -38,6 +38,12 @@ export interface PopoverContentProps extends Omit<ComponentProps<typeof PopoverP
|
|
|
38
38
|
arrow?: boolean
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
+
const popoverContent = tv({
|
|
42
|
+
base: 'float text-fg rounded-r16 z-overlay p-4'
|
|
43
|
+
+ ' open:animate-enter closed:animate-exit'
|
|
44
|
+
+ ' focus-visible:outline-none',
|
|
45
|
+
})
|
|
46
|
+
|
|
41
47
|
export function PopoverContent({
|
|
42
48
|
side = 'bottom',
|
|
43
49
|
align = 'center',
|
|
@@ -54,12 +60,16 @@ export function PopoverContent({
|
|
|
54
60
|
align={align}
|
|
55
61
|
sideOffset={8}
|
|
56
62
|
arrowPadding={16}
|
|
57
|
-
className={
|
|
58
|
-
+ ' open:animate-enter closed:animate-exit'
|
|
59
|
-
+ ' focus-visible:outline-none' })({ className })}
|
|
63
|
+
className={popoverContent({ className })}
|
|
60
64
|
>
|
|
61
65
|
{children}
|
|
62
|
-
{arrow &&
|
|
66
|
+
{arrow && (
|
|
67
|
+
<PopoverPrimitive.Arrow asChild width={12} height={6}>
|
|
68
|
+
<svg viewBox="0 0 12 6" preserveAspectRatio="none" className="fill-bg-panel -translate-y-px">
|
|
69
|
+
<path d="M0 0L4.58579 4.58579C5.36683 5.36683 6.63316 5.36684 7.41421 4.58579L12 0" className="stroke-line stroke-1" />
|
|
70
|
+
</svg>
|
|
71
|
+
</PopoverPrimitive.Arrow>
|
|
72
|
+
)}
|
|
63
73
|
</PopoverPrimitive.Content>
|
|
64
74
|
</PopoverPrimitive.Portal>
|
|
65
75
|
)
|