@boyernick/standard-ui-react 0.1.1-canary.2 → 0.1.1-canary.22
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 +5 -3
- package/src/accordion.tsx +1 -1
- package/src/alert-dialog.tsx +1 -1
- package/src/autocomplete.tsx +12 -11
- package/src/badge.tsx +73 -9
- package/src/brand.tsx +2 -2
- package/src/breadcrumb.tsx +38 -20
- package/src/button.tsx +2 -2
- package/src/calendar.tsx +22 -11
- package/src/card.tsx +57 -14
- package/src/carousel.tsx +163 -6
- package/src/checkbox.tsx +35 -13
- package/src/collapsible.tsx +4 -2
- package/src/combobox.tsx +13 -12
- package/src/command.tsx +38 -14
- package/src/context-menu.tsx +6 -3
- package/src/date-picker.tsx +174 -0
- package/src/dialog.tsx +33 -10
- package/src/drawer.tsx +1 -1
- package/src/empty.tsx +4 -4
- package/src/field.tsx +1 -1
- package/src/filter-group.tsx +139 -0
- package/src/icons.tsx +39 -0
- package/src/illustrations.tsx +219 -141
- package/src/image-modal.tsx +440 -49
- package/src/index.ts +188 -0
- package/src/input.tsx +1 -1
- package/src/kbd.tsx +49 -0
- package/src/lib/motion.ts +128 -18
- package/src/lib/popup.ts +45 -0
- package/src/menu.tsx +7 -4
- package/src/menubar.tsx +5 -0
- package/src/meter.tsx +1 -1
- package/src/minimap.tsx +267 -0
- package/src/navigation-menu.tsx +336 -67
- package/src/number-field.tsx +327 -61
- package/src/pagination.tsx +258 -42
- package/src/popover.tsx +3 -1
- package/src/preview-card.tsx +3 -1
- package/src/progress.tsx +6 -1
- package/src/questionnaire.tsx +279 -0
- package/src/scroll-area.tsx +1 -1
- package/src/select.tsx +8 -6
- package/src/sidebar.tsx +109 -28
- package/src/slider.tsx +64 -6
- package/src/sounds.tsx +6 -10
- package/src/spinner.tsx +105 -32
- package/src/switch.tsx +2 -2
- package/src/table.tsx +82 -15
- package/src/tabs.tsx +184 -38
- package/src/text-animate.tsx +71 -28
- package/src/textarea.tsx +1 -1
- package/src/timeline.tsx +321 -0
- package/src/toast.tsx +156 -23
- package/src/tooltip.tsx +43 -3
- package/src/video-player.tsx +296 -120
package/src/select.tsx
CHANGED
|
@@ -5,6 +5,7 @@ import type { ComponentProps } from "react"
|
|
|
5
5
|
import { IconChevronDownSmall } from "./icons"
|
|
6
6
|
import { cn } from "./lib/cn"
|
|
7
7
|
import { motion } from "./lib/motion"
|
|
8
|
+
import { popupInset, popupItem, popupLabel, popupSurface } from "./lib/popup"
|
|
8
9
|
|
|
9
10
|
export type SelectProps = ComponentProps<typeof BaseSelect.Root>
|
|
10
11
|
export type SelectTriggerProps = ComponentProps<typeof BaseSelect.Trigger>
|
|
@@ -33,7 +34,7 @@ export const SelectTrigger = ({
|
|
|
33
34
|
className={cn(
|
|
34
35
|
"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
36
|
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
|
|
37
|
+
"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
38
|
className,
|
|
38
39
|
)}
|
|
39
40
|
{...props}
|
|
@@ -71,7 +72,7 @@ export const SelectPortal = (props: SelectPortalProps) => (
|
|
|
71
72
|
|
|
72
73
|
export const SelectPositioner = ({
|
|
73
74
|
alignItemWithTrigger = false,
|
|
74
|
-
sideOffset =
|
|
75
|
+
sideOffset = 6,
|
|
75
76
|
className,
|
|
76
77
|
...props
|
|
77
78
|
}: SelectPositionerProps) => (
|
|
@@ -86,7 +87,8 @@ export const SelectPositioner = ({
|
|
|
86
87
|
export const SelectPopup = ({ className, ...props }: SelectPopupProps) => (
|
|
87
88
|
<BaseSelect.Popup
|
|
88
89
|
className={cn(
|
|
89
|
-
"z-50 max-h-[min(24rem,var(--available-height))] w-[var(--anchor-width)] overflow-hidden
|
|
90
|
+
"z-50 max-h-[min(24rem,var(--available-height))] w-[var(--anchor-width)] overflow-hidden",
|
|
91
|
+
popupSurface,
|
|
90
92
|
motion.popupAnchor,
|
|
91
93
|
className,
|
|
92
94
|
)}
|
|
@@ -96,7 +98,7 @@ export const SelectPopup = ({ className, ...props }: SelectPopupProps) => (
|
|
|
96
98
|
|
|
97
99
|
export const SelectList = ({ className, ...props }: SelectListProps) => (
|
|
98
100
|
<BaseSelect.List
|
|
99
|
-
className={cn("max-h-[inherit] overflow-y-auto
|
|
101
|
+
className={cn("max-h-[inherit] overflow-y-auto outline-none", popupInset, className)}
|
|
100
102
|
{...props}
|
|
101
103
|
/>
|
|
102
104
|
)
|
|
@@ -104,7 +106,7 @@ export const SelectList = ({ className, ...props }: SelectListProps) => (
|
|
|
104
106
|
export const SelectItem = ({ className, ...props }: SelectItemProps) => (
|
|
105
107
|
<BaseSelect.Item
|
|
106
108
|
className={cn(
|
|
107
|
-
|
|
109
|
+
popupItem,
|
|
108
110
|
motion.colors,
|
|
109
111
|
"data-disabled:cursor-not-allowed data-disabled:opacity-50 data-highlighted:bg-background-tertiary data-selected:text-fg-primary",
|
|
110
112
|
className,
|
|
@@ -145,7 +147,7 @@ export const SelectGroupLabel = ({
|
|
|
145
147
|
...props
|
|
146
148
|
}: SelectGroupLabelProps) => (
|
|
147
149
|
<BaseSelect.GroupLabel
|
|
148
|
-
className={cn(
|
|
150
|
+
className={cn(popupLabel, className)}
|
|
149
151
|
{...props}
|
|
150
152
|
/>
|
|
151
153
|
)
|
package/src/sidebar.tsx
CHANGED
|
@@ -1,56 +1,115 @@
|
|
|
1
|
-
import type
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { cva, type VariantProps } from "class-variance-authority"
|
|
2
|
+
import type { ComponentProps } from "react"
|
|
3
|
+
import { cn } from "./lib/cn"
|
|
4
|
+
import { motion } from "./lib/motion"
|
|
4
5
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
6
|
+
const sidebarVariants = cva(
|
|
7
|
+
"flex h-full shrink-0 flex-col overflow-hidden text-fg-primary",
|
|
8
|
+
{
|
|
9
|
+
variants: {
|
|
10
|
+
variant: {
|
|
11
|
+
default: "border-r border-border-primary bg-surface",
|
|
12
|
+
inset: "rounded-lg bg-background-secondary",
|
|
13
|
+
floating:
|
|
14
|
+
"rounded-xl border border-border-primary bg-surface-raised shadow-sm",
|
|
15
|
+
},
|
|
16
|
+
size: {
|
|
17
|
+
sm: "w-52",
|
|
18
|
+
md: "w-60",
|
|
19
|
+
lg: "w-72",
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
defaultVariants: {
|
|
23
|
+
variant: "default",
|
|
24
|
+
size: "md",
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
)
|
|
15
28
|
|
|
16
|
-
|
|
29
|
+
const sidebarNavItemVariants = cva(
|
|
30
|
+
"group/nav-item relative flex w-full cursor-pointer items-center gap-2 border border-transparent text-left text-fg-secondary 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 disabled:cursor-not-allowed disabled:opacity-50 [&_svg]:size-4 [&_svg]:shrink-0",
|
|
31
|
+
{
|
|
32
|
+
variants: {
|
|
33
|
+
variant: {
|
|
34
|
+
default:
|
|
35
|
+
"rounded-md hover:bg-background-tertiary hover:text-fg-primary data-[active]:bg-background-tertiary data-[active]:font-medium data-[active]:text-fg-primary",
|
|
36
|
+
pill: "rounded-full hover:bg-background-tertiary hover:text-fg-primary data-[active]:border-brand-primary-border data-[active]:bg-brand-primary data-[active]:font-medium data-[active]:text-brand-foreground",
|
|
37
|
+
indicator:
|
|
38
|
+
"rounded-md before:absolute before:inset-y-2 before:left-0 before:w-0.5 before:rounded-full before:bg-transparent before:content-[''] hover:bg-background-tertiary hover:text-fg-primary data-[active]:bg-background-tertiary data-[active]:font-medium data-[active]:text-fg-primary data-[active]:before:bg-brand-primary",
|
|
39
|
+
},
|
|
40
|
+
size: {
|
|
41
|
+
sm: "h-8 px-2.5 text-xs",
|
|
42
|
+
md: "h-9 px-3 text-sm",
|
|
43
|
+
lg: "h-10 px-3.5 text-sm",
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
defaultVariants: {
|
|
47
|
+
variant: "default",
|
|
48
|
+
size: "md",
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
export type SidebarProps = Omit<ComponentProps<"aside">, "size"> &
|
|
54
|
+
VariantProps<typeof sidebarVariants>
|
|
55
|
+
export type SidebarHeaderProps = ComponentProps<"div">
|
|
56
|
+
export type SidebarContentProps = ComponentProps<"div">
|
|
57
|
+
export type SidebarFooterProps = ComponentProps<"div">
|
|
58
|
+
export type SidebarNavProps = ComponentProps<"nav">
|
|
59
|
+
export type SidebarNavItemProps = Omit<ComponentProps<"button">, "size"> &
|
|
60
|
+
VariantProps<typeof sidebarNavItemVariants> & {
|
|
61
|
+
active?: boolean
|
|
62
|
+
}
|
|
63
|
+
export type SidebarNavItemLabelProps = ComponentProps<"span">
|
|
64
|
+
export type SidebarNavBadgeProps = ComponentProps<"span">
|
|
65
|
+
export type SidebarGroupProps = ComponentProps<"div">
|
|
66
|
+
export type SidebarGroupLabelProps = ComponentProps<"h3">
|
|
67
|
+
|
|
68
|
+
export const Sidebar = ({
|
|
69
|
+
className,
|
|
70
|
+
variant,
|
|
71
|
+
size,
|
|
72
|
+
...props
|
|
73
|
+
}: SidebarProps) => (
|
|
17
74
|
<aside
|
|
18
|
-
className={cn(
|
|
19
|
-
"flex h-full w-60 shrink-0 flex-col border-r border-border-primary bg-surface",
|
|
20
|
-
className,
|
|
21
|
-
)}
|
|
75
|
+
className={cn(sidebarVariants({ variant, size }), className)}
|
|
22
76
|
{...props}
|
|
23
77
|
/>
|
|
24
|
-
)
|
|
78
|
+
)
|
|
25
79
|
|
|
26
80
|
export const SidebarHeader = ({ className, ...props }: SidebarHeaderProps) => (
|
|
27
81
|
<div
|
|
28
82
|
className={cn("border-b border-border-primary p-4", className)}
|
|
29
83
|
{...props}
|
|
30
84
|
/>
|
|
31
|
-
)
|
|
85
|
+
)
|
|
32
86
|
|
|
33
87
|
export const SidebarContent = ({
|
|
34
88
|
className,
|
|
35
89
|
...props
|
|
36
90
|
}: SidebarContentProps) => (
|
|
37
|
-
<div
|
|
38
|
-
)
|
|
91
|
+
<div
|
|
92
|
+
className={cn("min-h-0 flex-1 overflow-y-auto p-3", className)}
|
|
93
|
+
{...props}
|
|
94
|
+
/>
|
|
95
|
+
)
|
|
39
96
|
|
|
40
97
|
export const SidebarFooter = ({ className, ...props }: SidebarFooterProps) => (
|
|
41
98
|
<div
|
|
42
99
|
className={cn("border-t border-border-primary p-3", className)}
|
|
43
100
|
{...props}
|
|
44
101
|
/>
|
|
45
|
-
)
|
|
102
|
+
)
|
|
46
103
|
|
|
47
104
|
export const SidebarNav = ({ className, ...props }: SidebarNavProps) => (
|
|
48
105
|
<nav className={cn("flex flex-col gap-1", className)} {...props} />
|
|
49
|
-
)
|
|
106
|
+
)
|
|
50
107
|
|
|
51
108
|
export const SidebarNavItem = ({
|
|
52
109
|
className,
|
|
53
110
|
active = false,
|
|
111
|
+
variant,
|
|
112
|
+
size,
|
|
54
113
|
type = "button",
|
|
55
114
|
...props
|
|
56
115
|
}: SidebarNavItemProps) => (
|
|
@@ -59,17 +118,37 @@ export const SidebarNavItem = ({
|
|
|
59
118
|
data-active={active || undefined}
|
|
60
119
|
aria-current={active ? "page" : undefined}
|
|
61
120
|
className={cn(
|
|
62
|
-
|
|
121
|
+
sidebarNavItemVariants({ variant, size }),
|
|
63
122
|
motion.colors,
|
|
64
123
|
className,
|
|
65
124
|
)}
|
|
66
125
|
{...props}
|
|
67
126
|
/>
|
|
68
|
-
)
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
export const SidebarNavItemLabel = ({
|
|
130
|
+
className,
|
|
131
|
+
...props
|
|
132
|
+
}: SidebarNavItemLabelProps) => (
|
|
133
|
+
<span className={cn("min-w-0 flex-1 truncate", className)} {...props} />
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
export const SidebarNavBadge = ({
|
|
137
|
+
className,
|
|
138
|
+
...props
|
|
139
|
+
}: SidebarNavBadgeProps) => (
|
|
140
|
+
<span
|
|
141
|
+
className={cn(
|
|
142
|
+
"text-2xs-strong ml-auto inline-flex min-w-5 shrink-0 items-center justify-center rounded-full border border-border-primary bg-surface px-1.5 py-0.5 text-fg-secondary",
|
|
143
|
+
className,
|
|
144
|
+
)}
|
|
145
|
+
{...props}
|
|
146
|
+
/>
|
|
147
|
+
)
|
|
69
148
|
|
|
70
149
|
export const SidebarGroup = ({ className, ...props }: SidebarGroupProps) => (
|
|
71
150
|
<div className={cn("flex flex-col gap-1 py-2", className)} {...props} />
|
|
72
|
-
)
|
|
151
|
+
)
|
|
73
152
|
|
|
74
153
|
export const SidebarGroupLabel = ({
|
|
75
154
|
className,
|
|
@@ -79,4 +158,6 @@ export const SidebarGroupLabel = ({
|
|
|
79
158
|
className={cn("px-3 py-1.5 text-xs-strong text-fg-tertiary", className)}
|
|
80
159
|
{...props}
|
|
81
160
|
/>
|
|
82
|
-
)
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
export { sidebarNavItemVariants, sidebarVariants }
|
package/src/slider.tsx
CHANGED
|
@@ -1,21 +1,51 @@
|
|
|
1
1
|
"use client"
|
|
2
2
|
|
|
3
3
|
import { Slider as BaseSlider } from "@base-ui/react/slider"
|
|
4
|
+
import { cva, type VariantProps } from "class-variance-authority"
|
|
4
5
|
import type { ComponentProps } from "react"
|
|
5
6
|
import { cn } from "./lib/cn"
|
|
6
7
|
|
|
7
|
-
|
|
8
|
+
const sliderVariants = cva(
|
|
9
|
+
"group/slider relative flex w-full data-disabled:opacity-50 data-[orientation=vertical]:h-48 data-[orientation=vertical]:w-fit",
|
|
10
|
+
{
|
|
11
|
+
variants: {
|
|
12
|
+
size: {
|
|
13
|
+
sm: "[--slider-thumb-size:0.875rem] [--slider-track-size:0.25rem]",
|
|
14
|
+
md: "[--slider-thumb-size:1rem] [--slider-track-size:0.375rem]",
|
|
15
|
+
lg: "[--slider-thumb-size:1.25rem] [--slider-track-size:0.5rem]",
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
defaultVariants: {
|
|
19
|
+
size: "md",
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
export type SliderProps = Omit<
|
|
25
|
+
ComponentProps<typeof BaseSlider.Root>,
|
|
26
|
+
"size"
|
|
27
|
+
> &
|
|
28
|
+
VariantProps<typeof sliderVariants>
|
|
8
29
|
export type SliderControlProps = ComponentProps<typeof BaseSlider.Control>
|
|
9
30
|
export type SliderTrackProps = ComponentProps<typeof BaseSlider.Track>
|
|
10
31
|
export type SliderIndicatorProps = ComponentProps<typeof BaseSlider.Indicator>
|
|
11
32
|
export type SliderThumbProps = ComponentProps<typeof BaseSlider.Thumb>
|
|
33
|
+
export type SliderTicksProps = ComponentProps<"div"> & {
|
|
34
|
+
/** Number of evenly spaced marks, including both ends. */
|
|
35
|
+
count?: number
|
|
36
|
+
}
|
|
12
37
|
|
|
13
|
-
export const Slider = (props: SliderProps) =>
|
|
38
|
+
export const Slider = ({ className, size, ...props }: SliderProps) => (
|
|
39
|
+
<BaseSlider.Root
|
|
40
|
+
className={cn(sliderVariants({ size }), className)}
|
|
41
|
+
{...props}
|
|
42
|
+
/>
|
|
43
|
+
)
|
|
14
44
|
|
|
15
45
|
export const SliderControl = ({ className, ...props }: SliderControlProps) => (
|
|
16
46
|
<BaseSlider.Control
|
|
17
47
|
className={cn(
|
|
18
|
-
"flex w-full touch-none items-center py-3 select-none",
|
|
48
|
+
"flex w-full touch-none items-center py-3 select-none data-disabled:cursor-not-allowed data-[orientation=vertical]:h-full data-[orientation=vertical]:w-auto data-[orientation=vertical]:px-3 data-[orientation=vertical]:py-0",
|
|
19
49
|
className,
|
|
20
50
|
)}
|
|
21
51
|
{...props}
|
|
@@ -25,7 +55,7 @@ export const SliderControl = ({ className, ...props }: SliderControlProps) => (
|
|
|
25
55
|
export const SliderTrack = ({ className, ...props }: SliderTrackProps) => (
|
|
26
56
|
<BaseSlider.Track
|
|
27
57
|
className={cn(
|
|
28
|
-
"relative h-
|
|
58
|
+
"relative h-[var(--slider-track-size)] w-full rounded-full bg-background-quaternary transition-colors duration-[var(--duration-sm)] group-hover/slider:bg-background-active data-[orientation=vertical]:h-full data-[orientation=vertical]:w-[var(--slider-track-size)]",
|
|
29
59
|
className,
|
|
30
60
|
)}
|
|
31
61
|
{...props}
|
|
@@ -38,7 +68,7 @@ export const SliderIndicator = ({
|
|
|
38
68
|
}: SliderIndicatorProps) => (
|
|
39
69
|
<BaseSlider.Indicator
|
|
40
70
|
className={cn(
|
|
41
|
-
"absolute h-full rounded-full bg-brand-primary
|
|
71
|
+
"absolute h-full rounded-full bg-brand-primary data-[orientation=vertical]:h-auto data-[orientation=vertical]:w-full",
|
|
42
72
|
className,
|
|
43
73
|
)}
|
|
44
74
|
{...props}
|
|
@@ -48,9 +78,37 @@ export const SliderIndicator = ({
|
|
|
48
78
|
export const SliderThumb = ({ className, ...props }: SliderThumbProps) => (
|
|
49
79
|
<BaseSlider.Thumb
|
|
50
80
|
className={cn(
|
|
51
|
-
"size-
|
|
81
|
+
"flex size-[var(--slider-thumb-size)] cursor-grab items-center justify-center rounded-full border border-brand-primary-border bg-surface shadow-sm outline-none transition-[scale,box-shadow,background-color,border-color] duration-[var(--duration-sm)] ease-enter after:size-1 after:rounded-full after:bg-brand-primary after:content-[''] hover:scale-110 hover:bg-background-secondary active:scale-105 data-dragging:cursor-grabbing data-dragging:scale-110 data-disabled:cursor-not-allowed data-disabled:hover:scale-100 focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-offset-1 focus-visible:ring-offset-background-primary focus-visible:ring-ring/20",
|
|
52
82
|
className,
|
|
53
83
|
)}
|
|
54
84
|
{...props}
|
|
55
85
|
/>
|
|
56
86
|
)
|
|
87
|
+
|
|
88
|
+
export const SliderTicks = ({
|
|
89
|
+
count = 5,
|
|
90
|
+
className,
|
|
91
|
+
...props
|
|
92
|
+
}: SliderTicksProps) => {
|
|
93
|
+
const tickCount = Number.isFinite(count) ? Math.max(2, Math.floor(count)) : 2
|
|
94
|
+
|
|
95
|
+
return (
|
|
96
|
+
<div
|
|
97
|
+
aria-hidden
|
|
98
|
+
className={cn(
|
|
99
|
+
"pointer-events-none absolute inset-0 flex items-center justify-between group-data-[orientation=vertical]/slider:flex-col",
|
|
100
|
+
className,
|
|
101
|
+
)}
|
|
102
|
+
{...props}
|
|
103
|
+
>
|
|
104
|
+
{Array.from({ length: tickCount }, (_, index) => (
|
|
105
|
+
<span
|
|
106
|
+
key={index}
|
|
107
|
+
className="h-2 w-px rounded-full bg-surface/70 group-data-[orientation=vertical]/slider:h-px group-data-[orientation=vertical]/slider:w-2"
|
|
108
|
+
/>
|
|
109
|
+
))}
|
|
110
|
+
</div>
|
|
111
|
+
)
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export { sliderVariants }
|
package/src/sounds.tsx
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use client"
|
|
2
2
|
|
|
3
|
+
import { IconPlay } from "@central-icons-react/round-filled-radius-2-stroke-2/IconPlay"
|
|
3
4
|
import {
|
|
4
5
|
createContext,
|
|
5
6
|
useCallback,
|
|
@@ -28,7 +29,7 @@ const SOUND_PRESETS: SoundPreset[] = [
|
|
|
28
29
|
{
|
|
29
30
|
id: "click",
|
|
30
31
|
label: "Click",
|
|
31
|
-
description: "
|
|
32
|
+
description: "Confirmation for toggles and secondary actions.",
|
|
32
33
|
play: (ctx, when, destination) => {
|
|
33
34
|
const osc = ctx.createOscillator()
|
|
34
35
|
const gain = ctx.createGain()
|
|
@@ -219,14 +220,15 @@ export const Sound = ({
|
|
|
219
220
|
>
|
|
220
221
|
<Button
|
|
221
222
|
type="button"
|
|
222
|
-
variant="
|
|
223
|
-
size="
|
|
223
|
+
variant="secondary"
|
|
224
|
+
size="md"
|
|
224
225
|
iconOnly
|
|
225
226
|
rounded
|
|
227
|
+
className="shrink-0 hover:scale-[1.04] active:scale-95"
|
|
226
228
|
aria-label={`Play ${resolvedLabel}`}
|
|
227
229
|
onClick={handlePlay}
|
|
228
230
|
>
|
|
229
|
-
<
|
|
231
|
+
<IconPlay size={12} className="size-3" aria-hidden />
|
|
230
232
|
</Button>
|
|
231
233
|
<div className="min-w-0 flex-1">
|
|
232
234
|
<p className="text-sm-strong text-fg-primary">{resolvedLabel}</p>
|
|
@@ -262,9 +264,3 @@ export const SoundToggle = ({
|
|
|
262
264
|
</Button>
|
|
263
265
|
)
|
|
264
266
|
}
|
|
265
|
-
|
|
266
|
-
const PlayIcon = () => (
|
|
267
|
-
<svg viewBox="0 0 24 24" fill="none" className="size-4" aria-hidden>
|
|
268
|
-
<path d="M9 7.5v9l8-4.5-8-4.5Z" fill="currentColor" />
|
|
269
|
-
</svg>
|
|
270
|
-
)
|
package/src/spinner.tsx
CHANGED
|
@@ -2,44 +2,117 @@ import { cva, type VariantProps } from "class-variance-authority";
|
|
|
2
2
|
import type { ComponentProps } from "react";
|
|
3
3
|
import { cn } from "./lib/cn";
|
|
4
4
|
|
|
5
|
+
const SPINNER_SPOKES = Array.from({ length: 12 }, (_, index) => index);
|
|
6
|
+
|
|
5
7
|
const spinnerVariants = cva(
|
|
6
|
-
"
|
|
7
|
-
{
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
"text-current motion-reduce:animate-none",
|
|
9
|
+
{
|
|
10
|
+
variants: {
|
|
11
|
+
variant: {
|
|
12
|
+
ring: "animate-spin",
|
|
13
|
+
arc: "animate-spin",
|
|
14
|
+
dots: "",
|
|
15
|
+
spokes: "",
|
|
16
|
+
},
|
|
17
|
+
size: {
|
|
18
|
+
sm: "size-3.5",
|
|
19
|
+
md: "size-4",
|
|
20
|
+
lg: "size-5",
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
defaultVariants: {
|
|
24
|
+
variant: "ring",
|
|
25
|
+
size: "md",
|
|
12
26
|
},
|
|
13
27
|
},
|
|
14
|
-
|
|
15
|
-
size: "md",
|
|
16
|
-
},
|
|
17
|
-
});
|
|
28
|
+
);
|
|
18
29
|
|
|
19
30
|
export type SpinnerProps = ComponentProps<"svg"> &
|
|
20
31
|
VariantProps<typeof spinnerVariants>;
|
|
21
32
|
|
|
22
|
-
export const Spinner = ({
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
<
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
33
|
+
export const Spinner = ({
|
|
34
|
+
className,
|
|
35
|
+
variant,
|
|
36
|
+
size,
|
|
37
|
+
...props
|
|
38
|
+
}: SpinnerProps) => {
|
|
39
|
+
const resolvedVariant = variant ?? "ring";
|
|
40
|
+
|
|
41
|
+
return (
|
|
42
|
+
<svg
|
|
43
|
+
role="status"
|
|
44
|
+
aria-label="Loading"
|
|
45
|
+
className={cn(
|
|
46
|
+
spinnerVariants({ variant: resolvedVariant, size }),
|
|
47
|
+
className,
|
|
48
|
+
)}
|
|
49
|
+
viewBox="0 0 24 24"
|
|
50
|
+
fill="none"
|
|
51
|
+
{...props}
|
|
52
|
+
>
|
|
53
|
+
{resolvedVariant === "spokes" ? (
|
|
54
|
+
<g stroke="currentColor" strokeWidth="2.25" strokeLinecap="round">
|
|
55
|
+
{SPINNER_SPOKES.map((spoke) => (
|
|
56
|
+
<line
|
|
57
|
+
key={spoke}
|
|
58
|
+
x1="12"
|
|
59
|
+
y1="3"
|
|
60
|
+
x2="12"
|
|
61
|
+
y2="6.25"
|
|
62
|
+
transform={`rotate(${spoke * 30} 12 12)`}
|
|
63
|
+
className="animate-[spinner-spoke_1.2s_linear_infinite] motion-reduce:animate-none motion-reduce:opacity-40"
|
|
64
|
+
style={{ animationDelay: `${spoke * -0.1}s` }}
|
|
65
|
+
/>
|
|
66
|
+
))}
|
|
67
|
+
</g>
|
|
68
|
+
) : resolvedVariant === "dots" ? (
|
|
69
|
+
<g fill="currentColor">
|
|
70
|
+
<circle
|
|
71
|
+
cx="5"
|
|
72
|
+
cy="12"
|
|
73
|
+
r="2.25"
|
|
74
|
+
className="animate-[spinner-dot_1.2s_var(--ease-passive)_infinite] [animation-delay:-0.32s] motion-reduce:animate-none"
|
|
75
|
+
/>
|
|
76
|
+
<circle
|
|
77
|
+
cx="12"
|
|
78
|
+
cy="12"
|
|
79
|
+
r="2.25"
|
|
80
|
+
className="animate-[spinner-dot_1.2s_var(--ease-passive)_infinite] [animation-delay:-0.16s] motion-reduce:animate-none"
|
|
81
|
+
/>
|
|
82
|
+
<circle
|
|
83
|
+
cx="19"
|
|
84
|
+
cy="12"
|
|
85
|
+
r="2.25"
|
|
86
|
+
className="animate-[spinner-dot_1.2s_var(--ease-passive)_infinite] motion-reduce:animate-none"
|
|
87
|
+
/>
|
|
88
|
+
</g>
|
|
89
|
+
) : resolvedVariant === "arc" ? (
|
|
90
|
+
<circle
|
|
91
|
+
cx="12"
|
|
92
|
+
cy="12"
|
|
93
|
+
r="9"
|
|
94
|
+
stroke="currentColor"
|
|
95
|
+
strokeWidth="2.5"
|
|
96
|
+
strokeLinecap="round"
|
|
97
|
+
strokeDasharray="42 15"
|
|
98
|
+
/>
|
|
99
|
+
) : (
|
|
100
|
+
<>
|
|
101
|
+
<path
|
|
102
|
+
d="M21 12C21 16.9706 16.9706 21 12 21C7.02944 21 3 16.9706 3 12C3 7.02944 7.02944 3 12 3C16.9706 3 21 7.02944 21 12Z"
|
|
103
|
+
stroke="currentColor"
|
|
104
|
+
strokeOpacity="0.3"
|
|
105
|
+
strokeWidth="2"
|
|
106
|
+
/>
|
|
107
|
+
<path
|
|
108
|
+
d="M21 12C21 16.9706 16.9706 21 12 21"
|
|
109
|
+
stroke="currentColor"
|
|
110
|
+
strokeWidth="2"
|
|
111
|
+
/>
|
|
112
|
+
</>
|
|
113
|
+
)}
|
|
114
|
+
</svg>
|
|
115
|
+
);
|
|
116
|
+
};
|
|
44
117
|
|
|
45
118
|
export { spinnerVariants };
|
package/src/switch.tsx
CHANGED
|
@@ -9,11 +9,11 @@ export type SwitchProps = ComponentProps<typeof BaseSwitch.Root>
|
|
|
9
9
|
export const Switch = ({ className, ...props }: SwitchProps) => (
|
|
10
10
|
<BaseSwitch.Root
|
|
11
11
|
className={cn(
|
|
12
|
-
"relative inline-flex h-6 w-10 shrink-0 items-center rounded-full bg-background-quaternary transition-colors duration-
|
|
12
|
+
"relative inline-flex h-6 w-10 shrink-0 items-center rounded-full bg-background-quaternary transition-colors duration-[var(--duration-sm)] ease-enter motion-reduce:transition-none 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-checked:bg-brand-primary data-disabled:cursor-not-allowed data-disabled:opacity-50",
|
|
13
13
|
className,
|
|
14
14
|
)}
|
|
15
15
|
{...props}
|
|
16
16
|
>
|
|
17
|
-
<BaseSwitch.Thumb className="pointer-events-none block size-5 translate-x-0.5 rounded-full bg-surface shadow-sm transition-transform duration-
|
|
17
|
+
<BaseSwitch.Thumb className="pointer-events-none block size-5 translate-x-0.5 rounded-full bg-surface shadow-sm transition-transform duration-[var(--duration-sm)] ease-enter motion-reduce:transition-none data-checked:translate-x-[1.125rem]" />
|
|
18
18
|
</BaseSwitch.Root>
|
|
19
19
|
)
|