@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.
Files changed (67) hide show
  1. package/accordion/AGENTS.md +60 -0
  2. package/accordion/index.module.css +10 -0
  3. package/accordion/index.tsx +91 -0
  4. package/alert-dialog/AGENTS.md +78 -0
  5. package/alert-dialog/index.tsx +119 -0
  6. package/badge/AGENTS.md +35 -0
  7. package/badge/index.tsx +34 -0
  8. package/button/AGENTS.md +39 -0
  9. package/button/index.tsx +98 -0
  10. package/callout/AGENTS.md +42 -0
  11. package/callout/index.tsx +70 -0
  12. package/checkbox/AGENTS.md +54 -0
  13. package/checkbox/index.tsx +151 -0
  14. package/code-block/AGENTS.md +60 -0
  15. package/code-block/index.module.css +46 -0
  16. package/code-block/index.tsx +127 -0
  17. package/combobox/AGENTS.md +150 -0
  18. package/combobox/index.tsx +420 -0
  19. package/command-palette/AGENTS.md +44 -0
  20. package/command-palette/index.tsx +108 -0
  21. package/copy-button/AGENTS.md +43 -0
  22. package/copy-button/index.tsx +119 -0
  23. package/dialog/AGENTS.md +81 -0
  24. package/dialog/index.tsx +108 -0
  25. package/dist/index.js +189 -0
  26. package/drawer/AGENTS.md +66 -0
  27. package/drawer/index.module.css +17 -0
  28. package/drawer/index.tsx +198 -0
  29. package/dropdown-menu/AGENTS.md +133 -0
  30. package/dropdown-menu/index.tsx +223 -0
  31. package/field/AGENTS.md +96 -0
  32. package/field/index.tsx +149 -0
  33. package/input/AGENTS.md +35 -0
  34. package/input/index.tsx +36 -0
  35. package/kbd/AGENTS.md +17 -0
  36. package/kbd/index.tsx +13 -0
  37. package/label/AGENTS.md +21 -0
  38. package/label/index.tsx +13 -0
  39. package/number-field/AGENTS.md +53 -0
  40. package/number-field/index.tsx +227 -0
  41. package/package.json +73 -0
  42. package/popover/AGENTS.md +64 -0
  43. package/popover/index.tsx +66 -0
  44. package/press.css +37 -0
  45. package/radio-group/AGENTS.md +81 -0
  46. package/radio-group/index.tsx +139 -0
  47. package/registry.json +726 -0
  48. package/select/AGENTS.md +90 -0
  49. package/select/index.tsx +169 -0
  50. package/styles.css +347 -0
  51. package/switch/AGENTS.md +37 -0
  52. package/switch/index.tsx +42 -0
  53. package/table/AGENTS.md +82 -0
  54. package/table/index.tsx +120 -0
  55. package/tabs/AGENTS.md +60 -0
  56. package/tabs/index.module.css +14 -0
  57. package/tabs/index.tsx +105 -0
  58. package/test-utils.ts +10 -0
  59. package/textarea/AGENTS.md +35 -0
  60. package/textarea/index.tsx +37 -0
  61. package/toast/AGENTS.md +42 -0
  62. package/toast/index.tsx +71 -0
  63. package/toggle/AGENTS.md +37 -0
  64. package/toggle/index.tsx +36 -0
  65. package/tooltip/AGENTS.md +50 -0
  66. package/tooltip/index.tsx +57 -0
  67. 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
+ }