@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
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pantoia/ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Pantoia Design System",
|
|
5
5
|
"homepage": "https://design.pantoia.com",
|
|
6
6
|
"repository": {
|
|
@@ -16,20 +16,21 @@
|
|
|
16
16
|
"files": [
|
|
17
17
|
"*/index.tsx",
|
|
18
18
|
"*/index.module.css",
|
|
19
|
-
"*/AGENTS.md",
|
|
20
19
|
"dist",
|
|
21
20
|
"tv.ts",
|
|
22
|
-
"
|
|
23
|
-
"
|
|
24
|
-
"
|
|
21
|
+
"tailwind.css",
|
|
22
|
+
"palette.css",
|
|
23
|
+
"tokens.css",
|
|
24
|
+
"utilities.css",
|
|
25
25
|
"registry.json"
|
|
26
26
|
],
|
|
27
27
|
"exports": {
|
|
28
28
|
"./tv": "./tv.ts",
|
|
29
|
-
"./
|
|
30
|
-
"./
|
|
29
|
+
"./tailwind.css": "./tailwind.css",
|
|
30
|
+
"./palette.css": "./palette.css",
|
|
31
|
+
"./tokens.css": "./tokens.css",
|
|
32
|
+
"./utilities.css": "./utilities.css",
|
|
31
33
|
"./registry.json": "./registry.json",
|
|
32
|
-
"./test-utils": "./test-utils.ts",
|
|
33
34
|
"./*": "./*/index.tsx"
|
|
34
35
|
},
|
|
35
36
|
"sideEffects": [
|
|
@@ -39,24 +40,20 @@
|
|
|
39
40
|
"access": "public"
|
|
40
41
|
},
|
|
41
42
|
"engines": {
|
|
42
|
-
"node": ">=
|
|
43
|
+
"node": ">=20.11"
|
|
43
44
|
},
|
|
44
45
|
"scripts": {
|
|
45
46
|
"prepack": "tsc cli/index.ts --ignoreConfig --outDir dist --target es2022 --module esnext --moduleResolution bundler --skipLibCheck --types node",
|
|
46
47
|
"typecheck": "tsc --noEmit"
|
|
47
48
|
},
|
|
48
49
|
"dependencies": {
|
|
49
|
-
"@
|
|
50
|
-
"lucide-react": "^1.39.0",
|
|
51
|
-
"pretendard": "1.3.9",
|
|
52
|
-
"radix-ui": "^1.6.7",
|
|
53
|
-
"sonner": "^2.0.8",
|
|
50
|
+
"@base-ui/react": "^1.8.0",
|
|
54
51
|
"tailwind-variants": "^3.3.1"
|
|
55
52
|
},
|
|
56
53
|
"peerDependencies": {
|
|
57
54
|
"react": "^19",
|
|
58
55
|
"react-dom": "^19",
|
|
59
|
-
"tailwindcss": "^4.
|
|
56
|
+
"tailwindcss": "^4.0.0"
|
|
60
57
|
},
|
|
61
58
|
"devDependencies": {
|
|
62
59
|
"@pantoia/typescript-config": "*",
|
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/index.tsx
CHANGED
|
@@ -1,49 +1,74 @@
|
|
|
1
1
|
'use client'
|
|
2
2
|
|
|
3
|
-
import { Popover as PopoverPrimitive } from '
|
|
4
|
-
import
|
|
3
|
+
import { Popover as PopoverPrimitive } from '@base-ui/react/popover'
|
|
4
|
+
import { useRender } from '@base-ui/react/use-render'
|
|
5
|
+
import { createContext, useContext, useState } from 'react'
|
|
6
|
+
import type { ComponentProps, Dispatch, SetStateAction } from 'react'
|
|
5
7
|
|
|
6
8
|
import { tv } from '../tv'
|
|
7
9
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
type AnchorState = [Element | null, Dispatch<SetStateAction<Element | null>>]
|
|
11
|
+
|
|
12
|
+
const AnchorContext = createContext<AnchorState>([null, () => {}])
|
|
13
|
+
|
|
14
|
+
export type PopoverProps = ComponentProps<typeof PopoverPrimitive.Root>
|
|
15
|
+
|
|
16
|
+
export function Popover(props: PopoverProps) {
|
|
17
|
+
const anchor = useState<Element | null>(null)
|
|
14
18
|
|
|
15
|
-
export function Popover({ open, defaultOpen, onOpenChange, children }: PopoverProps) {
|
|
16
19
|
return (
|
|
17
|
-
<
|
|
18
|
-
{
|
|
19
|
-
</
|
|
20
|
+
<AnchorContext.Provider value={anchor}>
|
|
21
|
+
<PopoverPrimitive.Root {...props} />
|
|
22
|
+
</AnchorContext.Provider>
|
|
20
23
|
)
|
|
21
24
|
}
|
|
22
25
|
|
|
23
|
-
export
|
|
24
|
-
|
|
26
|
+
export type PopoverTriggerProps = ComponentProps<typeof PopoverPrimitive.Trigger>
|
|
27
|
+
|
|
28
|
+
export function PopoverTrigger(props: PopoverTriggerProps) {
|
|
29
|
+
return <PopoverPrimitive.Trigger {...props} />
|
|
25
30
|
}
|
|
26
31
|
|
|
27
|
-
export
|
|
28
|
-
|
|
32
|
+
export type PopoverAnchorProps = useRender.ComponentProps<'div'>
|
|
33
|
+
|
|
34
|
+
export function PopoverAnchor({ render, ref, ...rest }: PopoverAnchorProps) {
|
|
35
|
+
const [, setAnchor] = useContext(AnchorContext)
|
|
36
|
+
|
|
37
|
+
return useRender({
|
|
38
|
+
defaultTagName: 'div',
|
|
39
|
+
render,
|
|
40
|
+
ref: ref ? [setAnchor, ref] : setAnchor,
|
|
41
|
+
props: rest,
|
|
42
|
+
})
|
|
29
43
|
}
|
|
30
44
|
|
|
31
|
-
export
|
|
32
|
-
|
|
45
|
+
export type PopoverCloseProps = ComponentProps<typeof PopoverPrimitive.Close>
|
|
46
|
+
|
|
47
|
+
export function PopoverClose(props: PopoverCloseProps) {
|
|
48
|
+
return <PopoverPrimitive.Close {...props} />
|
|
33
49
|
}
|
|
34
50
|
|
|
35
|
-
export
|
|
51
|
+
export type PopoverContentProps = Omit<ComponentProps<typeof PopoverPrimitive.Popup>, 'className'> & {
|
|
36
52
|
side?: 'top' | 'right' | 'bottom' | 'left'
|
|
37
53
|
align?: 'start' | 'center' | 'end'
|
|
38
54
|
arrow?: boolean
|
|
55
|
+
className?: string
|
|
39
56
|
}
|
|
40
57
|
|
|
41
58
|
const popoverContent = tv({
|
|
42
|
-
base: 'float text-
|
|
59
|
+
base: 'float text-fg rounded-r16 z-overlay p-4'
|
|
43
60
|
+ ' open:animate-enter closed:animate-exit'
|
|
44
61
|
+ ' focus-visible:outline-none',
|
|
45
62
|
})
|
|
46
63
|
|
|
64
|
+
const popoverArrow = tv({
|
|
65
|
+
base: 'data-uncentered:invisible'
|
|
66
|
+
+ ' side-top:top-full'
|
|
67
|
+
+ ' side-bottom:bottom-full side-bottom:rotate-180'
|
|
68
|
+
+ ' side-right:left-0 side-right:origin-top-left side-right:rotate-90 side-right:-translate-y-1/2'
|
|
69
|
+
+ ' side-left:right-0 side-left:origin-top-right side-left:-rotate-90 side-left:-translate-y-1/2',
|
|
70
|
+
})
|
|
71
|
+
|
|
47
72
|
export function PopoverContent({
|
|
48
73
|
side = 'bottom',
|
|
49
74
|
align = 'center',
|
|
@@ -52,25 +77,29 @@ export function PopoverContent({
|
|
|
52
77
|
children,
|
|
53
78
|
...rest
|
|
54
79
|
}: PopoverContentProps) {
|
|
80
|
+
const [anchor] = useContext(AnchorContext)
|
|
81
|
+
|
|
55
82
|
return (
|
|
56
83
|
<PopoverPrimitive.Portal>
|
|
57
|
-
<PopoverPrimitive.
|
|
58
|
-
{
|
|
84
|
+
<PopoverPrimitive.Positioner
|
|
85
|
+
anchor={anchor ?? undefined}
|
|
59
86
|
side={side}
|
|
60
87
|
align={align}
|
|
61
|
-
sideOffset={8}
|
|
88
|
+
sideOffset={arrow ? 14 : 8}
|
|
62
89
|
arrowPadding={16}
|
|
63
|
-
className=
|
|
90
|
+
className="z-overlay min-w-max will-change-transform"
|
|
64
91
|
>
|
|
65
|
-
{
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
<
|
|
69
|
-
<
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
92
|
+
<PopoverPrimitive.Popup {...rest} className={popoverContent({ className })}>
|
|
93
|
+
{children}
|
|
94
|
+
{arrow && (
|
|
95
|
+
<PopoverPrimitive.Arrow className={popoverArrow()}>
|
|
96
|
+
<svg width={12} height={6} viewBox="0 0 12 6" preserveAspectRatio="none" className="block fill-bg-panel -translate-y-px">
|
|
97
|
+
<path d="M0 0L4.58579 4.58579C5.36683 5.36683 6.63316 5.36684 7.41421 4.58579L12 0" className="stroke-line stroke-1" />
|
|
98
|
+
</svg>
|
|
99
|
+
</PopoverPrimitive.Arrow>
|
|
100
|
+
)}
|
|
101
|
+
</PopoverPrimitive.Popup>
|
|
102
|
+
</PopoverPrimitive.Positioner>
|
|
74
103
|
</PopoverPrimitive.Portal>
|
|
75
104
|
)
|
|
76
105
|
}
|
package/radio-group/index.tsx
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
'use client'
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
3
|
+
import { Radio } from '@base-ui/react/radio'
|
|
4
|
+
import { RadioGroup as RadioGroupPrimitive } from '@base-ui/react/radio-group'
|
|
5
|
+
import { cloneElement, createContext, use, useEffect, useId, useState, type ComponentProps, type ReactElement, type ReactNode } from 'react'
|
|
5
6
|
|
|
6
7
|
import { Label } from '../label'
|
|
7
8
|
import { tv } from '../tv'
|
|
@@ -14,6 +15,7 @@ export interface RadioItemContext {
|
|
|
14
15
|
id: string
|
|
15
16
|
labelId: string
|
|
16
17
|
descriptionId: string
|
|
18
|
+
setDescribed: (described: boolean) => void
|
|
17
19
|
}
|
|
18
20
|
|
|
19
21
|
const ItemContext = createContext<RadioItemContext | null>(null)
|
|
@@ -44,69 +46,57 @@ export const radioGroupItem = tv({
|
|
|
44
46
|
defaultVariants: { color: 'neutral' },
|
|
45
47
|
})
|
|
46
48
|
|
|
47
|
-
export
|
|
48
|
-
value?: string
|
|
49
|
-
defaultValue?: string
|
|
50
|
-
onValueChange?: (value: string) => void
|
|
49
|
+
export type RadioGroupProps = Omit<RadioGroupPrimitive.Props<string>, 'className'> & {
|
|
51
50
|
color?: RadioColor
|
|
52
|
-
disabled?: boolean
|
|
53
51
|
className?: string
|
|
54
|
-
children?: ReactNode
|
|
55
52
|
}
|
|
56
53
|
|
|
57
54
|
const radioGroup = tv({ base: 'flex flex-col gap-3' })
|
|
58
55
|
|
|
59
|
-
export function RadioGroup({
|
|
60
|
-
value,
|
|
61
|
-
defaultValue,
|
|
62
|
-
onValueChange,
|
|
63
|
-
color = 'neutral',
|
|
64
|
-
disabled = false,
|
|
65
|
-
className,
|
|
66
|
-
children,
|
|
67
|
-
...rest
|
|
68
|
-
}: RadioGroupProps) {
|
|
56
|
+
export function RadioGroup({ color = 'neutral', className, ...rest }: RadioGroupProps) {
|
|
69
57
|
return (
|
|
70
58
|
<ColorContext value={color}>
|
|
71
|
-
<RadioGroupPrimitive
|
|
72
|
-
{...rest}
|
|
73
|
-
value={value}
|
|
74
|
-
defaultValue={defaultValue}
|
|
75
|
-
onValueChange={onValueChange}
|
|
76
|
-
disabled={disabled}
|
|
77
|
-
className={radioGroup({ className })}
|
|
78
|
-
>
|
|
79
|
-
{children}
|
|
80
|
-
</RadioGroupPrimitive.Root>
|
|
59
|
+
<RadioGroupPrimitive<string> {...rest} className={radioGroup({ className })} />
|
|
81
60
|
</ColorContext>
|
|
82
61
|
)
|
|
83
62
|
}
|
|
84
63
|
|
|
85
|
-
export
|
|
64
|
+
export type RadioGroupItemProps = Omit<ComponentProps<typeof Radio.Root>, 'className' | 'value'> & {
|
|
86
65
|
value: string
|
|
87
|
-
disabled?: boolean
|
|
88
66
|
className?: string
|
|
89
|
-
children?: ReactNode
|
|
90
67
|
}
|
|
91
68
|
|
|
92
|
-
export function RadioGroupItem({
|
|
69
|
+
export function RadioGroupItem({
|
|
70
|
+
value,
|
|
71
|
+
className,
|
|
72
|
+
children,
|
|
73
|
+
nativeButton = true,
|
|
74
|
+
render = <button type="button" />,
|
|
75
|
+
...rest
|
|
76
|
+
}: RadioGroupItemProps) {
|
|
93
77
|
const id = useId()
|
|
78
|
+
const [described, setDescribed] = useState(false)
|
|
94
79
|
const color = use(ColorContext)
|
|
95
80
|
const ui = radioGroupItem({ color })
|
|
81
|
+
const renderWithId: RadioGroupItemProps['render'] = typeof render === 'function'
|
|
82
|
+
? (props, state) => render({ ...props, id }, state)
|
|
83
|
+
: cloneElement(render as ReactElement<{ id?: string }>, { id })
|
|
96
84
|
|
|
97
85
|
return (
|
|
98
|
-
<ItemContext value={{ id, labelId: `${id}-label`, descriptionId: `${id}-description
|
|
86
|
+
<ItemContext value={{ id, labelId: `${id}-label`, descriptionId: `${id}-description`, setDescribed }}>
|
|
99
87
|
<div className={ui.root({ className })}>
|
|
100
|
-
<
|
|
88
|
+
<Radio.Root<string>
|
|
89
|
+
{...rest}
|
|
90
|
+
nativeButton={nativeButton}
|
|
91
|
+
render={renderWithId}
|
|
101
92
|
id={id}
|
|
102
93
|
value={value}
|
|
103
|
-
disabled={disabled}
|
|
104
94
|
aria-labelledby={`${id}-label`}
|
|
105
|
-
aria-describedby={`${id}-description`}
|
|
95
|
+
aria-describedby={described ? `${id}-description` : undefined}
|
|
106
96
|
className={ui.control()}
|
|
107
97
|
>
|
|
108
|
-
<
|
|
109
|
-
</
|
|
98
|
+
<Radio.Indicator className="text-fg-neutral-solid-contrast size-2.5 rounded-full bg-current" />
|
|
99
|
+
</Radio.Root>
|
|
110
100
|
|
|
111
101
|
<div className="flex min-w-0 flex-col gap-0.5">
|
|
112
102
|
{children}
|
|
@@ -126,10 +116,17 @@ export function RadioGroupItemLabel({ className, children }: { className?: strin
|
|
|
126
116
|
)
|
|
127
117
|
}
|
|
128
118
|
|
|
129
|
-
const radioGroupItemDescription = tv({ base: 'text-caption text-
|
|
119
|
+
const radioGroupItemDescription = tv({ base: 'text-caption text-fg-subtle' })
|
|
130
120
|
|
|
131
121
|
export function RadioGroupItemDescription({ className, children }: { className?: string, children?: ReactNode }) {
|
|
132
122
|
const ctx = use(ItemContext)
|
|
123
|
+
const setDescribed = ctx?.setDescribed
|
|
124
|
+
|
|
125
|
+
useEffect(() => {
|
|
126
|
+
if (!setDescribed) return
|
|
127
|
+
setDescribed(true)
|
|
128
|
+
return () => setDescribed(false)
|
|
129
|
+
}, [setDescribed])
|
|
133
130
|
|
|
134
131
|
return (
|
|
135
132
|
<p
|