@stevederico/skateboard-ui 4.9.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/CHANGELOG.md CHANGED
@@ -1,5 +1,10 @@
1
1
  # CHANGELOG
2
2
 
3
+ 4.10.0
4
+
5
+ Fix dropdown menu item clicks
6
+ Register portaled layer after attach
7
+
3
8
  4.9.0
4
9
 
5
10
  Replace duration with transition-none
@@ -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
@@ -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);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@stevederico/skateboard-ui",
3
3
  "private": false,
4
- "version": "4.9.0",
4
+ "version": "4.10.0",
5
5
  "type": "module",
6
6
  "exports": {
7
7
  ".": {