@pantoia/ui 0.14.1 → 0.15.1
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/package.json +1 -1
- package/palette.css +6 -6
- package/registry.json +4 -0
- package/segmented-control/index.module.css +19 -0
- package/segmented-control/index.tsx +41 -5
- package/tabs/index.tsx +1 -1
package/package.json
CHANGED
package/palette.css
CHANGED
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
--pds-gray-400:#b0b8c1; --pds-gray-500:#8b95a1; --pds-gray-600:#6b7684; --pds-gray-700:#4e5968;
|
|
4
4
|
--pds-gray-800:#333d4b; --pds-gray-900:#191f28;
|
|
5
5
|
|
|
6
|
-
--pds-brand-50:#
|
|
7
|
-
--pds-brand-400:#
|
|
8
|
-
--pds-brand-800:#
|
|
6
|
+
--pds-brand-50:#e5f9f3; --pds-brand-100:#b7e5d8; --pds-brand-200:#84cfbc; --pds-brand-300:#6eb2a1;
|
|
7
|
+
--pds-brand-400:#43a18d; --pds-brand-500:#01937c; --pds-brand-600:#008671; --pds-brand-700:#017b67;
|
|
8
|
+
--pds-brand-800:#036e5d; --pds-brand-900:#036252;
|
|
9
9
|
|
|
10
10
|
--pds-blue-50:#e8f3ff; --pds-blue-100:#c9e2ff; --pds-blue-200:#90c2ff; --pds-blue-300:#64a8ff;
|
|
11
11
|
--pds-blue-400:#4593fc; --pds-blue-500:#3182f6; --pds-blue-600:#2272eb; --pds-blue-700:#1b64da;
|
|
@@ -29,9 +29,9 @@
|
|
|
29
29
|
--pds-gray-400:#62626d; --pds-gray-500:#7e7e87; --pds-gray-600:#9e9ea4; --pds-gray-700:#c3c3c6;
|
|
30
30
|
--pds-gray-800:#e4e4e5; --pds-gray-900:#ffffff;
|
|
31
31
|
|
|
32
|
-
--pds-brand-50:#
|
|
33
|
-
--pds-brand-400:#
|
|
34
|
-
--pds-brand-800:#
|
|
32
|
+
--pds-brand-50:#1d3630; --pds-brand-100:#13453b; --pds-brand-200:#065547; --pds-brand-300:#036555;
|
|
33
|
+
--pds-brand-400:#037d69; --pds-brand-500:#01937c; --pds-brand-600:#41a48f; --pds-brand-700:#6abba8;
|
|
34
|
+
--pds-brand-800:#9bd1c3; --pds-brand-900:#d7eae4;
|
|
35
35
|
|
|
36
36
|
--pds-blue-50:#202c4d; --pds-blue-100:#23386a; --pds-blue-200:#25478c; --pds-blue-300:#265ab3;
|
|
37
37
|
--pds-blue-400:#2970d9; --pds-blue-500:#3485fa; --pds-blue-600:#449bff; --pds-blue-700:#61b0ff;
|
package/registry.json
CHANGED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
.thumb {
|
|
2
|
+
display: none;
|
|
3
|
+
position: absolute;
|
|
4
|
+
inset-block: 4px;
|
|
5
|
+
left: 0;
|
|
6
|
+
width: var(--segmented-control-width);
|
|
7
|
+
translate: var(--segmented-control-left) 0;
|
|
8
|
+
border-radius: var(--radius-r6);
|
|
9
|
+
background: var(--color-bg-neutral-thumb);
|
|
10
|
+
box-shadow: var(--shadow-s1);
|
|
11
|
+
transition: translate var(--dur-state) var(--ease-state),
|
|
12
|
+
width var(--dur-state) var(--ease-state);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
[data-thumb] > .thumb { display: block; }
|
|
16
|
+
|
|
17
|
+
@media (prefers-reduced-motion: reduce) {
|
|
18
|
+
.thumb { transition: none; }
|
|
19
|
+
}
|
|
@@ -2,21 +2,24 @@
|
|
|
2
2
|
|
|
3
3
|
import { Radio } from '@base-ui/react/radio'
|
|
4
4
|
import { RadioGroup } from '@base-ui/react/radio-group'
|
|
5
|
-
import { createContext, use, type ComponentProps } from 'react'
|
|
5
|
+
import { createContext, use, useLayoutEffect, useState, type ComponentProps } from 'react'
|
|
6
6
|
|
|
7
7
|
import { tv } from '../tv'
|
|
8
8
|
|
|
9
|
+
import s from './index.module.css'
|
|
10
|
+
|
|
9
11
|
type Size = 'sm' | 'md' | 'lg'
|
|
10
12
|
|
|
11
13
|
const Context = createContext<{ size: Size, fill: boolean }>({ size: 'md', fill: false })
|
|
12
14
|
|
|
13
15
|
export const segmentedControl = tv({
|
|
14
16
|
slots: {
|
|
15
|
-
root: 'bg-bg-neutral-selected rounded-r10 inline-flex shrink-0 gap-0.5 p-1',
|
|
16
|
-
item: 'text-label text-fg-muted rounded-r6 inline-flex h-full items-center justify-center gap-tight whitespace-nowrap'
|
|
17
|
+
root: 'group/segmented-control bg-bg-neutral-selected rounded-r10 relative inline-flex shrink-0 gap-0.5 p-1',
|
|
18
|
+
item: 'text-label text-fg-muted rounded-r6 relative inline-flex h-full items-center justify-center gap-tight whitespace-nowrap'
|
|
17
19
|
+ ' transition-state press-shrink cursor-pointer'
|
|
18
20
|
+ ' not-data-disabled:hover:text-fg'
|
|
19
21
|
+ ' checked:bg-bg-neutral-thumb checked:text-fg checked:shadow-s1'
|
|
22
|
+
+ ' group-data-thumb/segmented-control:checked:bg-transparent group-data-thumb/segmented-control:checked:shadow-none'
|
|
20
23
|
+ ' focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-line-focus-ring'
|
|
21
24
|
+ ' data-disabled:text-fg-disabled data-disabled:cursor-not-allowed',
|
|
22
25
|
},
|
|
@@ -42,12 +45,45 @@ export type SegmentedControlProps<Value> = Omit<ComponentProps<typeof RadioGroup
|
|
|
42
45
|
className?: string
|
|
43
46
|
}
|
|
44
47
|
|
|
45
|
-
export function SegmentedControl<Value>({ size = 'md', fill = false, className, ...rest }: SegmentedControlProps<Value>) {
|
|
48
|
+
export function SegmentedControl<Value>({ size = 'md', fill = false, className, children, ref, ...rest }: SegmentedControlProps<Value>) {
|
|
46
49
|
const ui = segmentedControl({ size, fill })
|
|
50
|
+
const [root, setRoot] = useState<HTMLDivElement | null>(null)
|
|
51
|
+
|
|
52
|
+
useLayoutEffect(() => {
|
|
53
|
+
if (!root) return
|
|
54
|
+
const place = () => {
|
|
55
|
+
const on = root.querySelector<HTMLElement>('[role="radio"][data-checked]')
|
|
56
|
+
if (!on) {
|
|
57
|
+
root.removeAttribute('data-thumb')
|
|
58
|
+
return
|
|
59
|
+
}
|
|
60
|
+
root.style.setProperty('--segmented-control-left', `${on.offsetLeft}px`)
|
|
61
|
+
root.style.setProperty('--segmented-control-width', `${on.offsetWidth}px`)
|
|
62
|
+
root.setAttribute('data-thumb', '')
|
|
63
|
+
}
|
|
64
|
+
place()
|
|
65
|
+
const resize = new ResizeObserver(place)
|
|
66
|
+
const change = new MutationObserver(place)
|
|
67
|
+
resize.observe(root)
|
|
68
|
+
change.observe(root, { subtree: true, attributeFilter: ['data-checked'] })
|
|
69
|
+
return () => {
|
|
70
|
+
resize.disconnect()
|
|
71
|
+
change.disconnect()
|
|
72
|
+
}
|
|
73
|
+
}, [root])
|
|
74
|
+
|
|
75
|
+
const attach = (el: HTMLDivElement | null) => {
|
|
76
|
+
setRoot(el)
|
|
77
|
+
if (typeof ref === 'function') ref(el)
|
|
78
|
+
else if (ref) ref.current = el
|
|
79
|
+
}
|
|
47
80
|
|
|
48
81
|
return (
|
|
49
82
|
<Context value={{ size, fill }}>
|
|
50
|
-
<RadioGroup {...rest} className={ui.root({ className })}
|
|
83
|
+
<RadioGroup {...rest} ref={attach} className={ui.root({ className })}>
|
|
84
|
+
<span aria-hidden className={s.thumb} />
|
|
85
|
+
{children}
|
|
86
|
+
</RadioGroup>
|
|
51
87
|
</Context>
|
|
52
88
|
)
|
|
53
89
|
}
|
package/tabs/index.tsx
CHANGED
|
@@ -34,7 +34,7 @@ export function TabsList({ className, children, ...rest }: TabsListProps) {
|
|
|
34
34
|
const tabsTrigger = tv({
|
|
35
35
|
base: 'text-label text-fg-muted inline-flex h-9 items-center gap-tight px-3 transition-state'
|
|
36
36
|
+ ' [&_svg]:size-4'
|
|
37
|
-
+ '
|
|
37
|
+
+ ' not-data-disabled:cursor-pointer not-data-disabled:hover:text-fg'
|
|
38
38
|
+ ' data-disabled:text-fg-disabled data-disabled:cursor-not-allowed'
|
|
39
39
|
+ ' aria-selected:text-fg'
|
|
40
40
|
+ ' focus-visible:outline-2 focus-visible:-outline-offset-2'
|