@boyernick/standard-ui-react 0.1.1-canary.2 → 0.1.1-canary.3

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@boyernick/standard-ui-react",
3
- "version": "0.1.1-canary.2",
3
+ "version": "0.1.1-canary.3",
4
4
  "description": "React components for StandardUI",
5
5
  "license": "MIT",
6
6
  "type": "module",
package/src/accordion.tsx CHANGED
@@ -79,6 +79,6 @@ export const AccordionPanel = ({
79
79
  )}
80
80
  {...props}
81
81
  >
82
- <div className="px-4 pt-0 pb-4 leading-relaxed">{children}</div>
82
+ <div className="px-4 pt-2 pb-4 leading-relaxed">{children}</div>
83
83
  </BaseAccordion.Panel>
84
84
  )
@@ -66,8 +66,7 @@ export const AutocompleteInputGroup = ({
66
66
  }: AutocompleteInputGroupProps) => (
67
67
  <BaseAutocomplete.InputGroup
68
68
  className={cn(
69
- "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]",
70
- "has-[[data-popup-open]]:bg-background-tertiary/60",
69
+ "relative flex min-h-9 w-full items-center rounded-xl border border-border-secondary bg-surface inset-shadow-outline-top outline-none transition-[color,box-shadow]",
71
70
  "focus-within:border-ring focus-within:ring-[3px] focus-within:ring-offset-1 focus-within:ring-offset-background-primary focus-within:ring-ring/20",
72
71
  "aria-invalid:border-destructive aria-invalid:focus-within:border-destructive aria-invalid:focus-within:ring-destructive/20",
73
72
  "has-[[aria-invalid=true]]:border-destructive has-[[aria-invalid=true]]:focus-within:border-destructive has-[[aria-invalid=true]]:focus-within:ring-destructive/20",
@@ -84,7 +83,7 @@ export const AutocompleteInput = ({
84
83
  }: AutocompleteInputProps) => (
85
84
  <BaseAutocomplete.Input
86
85
  className={cn(
87
- "h-9 min-w-0 flex-1 cursor-text rounded-md bg-transparent px-3 text-sm text-fg-primary outline-none placeholder:text-fg-quaternary focus-visible:ring-0",
86
+ "h-9 min-w-0 flex-1 cursor-text rounded-xl bg-transparent px-3 text-sm text-fg-primary outline-none placeholder:text-fg-quaternary focus-visible:ring-0",
88
87
  className,
89
88
  )}
90
89
  {...props}
@@ -134,7 +133,7 @@ export const AutocompleteClear = ({
134
133
  {...props}
135
134
  >
136
135
  {children ?? (
137
- <IconCrossSmall size={14} className="size-3.5" aria-hidden />
136
+ <IconCrossSmall size={16} className="size-4" aria-hidden />
138
137
  )}
139
138
  </BaseAutocomplete.Clear>
140
139
  )
@@ -151,7 +150,7 @@ export const AutocompleteBackdrop = ({
151
150
  )
152
151
 
153
152
  export const AutocompletePositioner = ({
154
- sideOffset = 4,
153
+ sideOffset = 6,
155
154
  className,
156
155
  ...props
157
156
  }: AutocompletePositionerProps) => (
@@ -168,7 +167,7 @@ export const AutocompletePopup = ({
168
167
  }: AutocompletePopupProps) => (
169
168
  <BaseAutocomplete.Popup
170
169
  className={cn(
171
- "z-50 max-h-[min(24rem,var(--available-height))] w-[var(--anchor-width)] overflow-hidden rounded-md border border-border-primary bg-surface shadow-md outline-none",
170
+ "z-50 max-h-[min(24rem,var(--available-height))] w-[var(--anchor-width)] overflow-hidden rounded-xl border border-border-primary-solid bg-surface shadow-lg outline-none",
172
171
  motion.popupAnchor,
173
172
  className,
174
173
  )}
@@ -199,7 +198,7 @@ export const AutocompleteList = ({
199
198
  ...props
200
199
  }: AutocompleteListProps) => (
201
200
  <BaseAutocomplete.List
202
- className={cn("max-h-[inherit] overflow-y-auto p-1 outline-none", className)}
201
+ className={cn("max-h-[inherit] overflow-y-auto p-1.5 outline-none empty:p-0", className)}
203
202
  {...props}
204
203
  />
205
204
  )
@@ -210,7 +209,7 @@ export const AutocompleteItem = ({
210
209
  }: AutocompleteItemProps) => (
211
210
  <BaseAutocomplete.Item
212
211
  className={cn(
213
- "flex min-h-8 cursor-default items-center gap-2 rounded-xs px-2.5 py-1.5 text-sm text-fg-primary outline-none select-none",
212
+ "flex min-h-9 cursor-default items-center gap-2 rounded-sm px-3 py-2 text-sm text-fg-primary outline-none select-none",
214
213
  motion.colors,
215
214
  "data-disabled:cursor-not-allowed data-disabled:opacity-50 data-highlighted:bg-background-tertiary data-highlighted:text-fg-primary",
216
215
  className,
@@ -224,7 +223,7 @@ export const AutocompleteEmpty = ({
224
223
  ...props
225
224
  }: AutocompleteEmptyProps) => (
226
225
  <BaseAutocomplete.Empty
227
- className={cn("px-2.5 py-2 text-sm text-fg-tertiary empty:hidden", className)}
226
+ className={cn("px-3 py-2 text-sm text-fg-tertiary empty:hidden", className)}
228
227
  {...props}
229
228
  />
230
229
  )
@@ -234,7 +233,7 @@ export const AutocompleteStatus = ({
234
233
  ...props
235
234
  }: AutocompleteStatusProps) => (
236
235
  <BaseAutocomplete.Status
237
- className={cn("px-2.5 py-2 text-sm text-fg-tertiary", className)}
236
+ className={cn("px-3 py-2 text-sm text-fg-tertiary", className)}
238
237
  {...props}
239
238
  />
240
239
  )
@@ -251,7 +250,7 @@ export const AutocompleteGroupLabel = ({
251
250
  ...props
252
251
  }: AutocompleteGroupLabelProps) => (
253
252
  <BaseAutocomplete.GroupLabel
254
- className={cn("px-2.5 py-1.5 text-xs text-fg-tertiary", className)}
253
+ className={cn("px-3 py-1.5 text-xs text-fg-tertiary", className)}
255
254
  {...props}
256
255
  />
257
256
  )
package/src/button.tsx CHANGED
@@ -3,7 +3,7 @@ import type { ButtonHTMLAttributes, ReactNode } from "react"
3
3
  import { cn } from "./lib/cn"
4
4
 
5
5
  const buttonVariants = cva(
6
- "text-sm inline-flex cursor-pointer items-center justify-center gap-1.5 whitespace-nowrap transition-all duration-150 ease-out outline-none focus-visible:ring-[3px] focus-visible:ring-offset-1 focus-visible:ring-offset-background-primary disabled:cursor-not-allowed disabled:opacity-50 disabled:active:translate-y-0 active:translate-y-px [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
6
+ "text-sm inline-flex cursor-pointer items-center justify-center gap-1.5 whitespace-nowrap transition-all duration-[var(--duration-sm)] ease-enter outline-none focus-visible:ring-[3px] focus-visible:ring-offset-1 focus-visible:ring-offset-background-primary disabled:cursor-not-allowed disabled:opacity-50 disabled:active:translate-y-0 active:translate-y-px [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
7
7
  {
8
8
  variants: {
9
9
  variant: {
package/src/checkbox.tsx CHANGED
@@ -10,7 +10,7 @@ export type CheckboxProps = ComponentProps<typeof BaseCheckbox.Root>
10
10
  export const Checkbox = ({ className, ...props }: CheckboxProps) => (
11
11
  <BaseCheckbox.Root
12
12
  className={cn(
13
- "group flex size-4 shrink-0 items-center justify-center rounded-sm border border-border-secondary bg-surface transition-colors duration-150 ease-out 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:border-brand-primary data-checked:bg-brand-primary data-indeterminate:border-brand-primary data-indeterminate:bg-brand-primary data-disabled:cursor-not-allowed data-disabled:opacity-50",
13
+ "group flex size-4 shrink-0 items-center justify-center rounded-sm border border-border-secondary bg-surface 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:border-brand-primary data-checked:bg-brand-primary data-indeterminate:border-brand-primary data-indeterminate:bg-brand-primary data-disabled:cursor-not-allowed data-disabled:opacity-50",
14
14
  className,
15
15
  )}
16
16
  {...props}
package/src/drawer.tsx CHANGED
@@ -69,7 +69,7 @@ export const DrawerPopup = ({ className, ...props }: DrawerPopupProps) => (
69
69
  <BaseDrawer.Popup
70
70
  className={cn(
71
71
  "fixed z-50 flex flex-col border-border-primary bg-surface shadow-md outline-none",
72
- "transition-[transform,opacity] duration-300 ease-[cubic-bezier(0.22,1,0.36,1)] motion-reduce:transition-none",
72
+ "transition-[transform,opacity] duration-[var(--duration-lg)] ease-move motion-reduce:transition-none",
73
73
  "data-swiping:duration-0",
74
74
  // Right panel (swipeDirection="right")
75
75
  "data-[swipe-direction=right]:top-0 data-[swipe-direction=right]:right-0 data-[swipe-direction=right]:h-full data-[swipe-direction=right]:w-full data-[swipe-direction=right]:max-w-sm data-[swipe-direction=right]:border-l",
package/src/field.tsx CHANGED
@@ -49,7 +49,7 @@ export const FieldError = ({ className, ...props }: FieldErrorProps) => (
49
49
  export const FieldControl = ({ className, ...props }: FieldControlProps) => (
50
50
  <BaseField.Control
51
51
  className={cn(
52
- "text-sm flex h-9 w-full cursor-text rounded-md border border-border-secondary bg-surface px-3 text-fg-primary inset-shadow-outline-top outline-none transition-[color,box-shadow] duration-150 ease-out placeholder:text-fg-quaternary",
52
+ "text-sm flex h-9 w-full cursor-text rounded-md border border-border-secondary bg-surface px-3 text-fg-primary inset-shadow-outline-top outline-none transition-[color,box-shadow] duration-[var(--duration-sm)] ease-enter placeholder:text-fg-quaternary",
53
53
  "focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-offset-1 focus-visible:ring-offset-background-primary focus-visible:ring-ring/20",
54
54
  "data-invalid:border-destructive data-invalid:focus-visible:border-destructive data-invalid:focus-visible:ring-destructive/20",
55
55
  "aria-invalid:border-destructive aria-invalid:focus-visible:border-destructive aria-invalid:focus-visible:ring-destructive/20",
package/src/input.tsx CHANGED
@@ -5,7 +5,7 @@ import { forwardRef, type InputHTMLAttributes } from "react"
5
5
  import { cn } from "./lib/cn"
6
6
 
7
7
  const inputVariants = cva(
8
- "text-sm flex w-full cursor-text rounded-md text-fg-primary transition-[color,box-shadow] duration-150 ease-out placeholder:text-fg-quaternary outline-none aria-invalid:border-destructive disabled:cursor-not-allowed disabled:opacity-50",
8
+ "text-sm flex w-full cursor-text rounded-md text-fg-primary transition-[color,box-shadow] duration-[var(--duration-sm)] ease-enter placeholder:text-fg-quaternary outline-none aria-invalid:border-destructive disabled:cursor-not-allowed disabled:opacity-50",
9
9
  {
10
10
  variants: {
11
11
  variant: {
package/src/lib/motion.ts CHANGED
@@ -1,23 +1,118 @@
1
1
  /**
2
2
  * Shared motion classes for StandardUI.
3
- * Prefer CSS `scale` on centered modals so `translate` centering stays intact.
4
- * Anchored popups use `transform-origin` from Base UI.
3
+ *
4
+ * Every value resolves to a token in `@boyernick/standard-ui-tokens` the
5
+ * `--ease-*` ladder and the `--duration-*` scale. Nothing here hardcodes a
6
+ * curve or a millisecond count.
7
+ *
8
+ * The easing ladder is ordered by *onset* — how quickly a transition commits:
9
+ *
10
+ * passive ambient, system-initiated (slowest onset)
11
+ * enter surfaces arriving
12
+ * move things travelling across a surface
13
+ * snap direct response to a pointer (sharpest onset)
14
+ *
15
+ * Two kinds of token live here, and they behave differently:
16
+ *
17
+ * Mount tokens — backdrop, popupCenter, popupAnchor, accordionPanel.
18
+ * These carry separate enter and exit behaviour. Base UI flags the exit
19
+ * with `data-ending-style`, and the `data-ending-style:` variants below
20
+ * re-declare duration and easing for that direction. Exits always run at
21
+ * `--duration-exit`, so dismissing anything costs the same no matter how
22
+ * long the entrance took.
23
+ *
24
+ * State tokens — tabsIndicator, colors, transform, all.
25
+ * These animate between states on a mounted element, so there is no enter
26
+ * or exit to distinguish; they take a single curve.
27
+ *
28
+ * Fades are linear on purpose. Perceived brightness is already non-linear, so
29
+ * easing an opacity change makes it look like it sticks at the end.
5
30
  */
31
+
32
+ const DURATION = {
33
+ xs: "duration-[var(--duration-xs)]",
34
+ sm: "duration-[var(--duration-sm)]",
35
+ md: "duration-[var(--duration-md)]",
36
+ lg: "duration-[var(--duration-lg)]",
37
+ } as const
38
+
39
+ /** Every exit runs at the same length — see `--duration-exit`. */
40
+ const EXIT_DURATION = "data-ending-style:duration-[var(--duration-exit)]"
41
+
42
+ const REDUCED = "motion-reduce:transition-none"
43
+
6
44
  export const motion = {
7
- backdrop:
8
- "transition-opacity duration-150 ease-out motion-reduce:transition-none data-starting-style:opacity-0 data-ending-style:opacity-0",
9
- /** Centered dialog / alert — scale property, not transform */
10
- popupCenter:
11
- "transition-[scale,opacity] duration-150 ease-out motion-reduce:transition-none data-starting-style:scale-[0.96] data-starting-style:opacity-0 data-ending-style:scale-[0.96] data-ending-style:opacity-0",
12
- /** Select, tooltip, menus — transform-origin from Base UI */
13
- popupAnchor:
14
- "origin-[var(--transform-origin)] transition-[transform,scale,opacity] duration-150 ease-out motion-reduce:transition-none data-starting-style:scale-[0.96] data-starting-style:opacity-0 data-ending-style:scale-[0.96] data-ending-style:opacity-0",
15
- accordionPanel:
16
- "transition-[height] duration-200 ease-[cubic-bezier(0.22,1,0.36,1)] motion-reduce:transition-none data-starting-style:h-0 data-ending-style:h-0",
17
- tabsIndicator:
18
- "transition-[translate,width] duration-200 ease-[cubic-bezier(0.22,1,0.36,1)] motion-reduce:transition-none",
19
- colors: "transition-colors duration-150 ease-out motion-reduce:transition-none",
20
- transform:
21
- "transition-transform duration-150 ease-out motion-reduce:transition-none",
22
- all: "transition-all duration-150 ease-out motion-reduce:transition-none",
45
+ /** Overlay scrims. Linear both ways — see the note on fades above. */
46
+ backdrop: [
47
+ "transition-opacity",
48
+ DURATION.sm,
49
+ "ease-linear",
50
+ REDUCED,
51
+ "data-starting-style:opacity-0",
52
+ "data-ending-style:opacity-0",
53
+ EXIT_DURATION,
54
+ "data-ending-style:ease-linear",
55
+ ].join(" "),
56
+
57
+ /** Centred dialog / alert — animates `scale`, so translate centring holds. */
58
+ popupCenter: [
59
+ "transition-[scale,opacity]",
60
+ DURATION.md,
61
+ "ease-enter",
62
+ REDUCED,
63
+ "data-starting-style:scale-[0.96] data-starting-style:opacity-0",
64
+ "data-ending-style:scale-[0.96] data-ending-style:opacity-0",
65
+ EXIT_DURATION,
66
+ "data-ending-style:ease-move",
67
+ ].join(" "),
68
+
69
+ /** Select, tooltip, menus — transform-origin comes from Base UI. */
70
+ popupAnchor: [
71
+ "origin-[var(--transform-origin)]",
72
+ "transition-[transform,scale,opacity]",
73
+ DURATION.sm,
74
+ "ease-enter",
75
+ REDUCED,
76
+ "data-starting-style:scale-[0.96] data-starting-style:opacity-0",
77
+ "data-ending-style:scale-[0.96] data-ending-style:opacity-0",
78
+ EXIT_DURATION,
79
+ "data-ending-style:ease-move",
80
+ ].join(" "),
81
+
82
+ /** Height expand and collapse. */
83
+ accordionPanel: [
84
+ "transition-[height]",
85
+ DURATION.md,
86
+ "ease-move",
87
+ REDUCED,
88
+ "data-starting-style:h-0",
89
+ "data-ending-style:h-0",
90
+ EXIT_DURATION,
91
+ "data-ending-style:ease-move",
92
+ ].join(" "),
93
+
94
+ /** Sliding tab underline or pill — follows a pointer, so it snaps. */
95
+ tabsIndicator: [
96
+ "transition-[translate,width]",
97
+ DURATION.md,
98
+ "ease-snap",
99
+ REDUCED,
100
+ ].join(" "),
101
+
102
+ /** Hover and pressed colour changes. */
103
+ colors: ["transition-colors", DURATION.sm, "ease-enter", REDUCED].join(" "),
104
+
105
+ /** Icon rotates and simple transforms. */
106
+ transform: [
107
+ "transition-transform",
108
+ DURATION.sm,
109
+ "ease-move",
110
+ REDUCED,
111
+ ].join(" "),
112
+
113
+ /** Every property. Reach for a narrower token first. */
114
+ all: ["transition-all", DURATION.sm, "ease-enter", REDUCED].join(" "),
115
+
116
+ /** Long, ambient movement — progress fills, meters, background shifts. */
117
+ passive: ["transition-all", DURATION.lg, "ease-passive", REDUCED].join(" "),
23
118
  } as const
package/src/meter.tsx CHANGED
@@ -53,7 +53,7 @@ export const MeterIndicator = ({
53
53
  }: MeterIndicatorProps) => (
54
54
  <BaseMeter.Indicator
55
55
  className={cn(
56
- "h-full rounded-full bg-brand-primary transition-[width] duration-300 ease-out motion-reduce:transition-none",
56
+ "h-full rounded-full bg-brand-primary transition-[width] duration-[var(--duration-lg)] ease-enter motion-reduce:transition-none",
57
57
  className,
58
58
  )}
59
59
  {...props}
@@ -101,7 +101,7 @@ export const NavigationMenuIcon = ({
101
101
  }: NavigationMenuIconProps) => (
102
102
  <BaseNavigationMenu.Icon
103
103
  className={cn(
104
- "inline-flex text-fg-tertiary transition-transform duration-150 ease-out motion-reduce:transition-none data-popup-open:rotate-180",
104
+ "inline-flex text-fg-tertiary transition-transform duration-[var(--duration-sm)] ease-enter motion-reduce:transition-none data-popup-open:rotate-180",
105
105
  className,
106
106
  )}
107
107
  {...props}
@@ -178,7 +178,7 @@ export const NavigationMenuPopup = ({
178
178
  <BaseNavigationMenu.Popup
179
179
  className={cn(
180
180
  "relative z-50 w-[var(--popup-width)] overflow-hidden rounded-xl border border-border-primary bg-surface shadow-md outline-none",
181
- "h-[var(--popup-height)] transition-[width,height,opacity] duration-200 ease-out motion-reduce:transition-none",
181
+ "h-[var(--popup-height)] transition-[width,height,opacity] duration-[var(--duration-md)] ease-enter motion-reduce:transition-none",
182
182
  "data-starting-style:opacity-0 data-ending-style:opacity-0",
183
183
  className,
184
184
  )}
package/src/progress.tsx CHANGED
@@ -52,7 +52,7 @@ export const ProgressIndicator = ({
52
52
  }: ProgressIndicatorProps) => (
53
53
  <BaseProgress.Indicator
54
54
  className={cn(
55
- "h-full rounded-full bg-brand-primary transition-[width] duration-300 ease-out motion-reduce:transition-none",
55
+ "h-full rounded-full bg-brand-primary transition-[width] duration-[var(--duration-lg)] ease-enter motion-reduce:transition-none",
56
56
  className,
57
57
  )}
58
58
  {...props}
@@ -49,7 +49,7 @@ export const ScrollAreaScrollbar = ({
49
49
  }: ScrollAreaScrollbarProps) => (
50
50
  <BaseScrollArea.Scrollbar
51
51
  className={cn(
52
- "flex touch-none p-0.5 opacity-100 transition-opacity duration-150 ease-out motion-reduce:transition-none data-[orientation=horizontal]:h-2 data-[orientation=vertical]:w-2",
52
+ "flex touch-none p-0.5 opacity-100 transition-opacity duration-[var(--duration-sm)] ease-enter motion-reduce:transition-none data-[orientation=horizontal]:h-2 data-[orientation=vertical]:w-2",
53
53
  className,
54
54
  )}
55
55
  {...props}
package/src/slider.tsx CHANGED
@@ -38,7 +38,7 @@ export const SliderIndicator = ({
38
38
  }: SliderIndicatorProps) => (
39
39
  <BaseSlider.Indicator
40
40
  className={cn(
41
- "absolute h-full rounded-full bg-brand-primary transition-[width] duration-150 ease-out motion-reduce:transition-none",
41
+ "absolute h-full rounded-full bg-brand-primary transition-[width] duration-[var(--duration-sm)] ease-enter motion-reduce:transition-none",
42
42
  className,
43
43
  )}
44
44
  {...props}
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-150 ease-out 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",
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-150 ease-out motion-reduce:transition-none data-checked:translate-x-[1.125rem]" />
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
  )
@@ -122,9 +122,9 @@ export const TextAnimate = ({
122
122
  className={cn(
123
123
  "inline-block text-fg-primary",
124
124
  effect === "fade" &&
125
- "animate-[text-fade-in_0.6s_ease-out_both] motion-reduce:animate-none",
125
+ "animate-[text-fade-in_0.6s_var(--ease-enter)_both] motion-reduce:animate-none",
126
126
  effect === "blur" &&
127
- "animate-[text-blur-in_0.7s_ease-out_both] motion-reduce:animate-none",
127
+ "animate-[text-blur-in_0.7s_var(--ease-enter)_both] motion-reduce:animate-none",
128
128
  className,
129
129
  )}
130
130
  style={{ animationDelay: `${delay}ms` }}
package/src/textarea.tsx CHANGED
@@ -3,7 +3,7 @@ import type { TextareaHTMLAttributes } from "react"
3
3
  import { cn } from "./lib/cn"
4
4
 
5
5
  const textareaVariants = cva(
6
- "flex min-h-20 w-full cursor-text resize-y rounded-md px-3 py-2 text-sm text-fg-primary transition-[color,box-shadow] duration-150 ease-out placeholder:text-fg-quaternary 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 aria-invalid:border-destructive aria-invalid:focus-visible:border-destructive aria-invalid:focus-visible:ring-destructive/20 disabled:cursor-not-allowed disabled:opacity-50",
6
+ "flex min-h-20 w-full cursor-text resize-y rounded-md px-3 py-2 text-sm text-fg-primary transition-[color,box-shadow] duration-[var(--duration-sm)] ease-enter placeholder:text-fg-quaternary 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 aria-invalid:border-destructive aria-invalid:focus-visible:border-destructive aria-invalid:focus-visible:ring-destructive/20 disabled:cursor-not-allowed disabled:opacity-50",
7
7
  {
8
8
  variants: {
9
9
  variant: {
package/src/toast.tsx CHANGED
@@ -41,7 +41,7 @@ export const ToastRoot = ({ className, ...props }: ToastRootProps) => (
41
41
  className={cn(
42
42
  "relative z-[calc(1000-var(--toast-index))] mb-2 box-border w-full rounded-xl border border-border-primary bg-surface p-4 shadow-lg outline-none",
43
43
  "h-[var(--toast-frontmost-height,var(--toast-height))]",
44
- "transition-[transform,opacity] duration-200 ease-out motion-reduce:transition-none",
44
+ "transition-[transform,opacity] duration-[var(--duration-md)] ease-enter motion-reduce:transition-none",
45
45
  "data-starting-style:opacity-0 data-starting-style:translate-y-2",
46
46
  "data-ending-style:opacity-0 data-ending-style:translate-y-2",
47
47
  "data-expanded:h-[var(--toast-height)] data-expanded:translate-y-[var(--toast-offset-y)]",
@@ -56,7 +56,7 @@ export const ToastRoot = ({ className, ...props }: ToastRootProps) => (
56
56
  export const ToastContent = ({ className, ...props }: ToastContentProps) => (
57
57
  <BaseToast.Content
58
58
  className={cn(
59
- "flex flex-col gap-1 overflow-hidden transition-opacity duration-150",
59
+ "flex flex-col gap-1 overflow-hidden transition-opacity duration-[var(--duration-sm)]",
60
60
  "data-behind:pointer-events-none data-behind:opacity-0 data-expanded:data-behind:opacity-100",
61
61
  className,
62
62
  )}