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

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.
Files changed (89) hide show
  1. package/package.json +5 -3
  2. package/src/accordion.tsx +5 -2
  3. package/src/alert-dialog.tsx +1 -1
  4. package/src/attachment.tsx +5 -2
  5. package/src/autocomplete.tsx +12 -9
  6. package/src/badge.tsx +73 -9
  7. package/src/block-editor.tsx +1747 -0
  8. package/src/brand.tsx +2 -2
  9. package/src/breadcrumb.tsx +46 -21
  10. package/src/button.tsx +23 -12
  11. package/src/calendar.tsx +25 -11
  12. package/src/card.tsx +57 -14
  13. package/src/carousel.tsx +339 -15
  14. package/src/checkbox.tsx +36 -13
  15. package/src/code-block.tsx +66 -5
  16. package/src/collapsible.tsx +7 -3
  17. package/src/combobox.tsx +17 -15
  18. package/src/command.tsx +41 -14
  19. package/src/context-menu.tsx +6 -3
  20. package/src/date-picker.tsx +174 -0
  21. package/src/dialog.tsx +33 -10
  22. package/src/empty.tsx +4 -4
  23. package/src/field.tsx +4 -3
  24. package/src/filter-group.tsx +143 -0
  25. package/src/icons.tsx +55 -1
  26. package/src/illustrations.tsx +219 -141
  27. package/src/index.ts +263 -18
  28. package/src/input.tsx +8 -5
  29. package/src/kbd.tsx +49 -0
  30. package/src/lib/focus.ts +41 -0
  31. package/src/lib/motion.ts +16 -1
  32. package/src/lib/popup.ts +45 -0
  33. package/src/lifeline/company-icon.tsx +71 -0
  34. package/src/lifeline/index.ts +42 -0
  35. package/src/lifeline/lifeline-data.ts +97 -0
  36. package/src/lifeline/lifeline-desktop.tsx +204 -0
  37. package/src/lifeline/lifeline-event.tsx +108 -0
  38. package/src/lifeline/lifeline-fireworks.tsx +302 -0
  39. package/src/lifeline/lifeline-hover-image.tsx +269 -0
  40. package/src/lifeline/lifeline-icons.tsx +39 -0
  41. package/src/lifeline/lifeline-intro-timing.ts +105 -0
  42. package/src/lifeline/lifeline-labels.tsx +24 -0
  43. package/src/lifeline/lifeline-layout.ts +1 -0
  44. package/src/lifeline/lifeline-legend.tsx +31 -0
  45. package/src/lifeline/lifeline-lightbox.tsx +309 -0
  46. package/src/lifeline/lifeline-marker.tsx +183 -0
  47. package/src/lifeline/lifeline-people.tsx +99 -0
  48. package/src/lifeline/lifeline-photos.tsx +366 -0
  49. package/src/lifeline/lifeline-shell.tsx +135 -0
  50. package/src/lifeline/lifeline-utils.ts +83 -0
  51. package/src/lifeline/lifeline-vertical.tsx +482 -0
  52. package/src/lifeline/lifeline.tsx +69 -0
  53. package/src/lifeline/types.ts +112 -0
  54. package/src/lifeline/use-lifeline-intro.ts +130 -0
  55. package/src/lifeline/use-lifeline-scroll.ts +1011 -0
  56. package/src/lifeline/use-lifeline-vertical-scroll.ts +271 -0
  57. package/src/menu.tsx +7 -4
  58. package/src/menubar.tsx +9 -2
  59. package/src/minimap.tsx +296 -0
  60. package/src/modal.tsx +608 -0
  61. package/src/navigation-menu.tsx +340 -67
  62. package/src/number-field.tsx +336 -61
  63. package/src/otp-field.tsx +4 -3
  64. package/src/pagination.tsx +262 -42
  65. package/src/password-protection.tsx +345 -0
  66. package/src/popover.tsx +3 -1
  67. package/src/preview-card.tsx +3 -1
  68. package/src/progress.tsx +5 -0
  69. package/src/questionnaire.tsx +284 -0
  70. package/src/radio.tsx +4 -2
  71. package/src/scroll-area.tsx +4 -1
  72. package/src/select.tsx +12 -7
  73. package/src/sidebar.tsx +113 -28
  74. package/src/slider.tsx +66 -6
  75. package/src/sounds.tsx +6 -10
  76. package/src/spinner.tsx +105 -32
  77. package/src/switch.tsx +4 -1
  78. package/src/table.tsx +82 -15
  79. package/src/tabs.tsx +189 -38
  80. package/src/text-animate.tsx +71 -28
  81. package/src/textarea.tsx +6 -1
  82. package/src/timeline.tsx +378 -0
  83. package/src/toast.tsx +214 -35
  84. package/src/toggle.tsx +4 -2
  85. package/src/toolbar.tsx +12 -7
  86. package/src/tooltip.tsx +43 -3
  87. package/src/video-player.tsx +396 -127
  88. package/src/image-modal.tsx +0 -110
  89. package/src/markdown-editor.tsx +0 -302
package/src/tabs.tsx CHANGED
@@ -1,62 +1,213 @@
1
1
  "use client"
2
2
 
3
3
  import { Tabs as BaseTabs } from "@base-ui/react/tabs"
4
- import type { ComponentProps } from "react"
4
+ import { cva, type VariantProps } from "class-variance-authority"
5
+ import { createContext, type ComponentProps, useContext } from "react"
5
6
  import { cn } from "./lib/cn"
7
+ import { focusRing, focusRingBorder } from "./lib/focus"
6
8
  import { motion } from "./lib/motion"
7
9
 
8
- export type TabsProps = ComponentProps<typeof BaseTabs.Root>
9
- export type TabsListProps = ComponentProps<typeof BaseTabs.List>
10
- export type TabsTabProps = ComponentProps<typeof BaseTabs.Tab>
11
- export type TabsIndicatorProps = ComponentProps<typeof BaseTabs.Indicator>
12
- export type TabsPanelProps = ComponentProps<typeof BaseTabs.Panel>
10
+ const tabsListVariants = cva("relative flex items-center", {
11
+ variants: {
12
+ variant: {
13
+ underline:
14
+ "w-full gap-0.5 border-b border-border-primary data-[orientation=vertical]:w-40 data-[orientation=vertical]:shrink-0 data-[orientation=vertical]:flex-col data-[orientation=vertical]:items-stretch data-[orientation=vertical]:gap-0 data-[orientation=vertical]:border-r data-[orientation=vertical]:border-b-0",
15
+ segmented:
16
+ "w-fit rounded-lg bg-background-tertiary p-0.5 data-[orientation=vertical]:flex-col data-[orientation=vertical]:items-stretch",
17
+ pill: "w-fit gap-1 data-[orientation=vertical]:flex-col data-[orientation=vertical]:items-stretch",
18
+ },
19
+ },
20
+ defaultVariants: {
21
+ variant: "underline",
22
+ },
23
+ })
13
24
 
14
- export const Tabs = ({ className, ...props }: TabsProps) => (
15
- <BaseTabs.Root className={cn("flex w-full flex-col", className)} {...props} />
25
+ const tabsTabVariants = cva(
26
+ cn(
27
+ "relative z-10 inline-flex shrink-0 cursor-pointer items-center justify-center gap-1.5 whitespace-nowrap text-fg-tertiary select-none hover:text-fg-primary data-active:text-fg-primary data-disabled:cursor-not-allowed data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0",
28
+ focusRingBorder,
29
+ focusRing,
30
+ ),
31
+ {
32
+ variants: {
33
+ variant: {
34
+ underline:
35
+ "data-[orientation=horizontal]:pb-1 data-[orientation=vertical]:w-full data-[orientation=vertical]:justify-start",
36
+ segmented: "rounded-md",
37
+ pill: "rounded-full bg-background-tertiary data-active:bg-transparent",
38
+ },
39
+ size: {
40
+ sm: "text-xs [&_svg]:size-3.5",
41
+ md: "text-sm [&_svg]:size-4",
42
+ lg: "text-md [&_svg]:size-4",
43
+ },
44
+ },
45
+ compoundVariants: [
46
+ {
47
+ variant: "underline",
48
+ size: "sm",
49
+ class: "h-8 px-2.5 data-[orientation=horizontal]:h-9",
50
+ },
51
+ {
52
+ variant: "underline",
53
+ size: "md",
54
+ class: "h-10 px-3 data-[orientation=horizontal]:h-11",
55
+ },
56
+ {
57
+ variant: "underline",
58
+ size: "lg",
59
+ class: "h-12 px-3.5 data-[orientation=horizontal]:h-13",
60
+ },
61
+ { variant: "segmented", size: "sm", class: "h-7 px-2.5" },
62
+ { variant: "segmented", size: "md", class: "h-8 px-3" },
63
+ { variant: "segmented", size: "lg", class: "h-9 px-3.5" },
64
+ { variant: "pill", size: "sm", class: "h-7 px-2.5" },
65
+ { variant: "pill", size: "md", class: "h-8 px-3" },
66
+ { variant: "pill", size: "lg", class: "h-9 px-3.5" },
67
+ ],
68
+ defaultVariants: {
69
+ variant: "underline",
70
+ size: "md",
71
+ },
72
+ },
16
73
  )
17
74
 
18
- export const TabsList = ({ className, ...props }: TabsListProps) => (
19
- <BaseTabs.List
20
- className={cn(
21
- "relative flex gap-0.5 border-b border-border-primary",
22
- className,
23
- )}
24
- {...props}
25
- />
26
- )
75
+ const tabsIndicatorVariants = cva("absolute z-0", {
76
+ variants: {
77
+ variant: {
78
+ underline:
79
+ "bottom-0 left-0 h-0.5 w-(--active-tab-width) translate-x-(--active-tab-left) rounded-full bg-brand-primary data-[orientation=vertical]:top-0 data-[orientation=vertical]:right-0 data-[orientation=vertical]:bottom-auto data-[orientation=vertical]:left-auto data-[orientation=vertical]:h-(--active-tab-height) data-[orientation=vertical]:w-0.5 data-[orientation=vertical]:translate-x-0 data-[orientation=vertical]:translate-y-(--active-tab-top)",
80
+ segmented:
81
+ "inset-y-0.5 left-0 w-(--active-tab-width) translate-x-(--active-tab-left) rounded-md bg-surface-raised shadow-hairline data-[orientation=vertical]:inset-x-0.5 data-[orientation=vertical]:top-0 data-[orientation=vertical]:bottom-auto data-[orientation=vertical]:h-(--active-tab-height) data-[orientation=vertical]:w-auto data-[orientation=vertical]:translate-x-0 data-[orientation=vertical]:translate-y-(--active-tab-top)",
82
+ pill: "inset-y-0 left-0 w-(--active-tab-width) translate-x-(--active-tab-left) rounded-full bg-surface-raised shadow-hairline data-[orientation=vertical]:inset-x-0 data-[orientation=vertical]:top-0 data-[orientation=vertical]:bottom-auto data-[orientation=vertical]:h-(--active-tab-height) data-[orientation=vertical]:w-auto data-[orientation=vertical]:translate-x-0 data-[orientation=vertical]:translate-y-(--active-tab-top)",
83
+ },
84
+ },
85
+ defaultVariants: {
86
+ variant: "underline",
87
+ },
88
+ })
27
89
 
28
- export const TabsTab = ({ className, ...props }: TabsTabProps) => (
29
- <BaseTabs.Tab
30
- className={cn(
31
- "relative cursor-pointer px-3 py-2.5 text-sm text-fg-tertiary outline-none select-none",
32
- motion.colors,
33
- "hover:text-fg-primary 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-active:text-fg-primary data-disabled:cursor-not-allowed data-disabled:opacity-50",
34
- className,
35
- )}
36
- {...props}
37
- />
90
+ export type TabsVariant = NonNullable<
91
+ VariantProps<typeof tabsListVariants>["variant"]
92
+ >
93
+ export type TabsSize = NonNullable<
94
+ VariantProps<typeof tabsTabVariants>["size"]
95
+ >
96
+
97
+ type TabsStyleContextValue = {
98
+ variant: TabsVariant
99
+ size: TabsSize
100
+ }
101
+
102
+ const TabsStyleContext = createContext<TabsStyleContextValue>({
103
+ variant: "underline",
104
+ size: "md",
105
+ })
106
+
107
+ export type TabsProps = ComponentProps<typeof BaseTabs.Root> & {
108
+ /** Visual treatment shared by the list, tabs, and indicator. */
109
+ variant?: TabsVariant
110
+ /** Height and typography shared by every tab. */
111
+ size?: TabsSize
112
+ }
113
+ export type TabsListProps = ComponentProps<typeof BaseTabs.List> &
114
+ VariantProps<typeof tabsListVariants>
115
+ export type TabsTabProps = ComponentProps<typeof BaseTabs.Tab> &
116
+ VariantProps<typeof tabsTabVariants>
117
+ export type TabsIndicatorProps = ComponentProps<typeof BaseTabs.Indicator> &
118
+ VariantProps<typeof tabsIndicatorVariants>
119
+ export type TabsPanelProps = ComponentProps<typeof BaseTabs.Panel>
120
+
121
+ export const Tabs = ({
122
+ className,
123
+ variant = "underline",
124
+ size = "md",
125
+ ...props
126
+ }: TabsProps) => (
127
+ <TabsStyleContext.Provider value={{ variant, size }}>
128
+ <BaseTabs.Root
129
+ data-slot="tabs"
130
+ className={cn(
131
+ "flex w-full flex-col data-[orientation=vertical]:flex-row data-[orientation=vertical]:gap-6",
132
+ className,
133
+ )}
134
+ {...props}
135
+ />
136
+ </TabsStyleContext.Provider>
38
137
  )
39
138
 
139
+ export const TabsList = ({
140
+ className,
141
+ variant,
142
+ ...props
143
+ }: TabsListProps) => {
144
+ const styles = useContext(TabsStyleContext)
145
+
146
+ return (
147
+ <BaseTabs.List
148
+ data-slot="tabs-list"
149
+ className={cn(
150
+ tabsListVariants({ variant: variant ?? styles.variant }),
151
+ className,
152
+ )}
153
+ {...props}
154
+ />
155
+ )
156
+ }
157
+
158
+ export const TabsTab = ({
159
+ className,
160
+ variant,
161
+ size,
162
+ ...props
163
+ }: TabsTabProps) => {
164
+ const styles = useContext(TabsStyleContext)
165
+
166
+ return (
167
+ <BaseTabs.Tab
168
+ data-slot="tabs-tab"
169
+ className={cn(
170
+ tabsTabVariants({
171
+ variant: variant ?? styles.variant,
172
+ size: size ?? styles.size,
173
+ }),
174
+ motion.colors,
175
+ className,
176
+ )}
177
+ {...props}
178
+ />
179
+ )
180
+ }
181
+
40
182
  export const TabsIndicator = ({
41
183
  className,
184
+ variant,
42
185
  ...props
43
- }: TabsIndicatorProps) => (
44
- <BaseTabs.Indicator
45
- className={cn(
46
- "absolute bottom-0 left-0 z-10 h-0.5 w-(--active-tab-width) translate-x-(--active-tab-left) rounded-full bg-brand-primary",
47
- motion.tabsIndicator,
48
- className,
49
- )}
50
- {...props}
51
- />
52
- )
186
+ }: TabsIndicatorProps) => {
187
+ const styles = useContext(TabsStyleContext)
188
+
189
+ return (
190
+ <BaseTabs.Indicator
191
+ data-slot="tabs-indicator"
192
+ className={cn(
193
+ tabsIndicatorVariants({ variant: variant ?? styles.variant }),
194
+ motion.tabsIndicator,
195
+ className,
196
+ )}
197
+ {...props}
198
+ />
199
+ )
200
+ }
53
201
 
54
202
  export const TabsPanel = ({ className, ...props }: TabsPanelProps) => (
55
203
  <BaseTabs.Panel
204
+ data-slot="tabs-panel"
56
205
  className={cn(
57
- "pt-4 text-sm leading-relaxed text-fg-secondary outline-none focus-visible:outline-none",
206
+ "pt-4 text-sm leading-relaxed text-fg-secondary outline-none focus-visible:outline-none data-[orientation=vertical]:pt-0",
58
207
  className,
59
208
  )}
60
209
  {...props}
61
210
  />
62
211
  )
212
+
213
+ export { tabsIndicatorVariants, tabsListVariants, tabsTabVariants }
@@ -8,12 +8,18 @@ import {
8
8
  } from "react"
9
9
  import { cn } from "./lib/cn"
10
10
 
11
+ /** How many glyphs are scrambling at once. The window travels the line; behind
12
+ * it the text is settled, ahead of it nothing is drawn yet. 8 is the reference
13
+ * default from baffle.js, which this effect follows. */
14
+ const DECODE_WINDOW = 8
15
+
11
16
  const DECODE_GLYPHS =
12
17
  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789#@$%&*"
13
18
 
14
19
  export type TextAnimateEffect =
15
20
  | "typewriter"
16
21
  | "decode"
22
+ | "shimmer"
17
23
  | "fade"
18
24
  | "blur"
19
25
 
@@ -32,20 +38,25 @@ export type TextAnimateProps = HTMLAttributes<HTMLSpanElement> & {
32
38
  export const TextAnimate = ({
33
39
  text,
34
40
  effect = "typewriter",
35
- speed = 40,
41
+ speed = 60,
36
42
  delay = 0,
37
43
  replay = true,
38
44
  as: Tag = "span",
39
45
  className,
40
46
  ...props
41
47
  }: TextAnimateProps) => {
42
- const [output, setOutput] = useState(effect === "typewriter" || effect === "decode" ? "" : text)
43
- const [done, setDone] = useState(effect === "fade" || effect === "blur")
48
+ const [output, setOutput] = useState(
49
+ effect === "typewriter" || effect === "decode" ? "" : text,
50
+ )
51
+ const [done, setDone] = useState(
52
+ effect === "fade" || effect === "blur" || effect === "shimmer",
53
+ )
44
54
  const chars = useMemo(() => [...text], [text])
45
55
 
46
56
  useEffect(() => {
47
57
  let cancelled = false
48
58
  let timeoutId: ReturnType<typeof setTimeout> | undefined
59
+ let frameId: number | undefined
49
60
 
50
61
  const start = () => {
51
62
  if (
@@ -57,7 +68,7 @@ export const TextAnimate = ({
57
68
  return
58
69
  }
59
70
 
60
- if (effect === "fade" || effect === "blur") {
71
+ if (effect === "fade" || effect === "blur" || effect === "shimmer") {
61
72
  setOutput(text)
62
73
  setDone(true)
63
74
  return
@@ -82,30 +93,59 @@ export const TextAnimate = ({
82
93
  return
83
94
  }
84
95
 
85
- // decode
86
- setOutput(
87
- chars.map(() => DECODE_GLYPHS[Math.floor(Math.random() * DECODE_GLYPHS.length)]).join(""),
88
- )
89
- let revealed = 0
90
- const tick = () => {
96
+ // Decode follows baffle.js's `reveal`, which is the reference for this
97
+ // effect: a fixed-width window of scrambled glyphs travels left to
98
+ // right, the real text sits behind it, and nothing at all is drawn ahead
99
+ // of it — so the line grows in with a churning leading edge rather than
100
+ // resolving out of a full-width block of noise.
101
+ //
102
+ // It runs on rAF with a time accumulator rather than `setTimeout(speed)`.
103
+ // A 28ms timer does not divide into a ~16.7ms frame, so steps land on
104
+ // uneven frames and the text visibly stutters; accumulating elapsed time
105
+ // keeps the reference's cadence while landing each step on a real frame.
106
+ const slots = chars.reduce<number[]>((acc, char, index) => {
107
+ if (char !== " ") acc.push(index)
108
+ return acc
109
+ }, [])
110
+
111
+ // The window starts off the front of the line so the first glyph is
112
+ // already scrambling as it arrives.
113
+ let position = -DECODE_WINDOW
114
+ let previousStep = -Infinity
115
+ const startedAt = performance.now()
116
+
117
+ const frame = (now: number) => {
91
118
  if (cancelled) return
92
- revealed += 1
93
- const next = chars
94
- .map((char, index) => {
95
- if (char === " ") return " "
96
- if (index < revealed) return char
97
- return DECODE_GLYPHS[Math.floor(Math.random() * DECODE_GLYPHS.length)]
98
- })
99
- .join("")
100
- setOutput(next)
101
- if (revealed < chars.length) {
102
- timeoutId = setTimeout(tick, speed)
103
- } else {
104
- setOutput(text)
105
- setDone(true)
119
+
120
+ const step = Math.floor((now - startedAt) / speed) - DECODE_WINDOW
121
+ if (step !== previousStep) {
122
+ previousStep = step
123
+ position = step
124
+
125
+ if (position > slots.length) {
126
+ setOutput(text)
127
+ setDone(true)
128
+ return
129
+ }
130
+
131
+ const next = [...chars]
132
+ for (let p = Math.max(position, 0); p < slots.length; p += 1) {
133
+ next[slots[p]] =
134
+ p < position + DECODE_WINDOW
135
+ ? DECODE_GLYPHS[
136
+ Math.floor(Math.random() * DECODE_GLYPHS.length)
137
+ ]
138
+ : ""
139
+ }
140
+ setOutput(next.join(""))
106
141
  }
142
+
143
+ frameId = requestAnimationFrame(frame)
107
144
  }
108
- timeoutId = setTimeout(tick, speed)
145
+
146
+ setOutput("")
147
+ frameId = requestAnimationFrame(frame)
148
+ return
109
149
  }
110
150
 
111
151
  timeoutId = setTimeout(start, delay)
@@ -113,18 +153,21 @@ export const TextAnimate = ({
113
153
  return () => {
114
154
  cancelled = true
115
155
  if (timeoutId) clearTimeout(timeoutId)
156
+ if (frameId) cancelAnimationFrame(frameId)
116
157
  }
117
158
  }, [chars, delay, effect, replay, speed, text])
118
159
 
119
- if (effect === "fade" || effect === "blur") {
160
+ if (effect === "fade" || effect === "blur" || effect === "shimmer") {
120
161
  return (
121
162
  <Tag
122
163
  className={cn(
123
164
  "inline-block text-fg-primary",
124
165
  effect === "fade" &&
125
- "animate-[text-fade-in_0.6s_var(--ease-enter)_both] motion-reduce:animate-none",
166
+ "animate-[text-fade-in_0.9s_var(--ease-enter)_both] motion-reduce:animate-none",
126
167
  effect === "blur" &&
127
- "animate-[text-blur-in_0.7s_var(--ease-enter)_both] motion-reduce:animate-none",
168
+ "animate-[text-blur-in_1s_var(--ease-enter)_both] motion-reduce:animate-none",
169
+ effect === "shimmer" &&
170
+ "bg-[linear-gradient(110deg,var(--color-fg-tertiary)_35%,var(--color-fg-primary)_50%,var(--color-fg-tertiary)_65%)] bg-[length:250%_100%] bg-clip-text text-transparent animate-[text-shimmer_3s_linear_infinite] motion-reduce:animate-none motion-reduce:bg-none motion-reduce:text-fg-primary",
128
171
  className,
129
172
  )}
130
173
  style={{ animationDelay: `${delay}ms` }}
package/src/textarea.tsx CHANGED
@@ -1,9 +1,14 @@
1
1
  import { cva, type VariantProps } from "class-variance-authority"
2
2
  import type { TextareaHTMLAttributes } from "react"
3
3
  import { cn } from "./lib/cn"
4
+ import { focusRing, focusRingInvalid } from "./lib/focus"
4
5
 
5
6
  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-[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
+ cn(
8
+ "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 disabled:cursor-not-allowed disabled:opacity-50",
9
+ focusRing,
10
+ focusRingInvalid,
11
+ ),
7
12
  {
8
13
  variants: {
9
14
  variant: {