@boyernick/standard-ui-react 0.1.1-canary.12 → 0.1.1-canary.13

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.12",
3
+ "version": "0.1.1-canary.13",
4
4
  "description": "React components for StandardUI",
5
5
  "license": "MIT",
6
6
  "type": "module",
package/src/toast.tsx CHANGED
@@ -28,25 +28,45 @@ export const ToastPortal = (props: ToastPortalProps) => (
28
28
 
29
29
  export const ToastViewport = ({ className, ...props }: ToastViewportProps) => (
30
30
  <BaseToast.Viewport
31
+ // No flex column: the toasts inside are absolutely positioned so they pile
32
+ // up as a stack. In flow they would march down past the bottom edge.
31
33
  className={cn(
32
- "fixed right-4 bottom-4 z-[100] flex w-[min(100vw-2rem,24rem)] flex-col outline-none",
34
+ "fixed right-4 bottom-4 z-[100] w-[min(100vw-2rem,24rem)] outline-none",
33
35
  className,
34
36
  )}
35
37
  {...props}
36
38
  />
37
39
  )
38
40
 
41
+ /** Each toast is pinned to the bottom of the viewport and lifted by its own
42
+ * index, so the stack reads as a pile of cards rather than a list: the one
43
+ * behind peeks out by `--peek` and sits a step smaller. Hovering the viewport
44
+ * sets `data-expanded`, which fans them out to their real heights. */
39
45
  export const ToastRoot = ({ className, ...props }: ToastRootProps) => (
40
46
  <BaseToast.Root
41
47
  className={cn(
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
- "h-[var(--toast-frontmost-height,var(--toast-height))]",
44
- "transition-[transform,opacity] duration-[var(--duration-md)] ease-enter motion-reduce:transition-none",
45
- "data-starting-style:opacity-0 data-starting-style:translate-y-2",
46
- "data-ending-style:opacity-0 data-ending-style:translate-y-2",
47
- "data-expanded:h-[var(--toast-height)] data-expanded:translate-y-[var(--toast-offset-y)]",
48
- "data-[type=error]:border-destructive/40",
49
- "data-[type=success]:border-border-primary",
48
+ "absolute right-0 bottom-0 left-auto z-[calc(1000-var(--toast-index))] box-border w-full origin-bottom",
49
+ "[--gap:0.625rem] [--peek:0.75rem]",
50
+ "[--scale:calc(max(0,1-(var(--toast-index)*0.05)))] [--shrink:calc(1-var(--scale))]",
51
+ "[--height:var(--toast-frontmost-height,var(--toast-height))]",
52
+ "[--offset-y:calc(var(--toast-offset-y)*-1+calc(var(--toast-index)*var(--gap)*-1)+var(--toast-swipe-movement-y,0px))]",
53
+ // No border: `shadow-lg` composes `--elevation-hairline`, the same edge the
54
+ // dropdowns carry — theme-aware and 0.5px on hi-dpi. A border on top of it
55
+ // stacked a second, darker line. The error type tints that edge with a
56
+ // ring, which also sits outside the box model so the height never shifts.
57
+ "rounded-xl bg-surface px-3.5 py-3 shadow-lg outline-none select-none",
58
+ // Collapsed, every toast behind the front one is scaled down and shifted
59
+ // up; `--shrink` cancels the gap that scaling opens at the bottom edge.
60
+ "h-[var(--height)] data-expanded:h-[var(--toast-height)]",
61
+ "[transform:translateX(var(--toast-swipe-movement-x,0px))_translateY(calc(var(--toast-swipe-movement-y,0px)-(var(--toast-index)*var(--peek))-(var(--shrink)*var(--height))))_scale(var(--scale))]",
62
+ "data-expanded:[transform:translateX(var(--toast-swipe-movement-x,0px))_translateY(var(--offset-y))]",
63
+ // Bridges the gap between cards so crossing it does not collapse the fan.
64
+ "after:absolute after:top-full after:left-0 after:h-[calc(var(--gap)+1px)] after:w-full after:content-['']",
65
+ "transition-[transform,opacity,height] duration-[var(--duration-md)] ease-enter motion-reduce:transition-none",
66
+ "data-starting-style:[transform:translateY(150%)]",
67
+ "data-ending-style:opacity-0 data-limited:opacity-0",
68
+ "[&[data-ending-style]:not([data-limited]):not([data-swipe-direction])]:[transform:translateY(150%)]",
69
+ "data-[type=error]:ring-1 data-[type=error]:ring-destructive/40",
50
70
  className,
51
71
  )}
52
72
  {...props}
@@ -56,7 +76,7 @@ export const ToastRoot = ({ className, ...props }: ToastRootProps) => (
56
76
  export const ToastContent = ({ className, ...props }: ToastContentProps) => (
57
77
  <BaseToast.Content
58
78
  className={cn(
59
- "flex flex-col gap-1 overflow-hidden transition-opacity duration-[var(--duration-sm)]",
79
+ "flex flex-col gap-0.5 overflow-hidden transition-opacity duration-[var(--duration-sm)]",
60
80
  "data-behind:pointer-events-none data-behind:opacity-0 data-expanded:data-behind:opacity-100",
61
81
  className,
62
82
  )}
@@ -66,7 +86,7 @@ export const ToastContent = ({ className, ...props }: ToastContentProps) => (
66
86
 
67
87
  export const ToastTitle = ({ className, ...props }: ToastTitleProps) => (
68
88
  <BaseToast.Title
69
- className={cn("text-sm-strong pr-8 text-fg-primary", className)}
89
+ className={cn("text-xs-strong pr-10 text-fg-primary", className)}
70
90
  {...props}
71
91
  />
72
92
  )
@@ -76,7 +96,7 @@ export const ToastDescription = ({
76
96
  ...props
77
97
  }: ToastDescriptionProps) => (
78
98
  <BaseToast.Description
79
- className={cn("text-sm leading-relaxed text-fg-secondary", className)}
99
+ className={cn("text-xs text-fg-secondary", className)}
80
100
  {...props}
81
101
  />
82
102
  )
@@ -100,7 +120,7 @@ export const ToastClose = ({
100
120
  }: ToastCloseProps) => (
101
121
  <BaseToast.Close
102
122
  className={cn(
103
- "absolute top-3 right-3 inline-flex size-7 cursor-pointer items-center justify-center rounded-md text-fg-tertiary outline-none",
123
+ "absolute top-2.5 right-2.5 inline-flex size-7 cursor-pointer items-center justify-center rounded-md text-fg-tertiary outline-none",
104
124
  motion.colors,
105
125
  "hover:bg-background-tertiary 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",
106
126
  className,
@@ -108,7 +128,7 @@ export const ToastClose = ({
108
128
  {...props}
109
129
  >
110
130
  {children ?? (
111
- <IconCrossSmall size={14} className="size-3.5" aria-hidden />
131
+ <IconCrossSmall size={18} className="size-4.5" aria-hidden />
112
132
  )}
113
133
  </BaseToast.Close>
114
134
  )
package/src/tooltip.tsx CHANGED
@@ -52,9 +52,16 @@ const tooltipPopupVariants = cva(
52
52
  cn(
53
53
  "z-50 max-w-xs rounded-md px-2.5 py-1 text-xs shadow-md outline-none",
54
54
  // A trailing keycap already carries its own inset, so the full 10px beside
55
- // it reads as a gap rather than padding. Matching the vertical inset puts
56
- // the cap the same distance from every edge it is near.
57
- "has-[kbd]:pr-1",
55
+ // it reads as a gap rather than padding but sitting flush on the vertical
56
+ // inset crowds the corner, so it gets a touch more than that.
57
+ //
58
+ // Laying the row out as flex is what centres it. On a text line the keycap
59
+ // is an inline-flex aligned `middle`, which sets its centre against the
60
+ // baseline plus half an x-height rather than the line's centre — at 16px it
61
+ // hung 1.18px low, leaving 6.36px above and 4px below. Scoped to `has-[kbd]`
62
+ // because making every popup a flex container would turn a multi-child
63
+ // tooltip from stacked blocks into a row.
64
+ "has-[kbd]:flex has-[kbd]:items-center has-[kbd]:pr-1.5",
58
65
  ),
59
66
  {
60
67
  variants: {