{"version":3,"names":["ownerDocument","read","value","useMixedToggleClickHandler","params","ignoreClick","onMouseDown","event","enabled","action","mouseDownAction","open","target","currentTarget","addEventListener","once","onClick","preventBaseUIHandler"],"sources":["use-mixed-toggle-click-handler.ts"],"sourcesContent":["import { ownerDocument } from \"./dom/owner-document\";\nimport type { PropsLike } from \"./merge-props-n\";\n\n/**\n * Accessor-or-value. Consumers may pass plain values or Solid accessors for\n * any reactive gate; readers resolve at call time so the returned handlers\n * see the latest state without recreating the primitive.\n */\ntype MaybeAccessor<T> = T | (() => T);\n\nfunction read<T>(value: MaybeAccessor<T>): T {\n\treturn typeof value === \"function\" ? (value as () => T)() : value;\n}\n\n/**\n * Minimal event shape — both Solid JSX events and raw DOM events satisfy it.\n * `baseUIHandlerPrevented` / `preventBaseUIHandler` are layered on by\n * `mergePropsN` during the event chain (see `merge-props-n.ts`).\n */\ninterface BaseUIEventLike {\n\tbaseUIHandlerPrevented?: boolean;\n\tpreventBaseUIHandler?: () => void;\n\tcurrentTarget: EventTarget | null;\n}\n\nexport interface UseMixedToggleClickHandlerParameters {\n\t/**\n\t * Whether the mixed toggle click handler is enabled.\n\t * @default true\n\t */\n\tenabled?: MaybeAccessor<boolean | undefined> | undefined;\n\t/**\n\t * Which action the `mousedown` event performs on the popup — `\"open\"` means\n\t * the popup opens on mousedown (so the follow-up click must not close it),\n\t * `\"close\"` means the popup closes on mousedown (so the follow-up click\n\t * must not re-open it).\n\t */\n\tmouseDownAction: MaybeAccessor<\"open\" | \"close\">;\n\t/**\n\t * Current open state of the popup. Read at event-time — pass a signal\n\t * accessor to track updates.\n\t */\n\topen: MaybeAccessor<boolean>;\n}\n\n/**\n * Port of Base UI React's `useMixedToggleClickHandler`\n * (`packages/react/src/utils/useMixedToggleClickHandler.ts`).\n *\n * Produces a pair of `onMouseDown` / `onClick` handlers that fix the\n * \"mousedown opens, click closes\" (or \"mousedown closes, click opens\")\n * race that occurs when a popup trigger is toggled by different events:\n * the mousedown flips the popup state, and the ensuing click — fired by\n * the same user gesture — would otherwise immediately flip it back.\n *\n * The fix is to record, on mousedown, that a subsequent click should be\n * ignored; the one-shot `click` listener installed on the owner document\n * clears the latch at the end of the event loop so unrelated future\n * clicks still work.\n *\n * Solid 2 notes:\n *\n * - Unlike React's `useMemo` gate on `enabled`, the Solid port reads\n *   `enabled` at event time. That keeps the primitive's return value\n *   identity stable (`mergePropsN` doesn't care about identity, but\n *   callers that capture the handlers once don't need to rewire on\n *   toggle) and avoids a stale-closure hazard during a transition.\n * - `mouseDownAction` and `open` are likewise read at event time so the\n *   primitive can be called once during setup rather than inside an\n *   effect.\n * - The returned shape is `PropsLike` so consumers feed it directly into\n *   `mergePropsN`. The right-most handler can call `preventBaseUIHandler()`\n *   to short-circuit chained consumer handlers — matching the React\n *   source, which uses `event.preventBaseUIHandler()` for the same\n *   purpose.\n */\nexport function useMixedToggleClickHandler(\n\tparams: UseMixedToggleClickHandlerParameters,\n): PropsLike {\n\t// Closure-captured latch. Set on mousedown when the follow-up click would\n\t// unwind the popup toggle; cleared either by the one-shot document listener\n\t// (end-of-event-loop cleanup) or by the `onClick` handler itself (so a\n\t// direct same-gesture click path still preventBaseUIHandler's).\n\tlet ignoreClick = false;\n\n\tfunction onMouseDown(event: MouseEvent & BaseUIEventLike): void {\n\t\tif (read(params.enabled) === false) return;\n\t\tconst action = read(params.mouseDownAction);\n\t\tconst open = read(params.open);\n\t\t// Only engage when the mousedown is actually going to flip the popup.\n\t\t// If `mouseDownAction === \"open\"` and the popup is already open,\n\t\t// mousedown is a no-op and the follow-up click is fine; same for the\n\t\t// `close` side.\n\t\tif ((action === \"open\" && !open) || (action === \"close\" && open)) {\n\t\t\tignoreClick = true;\n\n\t\t\tconst target = event.currentTarget as Element | null;\n\t\t\t// Install a one-shot `click` listener on the owner document so the\n\t\t\t// latch is cleared even if the click bubbles out of our element\n\t\t\t// (e.g. consumer stopPropagation elsewhere in the tree). `once:\n\t\t\t// true` means we don't need to manage removal.\n\t\t\townerDocument(target).addEventListener(\n\t\t\t\t\"click\",\n\t\t\t\t() => {\n\t\t\t\t\tignoreClick = false;\n\t\t\t\t},\n\t\t\t\t{ once: true },\n\t\t\t);\n\t\t}\n\t}\n\n\tfunction onClick(event: MouseEvent & BaseUIEventLike): void {\n\t\tif (read(params.enabled) === false) return;\n\t\tif (ignoreClick) {\n\t\t\tignoreClick = false;\n\t\t\t// Tell downstream merged handlers not to act on this click — the\n\t\t\t// mousedown already toggled the popup, so the click would undo it.\n\t\t\tevent.preventBaseUIHandler?.();\n\t\t}\n\t}\n\n\treturn { onClick, onMouseDown } as PropsLike;\n}\n"],"mappings":"AAAA,SAASA,aAAa,QAAQ,sBAAsB;;AAGpD;AACA;AACA;AACA;AACA;;AAGA,SAASC,IAAIA,CAAIC,KAAuB,EAAK;EAC5C,OAAO,OAAOA,KAAK,KAAK,UAAU,GAAIA,KAAK,CAAa,CAAC,GAAGA,KAAK;AAClE;;AAEA;AACA;AACA;AACA;AACA;;AA2BA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASC,0BAA0BA,CACzCC,MAA4C,EAChC;EACZ;EACA;EACA;EACA;EACA,IAAIC,WAAW,GAAG,KAAK;EAEvB,SAASC,WAAWA,CAACC,KAAmC,EAAQ;IAC/D,IAAIN,IAAI,CAACG,MAAM,CAACI,OAAO,CAAC,KAAK,KAAK,EAAE;IACpC,MAAMC,MAAM,GAAGR,IAAI,CAACG,MAAM,CAACM,eAAe,CAAC;IAC3C,MAAMC,IAAI,GAAGV,IAAI,CAACG,MAAM,CAACO,IAAI,CAAC;IAC9B;IACA;IACA;IACA;IACA,IAAKF,MAAM,KAAK,MAAM,IAAI,CAACE,IAAI,IAAMF,MAAM,KAAK,OAAO,IAAIE,IAAK,EAAE;MACjEN,WAAW,GAAG,IAAI;MAElB,MAAMO,MAAM,GAAGL,KAAK,CAACM,aAA+B;MACpD;MACA;MACA;MACA;MACAb,aAAa,CAACY,MAAM,CAAC,CAACE,gBAAgB,CACrC,OAAO,EACP,MAAM;QACLT,WAAW,GAAG,KAAK;MACpB,CAAC,EACD;QAAEU,IAAI,EAAE;MAAK,CACd,CAAC;IACF;EACD;EAEA,SAASC,OAAOA,CAACT,KAAmC,EAAQ;IAC3D,IAAIN,IAAI,CAACG,MAAM,CAACI,OAAO,CAAC,KAAK,KAAK,EAAE;IACpC,IAAIH,WAAW,EAAE;MAChBA,WAAW,GAAG,KAAK;MACnB;MACA;MACAE,KAAK,CAACU,oBAAoB,GAAG,CAAC;IAC/B;EACD;EAEA,OAAO;IAAED,OAAO;IAAEV;EAAY,CAAC;AAChC","ignoreList":[]}