cursedbelt 5.15.0 → 5.15.2

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.
@@ -1,4 +1,4 @@
1
- import type { ReactNode } from 'react';
1
+ import { type ReactNode } from 'react';
2
2
  export interface DropdownMenuAction {
3
3
  key: string;
4
4
  label: ReactNode;
@@ -1 +1 @@
1
- {"version":3,"file":"DropdownMenu.d.ts","sourceRoot":"","sources":["../../../src/react/components/DropdownMenu.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAUvC,MAAM,WAAW,kBAAkB;IACjC,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,SAAS,CAAC;IACjB,WAAW,CAAC,EAAE,SAAS,CAAC;IACxB,mFAAmF;IACnF,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;;;;OAMG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,qDAAqD;IACrD,QAAQ,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAC9B,OAAO,CAAC,EAAE,KAAK,CAAC;CACjB;AAED,gEAAgE;AAChE,MAAM,WAAW,mBAAmB;IAClC,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,IAAI,CAAC;IACd;qFACiF;IACjF,KAAK,CAAC,EAAE,SAAS,CAAC;CACnB;AAED;;;;;GAKG;AACH,MAAM,MAAM,gBAAgB,GAAG,kBAAkB,GAAG,mBAAmB,CAAC;AAExE,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,SAAS,CAAC;IACnB,KAAK,EAAE,gBAAgB,EAAE,CAAC;IAC1B,iFAAiF;IACjF,KAAK,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,KAAK,CAAC;IACnC,8EAA8E;IAC9E,IAAI,CAAC,EAAE,KAAK,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAC;IAC3C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;OAKG;IACH,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;CACxC;AAED;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAAC,EAC3B,OAAO,EACP,KAAK,EACL,KAAe,EACf,IAAe,EACf,SAAS,EACT,IAAI,EACJ,YAAY,GACb,EAAE,iBAAiB,+BAqBnB"}
1
+ {"version":3,"file":"DropdownMenu.d.ts","sourceRoot":"","sources":["../../../src/react/components/DropdownMenu.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,SAAS,EAAiC,MAAM,OAAO,CAAC;AAWtE,MAAM,WAAW,kBAAkB;IACjC,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,SAAS,CAAC;IACjB,WAAW,CAAC,EAAE,SAAS,CAAC;IACxB,mFAAmF;IACnF,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;;;;OAMG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,qDAAqD;IACrD,QAAQ,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAC9B,OAAO,CAAC,EAAE,KAAK,CAAC;CACjB;AAED,gEAAgE;AAChE,MAAM,WAAW,mBAAmB;IAClC,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,IAAI,CAAC;IACd;qFACiF;IACjF,KAAK,CAAC,EAAE,SAAS,CAAC;CACnB;AAED;;;;;GAKG;AACH,MAAM,MAAM,gBAAgB,GAAG,kBAAkB,GAAG,mBAAmB,CAAC;AAExE,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,SAAS,CAAC;IACnB,KAAK,EAAE,gBAAgB,EAAE,CAAC;IAC1B,iFAAiF;IACjF,KAAK,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,KAAK,CAAC;IACnC,8EAA8E;IAC9E,IAAI,CAAC,EAAE,KAAK,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAC;IAC3C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;OAKG;IACH,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;CACxC;AAED;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAAC,EAC3B,OAAO,EACP,KAAK,EACL,KAAe,EACf,IAAe,EACf,SAAS,EACT,IAAI,EACJ,YAAY,GACb,EAAE,iBAAiB,+BAiDnB"}
@@ -1,6 +1,8 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import * as RDrop from '@radix-ui/react-dropdown-menu';
3
3
  import { Check, ChevronRight } from 'lucide-react';
4
+ import { useCallback, useRef, useState } from 'react';
5
+ import { useOutsidePress } from '../hooks/useOutsidePress.js';
4
6
  import { cn } from '../lib/cn.js';
5
7
  import { useFloatingContainer } from '../lib/floatingContainer.js';
6
8
  import { FLOATING_ANIMATION, FLOATING_COLLISION_PADDING, FLOATING_CONTENT_BASE, FLOATING_ITEM_BASE, } from '../lib/floatingStyles.js';
@@ -15,7 +17,29 @@ import { FLOATING_ANIMATION, FLOATING_COLLISION_PADDING, FLOATING_CONTENT_BASE,
15
17
  */
16
18
  export function DropdownMenu({ trigger, items, align = 'start', side = 'bottom', className, open, onOpenChange, }) {
17
19
  const container = useFloatingContainer();
18
- return (_jsxs(RDrop.Root, { open: open, onOpenChange: onOpenChange, children: [_jsx(RDrop.Trigger, { asChild: true, children: trigger }), _jsx(RDrop.Portal, { container: container, children: _jsxs(RDrop.Content, { align: align, side: side, sideOffset: 4, collisionPadding: FLOATING_COLLISION_PADDING, className: cn(FLOATING_CONTENT_BASE, FLOATING_ANIMATION, 'min-w-[8rem] p-1', className), children: [items.map((item) => (_jsx(DropdownItem, { item: item }, item.key))), _jsx(RDrop.Arrow, { className: 'fill-border' })] }) })] }));
20
+ // Always controlled underneath, so the outside-press fallback can close it too.
21
+ const [ownOpen, setOwnOpen] = useState(false);
22
+ const isOpen = open ?? ownOpen;
23
+ const setOpen = useCallback((next) => {
24
+ if (open === undefined)
25
+ setOwnOpen(next);
26
+ onOpenChange?.(next);
27
+ }, [open, onOpenChange]);
28
+ /*
29
+ * Radix's menu listens for the outside `pointerdown` in the BUBBLE phase, so a surface that
30
+ * stops its own pointerdown (a drag handle, a canvas) kept the menu open. The belt's one
31
+ * tap-away listener runs in the capture phase; see `useOutsidePress`. The menu is modal, so
32
+ * it decides on the pointerdown (an inert page sends an iPhone no click).
33
+ */
34
+ const triggerRef = useRef(null);
35
+ const pressInside = useOutsidePress({
36
+ open: isOpen,
37
+ onDismiss: () => setOpen(false),
38
+ inside: [triggerRef],
39
+ escape: false,
40
+ decideOn: 'pointerdown',
41
+ });
42
+ return (_jsxs(RDrop.Root, { open: isOpen, onOpenChange: setOpen, children: [_jsx(RDrop.Trigger, { asChild: true, ref: triggerRef, children: trigger }), _jsx(RDrop.Portal, { container: container, children: _jsxs(RDrop.Content, { align: align, side: side, sideOffset: 4, collisionPadding: FLOATING_COLLISION_PADDING, onClickCapture: pressInside.onClickCapture, onPointerDownCapture: pressInside.onPointerDownCapture, className: cn(FLOATING_CONTENT_BASE, FLOATING_ANIMATION, 'min-w-[8rem] p-1', className), children: [items.map((item) => (_jsx(DropdownItem, { item: item }, item.key))), _jsx(RDrop.Arrow, { className: 'fill-border' })] }) })] }));
19
43
  }
20
44
  function DropdownItem({ item }) {
21
45
  const container = useFloatingContainer();
@@ -1 +1 @@
1
- {"version":3,"file":"DropdownMenu.js","sourceRoot":"","sources":["../../../src/react/components/DropdownMenu.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"DropdownMenu.js","sourceRoot":"","sources":["../../../src/react/components/DropdownMenu.tsx"],"names":[],"mappings":";AAAA,OAAO,KAAK,KAAK,MAAM,+BAA+B,CAAC;AACvD,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EAAkB,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACtE,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAClC,OAAO,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AACnE,OAAO,EACL,kBAAkB,EAClB,0BAA0B,EAC1B,qBAAqB,EACrB,kBAAkB,GACnB,MAAM,0BAA0B,CAAC;AA4DlC;;;;;;;;GAQG;AACH,MAAM,UAAU,YAAY,CAAC,EAC3B,OAAO,EACP,KAAK,EACL,KAAK,GAAG,OAAO,EACf,IAAI,GAAG,QAAQ,EACf,SAAS,EACT,IAAI,EACJ,YAAY,GACM;IAClB,MAAM,SAAS,GAAG,oBAAoB,EAAE,CAAC;IACzC,gFAAgF;IAChF,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAC9C,MAAM,MAAM,GAAG,IAAI,IAAI,OAAO,CAAC;IAC/B,MAAM,OAAO,GAAG,WAAW,CACzB,CAAC,IAAa,EAAE,EAAE;QAChB,IAAI,IAAI,KAAK,SAAS;YAAE,UAAU,CAAC,IAAI,CAAC,CAAC;QACzC,YAAY,EAAE,CAAC,IAAI,CAAC,CAAC;IACvB,CAAC,EACD,CAAC,IAAI,EAAE,YAAY,CAAC,CACrB,CAAC;IACF;;;;;OAKG;IACH,MAAM,UAAU,GAAG,MAAM,CAA2B,IAAI,CAAC,CAAC;IAC1D,MAAM,WAAW,GAAG,eAAe,CAAC;QAClC,IAAI,EAAE,MAAM;QACZ,SAAS,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC;QAC/B,MAAM,EAAE,CAAC,UAAU,CAAC;QACpB,MAAM,EAAE,KAAK;QACb,QAAQ,EAAE,aAAa;KACxB,CAAC,CAAC;IACH,OAAO,CACL,MAAC,KAAK,CAAC,IAAI,IAAC,IAAI,EAAE,MAAM,EAAE,YAAY,EAAE,OAAO,aAC7C,KAAC,KAAK,CAAC,OAAO,IAAC,OAAO,QAAC,GAAG,EAAE,UAAU,YACnC,OAAO,GACM,EAChB,KAAC,KAAK,CAAC,MAAM,IAAC,SAAS,EAAE,SAAS,YAChC,MAAC,KAAK,CAAC,OAAO,IACZ,KAAK,EAAE,KAAK,EACZ,IAAI,EAAE,IAAI,EACV,UAAU,EAAE,CAAC,EACb,gBAAgB,EAAE,0BAA0B,EAC5C,cAAc,EAAE,WAAW,CAAC,cAAc,EAC1C,oBAAoB,EAAE,WAAW,CAAC,oBAAoB,EACtD,SAAS,EAAE,EAAE,CAAC,qBAAqB,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,SAAS,CAAC,aAEtF,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CACnB,KAAC,YAAY,IAAgB,IAAI,EAAE,IAAI,IAApB,IAAI,CAAC,GAAG,CAAgB,CAC5C,CAAC,EACF,KAAC,KAAK,CAAC,KAAK,IAAC,SAAS,EAAC,aAAa,GAAG,IACzB,GACH,IACJ,CACd,CAAC;AACJ,CAAC;AAED,SAAS,YAAY,CAAC,EAAE,IAAI,EAA8B;IACxD,MAAM,SAAS,GAAG,oBAAoB,EAAE,CAAC;IACzC,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;QACjB,OAAO,KAAC,KAAK,CAAC,SAAS,IAAC,SAAS,EAAC,qBAAqB,GAAG,CAAC;IAC7D,CAAC;IAED,IAAI,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,CAAC;QAC1B,OAAO,CACL,MAAC,KAAK,CAAC,GAAG,eACR,MAAC,KAAK,CAAC,UAAU,IAAC,SAAS,EAAE,EAAE,CAAC,kBAAkB,EAAE,iBAAiB,CAAC,aACpE,gBAAM,SAAS,EAAC,yBAAyB,aACtC,IAAI,CAAC,IAAI,IAAI,CACZ,eAAM,SAAS,EAAC,gDAAgD,iCAC7D,IAAI,CAAC,IAAI,GACL,CACR,EACA,IAAI,CAAC,KAAK,IACN,EACP,KAAC,YAAY,IAAC,SAAS,EAAC,mBAAmB,GAAG,IAC7B,EACnB,KAAC,KAAK,CAAC,MAAM,IAAC,SAAS,EAAE,SAAS,YAChC,KAAC,KAAK,CAAC,UAAU,IACf,SAAS,EAAE,EAAE,CAAC,qBAAqB,EAAE,kBAAkB,EAAE,kBAAkB,CAAC,EAC5E,UAAU,EAAE,CAAC,EACb,gBAAgB,EAAE,0BAA0B,YAE3C,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAC5B,KAAC,YAAY,IAAiB,IAAI,EAAE,KAAK,IAAtB,KAAK,CAAC,GAAG,CAAiB,CAC9C,CAAC,GACe,GACN,IACL,CACb,CAAC;IACJ,CAAC;IAED,IAAI,IAAI,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;QAC/B,OAAO,CACL,MAAC,KAAK,CAAC,YAAY,IACjB,OAAO,EAAE,IAAI,CAAC,OAAO,EACrB,eAAe,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,EACvC,QAAQ,EAAE,IAAI,CAAC,QAAQ,EACvB,SAAS,EAAE,EAAE,CACX,kBAAkB,EAClB,MAAM,EACN,IAAI,CAAC,WAAW,IAAI,yCAAyC,CAC9D,aAED,KAAC,KAAK,CAAC,aAAa,IAAC,SAAS,EAAC,yDAAyD,YACtF,KAAC,KAAK,IAAC,SAAS,EAAC,QAAQ,GAAG,GACR,EACrB,IAAI,CAAC,IAAI,IAAI,CACZ,eAAM,SAAS,EAAC,gDAAgD,iCAC7D,IAAI,CAAC,IAAI,GACL,CACR,EACD,yBAAO,IAAI,CAAC,KAAK,GAAQ,EACxB,IAAI,CAAC,WAAW,IAAI,CACnB,eAAM,SAAS,EAAC,uCAAuC,YAAE,IAAI,CAAC,WAAW,GAAQ,CAClF,IACkB,CACtB,CAAC;IACJ,CAAC;IAED,OAAO,CACL,MAAC,KAAK,CAAC,IAAI,IACT,QAAQ,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,EAChC,QAAQ,EAAE,IAAI,CAAC,QAAQ,EACvB,KAAK,EAAE,IAAI,CAAC,KAAK,EACjB,SAAS,EAAE,EAAE,CACX,kBAAkB,EAClB,IAAI,CAAC,WAAW,IAAI,iEAAiE,CACtF,aAEA,IAAI,CAAC,IAAI,IAAI,CACZ,eAAM,SAAS,EAAC,gDAAgD,iCAC7D,IAAI,CAAC,IAAI,GACL,CACR,EACD,yBAAO,IAAI,CAAC,KAAK,GAAQ,EACxB,IAAI,CAAC,WAAW,IAAI,CACnB,eAAM,SAAS,EAAC,uCAAuC,YAAE,IAAI,CAAC,WAAW,GAAQ,CAClF,IACU,CACd,CAAC;AACJ,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"Popover.d.ts","sourceRoot":"","sources":["../../../src/react/components/Popover.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,SAAS,EAA0C,MAAM,OAAO,CAAC;AAU/E;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;CAC1B;AAED,MAAM,WAAW,YAAY;IAC3B,uFAAuF;IACvF,OAAO,CAAC,EAAE,SAAS,CAAC;IACpB;;;;OAIG;IACH,MAAM,CAAC,EAAE,OAAO,GAAG,YAAY,GAAG,IAAI,CAAC;IACvC,QAAQ,EAAE,SAAS,CAAC;IACpB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACvC,KAAK,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,KAAK,CAAC;IACnC,IAAI,CAAC,EAAE,KAAK,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAC;IAC3C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,oEAAoE;IACpE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB,2FAA2F;IAC3F,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;;;OAKG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB;;;;OAIG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,4FAA4F;IAC5F,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,wEAAwE;IACxE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,0DAA0D;IAC1D,IAAI,CAAC,EAAE,QAAQ,GAAG,MAAM,GAAG,SAAS,CAAC;CACtC;AAMD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,OAAO,CAAC,EACtB,OAAO,EACP,MAAM,EACN,QAAQ,EACR,IAAI,EACJ,YAAY,EACZ,KAAe,EACf,IAAe,EACf,UAAc,EACd,KAAK,EACL,KAAK,EACL,SAAS,EACT,QAAgB,EAChB,KAAa,EACb,MAAa,EACb,SAAgB,EAChB,KAAK,EACL,IAAI,GACL,EAAE,YAAY,+BAuFd;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,EAAE,QAAQ,EAAE,EAAE;IAAE,QAAQ,EAAE,SAAS,CAAA;CAAE,+BAEjE"}
1
+ {"version":3,"file":"Popover.d.ts","sourceRoot":"","sources":["../../../src/react/components/Popover.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,SAAS,EAA0C,MAAM,OAAO,CAAC;AAU/E;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;CAC1B;AAED,MAAM,WAAW,YAAY;IAC3B,uFAAuF;IACvF,OAAO,CAAC,EAAE,SAAS,CAAC;IACpB;;;;OAIG;IACH,MAAM,CAAC,EAAE,OAAO,GAAG,YAAY,GAAG,IAAI,CAAC;IACvC,QAAQ,EAAE,SAAS,CAAC;IACpB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACvC,KAAK,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,KAAK,CAAC;IACnC,IAAI,CAAC,EAAE,KAAK,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAC;IAC3C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,oEAAoE;IACpE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB,2FAA2F;IAC3F,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;;;OAKG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB;;;;OAIG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,4FAA4F;IAC5F,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,wEAAwE;IACxE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,0DAA0D;IAC1D,IAAI,CAAC,EAAE,QAAQ,GAAG,MAAM,GAAG,SAAS,CAAC;CACtC;AAMD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,OAAO,CAAC,EACtB,OAAO,EACP,MAAM,EACN,QAAQ,EACR,IAAI,EACJ,YAAY,EACZ,KAAe,EACf,IAAe,EACf,UAAc,EACd,KAAK,EACL,KAAK,EACL,SAAS,EACT,QAAgB,EAChB,KAAa,EACb,MAAa,EACb,SAAgB,EAChB,KAAK,EACL,IAAI,GACL,EAAE,YAAY,+BA2Fd;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,EAAE,QAAQ,EAAE,EAAE;IAAE,QAAQ,EAAE,SAAS,CAAA;CAAE,+BAEjE"}
@@ -60,6 +60,9 @@ export function Popover({ trigger, anchor, children, open, onOpenChange, align =
60
60
  onDismiss: () => setOpen(false),
61
61
  inside: [triggerRef, anchorTrigger],
62
62
  escape: false,
63
+ // Under `modal` the page is inert and an iPhone sends no click for a tap on it — see
64
+ // `decideOn` in useOutsidePress.
65
+ decideOn: modal ? 'pointerdown' : 'click',
63
66
  });
64
67
  const content = (_jsxs(RPopover.Content, { align: align, side: side, sideOffset: sideOffset, collisionPadding: FLOATING_COLLISION_PADDING, style: width != null ? { width } : undefined, "aria-label": label, ...(role ? { role } : {}), onOpenAutoFocus: autoFocus ? undefined : (event) => event.preventDefault(), onInteractOutside: (event) => {
65
68
  // The anchor's own control decides open/shut with its click — see PopoverPoint.
@@ -68,7 +71,7 @@ export function Popover({ trigger, anchor, children, open, onOpenChange, align =
68
71
  },
69
72
  // React-tree capture: a press on a nested layer this panel portalled (a Select's
70
73
  // list, a sub-menu) is INSIDE even though the DOM puts it elsewhere.
71
- onClickCapture: pressInside.onClickCapture, className: cn(unstyled
74
+ onClickCapture: pressInside.onClickCapture, onPointerDownCapture: pressInside.onPointerDownCapture, className: cn(unstyled
72
75
  ? 'z-[var(--z-popover)] outline-none'
73
76
  : cn(FLOATING_CONTENT_BASE, 'p-3'), FLOATING_ANIMATION, className), children: [children, showArrow && _jsx(RPopover.Arrow, { className: 'fill-border' })] }));
74
77
  return (_jsxs(RPopover.Root, { open: isOpen, onOpenChange: setOpen, modal: modal, children: [virtualRef ? _jsx(RPopover.Anchor, { virtualRef: virtualRef }) : null, trigger !== undefined ? (_jsx(RPopover.Trigger, { asChild: true, ref: triggerRef, children: trigger })) : null, portal ? _jsx(RPopover.Portal, { container: container, children: content }) : content] }));
@@ -1 +1 @@
1
- {"version":3,"file":"Popover.js","sourceRoot":"","sources":["../../../src/react/components/Popover.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Popover.js","sourceRoot":"","sources":["../../../src/react/components/Popover.tsx"],"names":[],"mappings":"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"}
@@ -19,6 +19,17 @@ export interface UseOutsidePressOptions {
19
19
  * whose rows play on tap). Default false.
20
20
  */
21
21
  modal?: boolean;
22
+ /**
23
+ * Decide on the `pointerdown` rather than the `click`. Only for a panel that has made the
24
+ * page under it inert (`Popover`'s `modal`, which sets `pointer-events: none` on body).
25
+ *
26
+ * 🔴 Measured 2026-09-27 in Playwright's iPhone 15 WebKit: with the page inert, a tap
27
+ * outside hits `<html>`, which iOS does not consider clickable, so NO `click` is ever
28
+ * sent — the menu stayed open under the owner's finger, exactly as reported. Deciding on
29
+ * the pointerdown closes it; the `click` that same press may still produce is swallowed,
30
+ * or it would land on whatever the closed menu uncovered (the picture, which pauses).
31
+ */
32
+ decideOn?: 'click' | 'pointerdown';
22
33
  }
23
34
  /**
24
35
  * Close a panel when the reader presses anywhere else — the ONE implementation of it in the
@@ -41,8 +52,9 @@ export interface UseOutsidePressOptions {
41
52
  * · **the toggle is inside**, or pressing an open menu's own button shuts it and reopens
42
53
  * it a frame later — the "menu that ignores the second press" desk hit on 2026-09-07.
43
54
  */
44
- export declare function useOutsidePress({ open, onDismiss, inside, escape: closeOnEscape, modal, }: UseOutsidePressOptions): {
55
+ export declare function useOutsidePress({ open, onDismiss, inside, escape: closeOnEscape, modal, decideOn, }: UseOutsidePressOptions): {
45
56
  onClickCapture: () => void;
57
+ onPointerDownCapture: () => void;
46
58
  };
47
59
  export {};
48
60
  //# sourceMappingURL=useOutsidePress.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useOutsidePress.d.ts","sourceRoot":"","sources":["../../../src/react/hooks/useOutsidePress.ts"],"names":[],"mappings":"AAEA,KAAK,YAAY,GAAG;IAAE,OAAO,EAAE,OAAO,GAAG,IAAI,CAAA;CAAE,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,CAAC;AAE7E,MAAM,WAAW,sBAAsB;IACrC,+BAA+B;IAC/B,IAAI,EAAE,OAAO,CAAC;IACd,+EAA+E;IAC/E,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB;;;OAGG;IACH,MAAM,CAAC,EAAE,SAAS,YAAY,EAAE,CAAC;IACjC,4CAA4C;IAC5C,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB;;;;OAIG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAUD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,eAAe,CAAC,EAC9B,IAAI,EACJ,SAAS,EACT,MAAW,EACX,MAAM,EAAE,aAAoB,EAC5B,KAAa,GACd,EAAE,sBAAsB,GAAG;IAAE,cAAc,EAAE,MAAM,IAAI,CAAA;CAAE,CA8DzD"}
1
+ {"version":3,"file":"useOutsidePress.d.ts","sourceRoot":"","sources":["../../../src/react/hooks/useOutsidePress.ts"],"names":[],"mappings":"AAEA,KAAK,YAAY,GAAG;IAAE,OAAO,EAAE,OAAO,GAAG,IAAI,CAAA;CAAE,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,CAAC;AAE7E,MAAM,WAAW,sBAAsB;IACrC,+BAA+B;IAC/B,IAAI,EAAE,OAAO,CAAC;IACd,+EAA+E;IAC/E,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB;;;OAGG;IACH,MAAM,CAAC,EAAE,SAAS,YAAY,EAAE,CAAC;IACjC,4CAA4C;IAC5C,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB;;;;OAIG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB;;;;;;;;;OASG;IACH,QAAQ,CAAC,EAAE,OAAO,GAAG,aAAa,CAAC;CACpC;AAUD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,eAAe,CAAC,EAC9B,IAAI,EACJ,SAAS,EACT,MAAW,EACX,MAAM,EAAE,aAAoB,EAC5B,KAAa,EACb,QAAkB,GACnB,EAAE,sBAAsB,GAAG;IAAE,cAAc,EAAE,MAAM,IAAI,CAAC;IAAC,oBAAoB,EAAE,MAAM,IAAI,CAAA;CAAE,CAuF3F"}
@@ -25,7 +25,7 @@ function resolve(target) {
25
25
  * · **the toggle is inside**, or pressing an open menu's own button shuts it and reopens
26
26
  * it a frame later — the "menu that ignores the second press" desk hit on 2026-09-07.
27
27
  */
28
- export function useOutsidePress({ open, onDismiss, inside = [], escape: closeOnEscape = true, modal = false, }) {
28
+ export function useOutsidePress({ open, onDismiss, inside = [], escape: closeOnEscape = true, modal = false, decideOn = 'click', }) {
29
29
  const pressInsideRef = useRef(false);
30
30
  // Latest values without re-subscribing on every render — a listener torn down mid-gesture
31
31
  // would miss the very click it exists for.
@@ -50,15 +50,8 @@ export function useOutsidePress({ open, onDismiss, inside = [], escape: closeOnE
50
50
  return element ? layer.contains(element) : false;
51
51
  });
52
52
  };
53
- const onClick = (event) => {
54
- pressInsideRef.current = false;
55
- const target = event.target instanceof Node ? event.target : null;
56
- if (target && latest.current.modal && !isInside(target) && !onAnotherLayer(target)) {
57
- // Decidable now for a DOM-inside press; a React-tree-inside press would have been
58
- // swallowed too, so a modal panel's portalled layers must live inside `inside`.
59
- event.preventDefault();
60
- event.stopPropagation();
61
- }
53
+ /** Decide once the event has finished dispatching — see the header. */
54
+ const decideLater = (target) => {
62
55
  const timer = setTimeout(() => {
63
56
  timers.delete(timer);
64
57
  if (pressInsideRef.current || !target)
@@ -71,24 +64,57 @@ export function useOutsidePress({ open, onDismiss, inside = [], escape: closeOnE
71
64
  }, 0);
72
65
  timers.add(timer);
73
66
  };
67
+ const outside = (target) => Boolean(target) && !isInside(target) && !onAnotherLayer(target);
68
+ // `pointerdown` mode: the click the same press produces is not a second decision — it is
69
+ // swallowed, until the next press or a second later, whichever comes first.
70
+ let swallowUntil = 0;
71
+ const onPointerDown = (event) => {
72
+ pressInsideRef.current = false;
73
+ swallowUntil = 0;
74
+ const target = event.target instanceof Node ? event.target : null;
75
+ if (outside(target))
76
+ swallowUntil = Date.now() + 1000;
77
+ decideLater(target);
78
+ };
79
+ const onClick = (event) => {
80
+ const target = event.target instanceof Node ? event.target : null;
81
+ if (decideOn === 'pointerdown') {
82
+ if (Date.now() < swallowUntil) {
83
+ swallowUntil = 0;
84
+ event.preventDefault();
85
+ event.stopPropagation();
86
+ }
87
+ return;
88
+ }
89
+ pressInsideRef.current = false;
90
+ if (latest.current.modal && outside(target)) {
91
+ // Decidable now for a DOM-inside press; a React-tree-inside press would have been
92
+ // swallowed too, so a modal panel's portalled layers must live inside `inside`.
93
+ event.preventDefault();
94
+ event.stopPropagation();
95
+ }
96
+ decideLater(target);
97
+ };
74
98
  const onKeyDown = (event) => {
75
99
  if (event.key === 'Escape')
76
100
  latest.current.onDismiss();
77
101
  };
78
102
  document.addEventListener('click', onClick, true);
103
+ if (decideOn === 'pointerdown')
104
+ document.addEventListener('pointerdown', onPointerDown, true);
79
105
  if (closeOnEscape)
80
106
  document.addEventListener('keydown', onKeyDown);
81
107
  return () => {
82
108
  document.removeEventListener('click', onClick, true);
109
+ document.removeEventListener('pointerdown', onPointerDown, true);
83
110
  document.removeEventListener('keydown', onKeyDown);
84
111
  for (const timer of timers)
85
112
  clearTimeout(timer);
86
113
  };
87
- }, [open, closeOnEscape]);
88
- return {
89
- onClickCapture: () => {
90
- pressInsideRef.current = true;
91
- },
114
+ }, [open, closeOnEscape, decideOn]);
115
+ const markInside = () => {
116
+ pressInsideRef.current = true;
92
117
  };
118
+ return { onClickCapture: markInside, onPointerDownCapture: markInside };
93
119
  }
94
120
  //# sourceMappingURL=useOutsidePress.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"useOutsidePress.js","sourceRoot":"","sources":["../../../src/react/hooks/useOutsidePress.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"useOutsidePress.js","sourceRoot":"","sources":["../../../src/react/hooks/useOutsidePress.ts"],"names":[],"mappings":"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"}
@@ -75,7 +75,11 @@ export declare const defaultIconMap: Record<IconToken, IconComponent>;
75
75
  export declare function createIconMapRegistry(): IconMapRegistry;
76
76
  export interface DynamicIconProps {
77
77
  token?: IconToken;
78
- /** The icon map to resolve `token` against — typically `runtime.icons`. */
78
+ /**
79
+ * The icon map to resolve `token` against — typically `runtime.icons`. Omitted, the token
80
+ * resolves against `defaultIconMap`, so a plain `<DynamicIcon token="settings" />` draws the
81
+ * settings icon.
82
+ */
79
83
  iconMap?: IconMapRegistry | null;
80
84
  className?: string;
81
85
  }
@@ -91,8 +95,14 @@ export interface DynamicIconProps {
91
95
  * element and visually overflows into neighboring content instead of
92
96
  * respecting the icon's slot.
93
97
  *
94
- * The `iconMap` is typically the `runtime.icons` registry from the host shell —
95
- * pass it explicitly so this component stays framework/runtime-agnostic.
98
+ * The `iconMap` is typically the `runtime.icons` registry from the host shell.
99
+ *
100
+ * 🔴 Omitted, it is `defaultIconMap` — NOT "nothing registered". Until 5.15.1 a missing
101
+ * `iconMap` resolved every token to the letter fallback, so vault's header, which renders
102
+ * `<DynamicIcon token="unlock" />` and its neighbours with no map, painted the letters
103
+ * "U W S" where its lock, generator and settings icons belonged, on every screen, from the
104
+ * day it adopted the component. A registry that was never passed is not a registry that was
105
+ * cleared; only an explicit map may leave a token unresolved.
96
106
  */
97
107
  export declare function DynamicIcon({ token, iconMap, className }: DynamicIconProps): React.JSX.Element | null;
98
108
  //# sourceMappingURL=icons.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"icons.d.ts","sourceRoot":"","sources":["../../src/react/icons.tsx"],"names":[],"mappings":"AAyDA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAI/B,8DAA8D;AAC9D,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8Ef,CAAC;AAEX,MAAM,MAAM,SAAS,GAAG,MAAM,OAAO,YAAY,CAAC;AAElD,MAAM,MAAM,aAAa,GAAG,KAAK,CAAC,aAAa,CAAC;IAC9C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC,CAAC;AAEH,MAAM,WAAW,eAAe;IAC9B,kFAAkF;IAClF,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAC,MAAM,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC,GAAG,IAAI,CAAC;IAC/D,GAAG,CAAC,KAAK,EAAE,SAAS,GAAG,aAAa,GAAG,SAAS,CAAC;IACjD,KAAK,IAAI,IAAI,CAAC;CACf;AAED;;0EAE0E;AAC1E,eAAO,MAAM,cAAc,EAAE,MAAM,CAAC,SAAS,EAAE,aAAa,CAwD3D,CAAC;AAEF,wBAAgB,qBAAqB,IAAI,eAAe,CAavD;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,2EAA2E;IAC3E,OAAO,CAAC,EAAE,eAAe,GAAG,IAAI,CAAC;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,WAAW,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,EAAE,gBAAgB,4BAoB1E"}
1
+ {"version":3,"file":"icons.d.ts","sourceRoot":"","sources":["../../src/react/icons.tsx"],"names":[],"mappings":"AAyDA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAI/B,8DAA8D;AAC9D,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8Ef,CAAC;AAEX,MAAM,MAAM,SAAS,GAAG,MAAM,OAAO,YAAY,CAAC;AAElD,MAAM,MAAM,aAAa,GAAG,KAAK,CAAC,aAAa,CAAC;IAC9C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC,CAAC;AAEH,MAAM,WAAW,eAAe;IAC9B,kFAAkF;IAClF,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAC,MAAM,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC,GAAG,IAAI,CAAC;IAC/D,GAAG,CAAC,KAAK,EAAE,SAAS,GAAG,aAAa,GAAG,SAAS,CAAC;IACjD,KAAK,IAAI,IAAI,CAAC;CACf;AAED;;0EAE0E;AAC1E,eAAO,MAAM,cAAc,EAAE,MAAM,CAAC,SAAS,EAAE,aAAa,CAwD3D,CAAC;AAEF,wBAAgB,qBAAqB,IAAI,eAAe,CAavD;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB;;;;OAIG;IACH,OAAO,CAAC,EAAE,eAAe,GAAG,IAAI,CAAC;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,WAAW,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,EAAE,gBAAgB,4BAoB1E"}
@@ -168,13 +168,19 @@ export function createIconMapRegistry() {
168
168
  * element and visually overflows into neighboring content instead of
169
169
  * respecting the icon's slot.
170
170
  *
171
- * The `iconMap` is typically the `runtime.icons` registry from the host shell —
172
- * pass it explicitly so this component stays framework/runtime-agnostic.
171
+ * The `iconMap` is typically the `runtime.icons` registry from the host shell.
172
+ *
173
+ * 🔴 Omitted, it is `defaultIconMap` — NOT "nothing registered". Until 5.15.1 a missing
174
+ * `iconMap` resolved every token to the letter fallback, so vault's header, which renders
175
+ * `<DynamicIcon token="unlock" />` and its neighbours with no map, painted the letters
176
+ * "U W S" where its lock, generator and settings icons belonged, on every screen, from the
177
+ * day it adopted the component. A registry that was never passed is not a registry that was
178
+ * cleared; only an explicit map may leave a token unresolved.
173
179
  */
174
180
  export function DynamicIcon({ token, iconMap, className }) {
175
181
  if (!token)
176
182
  return null;
177
- const Icon = iconMap?.get(token);
183
+ const Icon = iconMap ? iconMap.get(token) : defaultIconMap[token];
178
184
  if (!Icon)
179
185
  return (_jsx(Tooltip, { content: token, children: _jsx("span", { className: cn(
180
186
  // guardrails-ignore micro-typography-floor: 0.6em is RELATIVE to the avatar box —
@@ -1 +1 @@
1
- {"version":3,"file":"icons.js","sourceRoot":"","sources":["../../src/react/icons.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"icons.js","sourceRoot":"","sources":["../../src/react/icons.tsx"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cursedbelt",
3
- "version": "5.15.0",
3
+ "version": "5.15.2",
4
4
  "license": "ISC",
5
5
  "type": "module",
6
6
  "description": "The React design system of the cursedbelt split — components, styles, theme. cursedbelt-core below it; server tier in cursedbelt-server.",
@@ -86,6 +86,7 @@
86
86
  "e2e:playback-degraded": "playwright test --config e2e/playwright.config.ts playback-degraded.spec.ts",
87
87
  "e2e:resize-grip": "playwright test --config e2e/playwright.config.ts resize-grip-rail.spec.ts",
88
88
  "e2e:touch": "playwright test --config e2e/playwright.config.ts --project=touch",
89
+ "e2e:tap-away": "playwright test --config e2e/playwright.config.ts tap-away.spec.ts",
89
90
  "done:serial": "bun run typecheck && bun run lint && bun run test && bun run build",
90
91
  "paths": "bun run scripts/paths.ts",
91
92
  "surface": "public-surface",
@@ -0,0 +1,39 @@
1
+ import { afterEach, describe, expect, test } from 'bun:test';
2
+ import { act, cleanup, fireEvent, render, screen } from '@testing-library/react';
3
+ import type { ButtonHTMLAttributes } from 'react';
4
+ import { DropdownMenu } from './DropdownMenu.js';
5
+
6
+ afterEach(cleanup);
7
+
8
+ function B(props: ButtonHTMLAttributes<HTMLButtonElement>) {
9
+ return (
10
+ <button
11
+ // guardrails-ignore no-raw-action-button: a spec fixture — any trigger element must work.
12
+ type='button'
13
+ {...props}
14
+ />
15
+ );
16
+ }
17
+
18
+ const menu = () => screen.queryByRole('menu', { hidden: true });
19
+
20
+ describe('DropdownMenu closes on a press anywhere else', () => {
21
+ test('even on a surface that stops its own pointerdown — a drag handle, a canvas', async () => {
22
+ render(
23
+ <div>
24
+ <B onPointerDown={(e) => e.stopPropagation()}>drag handle</B>
25
+ <DropdownMenu items={[{ key: 'a', label: 'Rename' }]} trigger={<B>actions</B>} />
26
+ </div>,
27
+ );
28
+ fireEvent.pointerDown(screen.getByText('actions'), { button: 0, ctrlKey: false });
29
+ expect(menu()).toBeTruthy();
30
+ await act(() => new Promise((r) => setTimeout(r, 0)));
31
+ act(() => {
32
+ screen.getByText('drag handle').dispatchEvent(
33
+ new PointerEvent('pointerdown', { bubbles: true, button: 0, pointerType: 'touch' }),
34
+ );
35
+ });
36
+ await act(() => new Promise((r) => setTimeout(r, 5)));
37
+ expect(menu()).toBeNull();
38
+ });
39
+ });
@@ -1,6 +1,7 @@
1
1
  import * as RDrop from '@radix-ui/react-dropdown-menu';
2
2
  import { Check, ChevronRight } from 'lucide-react';
3
- import type { ReactNode } from 'react';
3
+ import { type ReactNode, useCallback, useRef, useState } from 'react';
4
+ import { useOutsidePress } from '../hooks/useOutsidePress.js';
4
5
  import { cn } from '../lib/cn.js';
5
6
  import { useFloatingContainer } from '../lib/floatingContainer.js';
6
7
  import {
@@ -87,15 +88,43 @@ export function DropdownMenu({
87
88
  onOpenChange,
88
89
  }: DropdownMenuProps) {
89
90
  const container = useFloatingContainer();
91
+ // Always controlled underneath, so the outside-press fallback can close it too.
92
+ const [ownOpen, setOwnOpen] = useState(false);
93
+ const isOpen = open ?? ownOpen;
94
+ const setOpen = useCallback(
95
+ (next: boolean) => {
96
+ if (open === undefined) setOwnOpen(next);
97
+ onOpenChange?.(next);
98
+ },
99
+ [open, onOpenChange],
100
+ );
101
+ /*
102
+ * Radix's menu listens for the outside `pointerdown` in the BUBBLE phase, so a surface that
103
+ * stops its own pointerdown (a drag handle, a canvas) kept the menu open. The belt's one
104
+ * tap-away listener runs in the capture phase; see `useOutsidePress`. The menu is modal, so
105
+ * it decides on the pointerdown (an inert page sends an iPhone no click).
106
+ */
107
+ const triggerRef = useRef<HTMLButtonElement | null>(null);
108
+ const pressInside = useOutsidePress({
109
+ open: isOpen,
110
+ onDismiss: () => setOpen(false),
111
+ inside: [triggerRef],
112
+ escape: false,
113
+ decideOn: 'pointerdown',
114
+ });
90
115
  return (
91
- <RDrop.Root open={open} onOpenChange={onOpenChange}>
92
- <RDrop.Trigger asChild>{trigger}</RDrop.Trigger>
116
+ <RDrop.Root open={isOpen} onOpenChange={setOpen}>
117
+ <RDrop.Trigger asChild ref={triggerRef}>
118
+ {trigger}
119
+ </RDrop.Trigger>
93
120
  <RDrop.Portal container={container}>
94
121
  <RDrop.Content
95
122
  align={align}
96
123
  side={side}
97
124
  sideOffset={4}
98
125
  collisionPadding={FLOATING_COLLISION_PADDING}
126
+ onClickCapture={pressInside.onClickCapture}
127
+ onPointerDownCapture={pressInside.onPointerDownCapture}
99
128
  className={cn(FLOATING_CONTENT_BASE, FLOATING_ANIMATION, 'min-w-[8rem] p-1', className)}
100
129
  >
101
130
  {items.map((item) => (
@@ -130,6 +130,44 @@ describe('Popover closes when you press anywhere else', () => {
130
130
  expect(panel()).toBeNull();
131
131
  });
132
132
 
133
+ test('🔴 modal closes on a tap that sends NO click — an iPhone tapping the inert page', async () => {
134
+ // Measured in Playwright's iPhone 15 WebKit, 2026-09-27: under `modal` the tap lands on
135
+ // <html>, iOS sends no click for it, and a click-deciding popover never closed.
136
+ render(<Harness modal />);
137
+ openIt();
138
+ await act(() => new Promise((r) => setTimeout(r, 0)));
139
+ act(() => {
140
+ document.documentElement.dispatchEvent(
141
+ new PointerEvent('pointerdown', { bubbles: true, button: 0, pointerType: 'touch' }),
142
+ );
143
+ });
144
+ await act(() => new Promise((r) => setTimeout(r, 5)));
145
+ expect(panel()).toBeNull();
146
+ });
147
+
148
+ test('modal: the click the closing tap produces does not reach what the menu uncovered', async () => {
149
+ let played = 0;
150
+ function Player() {
151
+ const [open, setOpen] = useState(false);
152
+ return (
153
+ <div>
154
+ <B onClick={() => played++}>picture</B>
155
+ <Popover open={open} onOpenChange={setOpen} modal label='Subtitles' trigger={<B>subtitles</B>}>
156
+ <B>English</B>
157
+ </Popover>
158
+ </div>
159
+ );
160
+ }
161
+ render(<Player />);
162
+ openIt();
163
+ await act(() => new Promise((r) => setTimeout(r, 0)));
164
+ await tapOutside(screen.getByText('picture'), 'touch');
165
+ expect(panel()).toBeNull();
166
+ expect(played).toBe(0);
167
+ await tapOutside(screen.getByText('picture'), 'touch');
168
+ expect(played).toBe(1); // closed, the picture works again
169
+ });
170
+
133
171
  test('modal still closes on an outside press', async () => {
134
172
  render(<Harness modal />);
135
173
  openIt();
@@ -150,6 +150,9 @@ export function Popover({
150
150
  onDismiss: () => setOpen(false),
151
151
  inside: [triggerRef, anchorTrigger],
152
152
  escape: false,
153
+ // Under `modal` the page is inert and an iPhone sends no click for a tap on it — see
154
+ // `decideOn` in useOutsidePress.
155
+ decideOn: modal ? 'pointerdown' : 'click',
153
156
  });
154
157
 
155
158
  const content = (
@@ -171,6 +174,7 @@ export function Popover({
171
174
  // React-tree capture: a press on a nested layer this panel portalled (a Select's
172
175
  // list, a sub-menu) is INSIDE even though the DOM puts it elsewhere.
173
176
  onClickCapture={pressInside.onClickCapture}
177
+ onPointerDownCapture={pressInside.onPointerDownCapture}
174
178
  className={cn(
175
179
  unstyled
176
180
  ? 'z-[var(--z-popover)] outline-none'
@@ -20,6 +20,17 @@ export interface UseOutsidePressOptions {
20
20
  * whose rows play on tap). Default false.
21
21
  */
22
22
  modal?: boolean;
23
+ /**
24
+ * Decide on the `pointerdown` rather than the `click`. Only for a panel that has made the
25
+ * page under it inert (`Popover`'s `modal`, which sets `pointer-events: none` on body).
26
+ *
27
+ * 🔴 Measured 2026-09-27 in Playwright's iPhone 15 WebKit: with the page inert, a tap
28
+ * outside hits `<html>`, which iOS does not consider clickable, so NO `click` is ever
29
+ * sent — the menu stayed open under the owner's finger, exactly as reported. Deciding on
30
+ * the pointerdown closes it; the `click` that same press may still produce is swallowed,
31
+ * or it would land on whatever the closed menu uncovered (the picture, which pauses).
32
+ */
33
+ decideOn?: 'click' | 'pointerdown';
23
34
  }
24
35
 
25
36
  /** A floating layer another component portalled — a press there belongs to that layer. */
@@ -57,7 +68,8 @@ export function useOutsidePress({
57
68
  inside = [],
58
69
  escape: closeOnEscape = true,
59
70
  modal = false,
60
- }: UseOutsidePressOptions): { onClickCapture: () => void } {
71
+ decideOn = 'click',
72
+ }: UseOutsidePressOptions): { onClickCapture: () => void; onPointerDownCapture: () => void } {
61
73
  const pressInsideRef = useRef(false);
62
74
  // Latest values without re-subscribing on every render — a listener torn down mid-gesture
63
75
  // would miss the very click it exists for.
@@ -83,15 +95,8 @@ export function useOutsidePress({
83
95
  });
84
96
  };
85
97
 
86
- const onClick = (event: MouseEvent) => {
87
- pressInsideRef.current = false;
88
- const target = event.target instanceof Node ? event.target : null;
89
- if (target && latest.current.modal && !isInside(target) && !onAnotherLayer(target)) {
90
- // Decidable now for a DOM-inside press; a React-tree-inside press would have been
91
- // swallowed too, so a modal panel's portalled layers must live inside `inside`.
92
- event.preventDefault();
93
- event.stopPropagation();
94
- }
98
+ /** Decide once the event has finished dispatching — see the header. */
99
+ const decideLater = (target: Node | null) => {
95
100
  const timer = setTimeout(() => {
96
101
  timers.delete(timer);
97
102
  if (pressInsideRef.current || !target) return;
@@ -101,22 +106,54 @@ export function useOutsidePress({
101
106
  }, 0);
102
107
  timers.add(timer);
103
108
  };
109
+ const outside = (target: Node | null) => Boolean(target) && !isInside(target as Node) && !onAnotherLayer(target as Node);
110
+
111
+ // `pointerdown` mode: the click the same press produces is not a second decision — it is
112
+ // swallowed, until the next press or a second later, whichever comes first.
113
+ let swallowUntil = 0;
114
+ const onPointerDown = (event: PointerEvent) => {
115
+ pressInsideRef.current = false;
116
+ swallowUntil = 0;
117
+ const target = event.target instanceof Node ? event.target : null;
118
+ if (outside(target)) swallowUntil = Date.now() + 1000;
119
+ decideLater(target);
120
+ };
121
+ const onClick = (event: MouseEvent) => {
122
+ const target = event.target instanceof Node ? event.target : null;
123
+ if (decideOn === 'pointerdown') {
124
+ if (Date.now() < swallowUntil) {
125
+ swallowUntil = 0;
126
+ event.preventDefault();
127
+ event.stopPropagation();
128
+ }
129
+ return;
130
+ }
131
+ pressInsideRef.current = false;
132
+ if (latest.current.modal && outside(target)) {
133
+ // Decidable now for a DOM-inside press; a React-tree-inside press would have been
134
+ // swallowed too, so a modal panel's portalled layers must live inside `inside`.
135
+ event.preventDefault();
136
+ event.stopPropagation();
137
+ }
138
+ decideLater(target);
139
+ };
104
140
  const onKeyDown = (event: KeyboardEvent) => {
105
141
  if (event.key === 'Escape') latest.current.onDismiss();
106
142
  };
107
143
 
108
144
  document.addEventListener('click', onClick, true);
145
+ if (decideOn === 'pointerdown') document.addEventListener('pointerdown', onPointerDown, true);
109
146
  if (closeOnEscape) document.addEventListener('keydown', onKeyDown);
110
147
  return () => {
111
148
  document.removeEventListener('click', onClick, true);
149
+ document.removeEventListener('pointerdown', onPointerDown, true);
112
150
  document.removeEventListener('keydown', onKeyDown);
113
151
  for (const timer of timers) clearTimeout(timer);
114
152
  };
115
- }, [open, closeOnEscape]);
153
+ }, [open, closeOnEscape, decideOn]);
116
154
 
117
- return {
118
- onClickCapture: () => {
119
- pressInsideRef.current = true;
120
- },
155
+ const markInside = () => {
156
+ pressInsideRef.current = true;
121
157
  };
158
+ return { onClickCapture: markInside, onPointerDownCapture: markInside };
122
159
  }
@@ -42,3 +42,22 @@ describe('DynamicIcon fallback', () => {
42
42
  expect(container.innerHTML).toBe('');
43
43
  });
44
44
  });
45
+
46
+ describe('DynamicIcon with no iconMap', () => {
47
+ // 🔴 vault rendered `<DynamicIcon token="unlock" />` with no map, and every token fell to the
48
+ // letter fallback — "U W S" in its header where three icons belonged (2026-09-28).
49
+ test('draws the default icon, never the letter fallback', () => {
50
+ for (const token of ['unlock', 'wand', 'settings', 'search'] as const) {
51
+ const { container } = render(DynamicIcon({ token }));
52
+ expect(container.querySelector('[data-icon]'), `${token} fell back to a letter`).toBeNull();
53
+ expect(container.querySelector('svg'), `${token} drew no icon`).not.toBeNull();
54
+ }
55
+ });
56
+
57
+ test('an explicit map that lacks the token still falls back to its letter', () => {
58
+ const icons = createIconMapRegistry();
59
+ icons.clear();
60
+ const { container } = render(DynamicIcon({ token: 'settings', iconMap: icons }));
61
+ expect(container.querySelector('[data-icon="settings"]')?.textContent).toBe('s');
62
+ });
63
+ });
@@ -232,7 +232,11 @@ export function createIconMapRegistry(): IconMapRegistry {
232
232
 
233
233
  export interface DynamicIconProps {
234
234
  token?: IconToken;
235
- /** The icon map to resolve `token` against — typically `runtime.icons`. */
235
+ /**
236
+ * The icon map to resolve `token` against — typically `runtime.icons`. Omitted, the token
237
+ * resolves against `defaultIconMap`, so a plain `<DynamicIcon token="settings" />` draws the
238
+ * settings icon.
239
+ */
236
240
  iconMap?: IconMapRegistry | null;
237
241
  className?: string;
238
242
  }
@@ -249,12 +253,18 @@ export interface DynamicIconProps {
249
253
  * element and visually overflows into neighboring content instead of
250
254
  * respecting the icon's slot.
251
255
  *
252
- * The `iconMap` is typically the `runtime.icons` registry from the host shell —
253
- * pass it explicitly so this component stays framework/runtime-agnostic.
256
+ * The `iconMap` is typically the `runtime.icons` registry from the host shell.
257
+ *
258
+ * 🔴 Omitted, it is `defaultIconMap` — NOT "nothing registered". Until 5.15.1 a missing
259
+ * `iconMap` resolved every token to the letter fallback, so vault's header, which renders
260
+ * `<DynamicIcon token="unlock" />` and its neighbours with no map, painted the letters
261
+ * "U W S" where its lock, generator and settings icons belonged, on every screen, from the
262
+ * day it adopted the component. A registry that was never passed is not a registry that was
263
+ * cleared; only an explicit map may leave a token unresolved.
254
264
  */
255
265
  export function DynamicIcon({ token, iconMap, className }: DynamicIconProps) {
256
266
  if (!token) return null;
257
- const Icon = iconMap?.get(token);
267
+ const Icon = iconMap ? iconMap.get(token) : defaultIconMap[token];
258
268
  if (!Icon)
259
269
  return (
260
270
  <Tooltip content={token}>