@stevederico/skateboard-ui 4.6.0 → 4.10.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.
package/dist/App.d.ts CHANGED
@@ -14,6 +14,7 @@ export interface AppOverrides {
14
14
  signUp?: ComponentType<any>;
15
15
  signOut?: ComponentType<any>;
16
16
  notFound?: ComponentType<any>;
17
+ authOverlay?: ComponentType<any>;
17
18
  }
18
19
  /** Configuration accepted by createSkateboardApp. */
19
20
  export interface CreateSkateboardAppConfig {
@@ -46,6 +47,7 @@ export interface CreateSkateboardAppConfig {
46
47
  * @param {React.ComponentType} [config.overrides.signUp] - Replace SignUpView
47
48
  * @param {React.ComponentType} [config.overrides.signOut] - Replace SignOutView
48
49
  * @param {React.ComponentType} [config.overrides.notFound] - Replace NotFound
50
+ * @param {React.ComponentType} [config.overrides.authOverlay] - Replace AuthOverlay
49
51
  *
50
52
  * @example
51
53
  * import { createSkateboardApp } from '@stevederico/skateboard-ui/App';
package/dist/App.js CHANGED
@@ -77,6 +77,7 @@ function App({ constants, appRoutes, defaultRoute, landingPage, overrides = {} }
77
77
  * @param {React.ComponentType} [config.overrides.signUp] - Replace SignUpView
78
78
  * @param {React.ComponentType} [config.overrides.signOut] - Replace SignOutView
79
79
  * @param {React.ComponentType} [config.overrides.notFound] - Replace NotFound
80
+ * @param {React.ComponentType} [config.overrides.authOverlay] - Replace AuthOverlay
80
81
  *
81
82
  * @example
82
83
  * import { createSkateboardApp } from '@stevederico/skateboard-ui/App';
@@ -112,5 +113,6 @@ export function createSkateboardApp({ constants, appRoutes, defaultRoute = appRo
112
113
  document.documentElement.classList.toggle('dark', isDark);
113
114
  const container = document.getElementById('root');
114
115
  const root = createRoot(container);
115
- root.render(_jsx(ErrorBoundary, { children: _jsx(ThemeProvider, { attribute: "class", defaultTheme: "system", enableSystem: true, children: _jsx(ContextProvider, { constants: constants, children: Wrapper ? (_jsx(Wrapper, { children: _jsxs(Router, { children: [_jsx(AuthOverlay, {}), _jsx(App, { constants: constants, appRoutes: appRoutes, defaultRoute: defaultRoute, landingPage: landingPage, overrides: overrides })] }) })) : (_jsxs(Router, { children: [_jsx(AuthOverlay, {}), _jsx(App, { constants: constants, appRoutes: appRoutes, defaultRoute: defaultRoute, landingPage: landingPage, overrides: overrides })] })) }) }) }));
116
+ const AuthOverlayComponent = overrides?.authOverlay || AuthOverlay;
117
+ root.render(_jsx(ErrorBoundary, { children: _jsx(ThemeProvider, { attribute: "class", defaultTheme: "system", enableSystem: true, children: _jsx(ContextProvider, { constants: constants, children: Wrapper ? (_jsx(Wrapper, { children: _jsxs(Router, { children: [_jsx(AuthOverlayComponent, {}), _jsx(App, { constants: constants, appRoutes: appRoutes, defaultRoute: defaultRoute, landingPage: landingPage, overrides: overrides })] }) })) : (_jsxs(Router, { children: [_jsx(AuthOverlayComponent, {}), _jsx(App, { constants: constants, appRoutes: appRoutes, defaultRoute: defaultRoute, landingPage: landingPage, overrides: overrides })] })) }) }) }));
116
118
  }
@@ -9,7 +9,7 @@ function Command({ className, ...props }) {
9
9
  return (_jsx(CommandPrimitive, { "data-slot": "command", className: cn("bg-popover text-popover-foreground rounded-xl! p-1 flex size-full flex-col overflow-hidden", className), ...props }));
10
10
  }
11
11
  function CommandDialog({ title = "Command Palette", description = "Search for a command to run...", children, className, showCloseButton = false, ...props }) {
12
- return (_jsxs(Dialog, { ...props, children: [_jsxs(DialogHeader, { className: "sr-only", children: [_jsx(DialogTitle, { children: title }), _jsx(DialogDescription, { children: description })] }), _jsx(DialogContent, { className: cn("rounded-xl! top-1/3 translate-y-0 overflow-hidden p-0", className), showCloseButton: showCloseButton, children: children })] }));
12
+ return (_jsxs(Dialog, { ...props, children: [_jsxs(DialogHeader, { className: "sr-only", children: [_jsx(DialogTitle, { children: title }), _jsx(DialogDescription, { children: description })] }), _jsx(DialogContent, { className: cn("rounded-xl! self-start justify-self-center mt-[33vh] overflow-hidden p-0", className), showCloseButton: showCloseButton, children: children })] }));
13
13
  }
14
14
  function CommandInput({ className, ...props }) {
15
15
  return (_jsx("div", { "data-slot": "command-input-wrapper", className: "p-1 pb-0", children: _jsxs(InputGroup, { className: "bg-input/30 border-input/30 h-8! rounded-lg! shadow-none! *:data-[slot=input-group-addon]:pl-2!", children: [_jsx(CommandPrimitive.Input, { "data-slot": "command-input", className: cn("w-full text-sm outline-hidden disabled:cursor-not-allowed disabled:opacity-50", className), ...props }), _jsx(InputGroupAddon, { children: _jsx(SearchIcon, { className: "size-4 shrink-0 opacity-50" }) })] }) }));
@@ -213,7 +213,7 @@ function ContextMenuContent({ className, children, onKeyDown, ...props }) {
213
213
  match.focus();
214
214
  }
215
215
  }
216
- }, className: cn("z-50 max-h-(--available-height) min-w-36 origin-(--transform-origin) overflow-x-hidden overflow-y-auto rounded-md bg-popover p-1 text-popover-foreground shadow-md ring-1 ring-foreground/10 duration-100 outline-none data-[side=bottom]:slide-in-from-top-2 data-[side=inline-end]:slide-in-from-left-2 data-[side=inline-start]:slide-in-from-right-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95", className), ...props, children: children }) }));
216
+ }, className: cn("z-50 max-h-(--available-height) min-w-36 origin-(--transform-origin) overflow-x-hidden overflow-y-auto rounded-md bg-popover p-1 text-popover-foreground shadow-md ring-1 ring-foreground/10 transition-none outline-none data-[side=bottom]:slide-in-from-top-2 data-[side=inline-end]:slide-in-from-left-2 data-[side=inline-start]:slide-in-from-right-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95", className), ...props, children: children }) }));
217
217
  }
218
218
  function ContextMenuGroup({ className, ...props }) {
219
219
  return _jsx("div", { role: "group", "data-slot": "context-menu-group", className: className, ...props });
@@ -387,6 +387,6 @@ function ContextMenuSubContent({ className, children, onKeyDown, ...props }) {
387
387
  match.focus();
388
388
  }
389
389
  }
390
- }, className: cn("z-50 min-w-[96px] origin-(--transform-origin) overflow-hidden rounded-md bg-popover p-1 text-popover-foreground shadow-lg ring-1 ring-foreground/10 duration-100 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95", className), ...props, children: children }) }));
390
+ }, className: cn("z-50 min-w-[96px] origin-(--transform-origin) overflow-hidden rounded-md bg-popover p-1 text-popover-foreground shadow-lg ring-1 ring-foreground/10 transition-none data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95", className), ...props, children: children }) }));
391
391
  }
392
392
  export { ContextMenu, ContextMenuTrigger, ContextMenuContent, ContextMenuItem, ContextMenuCheckboxItem, ContextMenuRadioItem, ContextMenuLabel, ContextMenuSeparator, ContextMenuShortcut, ContextMenuGroup, ContextMenuPortal, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuRadioGroup, };
@@ -84,12 +84,31 @@ function DropdownMenuContent({ align = "start", alignOffset = 0, side = "bottom"
84
84
  const { onTypeaheadKeyDown } = useTypeahead();
85
85
  const hasPointerMoved = usePointerMoved();
86
86
  React.useEffect(() => {
87
- const node = containerRef.current;
88
- if (!node)
87
+ if (!mounted)
89
88
  return;
90
- layers.current.add(node);
89
+ // The popup is portaled and attaches a frame late (Portal defers its child to
90
+ // its own effect), so containerRef.current is null when this effect first runs
91
+ // and the deps don't change once it attaches. Retry each frame until the node
92
+ // exists, then register it. Without this the dismiss handler's `layers` set
93
+ // stays empty, so a pointerdown INSIDE the menu fails the contains() check and
94
+ // is treated as an outside click — closing the menu before the item's onClick
95
+ // fires (real mouse only; a synthetic click with no pointerdown masks it).
96
+ let raf = 0;
97
+ let added = null;
98
+ const attach = () => {
99
+ const node = containerRef.current;
100
+ if (!node) {
101
+ raf = requestAnimationFrame(attach);
102
+ return;
103
+ }
104
+ added = node;
105
+ layers.current.add(node);
106
+ };
107
+ attach();
91
108
  return () => {
92
- layers.current.delete(node);
109
+ cancelAnimationFrame(raf);
110
+ if (added)
111
+ layers.current.delete(added);
93
112
  };
94
113
  }, [mounted, layers]);
95
114
  // Focus the first item once the popup is actually visible — a
@@ -186,7 +205,7 @@ function DropdownMenuContent({ align = "start", alignOffset = 0, side = "bottom"
186
205
  match.focus();
187
206
  }
188
207
  }
189
- }, className: cn("z-50 max-h-(--available-height) min-w-32 origin-(--transform-origin) overflow-x-hidden overflow-y-auto rounded-md bg-popover p-1 text-popover-foreground shadow-md ring-1 ring-foreground/10 duration-100 outline-none data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95", className), ...props, children: children }) }));
208
+ }, className: cn("z-50 max-h-(--available-height) min-w-32 origin-(--transform-origin) overflow-x-hidden overflow-y-auto rounded-md bg-popover p-1 text-popover-foreground shadow-md ring-1 ring-foreground/10 transition-none outline-none data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95", className), ...props, children: children }) }));
190
209
  }
191
210
  function DropdownMenuGroup({ className, ...props }) {
192
211
  return _jsx("div", { role: "group", "data-slot": "dropdown-menu-group", className: className, ...props });
@@ -294,12 +313,31 @@ function DropdownMenuSubContent({ className, children, onKeyDown, ...props }) {
294
313
  const { onTypeaheadKeyDown } = useTypeahead();
295
314
  const hasPointerMoved = usePointerMoved();
296
315
  React.useEffect(() => {
297
- const node = containerRef.current;
298
- if (!node)
316
+ if (!mounted)
299
317
  return;
300
- layers.current.add(node);
318
+ // The popup is portaled and attaches a frame late (Portal defers its child to
319
+ // its own effect), so containerRef.current is null when this effect first runs
320
+ // and the deps don't change once it attaches. Retry each frame until the node
321
+ // exists, then register it. Without this the dismiss handler's `layers` set
322
+ // stays empty, so a pointerdown INSIDE the menu fails the contains() check and
323
+ // is treated as an outside click — closing the menu before the item's onClick
324
+ // fires (real mouse only; a synthetic click with no pointerdown masks it).
325
+ let raf = 0;
326
+ let added = null;
327
+ const attach = () => {
328
+ const node = containerRef.current;
329
+ if (!node) {
330
+ raf = requestAnimationFrame(attach);
331
+ return;
332
+ }
333
+ added = node;
334
+ layers.current.add(node);
335
+ };
336
+ attach();
301
337
  return () => {
302
- layers.current.delete(node);
338
+ cancelAnimationFrame(raf);
339
+ if (added)
340
+ layers.current.delete(added);
303
341
  };
304
342
  }, [mounted, layers]);
305
343
  const didFocus = React.useRef(false);
@@ -372,6 +410,6 @@ function DropdownMenuSubContent({ className, children, onKeyDown, ...props }) {
372
410
  match.focus();
373
411
  }
374
412
  }
375
- }, className: cn("z-50 min-w-[96px] origin-(--transform-origin) overflow-hidden rounded-md bg-popover p-1 text-popover-foreground shadow-lg ring-1 ring-foreground/10 duration-100 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95", className), ...props, children: children }) }));
413
+ }, className: cn("z-50 min-w-[96px] origin-(--transform-origin) overflow-hidden rounded-md bg-popover p-1 text-popover-foreground shadow-lg ring-1 ring-foreground/10 transition-none data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95", className), ...props, children: children }) }));
376
414
  }
377
415
  export { DropdownMenu, DropdownMenuPortal, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuGroup, DropdownMenuLabel, DropdownMenuItem, DropdownMenuCheckboxItem, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubTrigger, DropdownMenuSubContent, };
@@ -114,6 +114,6 @@ function HoverCardContent({ className, style, ref, side = "bottom", sideOffset =
114
114
  }, onMouseLeave: (e) => {
115
115
  onMouseLeave?.(e);
116
116
  scheduleClose();
117
- }, className: cn("isolate z-50 w-64 origin-(--transform-origin) rounded-lg bg-popover p-4 text-sm text-popover-foreground shadow-md ring-1 ring-foreground/10 outline-hidden duration-100 data-[side=bottom]:slide-in-from-top-2 data-[side=inline-end]:slide-in-from-left-2 data-[side=inline-start]:slide-in-from-right-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95", className), ...props }) }));
117
+ }, className: cn("isolate z-50 w-64 origin-(--transform-origin) rounded-lg bg-popover p-4 text-sm text-popover-foreground shadow-md ring-1 ring-foreground/10 outline-hidden transition-none data-[side=bottom]:slide-in-from-top-2 data-[side=inline-end]:slide-in-from-left-2 data-[side=inline-start]:slide-in-from-right-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95", className), ...props }) }));
118
118
  }
119
119
  export { HoverCard, HoverCardTrigger, HoverCardContent };
@@ -252,7 +252,7 @@ function MenubarContent({ align = "start", alignOffset = -4, side = "bottom", si
252
252
  match.focus();
253
253
  }
254
254
  }
255
- }, className: cn("z-50 min-w-36 origin-(--transform-origin) overflow-x-hidden overflow-y-auto rounded-md bg-popover p-1 text-popover-foreground shadow-md ring-1 ring-foreground/10 duration-100 outline-none data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95", className), ...props, children: children }) }));
255
+ }, className: cn("z-50 min-w-36 origin-(--transform-origin) overflow-x-hidden overflow-y-auto rounded-md bg-popover p-1 text-popover-foreground shadow-md ring-1 ring-foreground/10 transition-none outline-none data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95", className), ...props, children: children }) }));
256
256
  }
257
257
  function MenubarLabel({ className, inset, ...props }) {
258
258
  return (_jsx("div", { "data-slot": "menubar-label", "data-inset": inset ? "" : undefined, className: cn("px-2 py-1.5 text-sm font-medium data-inset:pl-8", className), ...props }));
@@ -413,6 +413,6 @@ function MenubarSubContent({ className, children, onKeyDown, ...props }) {
413
413
  active.click();
414
414
  }
415
415
  }
416
- }, className: cn("z-50 min-w-32 origin-(--transform-origin) overflow-hidden rounded-md bg-popover p-1 text-popover-foreground shadow-lg ring-1 ring-foreground/10 duration-100 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95", className), ...props, children: children }) }));
416
+ }, className: cn("z-50 min-w-32 origin-(--transform-origin) overflow-hidden rounded-md bg-popover p-1 text-popover-foreground shadow-lg ring-1 ring-foreground/10 transition-none data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95", className), ...props, children: children }) }));
417
417
  }
418
418
  export { Menubar, MenubarPortal, MenubarMenu, MenubarTrigger, MenubarContent, MenubarGroup, MenubarSeparator, MenubarLabel, MenubarItem, MenubarShortcut, MenubarCheckboxItem, MenubarRadioGroup, MenubarRadioItem, MenubarSub, MenubarSubTrigger, MenubarSubContent, };
@@ -125,7 +125,7 @@ function PopoverContent({ className, style, ref, align = "center", alignOffset =
125
125
  top: pos?.y ?? 0,
126
126
  visibility: pos ? "visible" : "hidden",
127
127
  ["--transform-origin"]: pos?.transformOrigin ?? "center",
128
- }, className: cn("isolate z-50 flex w-72 origin-(--transform-origin) flex-col gap-4 rounded-md bg-popover p-4 text-sm text-popover-foreground shadow-md ring-1 ring-foreground/10 outline-hidden duration-100 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95", className), ...props }) }));
128
+ }, className: cn("isolate z-50 flex w-72 origin-(--transform-origin) flex-col gap-4 rounded-md bg-popover p-4 text-sm text-popover-foreground shadow-md ring-1 ring-foreground/10 outline-hidden transition-none data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95", className), ...props }) }));
129
129
  }
130
130
  function PopoverHeader({ className, ...props }) {
131
131
  return (_jsx("div", { "data-slot": "popover-header", className: cn("flex flex-col gap-1 text-sm", className), ...props }));
package/dist/ui/select.js CHANGED
@@ -207,7 +207,7 @@ function SelectContent({ className, children, side = "bottom", sideOffset = 4, a
207
207
  match.focus();
208
208
  }
209
209
  }
210
- }, className: cn("relative isolate z-50 max-h-(--available-height) min-w-36 origin-(--transform-origin) overflow-x-hidden overflow-y-auto rounded-md bg-popover p-1 text-popover-foreground shadow-md ring-1 ring-foreground/10 duration-100 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95", className), ...props, children: children }) }));
210
+ }, className: cn("relative isolate z-50 max-h-(--available-height) min-w-36 origin-(--transform-origin) overflow-x-hidden overflow-y-auto rounded-md bg-popover p-1 text-popover-foreground shadow-md ring-1 ring-foreground/10 transition-none data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95", className), ...props, children: children }) }));
211
211
  }
212
212
  function SelectLabel({ className, ...props }) {
213
213
  return (_jsx("div", { "data-slot": "select-label", className: cn("px-2 py-1.5 text-xs text-muted-foreground", className), ...props }));
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@stevederico/skateboard-ui",
3
3
  "private": false,
4
- "version": "4.6.0",
4
+ "version": "4.10.0",
5
5
  "type": "module",
6
6
  "exports": {
7
7
  ".": {