@boyernick/standard-ui-react 0.1.1-canary.4 → 0.1.1-canary.6
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/src/checkbox.tsx +35 -13
- package/src/collapsible.tsx +4 -2
- package/src/combobox.tsx +0 -1
- package/src/lib/motion.ts +16 -1
- package/src/select.tsx +1 -1
package/package.json
CHANGED
package/src/checkbox.tsx
CHANGED
|
@@ -4,28 +4,50 @@ import { Checkbox as BaseCheckbox } from "@base-ui/react/checkbox"
|
|
|
4
4
|
import type { ComponentProps } from "react"
|
|
5
5
|
import { IconCheckmark1, IconMinus } from "./icons"
|
|
6
6
|
import { cn } from "./lib/cn"
|
|
7
|
+
import { motion } from "./lib/motion"
|
|
7
8
|
|
|
8
9
|
export type CheckboxProps = ComponentProps<typeof BaseCheckbox.Root>
|
|
9
10
|
|
|
10
11
|
export const Checkbox = ({ className, ...props }: CheckboxProps) => (
|
|
11
12
|
<BaseCheckbox.Root
|
|
12
13
|
className={cn(
|
|
13
|
-
"group flex size-4 shrink-0 items-center justify-center rounded-sm border border-border-secondary bg-surface
|
|
14
|
+
"group flex size-4 shrink-0 items-center justify-center rounded-sm border border-border-secondary bg-surface outline-none",
|
|
15
|
+
// motion.all, not motion.colors: the filled state brings a box shadow
|
|
16
|
+
// with it, which has to fade in alongside the background.
|
|
17
|
+
motion.all,
|
|
18
|
+
"focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-offset-1 focus-visible:ring-offset-background-primary focus-visible:ring-ring/20",
|
|
19
|
+
// Ticked and mixed are both filled controls, so they carry the primary
|
|
20
|
+
// button's treatment: brand fill, the border token that pairs with it,
|
|
21
|
+
// and the top-edge highlight that makes a solid control read as raised.
|
|
22
|
+
"data-checked:border-brand-primary-border data-checked:bg-brand-primary data-checked:inset-shadow-solid-top",
|
|
23
|
+
"data-indeterminate:border-brand-primary-border data-indeterminate:bg-brand-primary data-indeterminate:inset-shadow-solid-top",
|
|
24
|
+
"data-checked:hover:bg-brand-primary-hover data-indeterminate:hover:bg-brand-primary-hover",
|
|
25
|
+
"data-checked:active:bg-brand-primary-active data-indeterminate:active:bg-brand-primary-active",
|
|
26
|
+
"data-disabled:cursor-not-allowed data-disabled:opacity-50",
|
|
14
27
|
className,
|
|
15
28
|
)}
|
|
16
29
|
{...props}
|
|
17
30
|
>
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
31
|
+
{/* Only the active glyph is mounted. Central Icons give every instance of
|
|
32
|
+
an icon the same mask id, so a CSS-hidden twin would claim that id for
|
|
33
|
+
the whole document; a `display: none` subtree renders no mask, leaving
|
|
34
|
+
the visible instance to paint its backing rect unmasked as a solid
|
|
35
|
+
block. Mounting one icon keeps every id in the document resolvable. */}
|
|
36
|
+
{/* No `data-unchecked:hidden` here. Base UI keeps the indicator mounted
|
|
37
|
+
through its exit and flags it with both `data-unchecked` and
|
|
38
|
+
`data-ending-style`; hiding on the former would cut the latter's
|
|
39
|
+
transition short and the mark would vanish instantly. */}
|
|
40
|
+
<BaseCheckbox.Indicator
|
|
41
|
+
className={cn("flex text-brand-foreground", motion.checkIndicator)}
|
|
42
|
+
render={(props, state) => (
|
|
43
|
+
<span {...props}>
|
|
44
|
+
{state.indeterminate ? (
|
|
45
|
+
<IconMinus size={12} className="size-3" aria-hidden />
|
|
46
|
+
) : (
|
|
47
|
+
<IconCheckmark1 size={12} className="size-3" aria-hidden />
|
|
48
|
+
)}
|
|
49
|
+
</span>
|
|
50
|
+
)}
|
|
51
|
+
/>
|
|
30
52
|
</BaseCheckbox.Root>
|
|
31
53
|
)
|
package/src/collapsible.tsx
CHANGED
|
@@ -25,7 +25,7 @@ export const CollapsibleTrigger = ({
|
|
|
25
25
|
className={cn(
|
|
26
26
|
"group flex h-9 w-full cursor-pointer items-center justify-between gap-2 rounded-md border border-border-secondary bg-surface px-3 text-sm text-fg-primary inset-shadow-outline-top outline-none",
|
|
27
27
|
motion.colors,
|
|
28
|
-
"
|
|
28
|
+
"outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-offset-1 focus-visible:ring-offset-background-primary focus-visible:ring-ring/20 data-disabled:cursor-not-allowed data-disabled:opacity-50",
|
|
29
29
|
className,
|
|
30
30
|
)}
|
|
31
31
|
{...props}
|
|
@@ -56,6 +56,8 @@ export const CollapsiblePanel = ({
|
|
|
56
56
|
)}
|
|
57
57
|
{...props}
|
|
58
58
|
>
|
|
59
|
-
|
|
59
|
+
{/* px-3 matches the trigger's own padding, so the panel copy lines up
|
|
60
|
+
under the trigger's label instead of starting at the panel edge. */}
|
|
61
|
+
<div className="px-3 pt-2 leading-relaxed">{children}</div>
|
|
60
62
|
</BaseCollapsible.Panel>
|
|
61
63
|
)
|
package/src/combobox.tsx
CHANGED
|
@@ -77,7 +77,6 @@ export const ComboboxInputGroup = ({
|
|
|
77
77
|
<BaseCombobox.InputGroup
|
|
78
78
|
className={cn(
|
|
79
79
|
"relative flex min-h-9 w-full items-center rounded-md border border-border-secondary bg-surface inset-shadow-outline-top outline-none transition-[color,box-shadow]",
|
|
80
|
-
"has-[[data-popup-open]]:bg-background-tertiary/60",
|
|
81
80
|
"focus-within:border-ring focus-within:ring-[3px] focus-within:ring-offset-1 focus-within:ring-offset-background-primary focus-within:ring-ring/20",
|
|
82
81
|
"aria-invalid:border-destructive aria-invalid:focus-within:border-destructive aria-invalid:focus-within:ring-destructive/20",
|
|
83
82
|
"has-[[aria-invalid=true]]:border-destructive has-[[aria-invalid=true]]:focus-within:border-destructive has-[[aria-invalid=true]]:focus-within:ring-destructive/20",
|
package/src/lib/motion.ts
CHANGED
|
@@ -14,7 +14,8 @@
|
|
|
14
14
|
*
|
|
15
15
|
* Two kinds of token live here, and they behave differently:
|
|
16
16
|
*
|
|
17
|
-
* Mount tokens — backdrop, popupCenter, popupAnchor, accordionPanel
|
|
17
|
+
* Mount tokens — backdrop, popupCenter, popupAnchor, accordionPanel,
|
|
18
|
+
* checkIndicator.
|
|
18
19
|
* These carry separate enter and exit behaviour. Base UI flags the exit
|
|
19
20
|
* with `data-ending-style`, and the `data-ending-style:` variants below
|
|
20
21
|
* re-declare duration and easing for that direction. Exits always run at
|
|
@@ -91,6 +92,20 @@ export const motion = {
|
|
|
91
92
|
"data-ending-style:ease-move",
|
|
92
93
|
].join(" "),
|
|
93
94
|
|
|
95
|
+
/** Check and minus glyphs mounting inside a small control. Snaps, because
|
|
96
|
+
* it answers a click directly, and scales from the centre so the mark
|
|
97
|
+
* reads as landing in the box rather than fading onto it. */
|
|
98
|
+
checkIndicator: [
|
|
99
|
+
"transition-[scale,opacity]",
|
|
100
|
+
DURATION.sm,
|
|
101
|
+
"ease-snap",
|
|
102
|
+
REDUCED,
|
|
103
|
+
"data-starting-style:scale-50 data-starting-style:opacity-0",
|
|
104
|
+
"data-ending-style:scale-50 data-ending-style:opacity-0",
|
|
105
|
+
EXIT_DURATION,
|
|
106
|
+
"data-ending-style:ease-move",
|
|
107
|
+
].join(" "),
|
|
108
|
+
|
|
94
109
|
/** Sliding tab underline or pill — follows a pointer, so it snaps. */
|
|
95
110
|
tabsIndicator: [
|
|
96
111
|
"transition-[translate,width]",
|
package/src/select.tsx
CHANGED
|
@@ -33,7 +33,7 @@ export const SelectTrigger = ({
|
|
|
33
33
|
className={cn(
|
|
34
34
|
"flex h-9 w-full cursor-pointer items-center justify-between gap-2 rounded-md border border-border-secondary bg-surface px-3 text-sm text-fg-primary inset-shadow-outline-top outline-none",
|
|
35
35
|
motion.all,
|
|
36
|
-
"focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-offset-1 focus-visible:ring-offset-background-primary focus-visible:ring-ring/20 aria-invalid:border-destructive aria-invalid:focus-visible:border-destructive aria-invalid:focus-visible:ring-destructive/20 data-disabled:cursor-not-allowed data-disabled:opacity-50 data-placeholder:text-fg-quaternary data-popup-open:border-border-secondary
|
|
36
|
+
"focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-offset-1 focus-visible:ring-offset-background-primary focus-visible:ring-ring/20 aria-invalid:border-destructive aria-invalid:focus-visible:border-destructive aria-invalid:focus-visible:ring-destructive/20 data-disabled:cursor-not-allowed data-disabled:opacity-50 data-placeholder:text-fg-quaternary data-popup-open:border-border-secondary",
|
|
37
37
|
className,
|
|
38
38
|
)}
|
|
39
39
|
{...props}
|