@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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@boyernick/standard-ui-react",
3
- "version": "0.1.1-canary.3",
3
+ "version": "0.1.1-canary.34",
4
4
  "description": "React components for StandardUI",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -21,12 +21,14 @@
21
21
  "test": "node --test --experimental-strip-types \"src/**/*.test.ts\""
22
22
  },
23
23
  "peerDependencies": {
24
- "react": "^18.0.0 || ^19.0.0",
25
- "react-dom": "^18.0.0 || ^19.0.0"
24
+ "react": "^19.0.0",
25
+ "react-dom": "^19.0.0"
26
26
  },
27
27
  "dependencies": {
28
28
  "@base-ui/react": "^1.7.0",
29
+ "@central-icons-react/round-filled-radius-2-stroke-2": "^1.1.315",
29
30
  "@central-icons-react/round-outlined-radius-2-stroke-2": "^1.1.312",
31
+ "@shadcn/react": "^0.3.0",
30
32
  "class-variance-authority": "^0.7.1",
31
33
  "clsx": "^2.1.1",
32
34
  "date-fns": "^4.4.0",
package/src/accordion.tsx CHANGED
@@ -4,6 +4,7 @@ import { Accordion as BaseAccordion } from "@base-ui/react/accordion"
4
4
  import type { ComponentProps } from "react"
5
5
  import { IconChevronBottom } from "./icons"
6
6
  import { cn } from "./lib/cn"
7
+ import { focusRing, focusRingBorder } from "./lib/focus"
7
8
  import { motion } from "./lib/motion"
8
9
 
9
10
  export type AccordionProps = ComponentProps<typeof BaseAccordion.Root>
@@ -46,9 +47,11 @@ export const AccordionTrigger = ({
46
47
  }: AccordionTriggerProps) => (
47
48
  <BaseAccordion.Trigger
48
49
  className={cn(
49
- "group flex w-full cursor-pointer items-center justify-between gap-3 px-4 py-3.5 text-left text-sm text-fg-primary outline-none",
50
+ "group flex w-full cursor-pointer items-center justify-between gap-3 px-4 py-3.5 text-left text-sm text-fg-primary",
51
+ focusRingBorder,
50
52
  motion.colors,
51
- "hover:bg-background-tertiary focus-visible:relative focus-visible:z-10 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",
53
+ focusRing,
54
+ "hover:bg-background-tertiary focus-visible:relative focus-visible:z-10 data-disabled:cursor-not-allowed data-disabled:opacity-50",
52
55
  className,
53
56
  )}
54
57
  {...props}
@@ -58,7 +58,7 @@ export const AlertDialogPopup = ({
58
58
  }: AlertDialogPopupProps) => (
59
59
  <BaseAlertDialog.Popup
60
60
  className={cn(
61
- "fixed top-1/2 left-1/2 z-50 flex w-full max-w-md -translate-x-1/2 -translate-y-1/2 flex-col gap-6 rounded-xl border border-border-primary bg-surface p-5 shadow-md outline-none max-sm:max-w-[calc(100vw-2rem)]",
61
+ "fixed top-1/2 left-1/2 z-50 flex w-full max-w-md -translate-x-1/2 -translate-y-1/2 flex-col gap-6 rounded-xl border border-border-primary bg-surface p-5 shadow-md outline-none max-h-[calc(100dvh-2rem)] overflow-y-auto max-sm:max-w-[calc(100vw-2rem)]",
62
62
  motion.popupCenter,
63
63
  className,
64
64
  )}
@@ -8,6 +8,7 @@ import type {
8
8
  } from "react";
9
9
  import { IconCrossSmall } from "./icons";
10
10
  import { cn } from "./lib/cn";
11
+ import { focusRing, focusRingWithin } from "./lib/focus";
11
12
  import { motion } from "./lib/motion";
12
13
 
13
14
  export type AttachmentProps = Omit<ComponentProps<"label">, "onDrop"> & {
@@ -53,7 +54,8 @@ export const Attachment = ({
53
54
  <label
54
55
  data-disabled={disabled || undefined}
55
56
  className={cn(
56
- "flex min-h-32 cursor-pointer flex-col items-center justify-center gap-2 rounded-xl border border-dashed border-border-primary bg-surface p-6 text-center text-sm text-fg-secondary outline-none hover:bg-background-secondary focus-within:border-ring focus-within:ring-[3px] focus-within:ring-offset-1 focus-within:ring-offset-background-primary focus-within:ring-ring/20 data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50",
57
+ "flex min-h-32 cursor-pointer flex-col items-center justify-center gap-2 rounded-xl border border-dashed border-border-primary bg-surface p-6 text-center text-sm text-fg-secondary hover:bg-background-secondary data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50",
58
+ focusRingWithin,
57
59
  motion.colors,
58
60
  className,
59
61
  )}
@@ -127,7 +129,8 @@ export const AttachmentRemove = ({
127
129
  type={type}
128
130
  aria-label="Remove attachment"
129
131
  className={cn(
130
- "flex size-8 shrink-0 cursor-pointer items-center justify-center rounded-md border border-transparent text-fg-tertiary outline-none hover:bg-background-tertiary hover:text-fg-primary 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",
132
+ "flex size-8 shrink-0 cursor-pointer items-center justify-center rounded-md border border-transparent text-fg-tertiary hover:bg-background-tertiary hover:text-fg-primary disabled:cursor-not-allowed disabled:opacity-50",
133
+ focusRing,
131
134
  motion.colors,
132
135
  className,
133
136
  )}
@@ -4,7 +4,9 @@ import { Autocomplete as BaseAutocomplete } from "@base-ui/react/autocomplete"
4
4
  import type { ComponentProps, ReactElement } from "react"
5
5
  import { IconChevronDownSmall, IconCrossSmall } from "./icons"
6
6
  import { cn } from "./lib/cn"
7
+ import { focusRingWithin, focusRingInvalidWithin } from "./lib/focus"
7
8
  import { motion } from "./lib/motion"
9
+ import { popupInset, popupItem, popupLabel, popupMessage, popupSurface } from "./lib/popup"
8
10
 
9
11
  export type AutocompleteProps = ComponentProps<typeof BaseAutocomplete.Root>
10
12
  export type AutocompleteValueProps = ComponentProps<typeof BaseAutocomplete.Value>
@@ -66,9 +68,9 @@ export const AutocompleteInputGroup = ({
66
68
  }: AutocompleteInputGroupProps) => (
67
69
  <BaseAutocomplete.InputGroup
68
70
  className={cn(
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]",
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",
71
- "aria-invalid:border-destructive aria-invalid:focus-within:border-destructive aria-invalid:focus-within:ring-destructive/20",
71
+ "relative flex min-h-9 w-full items-center rounded-xl border border-border-secondary bg-surface inset-shadow-outline-top transition-[color,box-shadow]",
72
+ focusRingWithin,
73
+ focusRingInvalidWithin,
72
74
  "has-[[aria-invalid=true]]:border-destructive has-[[aria-invalid=true]]:focus-within:border-destructive has-[[aria-invalid=true]]:focus-within:ring-destructive/20",
73
75
  "has-[:disabled]:opacity-50",
74
76
  className,
@@ -167,7 +169,8 @@ export const AutocompletePopup = ({
167
169
  }: AutocompletePopupProps) => (
168
170
  <BaseAutocomplete.Popup
169
171
  className={cn(
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
+ "z-50 max-h-[min(24rem,var(--available-height))] w-[var(--anchor-width)] overflow-hidden",
173
+ popupSurface,
171
174
  motion.popupAnchor,
172
175
  className,
173
176
  )}
@@ -198,7 +201,7 @@ export const AutocompleteList = ({
198
201
  ...props
199
202
  }: AutocompleteListProps) => (
200
203
  <BaseAutocomplete.List
201
- className={cn("max-h-[inherit] overflow-y-auto p-1.5 outline-none empty:p-0", className)}
204
+ className={cn("max-h-[inherit] overflow-y-auto outline-none", popupInset, className)}
202
205
  {...props}
203
206
  />
204
207
  )
@@ -209,7 +212,7 @@ export const AutocompleteItem = ({
209
212
  }: AutocompleteItemProps) => (
210
213
  <BaseAutocomplete.Item
211
214
  className={cn(
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",
215
+ popupItem,
213
216
  motion.colors,
214
217
  "data-disabled:cursor-not-allowed data-disabled:opacity-50 data-highlighted:bg-background-tertiary data-highlighted:text-fg-primary",
215
218
  className,
@@ -223,7 +226,7 @@ export const AutocompleteEmpty = ({
223
226
  ...props
224
227
  }: AutocompleteEmptyProps) => (
225
228
  <BaseAutocomplete.Empty
226
- className={cn("px-3 py-2 text-sm text-fg-tertiary empty:hidden", className)}
229
+ className={cn(cn(popupMessage, "empty:hidden"), className)}
227
230
  {...props}
228
231
  />
229
232
  )
@@ -233,7 +236,7 @@ export const AutocompleteStatus = ({
233
236
  ...props
234
237
  }: AutocompleteStatusProps) => (
235
238
  <BaseAutocomplete.Status
236
- className={cn("px-3 py-2 text-sm text-fg-tertiary", className)}
239
+ className={cn(popupMessage, className)}
237
240
  {...props}
238
241
  />
239
242
  )
@@ -250,7 +253,7 @@ export const AutocompleteGroupLabel = ({
250
253
  ...props
251
254
  }: AutocompleteGroupLabelProps) => (
252
255
  <BaseAutocomplete.GroupLabel
253
- className={cn("px-3 py-1.5 text-xs text-fg-tertiary", className)}
256
+ className={cn(popupLabel, className)}
254
257
  {...props}
255
258
  />
256
259
  )
package/src/badge.tsx CHANGED
@@ -1,28 +1,92 @@
1
1
  import { cva, type VariantProps } from "class-variance-authority"
2
- import type { HTMLAttributes } from "react"
2
+ import type { HTMLAttributes, ReactNode } from "react"
3
3
  import { cn } from "./lib/cn"
4
4
 
5
5
  const badgeVariants = cva(
6
- "text-xs-strong inline-flex items-center rounded-full py-0.5",
6
+ "inline-flex shrink-0 items-center justify-center whitespace-nowrap align-middle [&>[data-badge-label]]:min-w-0 [&>[data-badge-label]]:truncate [&>[data-badge-slot]]:inline-flex [&>[data-badge-slot]]:shrink-0 [&>[data-badge-slot]]:items-center [&>[data-badge-slot]]:justify-center [&>[data-badge-slot]>svg]:size-full",
7
7
  {
8
8
  variants: {
9
9
  variant: {
10
- default: "bg-background-tertiary px-3 text-fg-primary",
11
- outline: "border border-border-primary px-2 text-fg-secondary",
12
- destructive: "bg-destructive/10 px-2 text-destructive",
10
+ default: "bg-background-tertiary text-fg-primary",
11
+ outline: "border border-border-primary text-fg-secondary",
12
+ info: "bg-status-info-background text-status-info",
13
+ success: "bg-status-success-background text-status-success",
14
+ warning: "bg-status-warning-background text-status-warning",
15
+ critical: "bg-status-critical-background text-status-critical",
16
+ destructive: "bg-status-critical-background text-status-critical",
17
+ },
18
+ size: {
19
+ xxs: "text-2xs-strong h-4 gap-0.5 px-1.5 [&>[data-badge-slot]]:size-2.5",
20
+ xs: "text-2xs-strong h-5 gap-1 px-1.5 [&>[data-badge-slot]]:size-3",
21
+ sm: "text-xs-strong h-6 gap-1 px-2 [&>[data-badge-slot]]:size-3.5",
22
+ md: "text-xs-strong h-7 gap-1.5 px-2.5 [&>[data-badge-slot]]:size-3.5",
23
+ lg: "text-sm-strong h-8 gap-1.5 px-3 [&>[data-badge-slot]]:size-4",
24
+ },
25
+ rounded: {
26
+ true: "rounded-full",
27
+ false: "rounded-sm",
28
+ },
29
+ iconOnly: {
30
+ true: "p-0",
31
+ false: "",
13
32
  },
14
33
  },
34
+ compoundVariants: [
35
+ { iconOnly: true, size: "xxs", class: "size-4" },
36
+ { iconOnly: true, size: "xs", class: "size-5" },
37
+ { iconOnly: true, size: "sm", class: "size-6" },
38
+ { iconOnly: true, size: "md", class: "size-7" },
39
+ { iconOnly: true, size: "lg", class: "size-8" },
40
+ ],
15
41
  defaultVariants: {
16
42
  variant: "default",
43
+ size: "sm",
44
+ rounded: false,
45
+ iconOnly: false,
17
46
  },
18
47
  },
19
48
  )
20
49
 
21
- export type BadgeProps = HTMLAttributes<HTMLSpanElement> &
22
- VariantProps<typeof badgeVariants>
50
+ export type BadgeProps = Omit<HTMLAttributes<HTMLSpanElement>, "prefix"> &
51
+ VariantProps<typeof badgeVariants> & {
52
+ /** Square badge sized to the height of `size`. */
53
+ iconOnly?: boolean
54
+ /** Pill shape (`rounded-full`) instead of the default light radius. */
55
+ rounded?: boolean
56
+ /** Icon or element before the label. */
57
+ prefix?: ReactNode
58
+ /** Icon or element after the label. */
59
+ suffix?: ReactNode
60
+ }
23
61
 
24
- export const Badge = ({ className, variant, ...props }: BadgeProps) => (
25
- <span className={cn(badgeVariants({ variant }), className)} {...props} />
62
+ export const Badge = ({
63
+ className,
64
+ variant,
65
+ size,
66
+ rounded,
67
+ iconOnly,
68
+ prefix,
69
+ suffix,
70
+ children,
71
+ ...props
72
+ }: BadgeProps) => (
73
+ <span
74
+ className={cn(
75
+ badgeVariants({ variant, size, rounded, iconOnly }),
76
+ className,
77
+ )}
78
+ {...props}
79
+ >
80
+ {iconOnly ? (
81
+ <span data-badge-slot="icon">{children}</span>
82
+ ) : (
83
+ <>
84
+ {prefix ? <span data-badge-slot="prefix">{prefix}</span> : null}
85
+ {children != null ? <span data-badge-label>{children}</span> : null}
86
+ {suffix ? <span data-badge-slot="suffix">{suffix}</span> : null}
87
+ </>
88
+ )}
89
+ </span>
26
90
  )
27
91
 
28
92
  export { badgeVariants }