@boyernick/standard-ui-react 0.1.1-canary.9 → 0.2.0

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 (82) 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 +4 -3
  6. package/src/block-editor.tsx +1747 -0
  7. package/src/brand.tsx +2 -2
  8. package/src/breadcrumb.tsx +14 -7
  9. package/src/button.tsx +22 -11
  10. package/src/calendar.tsx +6 -3
  11. package/src/carousel.tsx +220 -53
  12. package/src/checkbox.tsx +3 -2
  13. package/src/code-block.tsx +66 -5
  14. package/src/collapsible.tsx +4 -2
  15. package/src/combobox.tsx +4 -3
  16. package/src/command.tsx +27 -12
  17. package/src/dialog.tsx +33 -10
  18. package/src/empty.tsx +4 -4
  19. package/src/field.tsx +4 -3
  20. package/src/filter-group.tsx +143 -0
  21. package/src/icons.tsx +28 -1
  22. package/src/illustrations.tsx +219 -141
  23. package/src/index.ts +238 -18
  24. package/src/input.tsx +8 -5
  25. package/src/kbd.tsx +10 -4
  26. package/src/lib/focus.ts +41 -0
  27. package/src/lib/popup.ts +1 -1
  28. package/src/lifeline/company-icon.tsx +71 -0
  29. package/src/lifeline/index.ts +42 -0
  30. package/src/lifeline/lifeline-data.ts +97 -0
  31. package/src/lifeline/lifeline-desktop.tsx +204 -0
  32. package/src/lifeline/lifeline-event.tsx +108 -0
  33. package/src/lifeline/lifeline-fireworks.tsx +302 -0
  34. package/src/lifeline/lifeline-hover-image.tsx +269 -0
  35. package/src/lifeline/lifeline-icons.tsx +39 -0
  36. package/src/lifeline/lifeline-intro-timing.ts +105 -0
  37. package/src/lifeline/lifeline-labels.tsx +24 -0
  38. package/src/lifeline/lifeline-layout.ts +1 -0
  39. package/src/lifeline/lifeline-legend.tsx +31 -0
  40. package/src/lifeline/lifeline-lightbox.tsx +309 -0
  41. package/src/lifeline/lifeline-marker.tsx +183 -0
  42. package/src/lifeline/lifeline-people.tsx +99 -0
  43. package/src/lifeline/lifeline-photos.tsx +366 -0
  44. package/src/lifeline/lifeline-shell.tsx +135 -0
  45. package/src/lifeline/lifeline-utils.ts +83 -0
  46. package/src/lifeline/lifeline-vertical.tsx +482 -0
  47. package/src/lifeline/lifeline.tsx +69 -0
  48. package/src/lifeline/types.ts +112 -0
  49. package/src/lifeline/use-lifeline-intro.ts +130 -0
  50. package/src/lifeline/use-lifeline-scroll.ts +1011 -0
  51. package/src/lifeline/use-lifeline-vertical-scroll.ts +271 -0
  52. package/src/menubar.tsx +9 -2
  53. package/src/minimap.tsx +296 -0
  54. package/src/modal.tsx +608 -0
  55. package/src/navigation-menu.tsx +338 -67
  56. package/src/number-field.tsx +336 -61
  57. package/src/otp-field.tsx +4 -3
  58. package/src/pagination.tsx +262 -42
  59. package/src/password-protection.tsx +345 -0
  60. package/src/popover.tsx +1 -1
  61. package/src/progress.tsx +5 -0
  62. package/src/questionnaire.tsx +284 -0
  63. package/src/radio.tsx +4 -2
  64. package/src/scroll-area.tsx +4 -1
  65. package/src/select.tsx +5 -2
  66. package/src/sidebar.tsx +113 -28
  67. package/src/slider.tsx +66 -6
  68. package/src/sounds.tsx +6 -10
  69. package/src/spinner.tsx +105 -32
  70. package/src/switch.tsx +4 -1
  71. package/src/table.tsx +82 -15
  72. package/src/tabs.tsx +189 -38
  73. package/src/text-animate.tsx +71 -28
  74. package/src/textarea.tsx +6 -1
  75. package/src/timeline.tsx +378 -0
  76. package/src/toast.tsx +214 -35
  77. package/src/toggle.tsx +4 -2
  78. package/src/toolbar.tsx +12 -7
  79. package/src/tooltip.tsx +43 -3
  80. package/src/video-player.tsx +396 -127
  81. package/src/image-modal.tsx +0 -110
  82. package/src/markdown-editor.tsx +0 -302
@@ -1,20 +1,165 @@
1
1
  "use client"
2
2
 
3
3
  import { NumberField as BaseNumberField } from "@base-ui/react/number-field"
4
- import type { ComponentProps } from "react"
4
+ import { cva, type VariantProps } from "class-variance-authority"
5
+ import { createContext, useContext, type ComponentProps } from "react"
5
6
  import { IconMinus, IconPlus } from "./icons"
6
7
  import { cn } from "./lib/cn"
8
+ import {
9
+ focusRingWithin,
10
+ focusRingInvalidWithin,
11
+ } from "./lib/focus"
7
12
  import { motion } from "./lib/motion"
8
13
 
9
- export type NumberFieldProps = ComponentProps<typeof BaseNumberField.Root>
10
- export type NumberFieldGroupProps = ComponentProps<typeof BaseNumberField.Group>
11
- export type NumberFieldInputProps = ComponentProps<typeof BaseNumberField.Input>
12
- export type NumberFieldIncrementProps = ComponentProps<
13
- typeof BaseNumberField.Increment
14
- >
15
- export type NumberFieldDecrementProps = ComponentProps<
16
- typeof BaseNumberField.Decrement
17
- >
14
+ export type NumberFieldSize = "sm" | "md" | "lg"
15
+ export type NumberFieldAlign = "start" | "center" | "end"
16
+ type NumberFieldControlLayout = "split" | "stacked"
17
+
18
+ const NumberFieldSizeContext = createContext<NumberFieldSize>("md")
19
+ const NumberFieldControlLayoutContext =
20
+ createContext<NumberFieldControlLayout>("split")
21
+
22
+ const numberFieldGroupVariants = cva(
23
+ cn(
24
+ "flex w-full items-stretch overflow-hidden border border-border-secondary bg-surface inset-shadow-outline-top transition-[background-color,border-color,box-shadow]",
25
+ focusRingWithin,
26
+ focusRingInvalidWithin,
27
+ "has-[[aria-invalid=true]]:border-destructive has-[[aria-invalid=true]]:focus-within:border-destructive has-[[aria-invalid=true]]:focus-within:ring-destructive/20 data-disabled:opacity-50 data-readonly:bg-background-secondary has-[:disabled]:opacity-50",
28
+ ),
29
+ {
30
+ variants: {
31
+ size: {
32
+ sm: "h-8 rounded-md",
33
+ md: "h-9 rounded-md",
34
+ lg: "h-10 rounded-lg",
35
+ },
36
+ },
37
+ defaultVariants: {
38
+ size: "md",
39
+ },
40
+ },
41
+ )
42
+
43
+ const numberFieldInputVariants = cva(
44
+ "h-full min-w-0 flex-1 cursor-text bg-transparent tabular-nums text-fg-primary outline-none placeholder:text-fg-quaternary focus-visible:outline-none data-disabled:cursor-not-allowed data-readonly:cursor-default",
45
+ {
46
+ variants: {
47
+ size: {
48
+ sm: "px-2 text-xs",
49
+ md: "px-2.5 text-sm",
50
+ lg: "px-3 text-sm",
51
+ },
52
+ align: {
53
+ start: "text-left",
54
+ center: "text-center",
55
+ end: "text-right",
56
+ },
57
+ },
58
+ defaultVariants: {
59
+ size: "md",
60
+ align: "center",
61
+ },
62
+ },
63
+ )
64
+
65
+ const numberFieldControlVariants = cva(
66
+ cn(
67
+ "inline-flex shrink-0 cursor-pointer items-center justify-center text-fg-tertiary outline-none",
68
+ motion.colors,
69
+ "hover:bg-background-tertiary hover:text-fg-primary focus-visible:bg-background-tertiary focus-visible:text-fg-primary focus-visible:outline-none data-disabled:cursor-not-allowed data-disabled:opacity-50 data-readonly:cursor-default data-readonly:opacity-50",
70
+ ),
71
+ {
72
+ variants: {
73
+ size: {
74
+ sm: "",
75
+ md: "",
76
+ lg: "",
77
+ },
78
+ layout: {
79
+ split: "",
80
+ stacked: "h-1/2 w-full",
81
+ },
82
+ },
83
+ compoundVariants: [
84
+ { size: "sm", layout: "split", className: "size-8" },
85
+ { size: "md", layout: "split", className: "size-9" },
86
+ { size: "lg", layout: "split", className: "size-10" },
87
+ ],
88
+ defaultVariants: {
89
+ size: "md",
90
+ layout: "split",
91
+ },
92
+ },
93
+ )
94
+
95
+ const numberFieldStepperVariants = cva(
96
+ "flex h-full shrink-0 flex-col border-l border-border-primary [&>button+button]:border-t [&>button+button]:border-border-primary",
97
+ {
98
+ variants: {
99
+ size: {
100
+ sm: "w-7",
101
+ md: "w-8",
102
+ lg: "w-9",
103
+ },
104
+ },
105
+ defaultVariants: {
106
+ size: "md",
107
+ },
108
+ },
109
+ )
110
+
111
+ const numberFieldAffixVariants = cva(
112
+ "inline-flex h-full shrink-0 items-center text-fg-tertiary select-none",
113
+ {
114
+ variants: {
115
+ size: {
116
+ sm: "text-xs",
117
+ md: "text-sm",
118
+ lg: "text-sm",
119
+ },
120
+ side: {
121
+ prefix: "pl-2.5",
122
+ suffix: "pr-2.5",
123
+ },
124
+ },
125
+ defaultVariants: {
126
+ size: "md",
127
+ side: "prefix",
128
+ },
129
+ },
130
+ )
131
+
132
+ export type NumberFieldProps = Omit<
133
+ ComponentProps<typeof BaseNumberField.Root>,
134
+ "size"
135
+ > & {
136
+ size?: NumberFieldSize
137
+ }
138
+ export type NumberFieldGroupProps = Omit<
139
+ ComponentProps<typeof BaseNumberField.Group>,
140
+ "size"
141
+ > &
142
+ VariantProps<typeof numberFieldGroupVariants>
143
+ export type NumberFieldInputProps = Omit<
144
+ ComponentProps<typeof BaseNumberField.Input>,
145
+ "size"
146
+ > &
147
+ VariantProps<typeof numberFieldInputVariants>
148
+ export type NumberFieldIncrementProps = Omit<
149
+ ComponentProps<typeof BaseNumberField.Increment>,
150
+ "size"
151
+ > &
152
+ VariantProps<typeof numberFieldControlVariants>
153
+ export type NumberFieldDecrementProps = Omit<
154
+ ComponentProps<typeof BaseNumberField.Decrement>,
155
+ "size"
156
+ > &
157
+ VariantProps<typeof numberFieldControlVariants>
158
+ export type NumberFieldStepperProps = Omit<ComponentProps<"div">, "size"> &
159
+ VariantProps<typeof numberFieldStepperVariants>
160
+ export type NumberFieldPrefixProps = Omit<ComponentProps<"span">, "size"> &
161
+ Omit<VariantProps<typeof numberFieldAffixVariants>, "side">
162
+ export type NumberFieldSuffixProps = NumberFieldPrefixProps
18
163
  export type NumberFieldScrubAreaProps = ComponentProps<
19
164
  typeof BaseNumberField.ScrubArea
20
165
  >
@@ -22,78 +167,200 @@ export type NumberFieldScrubAreaCursorProps = ComponentProps<
22
167
  typeof BaseNumberField.ScrubAreaCursor
23
168
  >
24
169
 
25
- export const NumberField = ({ className, ...props }: NumberFieldProps) => (
26
- <BaseNumberField.Root
27
- className={cn("flex flex-col gap-1.5", className)}
28
- {...props}
29
- />
170
+ export const NumberField = ({
171
+ className,
172
+ size = "md",
173
+ ...props
174
+ }: NumberFieldProps) => (
175
+ <NumberFieldSizeContext.Provider value={size}>
176
+ <BaseNumberField.Root
177
+ className={cn("flex flex-col gap-1.5", className)}
178
+ {...props}
179
+ />
180
+ </NumberFieldSizeContext.Provider>
30
181
  )
31
182
 
32
183
  export const NumberFieldGroup = ({
33
184
  className,
185
+ size,
34
186
  ...props
35
- }: NumberFieldGroupProps) => (
36
- <BaseNumberField.Group
37
- className={cn(
38
- "flex h-9 w-full items-stretch overflow-hidden rounded-md border border-border-secondary bg-surface inset-shadow-outline-top outline-none transition-[color,box-shadow]",
39
- "focus-within:border-ring focus-within:ring-[3px] focus-within:ring-offset-1 focus-within:ring-offset-background-primary focus-within:ring-ring/20",
40
- "aria-invalid:border-destructive aria-invalid:focus-within:border-destructive aria-invalid:focus-within:ring-destructive/20",
41
- "has-[[aria-invalid=true]]:border-destructive has-[[aria-invalid=true]]:focus-within:border-destructive has-[[aria-invalid=true]]:focus-within:ring-destructive/20",
42
- "has-[:disabled]:opacity-50",
43
- className,
44
- )}
45
- {...props}
46
- />
47
- )
187
+ }: NumberFieldGroupProps) => {
188
+ const inheritedSize = useContext(NumberFieldSizeContext)
189
+
190
+ return (
191
+ <BaseNumberField.Group
192
+ className={cn(
193
+ numberFieldGroupVariants({ size: size ?? inheritedSize }),
194
+ className,
195
+ )}
196
+ {...props}
197
+ />
198
+ )
199
+ }
48
200
 
49
201
  export const NumberFieldInput = ({
50
202
  className,
203
+ size,
204
+ align,
51
205
  ...props
52
- }: NumberFieldInputProps) => (
53
- <BaseNumberField.Input
54
- className={cn(
55
- "h-full min-w-0 flex-1 cursor-text border-x border-border-primary bg-transparent px-2 text-center text-sm tabular-nums text-fg-primary outline-none focus-visible:outline-none",
56
- className,
57
- )}
58
- {...props}
59
- />
60
- )
206
+ }: NumberFieldInputProps) => {
207
+ const inheritedSize = useContext(NumberFieldSizeContext)
61
208
 
62
- const stepperClassName = cn(
63
- "inline-flex size-9 shrink-0 cursor-pointer items-center justify-center text-fg-tertiary outline-none",
64
- motion.colors,
65
- "hover:bg-background-tertiary hover:text-fg-primary focus-visible:bg-background-tertiary focus-visible:text-fg-primary focus-visible:outline-none data-disabled:cursor-not-allowed data-disabled:opacity-50",
66
- )
209
+ return (
210
+ <BaseNumberField.Input
211
+ className={cn(
212
+ numberFieldInputVariants({ size: size ?? inheritedSize, align }),
213
+ className,
214
+ )}
215
+ {...props}
216
+ />
217
+ )
218
+ }
219
+
220
+ const controlIconClassNames: Record<NumberFieldSize, string> = {
221
+ sm: "size-3",
222
+ md: "size-3.5",
223
+ lg: "size-4",
224
+ }
67
225
 
68
226
  export const NumberFieldDecrement = ({
69
227
  className,
70
228
  children,
229
+ size,
230
+ layout,
71
231
  "aria-label": ariaLabel = "Decrease",
72
232
  ...props
73
- }: NumberFieldDecrementProps) => (
74
- <BaseNumberField.Decrement
75
- aria-label={ariaLabel}
76
- className={cn(stepperClassName, className)}
77
- {...props}
78
- >
79
- {children ?? <IconMinus size={16} className="size-4" aria-hidden />}
80
- </BaseNumberField.Decrement>
81
- )
233
+ }: NumberFieldDecrementProps) => {
234
+ const inheritedSize = useContext(NumberFieldSizeContext)
235
+ const inheritedLayout = useContext(NumberFieldControlLayoutContext)
236
+ const resolvedSize = size ?? inheritedSize
237
+ const resolvedLayout = layout ?? inheritedLayout
238
+
239
+ return (
240
+ <BaseNumberField.Decrement
241
+ aria-label={ariaLabel}
242
+ className={cn(
243
+ numberFieldControlVariants({
244
+ size: resolvedSize,
245
+ layout: resolvedLayout,
246
+ }),
247
+ resolvedLayout === "split" && "border-r border-border-primary",
248
+ className,
249
+ )}
250
+ {...props}
251
+ >
252
+ {children ?? (
253
+ <IconMinus
254
+ size={16}
255
+ className={controlIconClassNames[resolvedSize]}
256
+ aria-hidden
257
+ />
258
+ )}
259
+ </BaseNumberField.Decrement>
260
+ )
261
+ }
82
262
 
83
263
  export const NumberFieldIncrement = ({
84
264
  className,
85
265
  children,
266
+ size,
267
+ layout,
86
268
  "aria-label": ariaLabel = "Increase",
87
269
  ...props
88
- }: NumberFieldIncrementProps) => (
89
- <BaseNumberField.Increment
90
- aria-label={ariaLabel}
91
- className={cn(stepperClassName, className)}
92
- {...props}
93
- >
94
- {children ?? <IconPlus size={16} className="size-4" aria-hidden />}
95
- </BaseNumberField.Increment>
96
- )
270
+ }: NumberFieldIncrementProps) => {
271
+ const inheritedSize = useContext(NumberFieldSizeContext)
272
+ const inheritedLayout = useContext(NumberFieldControlLayoutContext)
273
+ const resolvedSize = size ?? inheritedSize
274
+ const resolvedLayout = layout ?? inheritedLayout
275
+
276
+ return (
277
+ <BaseNumberField.Increment
278
+ aria-label={ariaLabel}
279
+ className={cn(
280
+ numberFieldControlVariants({
281
+ size: resolvedSize,
282
+ layout: resolvedLayout,
283
+ }),
284
+ resolvedLayout === "split" && "border-l border-border-primary",
285
+ className,
286
+ )}
287
+ {...props}
288
+ >
289
+ {children ?? (
290
+ <IconPlus
291
+ size={16}
292
+ className={controlIconClassNames[resolvedSize]}
293
+ aria-hidden
294
+ />
295
+ )}
296
+ </BaseNumberField.Increment>
297
+ )
298
+ }
299
+
300
+ export const NumberFieldStepper = ({
301
+ className,
302
+ size,
303
+ children,
304
+ ...props
305
+ }: NumberFieldStepperProps) => {
306
+ const inheritedSize = useContext(NumberFieldSizeContext)
307
+
308
+ return (
309
+ <NumberFieldControlLayoutContext.Provider value="stacked">
310
+ <div
311
+ className={cn(
312
+ numberFieldStepperVariants({ size: size ?? inheritedSize }),
313
+ className,
314
+ )}
315
+ {...props}
316
+ >
317
+ {children}
318
+ </div>
319
+ </NumberFieldControlLayoutContext.Provider>
320
+ )
321
+ }
322
+
323
+ export const NumberFieldPrefix = ({
324
+ className,
325
+ size,
326
+ ...props
327
+ }: NumberFieldPrefixProps) => {
328
+ const inheritedSize = useContext(NumberFieldSizeContext)
329
+
330
+ return (
331
+ <span
332
+ className={cn(
333
+ numberFieldAffixVariants({
334
+ size: size ?? inheritedSize,
335
+ side: "prefix",
336
+ }),
337
+ className,
338
+ )}
339
+ {...props}
340
+ />
341
+ )
342
+ }
343
+
344
+ export const NumberFieldSuffix = ({
345
+ className,
346
+ size,
347
+ ...props
348
+ }: NumberFieldSuffixProps) => {
349
+ const inheritedSize = useContext(NumberFieldSizeContext)
350
+
351
+ return (
352
+ <span
353
+ className={cn(
354
+ numberFieldAffixVariants({
355
+ size: size ?? inheritedSize,
356
+ side: "suffix",
357
+ }),
358
+ className,
359
+ )}
360
+ {...props}
361
+ />
362
+ )
363
+ }
97
364
 
98
365
  export const NumberFieldScrubArea = ({
99
366
  className,
@@ -101,7 +368,7 @@ export const NumberFieldScrubArea = ({
101
368
  }: NumberFieldScrubAreaProps) => (
102
369
  <BaseNumberField.ScrubArea
103
370
  className={cn(
104
- "inline-flex cursor-ew-resize items-center gap-1 text-sm text-fg-secondary select-none",
371
+ "inline-flex cursor-ew-resize items-center gap-1 text-sm text-fg-secondary select-none data-disabled:cursor-not-allowed data-disabled:opacity-50 data-readonly:cursor-default",
105
372
  className,
106
373
  )}
107
374
  {...props}
@@ -117,3 +384,11 @@ export const NumberFieldScrubAreaCursor = ({
117
384
  {...props}
118
385
  />
119
386
  )
387
+
388
+ export {
389
+ numberFieldAffixVariants,
390
+ numberFieldControlVariants,
391
+ numberFieldGroupVariants,
392
+ numberFieldInputVariants,
393
+ numberFieldStepperVariants,
394
+ }
package/src/otp-field.tsx CHANGED
@@ -3,6 +3,7 @@
3
3
  import { OTPField as BaseOTPField } from "@base-ui/react/otp-field"
4
4
  import type { ComponentProps } from "react"
5
5
  import { cn } from "./lib/cn"
6
+ import { focusRing, focusRingInvalid } from "./lib/focus"
6
7
  import { motion } from "./lib/motion"
7
8
 
8
9
  export type OTPFieldProps = ComponentProps<typeof BaseOTPField.Root>
@@ -19,10 +20,10 @@ export const OTPField = ({ className, ...props }: OTPFieldProps) => (
19
20
  export const OTPFieldInput = ({ className, ...props }: OTPFieldInputProps) => (
20
21
  <BaseOTPField.Input
21
22
  className={cn(
22
- "size-10 rounded-md border border-border-secondary bg-surface text-center text-sm tabular-nums text-fg-primary inset-shadow-outline-top outline-none",
23
+ "size-10 rounded-md border border-border-secondary bg-surface text-center text-sm tabular-nums text-fg-primary inset-shadow-outline-top",
23
24
  motion.colors,
24
- "focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-offset-1 focus-visible:ring-offset-background-primary focus-visible:ring-ring/20",
25
- "aria-invalid:border-destructive aria-invalid:focus-visible:border-destructive aria-invalid:focus-visible:ring-destructive/20",
25
+ focusRing,
26
+ focusRingInvalid,
26
27
  "data-disabled:cursor-not-allowed data-disabled:opacity-50",
27
28
  "data-filled:border-border-secondary",
28
29
  className,