@vielzeug/orbit 1.0.3

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.
Files changed (134) hide show
  1. package/README.md +77 -0
  2. package/dist/_dev.cjs +2 -0
  3. package/dist/_dev.cjs.map +1 -0
  4. package/dist/_dev.d.ts +2 -0
  5. package/dist/_dev.d.ts.map +1 -0
  6. package/dist/_dev.js +2 -0
  7. package/dist/_dev.js.map +1 -0
  8. package/dist/auto-update.cjs +2 -0
  9. package/dist/auto-update.cjs.map +1 -0
  10. package/dist/auto-update.d.ts +53 -0
  11. package/dist/auto-update.d.ts.map +1 -0
  12. package/dist/auto-update.js +2 -0
  13. package/dist/auto-update.js.map +1 -0
  14. package/dist/compose.cjs +2 -0
  15. package/dist/compose.cjs.map +1 -0
  16. package/dist/compose.d.ts +25 -0
  17. package/dist/compose.d.ts.map +1 -0
  18. package/dist/compose.js +2 -0
  19. package/dist/compose.js.map +1 -0
  20. package/dist/core.cjs +2 -0
  21. package/dist/core.cjs.map +1 -0
  22. package/dist/core.d.ts +43 -0
  23. package/dist/core.d.ts.map +1 -0
  24. package/dist/core.js +2 -0
  25. package/dist/core.js.map +1 -0
  26. package/dist/devtools.cjs +2 -0
  27. package/dist/devtools.cjs.map +1 -0
  28. package/dist/devtools.d.ts +36 -0
  29. package/dist/devtools.d.ts.map +1 -0
  30. package/dist/devtools.js +2 -0
  31. package/dist/devtools.js.map +1 -0
  32. package/dist/errors.cjs +2 -0
  33. package/dist/errors.cjs.map +1 -0
  34. package/dist/errors.d.ts +9 -0
  35. package/dist/errors.d.ts.map +1 -0
  36. package/dist/errors.js +2 -0
  37. package/dist/errors.js.map +1 -0
  38. package/dist/float.cjs +2 -0
  39. package/dist/float.cjs.map +1 -0
  40. package/dist/float.d.ts +73 -0
  41. package/dist/float.d.ts.map +1 -0
  42. package/dist/float.js +2 -0
  43. package/dist/float.js.map +1 -0
  44. package/dist/index.cjs +1 -0
  45. package/dist/index.d.ts +28 -0
  46. package/dist/index.d.ts.map +1 -0
  47. package/dist/index.js +1 -0
  48. package/dist/inline.cjs +2 -0
  49. package/dist/inline.cjs.map +1 -0
  50. package/dist/inline.d.ts +35 -0
  51. package/dist/inline.d.ts.map +1 -0
  52. package/dist/inline.js +2 -0
  53. package/dist/inline.js.map +1 -0
  54. package/dist/middleware/arrow.cjs +2 -0
  55. package/dist/middleware/arrow.cjs.map +1 -0
  56. package/dist/middleware/arrow.d.ts +25 -0
  57. package/dist/middleware/arrow.d.ts.map +1 -0
  58. package/dist/middleware/arrow.js +2 -0
  59. package/dist/middleware/arrow.js.map +1 -0
  60. package/dist/middleware/auto-placement.cjs +2 -0
  61. package/dist/middleware/auto-placement.cjs.map +1 -0
  62. package/dist/middleware/auto-placement.d.ts +28 -0
  63. package/dist/middleware/auto-placement.d.ts.map +1 -0
  64. package/dist/middleware/auto-placement.js +2 -0
  65. package/dist/middleware/auto-placement.js.map +1 -0
  66. package/dist/middleware/flip.cjs +2 -0
  67. package/dist/middleware/flip.cjs.map +1 -0
  68. package/dist/middleware/flip.d.ts +14 -0
  69. package/dist/middleware/flip.d.ts.map +1 -0
  70. package/dist/middleware/flip.js +2 -0
  71. package/dist/middleware/flip.js.map +1 -0
  72. package/dist/middleware/hide.cjs +2 -0
  73. package/dist/middleware/hide.cjs.map +1 -0
  74. package/dist/middleware/hide.d.ts +17 -0
  75. package/dist/middleware/hide.d.ts.map +1 -0
  76. package/dist/middleware/hide.js +2 -0
  77. package/dist/middleware/hide.js.map +1 -0
  78. package/dist/middleware/offset.cjs +2 -0
  79. package/dist/middleware/offset.cjs.map +1 -0
  80. package/dist/middleware/offset.d.ts +16 -0
  81. package/dist/middleware/offset.d.ts.map +1 -0
  82. package/dist/middleware/offset.js +2 -0
  83. package/dist/middleware/offset.js.map +1 -0
  84. package/dist/middleware/shift.cjs +2 -0
  85. package/dist/middleware/shift.cjs.map +1 -0
  86. package/dist/middleware/shift.d.ts +69 -0
  87. package/dist/middleware/shift.d.ts.map +1 -0
  88. package/dist/middleware/shift.js +2 -0
  89. package/dist/middleware/shift.js.map +1 -0
  90. package/dist/middleware/size.cjs +2 -0
  91. package/dist/middleware/size.cjs.map +1 -0
  92. package/dist/middleware/size.d.ts +22 -0
  93. package/dist/middleware/size.d.ts.map +1 -0
  94. package/dist/middleware/size.js +2 -0
  95. package/dist/middleware/size.js.map +1 -0
  96. package/dist/orbit.cjs +2 -0
  97. package/dist/orbit.cjs.map +1 -0
  98. package/dist/orbit.iife.js +2 -0
  99. package/dist/orbit.iife.js.map +1 -0
  100. package/dist/orbit.js +2 -0
  101. package/dist/orbit.js.map +1 -0
  102. package/dist/overflow.cjs +2 -0
  103. package/dist/overflow.cjs.map +1 -0
  104. package/dist/overflow.d.ts +32 -0
  105. package/dist/overflow.d.ts.map +1 -0
  106. package/dist/overflow.js +2 -0
  107. package/dist/overflow.js.map +1 -0
  108. package/dist/presets.cjs +2 -0
  109. package/dist/presets.cjs.map +1 -0
  110. package/dist/presets.d.ts +65 -0
  111. package/dist/presets.d.ts.map +1 -0
  112. package/dist/presets.js +2 -0
  113. package/dist/presets.js.map +1 -0
  114. package/dist/reactive.cjs +2 -0
  115. package/dist/reactive.cjs.map +1 -0
  116. package/dist/reactive.d.ts +47 -0
  117. package/dist/reactive.d.ts.map +1 -0
  118. package/dist/reactive.js +2 -0
  119. package/dist/reactive.js.map +1 -0
  120. package/dist/ssr.cjs +2 -0
  121. package/dist/ssr.cjs.map +1 -0
  122. package/dist/ssr.d.ts +41 -0
  123. package/dist/ssr.d.ts.map +1 -0
  124. package/dist/ssr.js +2 -0
  125. package/dist/ssr.js.map +1 -0
  126. package/dist/types.d.ts +166 -0
  127. package/dist/types.d.ts.map +1 -0
  128. package/dist/utils.cjs +2 -0
  129. package/dist/utils.cjs.map +1 -0
  130. package/dist/utils.d.ts +9 -0
  131. package/dist/utils.d.ts.map +1 -0
  132. package/dist/utils.js +2 -0
  133. package/dist/utils.js.map +1 -0
  134. package/package.json +67 -0
package/README.md ADDED
@@ -0,0 +1,77 @@
1
+ # @vielzeug/orbit
2
+
3
+ > Zero-dependency floating element positioning for tooltips, dropdowns, menus, and popovers.
4
+
5
+ [![npm version](https://img.shields.io/npm/v/@vielzeug/orbit)](https://www.npmjs.com/package/@vielzeug/orbit) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
6
+
7
+ <details>
8
+ <summary>Quick Reference</summary>
9
+
10
+ **Package:** `@vielzeug/orbit` &nbsp;·&nbsp; **Category:** UI Positioning
11
+
12
+ **Key exports:** `float`, `computePosition`, `getRects`, `detectOverflow`, `autoUpdate`, `offset`, `flip`, `shift`, `autoPlacement`, `arrow`, `size`, `hide`, `compose`, `limitShift`, `getSide`, `getAlignment`
13
+
14
+ **When to use:** Zero-dependency floating element positioning for tooltips, dropdowns, menus, and popovers.
15
+
16
+ **Related:** [@vielzeug/ore](https://vielzeug.dev/ore/) · [@vielzeug/refine](https://vielzeug.dev/refine/) · [@vielzeug/dnd](https://vielzeug.dev/dnd/)
17
+
18
+ </details>
19
+
20
+ `@vielzeug/orbit` is part of Vielzeug and ships as a zero-dependency TypeScript package with ESM+CJS output.
21
+
22
+ ## Installation
23
+
24
+ ```sh
25
+ pnpm add @vielzeug/orbit
26
+ npm install @vielzeug/orbit
27
+ yarn add @vielzeug/orbit
28
+ ```
29
+
30
+ ## Quick Start
31
+
32
+ ```ts
33
+ import { arrow, float, flip, offset, shift } from '@vielzeug/orbit';
34
+
35
+ const reference = document.querySelector<HTMLElement>('#trigger')!;
36
+ const floating = document.querySelector<HTMLElement>('#tooltip')!;
37
+ const arrowEl = floating.querySelector<HTMLElement>('.arrow')!;
38
+
39
+ const handle = float(reference, floating, {
40
+ placement: 'top',
41
+ middleware: [offset(8), flip(), shift({ padding: 6 }), arrow({ element: arrowEl, padding: 6 })],
42
+ apply(result) {
43
+ floating.style.left = `${result.x}px`;
44
+ floating.style.top = `${result.y}px`;
45
+
46
+ if (result.middlewareData.arrow) {
47
+ const { x, y } = result.middlewareData.arrow;
48
+ arrowEl.style.left = x != null ? `${x}px` : '';
49
+ arrowEl.style.top = y != null ? `${y}px` : '';
50
+ }
51
+ },
52
+ });
53
+
54
+ // On teardown:
55
+ handle.dispose();
56
+ ```
57
+
58
+ ## Sub-paths
59
+
60
+ | Import | Purpose |
61
+ | -------------------------- | ------------------------------------------------------------ |
62
+ | `@vielzeug/orbit` | Core API, middleware (`inline` included), utilities, types |
63
+ | `@vielzeug/orbit/presets` | Pre-configured middleware stacks |
64
+ | `@vielzeug/orbit/reactive` | Reactive signal adapter (`@vielzeug/ripple`) |
65
+ | `@vielzeug/orbit/devtools` | Visual debug overlay (development only) |
66
+ | `@vielzeug/orbit/ssr` | No-op stubs for server-side rendering |
67
+
68
+ ## Documentation
69
+
70
+ - [Overview](https://vielzeug.dev/orbit/)
71
+ - [Usage Guide](https://vielzeug.dev/orbit/usage)
72
+ - [API Reference](https://vielzeug.dev/orbit/api)
73
+ - [Examples](https://vielzeug.dev/orbit/examples)
74
+
75
+ ## License
76
+
77
+ MIT © [Helmuth Saatkamp](https://github.com/helmuthdu) — part of the [Vielzeug](https://github.com/helmuthdu/vielzeug) monorepo.
package/dist/_dev.cjs ADDED
@@ -0,0 +1,2 @@
1
+ var e=!globalThis.__ORBIT_PROD__;function t(t){e&&console.warn(`[@vielzeug/orbit] ${t}`)}function n(t){e&&t()}exports.devOnly=n,exports.warn=t;
2
+ //# sourceMappingURL=_dev.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"_dev.cjs","names":[],"sources":["../src/_dev.ts"],"sourcesContent":["const isDev = !(globalThis as { __ORBIT_PROD__?: boolean }).__ORBIT_PROD__;\n\n/** @internal @security Messages may include user-supplied element dimensions or computed styles. */\nexport function warn(msg: string): void {\n if (isDev) console.warn(`[@vielzeug/orbit] ${msg}`);\n}\n\n/** @internal — Run fn only in dev builds. Use when dev-only logic goes beyond a single warn() / error() call. */\nexport function devOnly(fn: () => void): void {\n if (isDev) fn();\n}\n"],"mappings":"AAAA,IAAM,EAAQ,CAAE,WAA4C,eAG5D,SAAgB,EAAK,EAAmB,CAClC,GAAO,QAAQ,KAAK,qBAAqB,GAAK,CACpD,CAGA,SAAgB,EAAQ,EAAsB,CACxC,GAAO,EAAG,CAChB"}
package/dist/_dev.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=_dev.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"_dev.d.ts","sourceRoot":"","sources":["../src/_dev.ts"],"names":[],"mappings":""}
package/dist/_dev.js ADDED
@@ -0,0 +1,2 @@
1
+ var e=!globalThis.__ORBIT_PROD__;function t(t){e&&console.warn(`[@vielzeug/orbit] ${t}`)}function n(t){e&&t()}export{n as devOnly,t as warn};
2
+ //# sourceMappingURL=_dev.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"_dev.js","names":[],"sources":["../src/_dev.ts"],"sourcesContent":["const isDev = !(globalThis as { __ORBIT_PROD__?: boolean }).__ORBIT_PROD__;\n\n/** @internal @security Messages may include user-supplied element dimensions or computed styles. */\nexport function warn(msg: string): void {\n if (isDev) console.warn(`[@vielzeug/orbit] ${msg}`);\n}\n\n/** @internal — Run fn only in dev builds. Use when dev-only logic goes beyond a single warn() / error() call. */\nexport function devOnly(fn: () => void): void {\n if (isDev) fn();\n}\n"],"mappings":"AAAA,IAAM,EAAQ,CAAE,WAA4C,eAG5D,SAAgB,EAAK,EAAmB,CAClC,GAAO,QAAQ,KAAK,qBAAqB,GAAK,CACpD,CAGA,SAAgB,EAAQ,EAAsB,CACxC,GAAO,EAAG,CAChB"}
@@ -0,0 +1,2 @@
1
+ const e=require("./utils.cjs");let t=require("@vielzeug/arsenal");function n(e){let t=[],n=e.parentElement;for(;n;){let e=getComputedStyle(n),r=e.overflow+e.overflowX+e.overflowY;if(/auto|scroll|overlay/.test(r)&&t.push(n),n.parentElement)n=n.parentElement;else{let e=n.getRootNode();n=e instanceof ShadowRoot?e.host:null}}return t}function r(r,i,a,{animationFrame:o=!1,observeAncestors:s=!0,observeFloating:c=!0,observeVisualViewport:l=!0,pauseWhenHidden:u=!0,throttle:d=0}={}){let f=d>0?(0,t.throttle)(a,d,{leading:!0,trailing:!0}):null,p=f??a,m=!0,h=()=>{m&&p()};p();let g=[];if(u&&e.isElement(r)&&typeof IntersectionObserver<`u`){let e=new IntersectionObserver(e=>{m=e.at(-1)?.isIntersecting??!0,m&&p()});e.observe(r),g.push(()=>e.disconnect())}if(e.isElement(r)&&s){let e=n(r);for(let t of e)t.addEventListener(`scroll`,h,{passive:!0}),g.push(()=>t.removeEventListener(`scroll`,h));window.addEventListener(`scroll`,h,{passive:!0}),g.push(()=>window.removeEventListener(`scroll`,h))}else{let e=e=>{e.composedPath().includes(i)||h()};window.addEventListener(`scroll`,e,{capture:!0,passive:!0}),g.push(()=>window.removeEventListener(`scroll`,e,{capture:!0}))}window.addEventListener(`resize`,h,{passive:!0}),g.push(()=>window.removeEventListener(`resize`,h));let _=l?window.visualViewport:null;_&&(_.addEventListener(`resize`,h,{passive:!0}),_.addEventListener(`scroll`,h,{passive:!0}),g.push(()=>{_.removeEventListener(`resize`,h),_.removeEventListener(`scroll`,h)}));let v=new ResizeObserver(h);e.isElement(r)&&v.observe(r),c&&v.observe(i),g.push(()=>v.disconnect());let y=0;if(o){let e=()=>{h(),y=window.requestAnimationFrame(e)};y=window.requestAnimationFrame(e),g.push(()=>window.cancelAnimationFrame(y))}return()=>{f?.cancel();for(let e of g)e()}}exports.autoUpdate=r;
2
+ //# sourceMappingURL=auto-update.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auto-update.cjs","names":[],"sources":["../src/auto-update.ts"],"sourcesContent":["import { throttle } from '@vielzeug/arsenal';\n\nimport type { ReferenceElement } from './types';\n\nimport { isElement } from './utils';\n\nexport interface AutoUpdateOptions {\n /** Watch the floating element for size changes. Default: `true`. */\n observeFloating?: boolean;\n /**\n * Listen to scroll events on ancestor scroll containers of the reference element\n * in addition to the window. More efficient in deeply nested DOMs.\n * Set to `false` to use only a capture-phase window listener.\n * Default: `true`.\n */\n observeAncestors?: boolean;\n /** Track visual viewport scroll and resize (useful for pinch-zoom). Default: `true`. */\n observeVisualViewport?: boolean;\n /** Re-position on every animation frame. Use only when the reference itself animates. Default: `false`. */\n animationFrame?: boolean;\n /**\n * Throttle update calls to at most once every `throttle` milliseconds.\n * Uses a leading + trailing strategy: fires immediately, then once more after the interval.\n * Default: `0` (no throttling).\n */\n throttle?: number;\n /**\n * Pause position updates while the reference element is scrolled out of the viewport.\n * Uses IntersectionObserver to detect visibility. When the reference becomes visible again,\n * one position update is fired immediately.\n * Default: `true`.\n */\n pauseWhenHidden?: boolean;\n}\n\n/**\n * Collects the ancestor scroll containers of an element (up to and including the\n * nearest scrollable ancestor). Used to scope scroll listeners to the minimal\n * set of elements rather than relying on a capture-phase window listener.\n */\nfunction getScrollAncestors(el: Element): Element[] {\n const ancestors: Element[] = [];\n let current: Element | null = el.parentElement;\n\n while (current) {\n const style = getComputedStyle(current);\n const overflow = style.overflow + style.overflowX + style.overflowY;\n\n if (/auto|scroll|overlay/.test(overflow)) {\n ancestors.push(current);\n }\n\n if (current.parentElement) {\n current = current.parentElement;\n } else {\n const root = current.getRootNode();\n\n current = root instanceof ShadowRoot ? root.host : null;\n }\n }\n\n return ancestors;\n}\n\n/**\n * Calls `update` immediately and re-calls it whenever the reference or floating element\n * could have changed position: scroll, resize, ResizeObserver, or animation frames.\n *\n * By default, scroll listeners are attached to both ancestor scroll containers of the reference\n * AND the window (for document scroll). The ancestor listeners fire for nested container scrolls;\n * the window listener fires for page-level scroll. Set `observeAncestors: false` to use only a\n * capture-phase window listener.\n *\n * Returns a cleanup function that removes all listeners.\n *\n * @example\n * ```ts\n * const cleanup = autoUpdate(reference, floating, () => {\n * const { x, y } = computePosition(reference, floating, options);\n * floating.style.left = `${x}px`;\n * floating.style.top = `${y}px`;\n * });\n * // later:\n * cleanup();\n * ```\n */\nexport function autoUpdate(\n reference: ReferenceElement,\n floating: HTMLElement,\n update: () => void,\n {\n animationFrame = false,\n observeAncestors = true,\n observeFloating = true,\n observeVisualViewport = true,\n pauseWhenHidden = true,\n throttle: throttleMs = 0,\n }: AutoUpdateOptions = {},\n): () => void {\n const throttled = throttleMs > 0 ? throttle(update, throttleMs, { leading: true, trailing: true }) : null;\n const notify = throttled ?? update;\n\n // ── Visibility guard ─────────────────────────────────────────────────────────\n let referenceVisible = true;\n const conditionalNotify = (): void => {\n if (referenceVisible) notify();\n };\n\n // Initial call always runs regardless of visibility state.\n notify();\n\n const cleanups: Array<() => void> = [];\n\n // IntersectionObserver: pause updates when reference is off-screen.\n if (pauseWhenHidden && isElement(reference) && typeof IntersectionObserver !== 'undefined') {\n const io = new IntersectionObserver((entries) => {\n referenceVisible = entries.at(-1)?.isIntersecting ?? true;\n\n if (referenceVisible) notify(); // Re-position immediately when becoming visible.\n });\n\n io.observe(reference);\n cleanups.push(() => io.disconnect());\n }\n\n // ── Scroll listeners ────────────────────────────────────────────────────────\n if (isElement(reference) && observeAncestors) {\n // Targeted ancestor listeners for nested container scroll.\n const ancestors = getScrollAncestors(reference);\n\n for (const ancestor of ancestors) {\n ancestor.addEventListener('scroll', conditionalNotify, { passive: true });\n cleanups.push(() => ancestor.removeEventListener('scroll', conditionalNotify));\n }\n\n // Always add window scroll for document-level scroll (non-capture, doesn't fire for nested containers).\n window.addEventListener('scroll', conditionalNotify, { passive: true });\n cleanups.push(() => window.removeEventListener('scroll', conditionalNotify));\n } else {\n // VirtualReference or observeAncestors: false — capture-phase window listener catches all scrolls.\n const scrollHandler = (e: Event): void => {\n if (e.composedPath().includes(floating)) return;\n\n conditionalNotify();\n };\n\n window.addEventListener('scroll', scrollHandler, { capture: true, passive: true });\n cleanups.push(() => window.removeEventListener('scroll', scrollHandler, { capture: true }));\n }\n\n window.addEventListener('resize', conditionalNotify, { passive: true });\n cleanups.push(() => window.removeEventListener('resize', conditionalNotify));\n\n const vv = observeVisualViewport ? window.visualViewport : null;\n\n if (vv) {\n vv.addEventListener('resize', conditionalNotify, { passive: true });\n vv.addEventListener('scroll', conditionalNotify, { passive: true });\n cleanups.push(() => {\n vv.removeEventListener('resize', conditionalNotify);\n vv.removeEventListener('scroll', conditionalNotify);\n });\n }\n\n const ro = new ResizeObserver(conditionalNotify);\n\n if (isElement(reference)) ro.observe(reference);\n\n if (observeFloating) ro.observe(floating);\n\n cleanups.push(() => ro.disconnect());\n\n let frameId = 0;\n\n if (animationFrame) {\n const frameLoop = (): void => {\n conditionalNotify();\n frameId = window.requestAnimationFrame(frameLoop);\n };\n\n frameId = window.requestAnimationFrame(frameLoop);\n cleanups.push(() => window.cancelAnimationFrame(frameId));\n }\n\n return (): void => {\n throttled?.cancel();\n\n for (const fn of cleanups) fn();\n };\n}\n"],"mappings":"kEAwCA,SAAS,EAAmB,EAAwB,CAClD,IAAM,EAAuB,CAAC,EAC1B,EAA0B,EAAG,cAEjC,KAAO,GAAS,CACd,IAAM,EAAQ,iBAAiB,CAAO,EAChC,EAAW,EAAM,SAAW,EAAM,UAAY,EAAM,UAM1D,GAJI,sBAAsB,KAAK,CAAQ,GACrC,EAAU,KAAK,CAAO,EAGpB,EAAQ,cACV,EAAU,EAAQ,kBACb,CACL,IAAM,EAAO,EAAQ,YAAY,EAEjC,EAAU,aAAgB,WAAa,EAAK,KAAO,IACrD,CACF,CAEA,OAAO,CACT,CAwBA,SAAgB,EACd,EACA,EACA,EACA,CACE,iBAAiB,GACjB,mBAAmB,GACnB,kBAAkB,GAClB,wBAAwB,GACxB,kBAAkB,GAClB,SAAU,EAAa,GACF,CAAC,EACZ,CACZ,IAAM,EAAY,EAAa,GAAA,EAAA,EAAA,SAAA,CAAa,EAAQ,EAAY,CAAE,QAAS,GAAM,SAAU,EAAK,CAAC,EAAI,KAC/F,EAAS,GAAa,EAGxB,EAAmB,GACjB,MAAgC,CAChC,GAAkB,EAAO,CAC/B,EAGA,EAAO,EAEP,IAAM,EAA8B,CAAC,EAGrC,GAAI,GAAmB,EAAA,UAAU,CAAS,GAAK,OAAO,qBAAyB,IAAa,CAC1F,IAAM,EAAK,IAAI,qBAAsB,GAAY,CAC/C,EAAmB,EAAQ,GAAG,EAAE,CAAC,EAAE,gBAAkB,GAEjD,GAAkB,EAAO,CAC/B,CAAC,EAED,EAAG,QAAQ,CAAS,EACpB,EAAS,SAAW,EAAG,WAAW,CAAC,CACrC,CAGA,GAAI,EAAA,UAAU,CAAS,GAAK,EAAkB,CAE5C,IAAM,EAAY,EAAmB,CAAS,EAE9C,IAAK,IAAM,KAAY,EACrB,EAAS,iBAAiB,SAAU,EAAmB,CAAE,QAAS,EAAK,CAAC,EACxE,EAAS,SAAW,EAAS,oBAAoB,SAAU,CAAiB,CAAC,EAI/E,OAAO,iBAAiB,SAAU,EAAmB,CAAE,QAAS,EAAK,CAAC,EACtE,EAAS,SAAW,OAAO,oBAAoB,SAAU,CAAiB,CAAC,CAC7E,KAAO,CAEL,IAAM,EAAiB,GAAmB,CACpC,EAAE,aAAa,CAAC,CAAC,SAAS,CAAQ,GAEtC,EAAkB,CACpB,EAEA,OAAO,iBAAiB,SAAU,EAAe,CAAE,QAAS,GAAM,QAAS,EAAK,CAAC,EACjF,EAAS,SAAW,OAAO,oBAAoB,SAAU,EAAe,CAAE,QAAS,EAAK,CAAC,CAAC,CAC5F,CAEA,OAAO,iBAAiB,SAAU,EAAmB,CAAE,QAAS,EAAK,CAAC,EACtE,EAAS,SAAW,OAAO,oBAAoB,SAAU,CAAiB,CAAC,EAE3E,IAAM,EAAK,EAAwB,OAAO,eAAiB,KAEvD,IACF,EAAG,iBAAiB,SAAU,EAAmB,CAAE,QAAS,EAAK,CAAC,EAClE,EAAG,iBAAiB,SAAU,EAAmB,CAAE,QAAS,EAAK,CAAC,EAClE,EAAS,SAAW,CAClB,EAAG,oBAAoB,SAAU,CAAiB,EAClD,EAAG,oBAAoB,SAAU,CAAiB,CACpD,CAAC,GAGH,IAAM,EAAK,IAAI,eAAe,CAAiB,EAE3C,EAAA,UAAU,CAAS,GAAG,EAAG,QAAQ,CAAS,EAE1C,GAAiB,EAAG,QAAQ,CAAQ,EAExC,EAAS,SAAW,EAAG,WAAW,CAAC,EAEnC,IAAI,EAAU,EAEd,GAAI,EAAgB,CAClB,IAAM,MAAwB,CAC5B,EAAkB,EAClB,EAAU,OAAO,sBAAsB,CAAS,CAClD,EAEA,EAAU,OAAO,sBAAsB,CAAS,EAChD,EAAS,SAAW,OAAO,qBAAqB,CAAO,CAAC,CAC1D,CAEA,UAAmB,CACjB,GAAW,OAAO,EAElB,IAAK,IAAM,KAAM,EAAU,EAAG,CAChC,CACF"}
@@ -0,0 +1,53 @@
1
+ import type { ReferenceElement } from './types';
2
+ export interface AutoUpdateOptions {
3
+ /** Watch the floating element for size changes. Default: `true`. */
4
+ observeFloating?: boolean;
5
+ /**
6
+ * Listen to scroll events on ancestor scroll containers of the reference element
7
+ * in addition to the window. More efficient in deeply nested DOMs.
8
+ * Set to `false` to use only a capture-phase window listener.
9
+ * Default: `true`.
10
+ */
11
+ observeAncestors?: boolean;
12
+ /** Track visual viewport scroll and resize (useful for pinch-zoom). Default: `true`. */
13
+ observeVisualViewport?: boolean;
14
+ /** Re-position on every animation frame. Use only when the reference itself animates. Default: `false`. */
15
+ animationFrame?: boolean;
16
+ /**
17
+ * Throttle update calls to at most once every `throttle` milliseconds.
18
+ * Uses a leading + trailing strategy: fires immediately, then once more after the interval.
19
+ * Default: `0` (no throttling).
20
+ */
21
+ throttle?: number;
22
+ /**
23
+ * Pause position updates while the reference element is scrolled out of the viewport.
24
+ * Uses IntersectionObserver to detect visibility. When the reference becomes visible again,
25
+ * one position update is fired immediately.
26
+ * Default: `true`.
27
+ */
28
+ pauseWhenHidden?: boolean;
29
+ }
30
+ /**
31
+ * Calls `update` immediately and re-calls it whenever the reference or floating element
32
+ * could have changed position: scroll, resize, ResizeObserver, or animation frames.
33
+ *
34
+ * By default, scroll listeners are attached to both ancestor scroll containers of the reference
35
+ * AND the window (for document scroll). The ancestor listeners fire for nested container scrolls;
36
+ * the window listener fires for page-level scroll. Set `observeAncestors: false` to use only a
37
+ * capture-phase window listener.
38
+ *
39
+ * Returns a cleanup function that removes all listeners.
40
+ *
41
+ * @example
42
+ * ```ts
43
+ * const cleanup = autoUpdate(reference, floating, () => {
44
+ * const { x, y } = computePosition(reference, floating, options);
45
+ * floating.style.left = `${x}px`;
46
+ * floating.style.top = `${y}px`;
47
+ * });
48
+ * // later:
49
+ * cleanup();
50
+ * ```
51
+ */
52
+ export declare function autoUpdate(reference: ReferenceElement, floating: HTMLElement, update: () => void, { animationFrame, observeAncestors, observeFloating, observeVisualViewport, pauseWhenHidden, throttle: throttleMs, }?: AutoUpdateOptions): () => void;
53
+ //# sourceMappingURL=auto-update.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auto-update.d.ts","sourceRoot":"","sources":["../src/auto-update.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAIhD,MAAM,WAAW,iBAAiB;IAChC,oEAAoE;IACpE,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,wFAAwF;IACxF,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,2GAA2G;IAC3G,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;;OAKG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AA+BD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,UAAU,CACxB,SAAS,EAAE,gBAAgB,EAC3B,QAAQ,EAAE,WAAW,EACrB,MAAM,EAAE,MAAM,IAAI,EAClB,EACE,cAAsB,EACtB,gBAAuB,EACvB,eAAsB,EACtB,qBAA4B,EAC5B,eAAsB,EACtB,QAAQ,EAAE,UAAc,GACzB,GAAE,iBAAsB,GACxB,MAAM,IAAI,CA2FZ"}
@@ -0,0 +1,2 @@
1
+ import{isElement as e}from"./utils.js";import{throttle as t}from"@vielzeug/arsenal";function n(e){let t=[],n=e.parentElement;for(;n;){let e=getComputedStyle(n),r=e.overflow+e.overflowX+e.overflowY;if(/auto|scroll|overlay/.test(r)&&t.push(n),n.parentElement)n=n.parentElement;else{let e=n.getRootNode();n=e instanceof ShadowRoot?e.host:null}}return t}function r(r,i,a,{animationFrame:o=!1,observeAncestors:s=!0,observeFloating:c=!0,observeVisualViewport:l=!0,pauseWhenHidden:u=!0,throttle:d=0}={}){let f=d>0?t(a,d,{leading:!0,trailing:!0}):null,p=f??a,m=!0,h=()=>{m&&p()};p();let g=[];if(u&&e(r)&&typeof IntersectionObserver<`u`){let e=new IntersectionObserver(e=>{m=e.at(-1)?.isIntersecting??!0,m&&p()});e.observe(r),g.push(()=>e.disconnect())}if(e(r)&&s){let e=n(r);for(let t of e)t.addEventListener(`scroll`,h,{passive:!0}),g.push(()=>t.removeEventListener(`scroll`,h));window.addEventListener(`scroll`,h,{passive:!0}),g.push(()=>window.removeEventListener(`scroll`,h))}else{let e=e=>{e.composedPath().includes(i)||h()};window.addEventListener(`scroll`,e,{capture:!0,passive:!0}),g.push(()=>window.removeEventListener(`scroll`,e,{capture:!0}))}window.addEventListener(`resize`,h,{passive:!0}),g.push(()=>window.removeEventListener(`resize`,h));let _=l?window.visualViewport:null;_&&(_.addEventListener(`resize`,h,{passive:!0}),_.addEventListener(`scroll`,h,{passive:!0}),g.push(()=>{_.removeEventListener(`resize`,h),_.removeEventListener(`scroll`,h)}));let v=new ResizeObserver(h);e(r)&&v.observe(r),c&&v.observe(i),g.push(()=>v.disconnect());let y=0;if(o){let e=()=>{h(),y=window.requestAnimationFrame(e)};y=window.requestAnimationFrame(e),g.push(()=>window.cancelAnimationFrame(y))}return()=>{f?.cancel();for(let e of g)e()}}export{r as autoUpdate};
2
+ //# sourceMappingURL=auto-update.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auto-update.js","names":[],"sources":["../src/auto-update.ts"],"sourcesContent":["import { throttle } from '@vielzeug/arsenal';\n\nimport type { ReferenceElement } from './types';\n\nimport { isElement } from './utils';\n\nexport interface AutoUpdateOptions {\n /** Watch the floating element for size changes. Default: `true`. */\n observeFloating?: boolean;\n /**\n * Listen to scroll events on ancestor scroll containers of the reference element\n * in addition to the window. More efficient in deeply nested DOMs.\n * Set to `false` to use only a capture-phase window listener.\n * Default: `true`.\n */\n observeAncestors?: boolean;\n /** Track visual viewport scroll and resize (useful for pinch-zoom). Default: `true`. */\n observeVisualViewport?: boolean;\n /** Re-position on every animation frame. Use only when the reference itself animates. Default: `false`. */\n animationFrame?: boolean;\n /**\n * Throttle update calls to at most once every `throttle` milliseconds.\n * Uses a leading + trailing strategy: fires immediately, then once more after the interval.\n * Default: `0` (no throttling).\n */\n throttle?: number;\n /**\n * Pause position updates while the reference element is scrolled out of the viewport.\n * Uses IntersectionObserver to detect visibility. When the reference becomes visible again,\n * one position update is fired immediately.\n * Default: `true`.\n */\n pauseWhenHidden?: boolean;\n}\n\n/**\n * Collects the ancestor scroll containers of an element (up to and including the\n * nearest scrollable ancestor). Used to scope scroll listeners to the minimal\n * set of elements rather than relying on a capture-phase window listener.\n */\nfunction getScrollAncestors(el: Element): Element[] {\n const ancestors: Element[] = [];\n let current: Element | null = el.parentElement;\n\n while (current) {\n const style = getComputedStyle(current);\n const overflow = style.overflow + style.overflowX + style.overflowY;\n\n if (/auto|scroll|overlay/.test(overflow)) {\n ancestors.push(current);\n }\n\n if (current.parentElement) {\n current = current.parentElement;\n } else {\n const root = current.getRootNode();\n\n current = root instanceof ShadowRoot ? root.host : null;\n }\n }\n\n return ancestors;\n}\n\n/**\n * Calls `update` immediately and re-calls it whenever the reference or floating element\n * could have changed position: scroll, resize, ResizeObserver, or animation frames.\n *\n * By default, scroll listeners are attached to both ancestor scroll containers of the reference\n * AND the window (for document scroll). The ancestor listeners fire for nested container scrolls;\n * the window listener fires for page-level scroll. Set `observeAncestors: false` to use only a\n * capture-phase window listener.\n *\n * Returns a cleanup function that removes all listeners.\n *\n * @example\n * ```ts\n * const cleanup = autoUpdate(reference, floating, () => {\n * const { x, y } = computePosition(reference, floating, options);\n * floating.style.left = `${x}px`;\n * floating.style.top = `${y}px`;\n * });\n * // later:\n * cleanup();\n * ```\n */\nexport function autoUpdate(\n reference: ReferenceElement,\n floating: HTMLElement,\n update: () => void,\n {\n animationFrame = false,\n observeAncestors = true,\n observeFloating = true,\n observeVisualViewport = true,\n pauseWhenHidden = true,\n throttle: throttleMs = 0,\n }: AutoUpdateOptions = {},\n): () => void {\n const throttled = throttleMs > 0 ? throttle(update, throttleMs, { leading: true, trailing: true }) : null;\n const notify = throttled ?? update;\n\n // ── Visibility guard ─────────────────────────────────────────────────────────\n let referenceVisible = true;\n const conditionalNotify = (): void => {\n if (referenceVisible) notify();\n };\n\n // Initial call always runs regardless of visibility state.\n notify();\n\n const cleanups: Array<() => void> = [];\n\n // IntersectionObserver: pause updates when reference is off-screen.\n if (pauseWhenHidden && isElement(reference) && typeof IntersectionObserver !== 'undefined') {\n const io = new IntersectionObserver((entries) => {\n referenceVisible = entries.at(-1)?.isIntersecting ?? true;\n\n if (referenceVisible) notify(); // Re-position immediately when becoming visible.\n });\n\n io.observe(reference);\n cleanups.push(() => io.disconnect());\n }\n\n // ── Scroll listeners ────────────────────────────────────────────────────────\n if (isElement(reference) && observeAncestors) {\n // Targeted ancestor listeners for nested container scroll.\n const ancestors = getScrollAncestors(reference);\n\n for (const ancestor of ancestors) {\n ancestor.addEventListener('scroll', conditionalNotify, { passive: true });\n cleanups.push(() => ancestor.removeEventListener('scroll', conditionalNotify));\n }\n\n // Always add window scroll for document-level scroll (non-capture, doesn't fire for nested containers).\n window.addEventListener('scroll', conditionalNotify, { passive: true });\n cleanups.push(() => window.removeEventListener('scroll', conditionalNotify));\n } else {\n // VirtualReference or observeAncestors: false — capture-phase window listener catches all scrolls.\n const scrollHandler = (e: Event): void => {\n if (e.composedPath().includes(floating)) return;\n\n conditionalNotify();\n };\n\n window.addEventListener('scroll', scrollHandler, { capture: true, passive: true });\n cleanups.push(() => window.removeEventListener('scroll', scrollHandler, { capture: true }));\n }\n\n window.addEventListener('resize', conditionalNotify, { passive: true });\n cleanups.push(() => window.removeEventListener('resize', conditionalNotify));\n\n const vv = observeVisualViewport ? window.visualViewport : null;\n\n if (vv) {\n vv.addEventListener('resize', conditionalNotify, { passive: true });\n vv.addEventListener('scroll', conditionalNotify, { passive: true });\n cleanups.push(() => {\n vv.removeEventListener('resize', conditionalNotify);\n vv.removeEventListener('scroll', conditionalNotify);\n });\n }\n\n const ro = new ResizeObserver(conditionalNotify);\n\n if (isElement(reference)) ro.observe(reference);\n\n if (observeFloating) ro.observe(floating);\n\n cleanups.push(() => ro.disconnect());\n\n let frameId = 0;\n\n if (animationFrame) {\n const frameLoop = (): void => {\n conditionalNotify();\n frameId = window.requestAnimationFrame(frameLoop);\n };\n\n frameId = window.requestAnimationFrame(frameLoop);\n cleanups.push(() => window.cancelAnimationFrame(frameId));\n }\n\n return (): void => {\n throttled?.cancel();\n\n for (const fn of cleanups) fn();\n };\n}\n"],"mappings":"oFAwCA,SAAS,EAAmB,EAAwB,CAClD,IAAM,EAAuB,CAAC,EAC1B,EAA0B,EAAG,cAEjC,KAAO,GAAS,CACd,IAAM,EAAQ,iBAAiB,CAAO,EAChC,EAAW,EAAM,SAAW,EAAM,UAAY,EAAM,UAM1D,GAJI,sBAAsB,KAAK,CAAQ,GACrC,EAAU,KAAK,CAAO,EAGpB,EAAQ,cACV,EAAU,EAAQ,kBACb,CACL,IAAM,EAAO,EAAQ,YAAY,EAEjC,EAAU,aAAgB,WAAa,EAAK,KAAO,IACrD,CACF,CAEA,OAAO,CACT,CAwBA,SAAgB,EACd,EACA,EACA,EACA,CACE,iBAAiB,GACjB,mBAAmB,GACnB,kBAAkB,GAClB,wBAAwB,GACxB,kBAAkB,GAClB,SAAU,EAAa,GACF,CAAC,EACZ,CACZ,IAAM,EAAY,EAAa,EAAI,EAAS,EAAQ,EAAY,CAAE,QAAS,GAAM,SAAU,EAAK,CAAC,EAAI,KAC/F,EAAS,GAAa,EAGxB,EAAmB,GACjB,MAAgC,CAChC,GAAkB,EAAO,CAC/B,EAGA,EAAO,EAEP,IAAM,EAA8B,CAAC,EAGrC,GAAI,GAAmB,EAAU,CAAS,GAAK,OAAO,qBAAyB,IAAa,CAC1F,IAAM,EAAK,IAAI,qBAAsB,GAAY,CAC/C,EAAmB,EAAQ,GAAG,EAAE,CAAC,EAAE,gBAAkB,GAEjD,GAAkB,EAAO,CAC/B,CAAC,EAED,EAAG,QAAQ,CAAS,EACpB,EAAS,SAAW,EAAG,WAAW,CAAC,CACrC,CAGA,GAAI,EAAU,CAAS,GAAK,EAAkB,CAE5C,IAAM,EAAY,EAAmB,CAAS,EAE9C,IAAK,IAAM,KAAY,EACrB,EAAS,iBAAiB,SAAU,EAAmB,CAAE,QAAS,EAAK,CAAC,EACxE,EAAS,SAAW,EAAS,oBAAoB,SAAU,CAAiB,CAAC,EAI/E,OAAO,iBAAiB,SAAU,EAAmB,CAAE,QAAS,EAAK,CAAC,EACtE,EAAS,SAAW,OAAO,oBAAoB,SAAU,CAAiB,CAAC,CAC7E,KAAO,CAEL,IAAM,EAAiB,GAAmB,CACpC,EAAE,aAAa,CAAC,CAAC,SAAS,CAAQ,GAEtC,EAAkB,CACpB,EAEA,OAAO,iBAAiB,SAAU,EAAe,CAAE,QAAS,GAAM,QAAS,EAAK,CAAC,EACjF,EAAS,SAAW,OAAO,oBAAoB,SAAU,EAAe,CAAE,QAAS,EAAK,CAAC,CAAC,CAC5F,CAEA,OAAO,iBAAiB,SAAU,EAAmB,CAAE,QAAS,EAAK,CAAC,EACtE,EAAS,SAAW,OAAO,oBAAoB,SAAU,CAAiB,CAAC,EAE3E,IAAM,EAAK,EAAwB,OAAO,eAAiB,KAEvD,IACF,EAAG,iBAAiB,SAAU,EAAmB,CAAE,QAAS,EAAK,CAAC,EAClE,EAAG,iBAAiB,SAAU,EAAmB,CAAE,QAAS,EAAK,CAAC,EAClE,EAAS,SAAW,CAClB,EAAG,oBAAoB,SAAU,CAAiB,EAClD,EAAG,oBAAoB,SAAU,CAAiB,CACpD,CAAC,GAGH,IAAM,EAAK,IAAI,eAAe,CAAiB,EAE3C,EAAU,CAAS,GAAG,EAAG,QAAQ,CAAS,EAE1C,GAAiB,EAAG,QAAQ,CAAQ,EAExC,EAAS,SAAW,EAAG,WAAW,CAAC,EAEnC,IAAI,EAAU,EAEd,GAAI,EAAgB,CAClB,IAAM,MAAwB,CAC5B,EAAkB,EAClB,EAAU,OAAO,sBAAsB,CAAS,CAClD,EAEA,EAAU,OAAO,sBAAsB,CAAS,EAChD,EAAS,SAAW,OAAO,qBAAqB,CAAO,CAAC,CAC1D,CAEA,UAAmB,CACjB,GAAW,OAAO,EAElB,IAAK,IAAM,KAAM,EAAU,EAAG,CAChC,CACF"}
@@ -0,0 +1,2 @@
1
+ function e(...e){return e.filter(Boolean)}exports.compose=e;
2
+ //# sourceMappingURL=compose.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compose.cjs","names":[],"sources":["../src/compose.ts"],"sourcesContent":["import type { Middleware } from './types';\n\ntype Falsy = false | null | undefined;\n\n/**\n * Filters out falsy middleware entries (`null`, `undefined`, `false`) and returns a clean array.\n *\n * Middleware ordering validation runs automatically inside `computePosition()` in development —\n * you do not need `compose()` to get ordering warnings. Use it purely for its falsy-filter\n * ergonomics when conditionally including middleware.\n *\n * @example\n * ```ts\n * import { compose, offset, flip, shift, arrow } from '@vielzeug/orbit';\n *\n * const middleware = compose(\n * offset(8),\n * flip(),\n * shift({ padding: 6 }),\n * hasArrow && arrow({ element: arrowEl }),\n * );\n * float(trigger, tooltip, { middleware });\n * ```\n */\nexport function compose(...middleware: Array<Middleware | Falsy>): Middleware[] {\n return middleware.filter(Boolean) as Middleware[];\n}\n"],"mappings":"AAwBA,SAAgB,EAAQ,GAAG,EAAqD,CAC9E,OAAO,EAAW,OAAO,OAAO,CAClC"}
@@ -0,0 +1,25 @@
1
+ import type { Middleware } from './types';
2
+ type Falsy = false | null | undefined;
3
+ /**
4
+ * Filters out falsy middleware entries (`null`, `undefined`, `false`) and returns a clean array.
5
+ *
6
+ * Middleware ordering validation runs automatically inside `computePosition()` in development —
7
+ * you do not need `compose()` to get ordering warnings. Use it purely for its falsy-filter
8
+ * ergonomics when conditionally including middleware.
9
+ *
10
+ * @example
11
+ * ```ts
12
+ * import { compose, offset, flip, shift, arrow } from '@vielzeug/orbit';
13
+ *
14
+ * const middleware = compose(
15
+ * offset(8),
16
+ * flip(),
17
+ * shift({ padding: 6 }),
18
+ * hasArrow && arrow({ element: arrowEl }),
19
+ * );
20
+ * float(trigger, tooltip, { middleware });
21
+ * ```
22
+ */
23
+ export declare function compose(...middleware: Array<Middleware | Falsy>): Middleware[];
24
+ export {};
25
+ //# sourceMappingURL=compose.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compose.d.ts","sourceRoot":"","sources":["../src/compose.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAE1C,KAAK,KAAK,GAAG,KAAK,GAAG,IAAI,GAAG,SAAS,CAAC;AAEtC;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,OAAO,CAAC,GAAG,UAAU,EAAE,KAAK,CAAC,UAAU,GAAG,KAAK,CAAC,GAAG,UAAU,EAAE,CAE9E"}
@@ -0,0 +1,2 @@
1
+ function e(...e){return e.filter(Boolean)}export{e as compose};
2
+ //# sourceMappingURL=compose.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compose.js","names":[],"sources":["../src/compose.ts"],"sourcesContent":["import type { Middleware } from './types';\n\ntype Falsy = false | null | undefined;\n\n/**\n * Filters out falsy middleware entries (`null`, `undefined`, `false`) and returns a clean array.\n *\n * Middleware ordering validation runs automatically inside `computePosition()` in development —\n * you do not need `compose()` to get ordering warnings. Use it purely for its falsy-filter\n * ergonomics when conditionally including middleware.\n *\n * @example\n * ```ts\n * import { compose, offset, flip, shift, arrow } from '@vielzeug/orbit';\n *\n * const middleware = compose(\n * offset(8),\n * flip(),\n * shift({ padding: 6 }),\n * hasArrow && arrow({ element: arrowEl }),\n * );\n * float(trigger, tooltip, { middleware });\n * ```\n */\nexport function compose(...middleware: Array<Middleware | Falsy>): Middleware[] {\n return middleware.filter(Boolean) as Middleware[];\n}\n"],"mappings":"AAwBA,SAAgB,EAAQ,GAAG,EAAqD,CAC9E,OAAO,EAAW,OAAO,OAAO,CAClC"}
package/dist/core.cjs ADDED
@@ -0,0 +1,2 @@
1
+ const e=require("./errors.cjs"),t=require("./utils.cjs"),n=require("./_dev.cjs");function r(e,n){return{floating:t.toRect(n.getBoundingClientRect()),reference:t.toRect(e.getBoundingClientRect())}}function i(e,t){return t?{...e,middlewareData:t.data?Object.assign(Object.create(null),e.middlewareData,t.data):e.middlewareData,placement:t.placement??e.placement,x:t.x??e.x,y:t.y??e.y}:e}var a=8;function o(e,t,n){return Promise.resolve().then(()=>c(e,t,n))}function s(e,t,n){return new Promise((r,i)=>{requestAnimationFrame(()=>{try{r(c(e,t,n))}catch(e){i(e)}})})}function c(o,s,{boundary:c,containingBlock:l,middleware:u=[],padding:d,placement:f=`bottom`}={}){let p=u.filter(Boolean);o===s&&n.warn(`computePosition: reference and floating are the same element.`),t.validateMiddlewareNames(p.map(e=>{let n=e[t.MIDDLEWARE_NAME];return typeof n==`string`?n:null}));let m=f,h={},g=r(o,s);n.devOnly(()=>{g.floating.width===0&&g.floating.height===0&&n.warn(`computePosition: floating element has zero dimensions — is it hidden or detached from the DOM?`);let e=getComputedStyle(s).position;e!==`fixed`&&e!==`absolute`&&n.warn(`computePosition: floating element has \`position: ${e}\`. Orbit computes viewport-relative coordinates and expects position: fixed (or absolute for scoped stacking contexts).`)});for(let e=0;e<a;e+=1){let e={...t.baseCoords(m,g.reference,g.floating),boundary:c,elements:{floating:s,reference:o},initialPlacement:f,middlewareData:h,padding:d,placement:m,rects:g},n;for(let t of p){let r=t(e);if(e=i(e,r),h=e.middlewareData,n=r?.reset,n)break}if(!n){let t={middlewareData:e.middlewareData,placement:e.placement,x:e.x,y:e.y};if(l){let e=l.getBoundingClientRect();return{...t,x:t.x-e.x,y:t.y-e.y}}return t}n.remeasure?g=r(o,s):n.rects!=null&&(g=n.rects),m=n.placement??e.placement}throw new e.OrbitConfigError(`Middleware triggered too many resets in a single compute cycle.`)}exports.computePosition=c,exports.computePositionAsync=o,exports.computePositionRaf=s,exports.getRects=r;
2
+ //# sourceMappingURL=core.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"core.cjs","names":[],"sources":["../src/core.ts"],"sourcesContent":["import type {\n ComputePositionOptions,\n ComputePositionResult,\n Middleware,\n MiddlewareData,\n MiddlewareReset,\n MiddlewareResult,\n MiddlewareState,\n ReferenceElement,\n} from './types';\n\nimport { devOnly, warn } from './_dev';\nimport { OrbitConfigError } from './errors';\nimport { baseCoords, MIDDLEWARE_NAME, toRect, validateMiddlewareNames } from './utils';\n\n// ── DOM helpers ────────────────────────────────────────────────────────────────────────────────\n\n/** Reads the bounding rects of the reference and floating elements from the DOM. */\nexport function getRects(reference: ReferenceElement, floating: HTMLElement): MiddlewareState['rects'] {\n return {\n floating: toRect(floating.getBoundingClientRect()),\n reference: toRect(reference.getBoundingClientRect()),\n };\n}\n\n// ── Internal state helpers ───────────────────────────────────────────────────────────\n\nfunction mergeState(state: MiddlewareState, result: MiddlewareResult | void): MiddlewareState {\n if (!result) return state;\n\n return {\n ...state,\n middlewareData: result.data\n ? (Object.assign(Object.create(null), state.middlewareData, result.data) as MiddlewareData)\n : state.middlewareData,\n placement: result.placement ?? state.placement,\n x: result.x ?? state.x,\n y: result.y ?? state.y,\n };\n}\n\n// ── Constants ─────────────────────────────────────────────────────────────────────────────────\n\n/** Maximum number of pipeline restarts allowed per `computePosition` call before throwing. */\nconst MAX_RESETS = 8;\n\n// ── Public API ────────────────────────────────────────────────────────────────────────────────\n\n/**\n * Deferred position computation. Runs `computePosition` in the next **microtask** and\n * returns a `Promise<ComputePositionResult>`.\n *\n * Useful for async component lifecycles (e.g. `await nextTick()` in Vue/React) where the\n * synchronous `computePosition` would read stale DOM measurements because layout has not been\n * committed yet. Note: this defers to the microtask queue, not the next animation frame — if you\n * need post-layout measurements use `requestAnimationFrame` instead.\n *\n * @example\n * ```ts\n * const result = await computePositionAsync(reference, floating, { placement: 'top' });\n * floating.style.left = `${result.x}px`;\n * floating.style.top = `${result.y}px`;\n * ```\n */\nexport function computePositionAsync(\n reference: ReferenceElement,\n floating: HTMLElement,\n options?: ComputePositionOptions,\n): Promise<ComputePositionResult> {\n return Promise.resolve().then(() => computePosition(reference, floating, options));\n}\n\n/**\n * Deferred position computation. Runs `computePosition` in the next **animation frame** and\n * returns a `Promise<ComputePositionResult>`.\n *\n * Useful when the layout has not yet committed (e.g. immediately after DOM insertion). Unlike\n * `computePositionAsync` which defers to the microtask queue, this waits for the next\n * `requestAnimationFrame` tick — guaranteeing post-layout DOM measurements.\n *\n * @example\n * ```ts\n * const result = await computePositionRaf(reference, floating, { placement: 'top' });\n * floating.style.left = `${result.x}px`;\n * floating.style.top = `${result.y}px`;\n * ```\n */\nexport function computePositionRaf(\n reference: ReferenceElement,\n floating: HTMLElement,\n options?: ComputePositionOptions,\n): Promise<ComputePositionResult> {\n return new Promise((resolve, reject) => {\n requestAnimationFrame(() => {\n try {\n resolve(computePosition(reference, floating, options));\n } catch (err) {\n reject(err);\n }\n });\n });\n}\n\n/**\n * Runs the middleware pipeline and returns the final position.\n *\n * Position is computed in viewport-relative coordinates assuming `position: fixed`.\n */\nexport function computePosition(\n reference: ReferenceElement,\n floating: HTMLElement,\n { boundary, containingBlock, middleware = [], padding, placement = 'bottom' }: ComputePositionOptions = {},\n): ComputePositionResult {\n const mws = middleware.filter(Boolean) as Middleware[];\n\n if (reference === floating) {\n warn('computePosition: reference and floating are the same element.');\n }\n\n const names = mws.map((mw) => {\n const tag = (mw as unknown as Record<symbol, unknown>)[MIDDLEWARE_NAME];\n\n return typeof tag === 'string' ? tag : null;\n });\n\n validateMiddlewareNames(names);\n\n let currentPlacement = placement;\n let middlewareData: MiddlewareData = {};\n let rects = getRects(reference, floating);\n\n devOnly(() => {\n if (rects.floating.width === 0 && rects.floating.height === 0) {\n warn('computePosition: floating element has zero dimensions — is it hidden or detached from the DOM?');\n }\n\n const pos = getComputedStyle(floating).position;\n\n if (pos !== 'fixed' && pos !== 'absolute') {\n warn(\n `computePosition: floating element has \\`position: ${pos}\\`. ` +\n 'Orbit computes viewport-relative coordinates and expects position: fixed ' +\n '(or absolute for scoped stacking contexts).',\n );\n }\n });\n\n for (let resets = 0; resets < MAX_RESETS; resets += 1) {\n let state: MiddlewareState = {\n ...baseCoords(currentPlacement, rects.reference, rects.floating),\n boundary,\n elements: { floating, reference },\n initialPlacement: placement,\n middlewareData,\n padding,\n placement: currentPlacement,\n rects,\n };\n\n let reset: MiddlewareReset | undefined;\n\n for (const mw of mws) {\n const result = mw(state);\n\n state = mergeState(state, result);\n middlewareData = state.middlewareData;\n reset = result?.reset;\n\n if (reset) break;\n }\n\n if (!reset) {\n const result: ComputePositionResult = {\n middlewareData: state.middlewareData,\n placement: state.placement,\n x: state.x,\n y: state.y,\n };\n\n if (containingBlock) {\n const cb = containingBlock.getBoundingClientRect();\n\n return { ...result, x: result.x - cb.x, y: result.y - cb.y };\n }\n\n return result;\n }\n\n if (reset.remeasure) {\n rects = getRects(reference, floating);\n } else if (reset.rects != null) {\n rects = reset.rects;\n }\n\n currentPlacement = reset.placement ?? state.placement;\n }\n\n throw new OrbitConfigError('Middleware triggered too many resets in a single compute cycle.');\n}\n"],"mappings":"iFAkBA,SAAgB,EAAS,EAA6B,EAAiD,CACrG,MAAO,CACL,SAAU,EAAA,OAAO,EAAS,sBAAsB,CAAC,EACjD,UAAW,EAAA,OAAO,EAAU,sBAAsB,CAAC,CACrD,CACF,CAIA,SAAS,EAAW,EAAwB,EAAkD,CAG5F,OAFK,EAEE,CACL,GAAG,EACH,eAAgB,EAAO,KAClB,OAAO,OAAO,OAAO,OAAO,IAAI,EAAG,EAAM,eAAgB,EAAO,IAAI,EACrE,EAAM,eACV,UAAW,EAAO,WAAa,EAAM,UACrC,EAAG,EAAO,GAAK,EAAM,EACrB,EAAG,EAAO,GAAK,EAAM,CACvB,EAVoB,CAWtB,CAKA,IAAM,EAAa,EAoBnB,SAAgB,EACd,EACA,EACA,EACgC,CAChC,OAAO,QAAQ,QAAQ,CAAC,CAAC,SAAW,EAAgB,EAAW,EAAU,CAAO,CAAC,CACnF,CAiBA,SAAgB,EACd,EACA,EACA,EACgC,CAChC,OAAO,IAAI,SAAS,EAAS,IAAW,CACtC,0BAA4B,CAC1B,GAAI,CACF,EAAQ,EAAgB,EAAW,EAAU,CAAO,CAAC,CACvD,OAAS,EAAK,CACZ,EAAO,CAAG,CACZ,CACF,CAAC,CACH,CAAC,CACH,CAOA,SAAgB,EACd,EACA,EACA,CAAE,WAAU,kBAAiB,aAAa,CAAC,EAAG,UAAS,YAAY,UAAqC,CAAC,EAClF,CACvB,IAAM,EAAM,EAAW,OAAO,OAAO,EAEjC,IAAc,GAChB,EAAA,KAAK,+DAA+D,EAStE,EAAA,wBANc,EAAI,IAAK,GAAO,CAC5B,IAAM,EAAO,EAA0C,EAAA,iBAEvD,OAAO,OAAO,GAAQ,SAAW,EAAM,IACzC,CAEwB,CAAK,EAE7B,IAAI,EAAmB,EACnB,EAAiC,CAAC,EAClC,EAAQ,EAAS,EAAW,CAAQ,EAExC,EAAA,YAAc,CACR,EAAM,SAAS,QAAU,GAAK,EAAM,SAAS,SAAW,GAC1D,EAAA,KAAK,gGAAgG,EAGvG,IAAM,EAAM,iBAAiB,CAAQ,CAAC,CAAC,SAEnC,IAAQ,SAAW,IAAQ,YAC7B,EAAA,KACE,qDAAqD,EAAI,yHAG3D,CAEJ,CAAC,EAED,IAAK,IAAI,EAAS,EAAG,EAAS,EAAY,GAAU,EAAG,CACrD,IAAI,EAAyB,CAC3B,GAAG,EAAA,WAAW,EAAkB,EAAM,UAAW,EAAM,QAAQ,EAC/D,WACA,SAAU,CAAE,WAAU,WAAU,EAChC,iBAAkB,EAClB,iBACA,UACA,UAAW,EACX,OACF,EAEI,EAEJ,IAAK,IAAM,KAAM,EAAK,CACpB,IAAM,EAAS,EAAG,CAAK,EAMvB,GAJA,EAAQ,EAAW,EAAO,CAAM,EAChC,EAAiB,EAAM,eACvB,EAAQ,GAAQ,MAEZ,EAAO,KACb,CAEA,GAAI,CAAC,EAAO,CACV,IAAM,EAAgC,CACpC,eAAgB,EAAM,eACtB,UAAW,EAAM,UACjB,EAAG,EAAM,EACT,EAAG,EAAM,CACX,EAEA,GAAI,EAAiB,CACnB,IAAM,EAAK,EAAgB,sBAAsB,EAEjD,MAAO,CAAE,GAAG,EAAQ,EAAG,EAAO,EAAI,EAAG,EAAG,EAAG,EAAO,EAAI,EAAG,CAAE,CAC7D,CAEA,OAAO,CACT,CAEI,EAAM,UACR,EAAQ,EAAS,EAAW,CAAQ,EAC3B,EAAM,OAAS,OACxB,EAAQ,EAAM,OAGhB,EAAmB,EAAM,WAAa,EAAM,SAC9C,CAEA,MAAM,IAAI,EAAA,iBAAiB,iEAAiE,CAC9F"}
package/dist/core.d.ts ADDED
@@ -0,0 +1,43 @@
1
+ import type { ComputePositionOptions, ComputePositionResult, MiddlewareState, ReferenceElement } from './types';
2
+ /** Reads the bounding rects of the reference and floating elements from the DOM. */
3
+ export declare function getRects(reference: ReferenceElement, floating: HTMLElement): MiddlewareState['rects'];
4
+ /**
5
+ * Deferred position computation. Runs `computePosition` in the next **microtask** and
6
+ * returns a `Promise<ComputePositionResult>`.
7
+ *
8
+ * Useful for async component lifecycles (e.g. `await nextTick()` in Vue/React) where the
9
+ * synchronous `computePosition` would read stale DOM measurements because layout has not been
10
+ * committed yet. Note: this defers to the microtask queue, not the next animation frame — if you
11
+ * need post-layout measurements use `requestAnimationFrame` instead.
12
+ *
13
+ * @example
14
+ * ```ts
15
+ * const result = await computePositionAsync(reference, floating, { placement: 'top' });
16
+ * floating.style.left = `${result.x}px`;
17
+ * floating.style.top = `${result.y}px`;
18
+ * ```
19
+ */
20
+ export declare function computePositionAsync(reference: ReferenceElement, floating: HTMLElement, options?: ComputePositionOptions): Promise<ComputePositionResult>;
21
+ /**
22
+ * Deferred position computation. Runs `computePosition` in the next **animation frame** and
23
+ * returns a `Promise<ComputePositionResult>`.
24
+ *
25
+ * Useful when the layout has not yet committed (e.g. immediately after DOM insertion). Unlike
26
+ * `computePositionAsync` which defers to the microtask queue, this waits for the next
27
+ * `requestAnimationFrame` tick — guaranteeing post-layout DOM measurements.
28
+ *
29
+ * @example
30
+ * ```ts
31
+ * const result = await computePositionRaf(reference, floating, { placement: 'top' });
32
+ * floating.style.left = `${result.x}px`;
33
+ * floating.style.top = `${result.y}px`;
34
+ * ```
35
+ */
36
+ export declare function computePositionRaf(reference: ReferenceElement, floating: HTMLElement, options?: ComputePositionOptions): Promise<ComputePositionResult>;
37
+ /**
38
+ * Runs the middleware pipeline and returns the final position.
39
+ *
40
+ * Position is computed in viewport-relative coordinates assuming `position: fixed`.
41
+ */
42
+ export declare function computePosition(reference: ReferenceElement, floating: HTMLElement, { boundary, containingBlock, middleware, padding, placement }?: ComputePositionOptions): ComputePositionResult;
43
+ //# sourceMappingURL=core.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../src/core.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,sBAAsB,EACtB,qBAAqB,EAKrB,eAAe,EACf,gBAAgB,EACjB,MAAM,SAAS,CAAC;AAQjB,oFAAoF;AACpF,wBAAgB,QAAQ,CAAC,SAAS,EAAE,gBAAgB,EAAE,QAAQ,EAAE,WAAW,GAAG,eAAe,CAAC,OAAO,CAAC,CAKrG;AAyBD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,gBAAgB,EAC3B,QAAQ,EAAE,WAAW,EACrB,OAAO,CAAC,EAAE,sBAAsB,GAC/B,OAAO,CAAC,qBAAqB,CAAC,CAEhC;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,kBAAkB,CAChC,SAAS,EAAE,gBAAgB,EAC3B,QAAQ,EAAE,WAAW,EACrB,OAAO,CAAC,EAAE,sBAAsB,GAC/B,OAAO,CAAC,qBAAqB,CAAC,CAUhC;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAC7B,SAAS,EAAE,gBAAgB,EAC3B,QAAQ,EAAE,WAAW,EACrB,EAAE,QAAQ,EAAE,eAAe,EAAE,UAAe,EAAE,OAAO,EAAE,SAAoB,EAAE,GAAE,sBAA2B,GACzG,qBAAqB,CAsFvB"}
package/dist/core.js ADDED
@@ -0,0 +1,2 @@
1
+ import{OrbitConfigError as e}from"./errors.js";import{MIDDLEWARE_NAME as t,baseCoords as n,toRect as r,validateMiddlewareNames as i}from"./utils.js";import{devOnly as a,warn as o}from"./_dev.js";function s(e,t){return{floating:r(t.getBoundingClientRect()),reference:r(e.getBoundingClientRect())}}function c(e,t){return t?{...e,middlewareData:t.data?Object.assign(Object.create(null),e.middlewareData,t.data):e.middlewareData,placement:t.placement??e.placement,x:t.x??e.x,y:t.y??e.y}:e}var l=8;function u(e,t,n){return Promise.resolve().then(()=>f(e,t,n))}function d(e,t,n){return new Promise((r,i)=>{requestAnimationFrame(()=>{try{r(f(e,t,n))}catch(e){i(e)}})})}function f(r,u,{boundary:d,containingBlock:f,middleware:p=[],padding:m,placement:h=`bottom`}={}){let g=p.filter(Boolean);r===u&&o(`computePosition: reference and floating are the same element.`),i(g.map(e=>{let n=e[t];return typeof n==`string`?n:null}));let _=h,v={},y=s(r,u);a(()=>{y.floating.width===0&&y.floating.height===0&&o(`computePosition: floating element has zero dimensions — is it hidden or detached from the DOM?`);let e=getComputedStyle(u).position;e!==`fixed`&&e!==`absolute`&&o(`computePosition: floating element has \`position: ${e}\`. Orbit computes viewport-relative coordinates and expects position: fixed (or absolute for scoped stacking contexts).`)});for(let e=0;e<l;e+=1){let e={...n(_,y.reference,y.floating),boundary:d,elements:{floating:u,reference:r},initialPlacement:h,middlewareData:v,padding:m,placement:_,rects:y},t;for(let n of g){let r=n(e);if(e=c(e,r),v=e.middlewareData,t=r?.reset,t)break}if(!t){let t={middlewareData:e.middlewareData,placement:e.placement,x:e.x,y:e.y};if(f){let e=f.getBoundingClientRect();return{...t,x:t.x-e.x,y:t.y-e.y}}return t}t.remeasure?y=s(r,u):t.rects!=null&&(y=t.rects),_=t.placement??e.placement}throw new e(`Middleware triggered too many resets in a single compute cycle.`)}export{f as computePosition,u as computePositionAsync,d as computePositionRaf,s as getRects};
2
+ //# sourceMappingURL=core.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"core.js","names":[],"sources":["../src/core.ts"],"sourcesContent":["import type {\n ComputePositionOptions,\n ComputePositionResult,\n Middleware,\n MiddlewareData,\n MiddlewareReset,\n MiddlewareResult,\n MiddlewareState,\n ReferenceElement,\n} from './types';\n\nimport { devOnly, warn } from './_dev';\nimport { OrbitConfigError } from './errors';\nimport { baseCoords, MIDDLEWARE_NAME, toRect, validateMiddlewareNames } from './utils';\n\n// ── DOM helpers ────────────────────────────────────────────────────────────────────────────────\n\n/** Reads the bounding rects of the reference and floating elements from the DOM. */\nexport function getRects(reference: ReferenceElement, floating: HTMLElement): MiddlewareState['rects'] {\n return {\n floating: toRect(floating.getBoundingClientRect()),\n reference: toRect(reference.getBoundingClientRect()),\n };\n}\n\n// ── Internal state helpers ───────────────────────────────────────────────────────────\n\nfunction mergeState(state: MiddlewareState, result: MiddlewareResult | void): MiddlewareState {\n if (!result) return state;\n\n return {\n ...state,\n middlewareData: result.data\n ? (Object.assign(Object.create(null), state.middlewareData, result.data) as MiddlewareData)\n : state.middlewareData,\n placement: result.placement ?? state.placement,\n x: result.x ?? state.x,\n y: result.y ?? state.y,\n };\n}\n\n// ── Constants ─────────────────────────────────────────────────────────────────────────────────\n\n/** Maximum number of pipeline restarts allowed per `computePosition` call before throwing. */\nconst MAX_RESETS = 8;\n\n// ── Public API ────────────────────────────────────────────────────────────────────────────────\n\n/**\n * Deferred position computation. Runs `computePosition` in the next **microtask** and\n * returns a `Promise<ComputePositionResult>`.\n *\n * Useful for async component lifecycles (e.g. `await nextTick()` in Vue/React) where the\n * synchronous `computePosition` would read stale DOM measurements because layout has not been\n * committed yet. Note: this defers to the microtask queue, not the next animation frame — if you\n * need post-layout measurements use `requestAnimationFrame` instead.\n *\n * @example\n * ```ts\n * const result = await computePositionAsync(reference, floating, { placement: 'top' });\n * floating.style.left = `${result.x}px`;\n * floating.style.top = `${result.y}px`;\n * ```\n */\nexport function computePositionAsync(\n reference: ReferenceElement,\n floating: HTMLElement,\n options?: ComputePositionOptions,\n): Promise<ComputePositionResult> {\n return Promise.resolve().then(() => computePosition(reference, floating, options));\n}\n\n/**\n * Deferred position computation. Runs `computePosition` in the next **animation frame** and\n * returns a `Promise<ComputePositionResult>`.\n *\n * Useful when the layout has not yet committed (e.g. immediately after DOM insertion). Unlike\n * `computePositionAsync` which defers to the microtask queue, this waits for the next\n * `requestAnimationFrame` tick — guaranteeing post-layout DOM measurements.\n *\n * @example\n * ```ts\n * const result = await computePositionRaf(reference, floating, { placement: 'top' });\n * floating.style.left = `${result.x}px`;\n * floating.style.top = `${result.y}px`;\n * ```\n */\nexport function computePositionRaf(\n reference: ReferenceElement,\n floating: HTMLElement,\n options?: ComputePositionOptions,\n): Promise<ComputePositionResult> {\n return new Promise((resolve, reject) => {\n requestAnimationFrame(() => {\n try {\n resolve(computePosition(reference, floating, options));\n } catch (err) {\n reject(err);\n }\n });\n });\n}\n\n/**\n * Runs the middleware pipeline and returns the final position.\n *\n * Position is computed in viewport-relative coordinates assuming `position: fixed`.\n */\nexport function computePosition(\n reference: ReferenceElement,\n floating: HTMLElement,\n { boundary, containingBlock, middleware = [], padding, placement = 'bottom' }: ComputePositionOptions = {},\n): ComputePositionResult {\n const mws = middleware.filter(Boolean) as Middleware[];\n\n if (reference === floating) {\n warn('computePosition: reference and floating are the same element.');\n }\n\n const names = mws.map((mw) => {\n const tag = (mw as unknown as Record<symbol, unknown>)[MIDDLEWARE_NAME];\n\n return typeof tag === 'string' ? tag : null;\n });\n\n validateMiddlewareNames(names);\n\n let currentPlacement = placement;\n let middlewareData: MiddlewareData = {};\n let rects = getRects(reference, floating);\n\n devOnly(() => {\n if (rects.floating.width === 0 && rects.floating.height === 0) {\n warn('computePosition: floating element has zero dimensions — is it hidden or detached from the DOM?');\n }\n\n const pos = getComputedStyle(floating).position;\n\n if (pos !== 'fixed' && pos !== 'absolute') {\n warn(\n `computePosition: floating element has \\`position: ${pos}\\`. ` +\n 'Orbit computes viewport-relative coordinates and expects position: fixed ' +\n '(or absolute for scoped stacking contexts).',\n );\n }\n });\n\n for (let resets = 0; resets < MAX_RESETS; resets += 1) {\n let state: MiddlewareState = {\n ...baseCoords(currentPlacement, rects.reference, rects.floating),\n boundary,\n elements: { floating, reference },\n initialPlacement: placement,\n middlewareData,\n padding,\n placement: currentPlacement,\n rects,\n };\n\n let reset: MiddlewareReset | undefined;\n\n for (const mw of mws) {\n const result = mw(state);\n\n state = mergeState(state, result);\n middlewareData = state.middlewareData;\n reset = result?.reset;\n\n if (reset) break;\n }\n\n if (!reset) {\n const result: ComputePositionResult = {\n middlewareData: state.middlewareData,\n placement: state.placement,\n x: state.x,\n y: state.y,\n };\n\n if (containingBlock) {\n const cb = containingBlock.getBoundingClientRect();\n\n return { ...result, x: result.x - cb.x, y: result.y - cb.y };\n }\n\n return result;\n }\n\n if (reset.remeasure) {\n rects = getRects(reference, floating);\n } else if (reset.rects != null) {\n rects = reset.rects;\n }\n\n currentPlacement = reset.placement ?? state.placement;\n }\n\n throw new OrbitConfigError('Middleware triggered too many resets in a single compute cycle.');\n}\n"],"mappings":"mMAkBA,SAAgB,EAAS,EAA6B,EAAiD,CACrG,MAAO,CACL,SAAU,EAAO,EAAS,sBAAsB,CAAC,EACjD,UAAW,EAAO,EAAU,sBAAsB,CAAC,CACrD,CACF,CAIA,SAAS,EAAW,EAAwB,EAAkD,CAG5F,OAFK,EAEE,CACL,GAAG,EACH,eAAgB,EAAO,KAClB,OAAO,OAAO,OAAO,OAAO,IAAI,EAAG,EAAM,eAAgB,EAAO,IAAI,EACrE,EAAM,eACV,UAAW,EAAO,WAAa,EAAM,UACrC,EAAG,EAAO,GAAK,EAAM,EACrB,EAAG,EAAO,GAAK,EAAM,CACvB,EAVoB,CAWtB,CAKA,IAAM,EAAa,EAoBnB,SAAgB,EACd,EACA,EACA,EACgC,CAChC,OAAO,QAAQ,QAAQ,CAAC,CAAC,SAAW,EAAgB,EAAW,EAAU,CAAO,CAAC,CACnF,CAiBA,SAAgB,EACd,EACA,EACA,EACgC,CAChC,OAAO,IAAI,SAAS,EAAS,IAAW,CACtC,0BAA4B,CAC1B,GAAI,CACF,EAAQ,EAAgB,EAAW,EAAU,CAAO,CAAC,CACvD,OAAS,EAAK,CACZ,EAAO,CAAG,CACZ,CACF,CAAC,CACH,CAAC,CACH,CAOA,SAAgB,EACd,EACA,EACA,CAAE,WAAU,kBAAiB,aAAa,CAAC,EAAG,UAAS,YAAY,UAAqC,CAAC,EAClF,CACvB,IAAM,EAAM,EAAW,OAAO,OAAO,EAEjC,IAAc,GAChB,EAAK,+DAA+D,EAStE,EANc,EAAI,IAAK,GAAO,CAC5B,IAAM,EAAO,EAA0C,GAEvD,OAAO,OAAO,GAAQ,SAAW,EAAM,IACzC,CAEwB,CAAK,EAE7B,IAAI,EAAmB,EACnB,EAAiC,CAAC,EAClC,EAAQ,EAAS,EAAW,CAAQ,EAExC,MAAc,CACR,EAAM,SAAS,QAAU,GAAK,EAAM,SAAS,SAAW,GAC1D,EAAK,gGAAgG,EAGvG,IAAM,EAAM,iBAAiB,CAAQ,CAAC,CAAC,SAEnC,IAAQ,SAAW,IAAQ,YAC7B,EACE,qDAAqD,EAAI,yHAG3D,CAEJ,CAAC,EAED,IAAK,IAAI,EAAS,EAAG,EAAS,EAAY,GAAU,EAAG,CACrD,IAAI,EAAyB,CAC3B,GAAG,EAAW,EAAkB,EAAM,UAAW,EAAM,QAAQ,EAC/D,WACA,SAAU,CAAE,WAAU,WAAU,EAChC,iBAAkB,EAClB,iBACA,UACA,UAAW,EACX,OACF,EAEI,EAEJ,IAAK,IAAM,KAAM,EAAK,CACpB,IAAM,EAAS,EAAG,CAAK,EAMvB,GAJA,EAAQ,EAAW,EAAO,CAAM,EAChC,EAAiB,EAAM,eACvB,EAAQ,GAAQ,MAEZ,EAAO,KACb,CAEA,GAAI,CAAC,EAAO,CACV,IAAM,EAAgC,CACpC,eAAgB,EAAM,eACtB,UAAW,EAAM,UACjB,EAAG,EAAM,EACT,EAAG,EAAM,CACX,EAEA,GAAI,EAAiB,CACnB,IAAM,EAAK,EAAgB,sBAAsB,EAEjD,MAAO,CAAE,GAAG,EAAQ,EAAG,EAAO,EAAI,EAAG,EAAG,EAAG,EAAO,EAAI,EAAG,CAAE,CAC7D,CAEA,OAAO,CACT,CAEI,EAAM,UACR,EAAQ,EAAS,EAAW,CAAQ,EAC3B,EAAM,OAAS,OACxB,EAAQ,EAAM,OAGhB,EAAmB,EAAM,WAAa,EAAM,SAC9C,CAEA,MAAM,IAAI,EAAiB,iEAAiE,CAC9F"}
@@ -0,0 +1,2 @@
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./float.cjs");function t(e,t){for(let[n,r]of Object.entries(t))e.style.setProperty(n,r)}function n(){let e=document.createElement(`div`);return e.dataset.orbitDebug=``,t(e,{"font-family":`monospace`,"font-size":`11px`,left:`0`,"pointer-events":`none`,position:`fixed`,top:`0`,"z-index":`2147483647`}),e}function r(e,n,r){let i=document.createElement(`div`);return i.textContent=e,t(i,{background:`rgba(0,100,255,0.85)`,"border-radius":`3px`,color:`#fff`,left:`${n}px`,padding:`1px 6px`,position:`fixed`,top:`${Math.max(0,r)}px`,"white-space":`nowrap`}),i}function i(e,n,r,i,a){let o=document.createElement(`div`);return t(o,{border:`1.5px dashed ${a}`,height:`${i}px`,left:`${e}px`,position:`fixed`,top:`${n}px`,width:`${r}px`}),o}function a(t,a,o={}){let s=n();document.body.appendChild(s);function c(e){if(s.innerHTML=``,s.appendChild(i(1,1,window.innerWidth-2,window.innerHeight-2,`rgba(0,100,255,0.3)`)),t instanceof Element){let e=t.getBoundingClientRect();s.appendChild(i(e.left,e.top,e.width,e.height,`rgba(255,120,0,0.7)`))}let n=a.getBoundingClientRect();s.appendChild(r(e.placement,n.left,n.top-22))}let l=o.apply;function u(e){l?l(e):(a.style.left=`${e.x}px`,a.style.top=`${e.y}px`),c(e)}let d=e.float(t,a,{...o,apply:u});return e.makeHandle(()=>{d.dispose(),s.remove()},()=>d.getPosition(),()=>d.update())}exports.debugFloat=a;
2
+ //# sourceMappingURL=devtools.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"devtools.cjs","names":[],"sources":["../src/devtools.ts"],"sourcesContent":["/**\n * @vielzeug/orbit — debug overlay for positioning visualisation.\n *\n * Import from the dedicated sub-path so it is tree-shaken from production bundles:\n * ```ts\n * import { debugFloat } from '@vielzeug/orbit/devtools';\n * ```\n */\n\nimport type { FloatOptions } from './float';\nimport type { ComputePositionResult, FloatHandle, ReferenceElement } from './types';\n\nimport { float, makeHandle } from './float';\n\n// ── Overlay helpers ───────────────────────────────────────────────────────────\n\nfunction setStyles(el: HTMLElement, styles: Record<string, string>): void {\n for (const [key, val] of Object.entries(styles)) {\n el.style.setProperty(key, val);\n }\n}\n\nfunction createOverlay(): HTMLElement {\n const el = document.createElement('div');\n\n el.dataset['orbitDebug'] = '';\n setStyles(el, {\n 'font-family': 'monospace',\n 'font-size': '11px',\n left: '0',\n 'pointer-events': 'none',\n position: 'fixed',\n top: '0',\n 'z-index': '2147483647',\n });\n\n return el;\n}\n\nfunction createPlacementBadge(text: string, x: number, y: number): HTMLElement {\n const el = document.createElement('div');\n\n el.textContent = text;\n setStyles(el, {\n background: 'rgba(0,100,255,0.85)',\n 'border-radius': '3px',\n color: '#fff',\n left: `${x}px`,\n padding: '1px 6px',\n position: 'fixed',\n top: `${Math.max(0, y)}px`,\n 'white-space': 'nowrap',\n });\n\n return el;\n}\n\nfunction createOutlineBox(x: number, y: number, width: number, height: number, color: string): HTMLElement {\n const el = document.createElement('div');\n\n setStyles(el, {\n border: `1.5px dashed ${color}`,\n height: `${height}px`,\n left: `${x}px`,\n position: 'fixed',\n top: `${y}px`,\n width: `${width}px`,\n });\n\n return el;\n}\n\n// ── Public API ────────────────────────────────────────────────────────────────\n\n/**\n * Wraps `float()` and attaches a persistent visual debug overlay to the document.\n *\n * The overlay renders on every position update:\n * - **Blue dashed outline** — the viewport boundary used by overflow detection.\n * - **Orange dashed outline** — the reference element's bounding rect.\n * - **Blue label** — the active placement string (e.g. `\"top-start\"`).\n *\n * The overlay is automatically removed when `handle.dispose()` is called.\n *\n * Use only in development. Tree-shaken from production bundles via the sub-path import.\n *\n * @example\n * ```ts\n * import { debugFloat } from '@vielzeug/orbit/devtools';\n *\n * const handle = debugFloat(reference, tooltip, {\n * placement: 'top',\n * middleware: [offset(8), flip(), shift({ padding: 6 })],\n * });\n * // on teardown:\n * handle.dispose();\n * ```\n */\nexport function debugFloat(\n reference: ReferenceElement,\n floating: HTMLElement,\n options: FloatOptions = {},\n): FloatHandle {\n const overlay = createOverlay();\n\n document.body.appendChild(overlay);\n\n function renderOverlay(result: ComputePositionResult): void {\n overlay.innerHTML = '';\n\n // Viewport boundary.\n overlay.appendChild(createOutlineBox(1, 1, window.innerWidth - 2, window.innerHeight - 2, 'rgba(0,100,255,0.3)'));\n\n // Reference element.\n if (reference instanceof Element) {\n const r = reference.getBoundingClientRect();\n\n overlay.appendChild(createOutlineBox(r.left, r.top, r.width, r.height, 'rgba(255,120,0,0.7)'));\n }\n\n // Placement label — positioned just above the floating element.\n const fr = floating.getBoundingClientRect();\n\n overlay.appendChild(createPlacementBadge(result.placement, fr.left, fr.top - 22));\n }\n\n const userApply = options.apply;\n\n function wrappedApply(result: ComputePositionResult): void {\n if (userApply) {\n userApply(result);\n } else {\n floating.style.left = `${result.x}px`;\n floating.style.top = `${result.y}px`;\n }\n\n renderOverlay(result);\n }\n\n const handle = float(reference, floating, { ...options, apply: wrappedApply });\n\n return makeHandle(\n () => {\n handle.dispose();\n overlay.remove();\n },\n () => handle.getPosition(),\n () => handle.update(),\n );\n}\n"],"mappings":"kGAgBA,SAAS,EAAU,EAAiB,EAAsC,CACxE,IAAK,GAAM,CAAC,EAAK,KAAQ,OAAO,QAAQ,CAAM,EAC5C,EAAG,MAAM,YAAY,EAAK,CAAG,CAEjC,CAEA,SAAS,GAA6B,CACpC,IAAM,EAAK,SAAS,cAAc,KAAK,EAavC,MAXA,GAAG,QAAQ,WAAgB,GAC3B,EAAU,EAAI,CACZ,cAAe,YACf,YAAa,OACb,KAAM,IACN,iBAAkB,OAClB,SAAU,QACV,IAAK,IACL,UAAW,YACb,CAAC,EAEM,CACT,CAEA,SAAS,EAAqB,EAAc,EAAW,EAAwB,CAC7E,IAAM,EAAK,SAAS,cAAc,KAAK,EAcvC,MAZA,GAAG,YAAc,EACjB,EAAU,EAAI,CACZ,WAAY,uBACZ,gBAAiB,MACjB,MAAO,OACP,KAAM,GAAG,EAAE,IACX,QAAS,UACT,SAAU,QACV,IAAK,GAAG,KAAK,IAAI,EAAG,CAAC,EAAE,IACvB,cAAe,QACjB,CAAC,EAEM,CACT,CAEA,SAAS,EAAiB,EAAW,EAAW,EAAe,EAAgB,EAA4B,CACzG,IAAM,EAAK,SAAS,cAAc,KAAK,EAWvC,OATA,EAAU,EAAI,CACZ,OAAQ,gBAAgB,IACxB,OAAQ,GAAG,EAAO,IAClB,KAAM,GAAG,EAAE,IACX,SAAU,QACV,IAAK,GAAG,EAAE,IACV,MAAO,GAAG,EAAM,GAClB,CAAC,EAEM,CACT,CA4BA,SAAgB,EACd,EACA,EACA,EAAwB,CAAC,EACZ,CACb,IAAM,EAAU,EAAc,EAE9B,SAAS,KAAK,YAAY,CAAO,EAEjC,SAAS,EAAc,EAAqC,CAO1D,GANA,EAAQ,UAAY,GAGpB,EAAQ,YAAY,EAAiB,EAAG,EAAG,OAAO,WAAa,EAAG,OAAO,YAAc,EAAG,qBAAqB,CAAC,EAG5G,aAAqB,QAAS,CAChC,IAAM,EAAI,EAAU,sBAAsB,EAE1C,EAAQ,YAAY,EAAiB,EAAE,KAAM,EAAE,IAAK,EAAE,MAAO,EAAE,OAAQ,qBAAqB,CAAC,CAC/F,CAGA,IAAM,EAAK,EAAS,sBAAsB,EAE1C,EAAQ,YAAY,EAAqB,EAAO,UAAW,EAAG,KAAM,EAAG,IAAM,EAAE,CAAC,CAClF,CAEA,IAAM,EAAY,EAAQ,MAE1B,SAAS,EAAa,EAAqC,CACrD,EACF,EAAU,CAAM,GAEhB,EAAS,MAAM,KAAO,GAAG,EAAO,EAAE,IAClC,EAAS,MAAM,IAAM,GAAG,EAAO,EAAE,KAGnC,EAAc,CAAM,CACtB,CAEA,IAAM,EAAS,EAAA,MAAM,EAAW,EAAU,CAAE,GAAG,EAAS,MAAO,CAAa,CAAC,EAE7E,OAAO,EAAA,eACC,CACJ,EAAO,QAAQ,EACf,EAAQ,OAAO,CACjB,MACM,EAAO,YAAY,MACnB,EAAO,OAAO,CACtB,CACF"}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * @vielzeug/orbit — debug overlay for positioning visualisation.
3
+ *
4
+ * Import from the dedicated sub-path so it is tree-shaken from production bundles:
5
+ * ```ts
6
+ * import { debugFloat } from '@vielzeug/orbit/devtools';
7
+ * ```
8
+ */
9
+ import type { FloatOptions } from './float';
10
+ import type { FloatHandle, ReferenceElement } from './types';
11
+ /**
12
+ * Wraps `float()` and attaches a persistent visual debug overlay to the document.
13
+ *
14
+ * The overlay renders on every position update:
15
+ * - **Blue dashed outline** — the viewport boundary used by overflow detection.
16
+ * - **Orange dashed outline** — the reference element's bounding rect.
17
+ * - **Blue label** — the active placement string (e.g. `"top-start"`).
18
+ *
19
+ * The overlay is automatically removed when `handle.dispose()` is called.
20
+ *
21
+ * Use only in development. Tree-shaken from production bundles via the sub-path import.
22
+ *
23
+ * @example
24
+ * ```ts
25
+ * import { debugFloat } from '@vielzeug/orbit/devtools';
26
+ *
27
+ * const handle = debugFloat(reference, tooltip, {
28
+ * placement: 'top',
29
+ * middleware: [offset(8), flip(), shift({ padding: 6 })],
30
+ * });
31
+ * // on teardown:
32
+ * handle.dispose();
33
+ * ```
34
+ */
35
+ export declare function debugFloat(reference: ReferenceElement, floating: HTMLElement, options?: FloatOptions): FloatHandle;
36
+ //# sourceMappingURL=devtools.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"devtools.d.ts","sourceRoot":"","sources":["../src/devtools.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,KAAK,EAAyB,WAAW,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAgEpF;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,UAAU,CACxB,SAAS,EAAE,gBAAgB,EAC3B,QAAQ,EAAE,WAAW,EACrB,OAAO,GAAE,YAAiB,GACzB,WAAW,CA+Cb"}
@@ -0,0 +1,2 @@
1
+ import{float as e,makeHandle as t}from"./float.js";function n(e,t){for(let[n,r]of Object.entries(t))e.style.setProperty(n,r)}function r(){let e=document.createElement(`div`);return e.dataset.orbitDebug=``,n(e,{"font-family":`monospace`,"font-size":`11px`,left:`0`,"pointer-events":`none`,position:`fixed`,top:`0`,"z-index":`2147483647`}),e}function i(e,t,r){let i=document.createElement(`div`);return i.textContent=e,n(i,{background:`rgba(0,100,255,0.85)`,"border-radius":`3px`,color:`#fff`,left:`${t}px`,padding:`1px 6px`,position:`fixed`,top:`${Math.max(0,r)}px`,"white-space":`nowrap`}),i}function a(e,t,r,i,a){let o=document.createElement(`div`);return n(o,{border:`1.5px dashed ${a}`,height:`${i}px`,left:`${e}px`,position:`fixed`,top:`${t}px`,width:`${r}px`}),o}function o(n,o,s={}){let c=r();document.body.appendChild(c);function l(e){if(c.innerHTML=``,c.appendChild(a(1,1,window.innerWidth-2,window.innerHeight-2,`rgba(0,100,255,0.3)`)),n instanceof Element){let e=n.getBoundingClientRect();c.appendChild(a(e.left,e.top,e.width,e.height,`rgba(255,120,0,0.7)`))}let t=o.getBoundingClientRect();c.appendChild(i(e.placement,t.left,t.top-22))}let u=s.apply;function d(e){u?u(e):(o.style.left=`${e.x}px`,o.style.top=`${e.y}px`),l(e)}let f=e(n,o,{...s,apply:d});return t(()=>{f.dispose(),c.remove()},()=>f.getPosition(),()=>f.update())}export{o as debugFloat};
2
+ //# sourceMappingURL=devtools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"devtools.js","names":[],"sources":["../src/devtools.ts"],"sourcesContent":["/**\n * @vielzeug/orbit — debug overlay for positioning visualisation.\n *\n * Import from the dedicated sub-path so it is tree-shaken from production bundles:\n * ```ts\n * import { debugFloat } from '@vielzeug/orbit/devtools';\n * ```\n */\n\nimport type { FloatOptions } from './float';\nimport type { ComputePositionResult, FloatHandle, ReferenceElement } from './types';\n\nimport { float, makeHandle } from './float';\n\n// ── Overlay helpers ───────────────────────────────────────────────────────────\n\nfunction setStyles(el: HTMLElement, styles: Record<string, string>): void {\n for (const [key, val] of Object.entries(styles)) {\n el.style.setProperty(key, val);\n }\n}\n\nfunction createOverlay(): HTMLElement {\n const el = document.createElement('div');\n\n el.dataset['orbitDebug'] = '';\n setStyles(el, {\n 'font-family': 'monospace',\n 'font-size': '11px',\n left: '0',\n 'pointer-events': 'none',\n position: 'fixed',\n top: '0',\n 'z-index': '2147483647',\n });\n\n return el;\n}\n\nfunction createPlacementBadge(text: string, x: number, y: number): HTMLElement {\n const el = document.createElement('div');\n\n el.textContent = text;\n setStyles(el, {\n background: 'rgba(0,100,255,0.85)',\n 'border-radius': '3px',\n color: '#fff',\n left: `${x}px`,\n padding: '1px 6px',\n position: 'fixed',\n top: `${Math.max(0, y)}px`,\n 'white-space': 'nowrap',\n });\n\n return el;\n}\n\nfunction createOutlineBox(x: number, y: number, width: number, height: number, color: string): HTMLElement {\n const el = document.createElement('div');\n\n setStyles(el, {\n border: `1.5px dashed ${color}`,\n height: `${height}px`,\n left: `${x}px`,\n position: 'fixed',\n top: `${y}px`,\n width: `${width}px`,\n });\n\n return el;\n}\n\n// ── Public API ────────────────────────────────────────────────────────────────\n\n/**\n * Wraps `float()` and attaches a persistent visual debug overlay to the document.\n *\n * The overlay renders on every position update:\n * - **Blue dashed outline** — the viewport boundary used by overflow detection.\n * - **Orange dashed outline** — the reference element's bounding rect.\n * - **Blue label** — the active placement string (e.g. `\"top-start\"`).\n *\n * The overlay is automatically removed when `handle.dispose()` is called.\n *\n * Use only in development. Tree-shaken from production bundles via the sub-path import.\n *\n * @example\n * ```ts\n * import { debugFloat } from '@vielzeug/orbit/devtools';\n *\n * const handle = debugFloat(reference, tooltip, {\n * placement: 'top',\n * middleware: [offset(8), flip(), shift({ padding: 6 })],\n * });\n * // on teardown:\n * handle.dispose();\n * ```\n */\nexport function debugFloat(\n reference: ReferenceElement,\n floating: HTMLElement,\n options: FloatOptions = {},\n): FloatHandle {\n const overlay = createOverlay();\n\n document.body.appendChild(overlay);\n\n function renderOverlay(result: ComputePositionResult): void {\n overlay.innerHTML = '';\n\n // Viewport boundary.\n overlay.appendChild(createOutlineBox(1, 1, window.innerWidth - 2, window.innerHeight - 2, 'rgba(0,100,255,0.3)'));\n\n // Reference element.\n if (reference instanceof Element) {\n const r = reference.getBoundingClientRect();\n\n overlay.appendChild(createOutlineBox(r.left, r.top, r.width, r.height, 'rgba(255,120,0,0.7)'));\n }\n\n // Placement label — positioned just above the floating element.\n const fr = floating.getBoundingClientRect();\n\n overlay.appendChild(createPlacementBadge(result.placement, fr.left, fr.top - 22));\n }\n\n const userApply = options.apply;\n\n function wrappedApply(result: ComputePositionResult): void {\n if (userApply) {\n userApply(result);\n } else {\n floating.style.left = `${result.x}px`;\n floating.style.top = `${result.y}px`;\n }\n\n renderOverlay(result);\n }\n\n const handle = float(reference, floating, { ...options, apply: wrappedApply });\n\n return makeHandle(\n () => {\n handle.dispose();\n overlay.remove();\n },\n () => handle.getPosition(),\n () => handle.update(),\n );\n}\n"],"mappings":"mDAgBA,SAAS,EAAU,EAAiB,EAAsC,CACxE,IAAK,GAAM,CAAC,EAAK,KAAQ,OAAO,QAAQ,CAAM,EAC5C,EAAG,MAAM,YAAY,EAAK,CAAG,CAEjC,CAEA,SAAS,GAA6B,CACpC,IAAM,EAAK,SAAS,cAAc,KAAK,EAavC,MAXA,GAAG,QAAQ,WAAgB,GAC3B,EAAU,EAAI,CACZ,cAAe,YACf,YAAa,OACb,KAAM,IACN,iBAAkB,OAClB,SAAU,QACV,IAAK,IACL,UAAW,YACb,CAAC,EAEM,CACT,CAEA,SAAS,EAAqB,EAAc,EAAW,EAAwB,CAC7E,IAAM,EAAK,SAAS,cAAc,KAAK,EAcvC,MAZA,GAAG,YAAc,EACjB,EAAU,EAAI,CACZ,WAAY,uBACZ,gBAAiB,MACjB,MAAO,OACP,KAAM,GAAG,EAAE,IACX,QAAS,UACT,SAAU,QACV,IAAK,GAAG,KAAK,IAAI,EAAG,CAAC,EAAE,IACvB,cAAe,QACjB,CAAC,EAEM,CACT,CAEA,SAAS,EAAiB,EAAW,EAAW,EAAe,EAAgB,EAA4B,CACzG,IAAM,EAAK,SAAS,cAAc,KAAK,EAWvC,OATA,EAAU,EAAI,CACZ,OAAQ,gBAAgB,IACxB,OAAQ,GAAG,EAAO,IAClB,KAAM,GAAG,EAAE,IACX,SAAU,QACV,IAAK,GAAG,EAAE,IACV,MAAO,GAAG,EAAM,GAClB,CAAC,EAEM,CACT,CA4BA,SAAgB,EACd,EACA,EACA,EAAwB,CAAC,EACZ,CACb,IAAM,EAAU,EAAc,EAE9B,SAAS,KAAK,YAAY,CAAO,EAEjC,SAAS,EAAc,EAAqC,CAO1D,GANA,EAAQ,UAAY,GAGpB,EAAQ,YAAY,EAAiB,EAAG,EAAG,OAAO,WAAa,EAAG,OAAO,YAAc,EAAG,qBAAqB,CAAC,EAG5G,aAAqB,QAAS,CAChC,IAAM,EAAI,EAAU,sBAAsB,EAE1C,EAAQ,YAAY,EAAiB,EAAE,KAAM,EAAE,IAAK,EAAE,MAAO,EAAE,OAAQ,qBAAqB,CAAC,CAC/F,CAGA,IAAM,EAAK,EAAS,sBAAsB,EAE1C,EAAQ,YAAY,EAAqB,EAAO,UAAW,EAAG,KAAM,EAAG,IAAM,EAAE,CAAC,CAClF,CAEA,IAAM,EAAY,EAAQ,MAE1B,SAAS,EAAa,EAAqC,CACrD,EACF,EAAU,CAAM,GAEhB,EAAS,MAAM,KAAO,GAAG,EAAO,EAAE,IAClC,EAAS,MAAM,IAAM,GAAG,EAAO,EAAE,KAGnC,EAAc,CAAM,CACtB,CAEA,IAAM,EAAS,EAAM,EAAW,EAAU,CAAE,GAAG,EAAS,MAAO,CAAa,CAAC,EAE7E,OAAO,MACC,CACJ,EAAO,QAAQ,EACf,EAAQ,OAAO,CACjB,MACM,EAAO,YAAY,MACnB,EAAO,OAAO,CACtB,CACF"}
@@ -0,0 +1,2 @@
1
+ var e=class e extends Error{constructor(e,t){super(e,t),this.name=new.target.name,Object.setPrototypeOf(this,new.target.prototype)}static is(t){return t instanceof e}},t=class extends e{};exports.OrbitConfigError=t,exports.OrbitError=e;
2
+ //# sourceMappingURL=errors.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.cjs","names":[],"sources":["../src/errors.ts"],"sourcesContent":["/** Base class for all orbit errors. Use `instanceof OrbitError` to catch any orbit-originated error. */\nexport class OrbitError extends Error {\n constructor(message: string, opts?: ErrorOptions) {\n super(message, opts);\n this.name = new.target.name;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n\n static is(err: unknown): err is OrbitError {\n return err instanceof OrbitError;\n }\n}\n\n/** Thrown when a middleware pipeline is configured incorrectly. */\nexport class OrbitConfigError extends OrbitError {}\n"],"mappings":"AACA,IAAa,EAAb,MAAa,UAAmB,KAAM,CACpC,YAAY,EAAiB,EAAqB,CAChD,MAAM,EAAS,CAAI,EACnB,KAAK,KAAO,IAAI,OAAO,KACvB,OAAO,eAAe,KAAM,IAAI,OAAO,SAAS,CAClD,CAEA,OAAO,GAAG,EAAiC,CACzC,OAAO,aAAe,CACxB,CACF,EAGa,EAAb,cAAsC,CAAW,CAAC"}
@@ -0,0 +1,9 @@
1
+ /** Base class for all orbit errors. Use `instanceof OrbitError` to catch any orbit-originated error. */
2
+ export declare class OrbitError extends Error {
3
+ constructor(message: string, opts?: ErrorOptions);
4
+ static is(err: unknown): err is OrbitError;
5
+ }
6
+ /** Thrown when a middleware pipeline is configured incorrectly. */
7
+ export declare class OrbitConfigError extends OrbitError {
8
+ }
9
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,wGAAwG;AACxG,qBAAa,UAAW,SAAQ,KAAK;gBACvB,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,YAAY;IAMhD,MAAM,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,GAAG,GAAG,IAAI,UAAU;CAG3C;AAED,mEAAmE;AACnE,qBAAa,gBAAiB,SAAQ,UAAU;CAAG"}
package/dist/errors.js ADDED
@@ -0,0 +1,2 @@
1
+ var e=class e extends Error{constructor(e,t){super(e,t),this.name=new.target.name,Object.setPrototypeOf(this,new.target.prototype)}static is(t){return t instanceof e}},t=class extends e{};export{t as OrbitConfigError,e as OrbitError};
2
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","names":[],"sources":["../src/errors.ts"],"sourcesContent":["/** Base class for all orbit errors. Use `instanceof OrbitError` to catch any orbit-originated error. */\nexport class OrbitError extends Error {\n constructor(message: string, opts?: ErrorOptions) {\n super(message, opts);\n this.name = new.target.name;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n\n static is(err: unknown): err is OrbitError {\n return err instanceof OrbitError;\n }\n}\n\n/** Thrown when a middleware pipeline is configured incorrectly. */\nexport class OrbitConfigError extends OrbitError {}\n"],"mappings":"AACA,IAAa,EAAb,MAAa,UAAmB,KAAM,CACpC,YAAY,EAAiB,EAAqB,CAChD,MAAM,EAAS,CAAI,EACnB,KAAK,KAAO,IAAI,OAAO,KACvB,OAAO,eAAe,KAAM,IAAI,OAAO,SAAS,CAClD,CAEA,OAAO,GAAG,EAAiC,CACzC,OAAO,aAAe,CACxB,CACF,EAGa,EAAb,cAAsC,CAAW,CAAC"}
package/dist/float.cjs ADDED
@@ -0,0 +1,2 @@
1
+ const e=require("./auto-update.cjs"),t=require("./core.cjs");function n(e,t,n){let r=new AbortController,i=!1;return{get disposalSignal(){return r.signal},dispose(){i||(i=!0,r.abort(),e())},get disposed(){return i},getPosition:t,[Symbol.dispose](){this.dispose()},update:n}}function r(){return typeof CSS<`u`&&CSS.supports(`anchor-name`,`--orbit`)}var i=0,a={bottom:`block-end center`,"bottom-end":`block-end span-inline-end`,"bottom-start":`block-end span-inline-start`,left:`inline-start center`,"left-end":`inline-start span-block-end`,"left-start":`inline-start span-block-start`,right:`inline-end center`,"right-end":`inline-end span-block-end`,"right-start":`inline-end span-block-start`,top:`block-start center`,"top-end":`block-start span-inline-end`,"top-start":`block-start span-inline-start`};function o(e,t){let n={};for(let r of Object.keys(t)){let i=e.style.getPropertyValue(r);n[r]=i===``?void 0:i,e.style.setProperty(r,t[r])}return()=>{for(let r of Object.keys(t)){let t=n[r];t===void 0?e.style.removeProperty(r):e.style.setProperty(r,t)}}}function s(e,t,n,r){let s=`--orbit-${++i}`,c=o(e,{"anchor-name":s}),l=o(t,{position:`fixed`,"position-anchor":s,"position-area":a[n],"position-try-fallbacks":r});return()=>{c(),l()}}function c(e,t,{fallbacks:r=`flip-block, flip-inline, flip-block flip-inline`,placement:i=`bottom`}={}){let a=s(e,t,i,r),o=n(()=>a(),()=>null,()=>{});return Object.assign(o,{cssAnchor:!0})}function l(e,t){t.style.left=`${e.x}px`,t.style.top=`${e.y}px`}function u(r,i,{apply:a,autoUpdate:o={},boundary:s,containingBlock:c,middleware:u,padding:d,placement:f=`bottom`}={}){let p=null,m=a??(e=>l(e,i));function h(){let e=t.computePosition(r,i,{boundary:s,containingBlock:c,middleware:u,padding:d,placement:f});p=e,m(e)}if(o===!1)return h(),n(()=>{},()=>p,h);let g=e.autoUpdate(r,i,h,o);return n(()=>g(),()=>p,h)}exports.float=u,exports.floatWithAnchor=c,exports.isCssAnchorSupported=r,exports.makeHandle=n;
2
+ //# sourceMappingURL=float.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"float.cjs","names":[],"sources":["../src/float.ts"],"sourcesContent":["import type { ComputePositionOptions, ComputePositionResult, FloatHandle, Placement, ReferenceElement } from './types';\n\nimport { autoUpdate, type AutoUpdateOptions } from './auto-update';\nimport { computePosition } from './core';\n\n// ── makeHandle ────────────────────────────────────────────────────────────────\n\n/**\n * Constructs a {@link FloatHandle} with idempotent dispose, disposalSignal, and disposed getter.\n * @internal — exported for use by ssr.ts and devtools.ts only.\n */\nexport function makeHandle(\n rawDispose: () => void,\n getPosition: () => ComputePositionResult | null,\n update: () => void,\n): FloatHandle {\n const controller = new AbortController();\n let disposed = false;\n\n return {\n get disposalSignal() {\n return controller.signal;\n },\n dispose() {\n if (disposed) return;\n\n disposed = true;\n controller.abort();\n rawDispose();\n },\n get disposed() {\n return disposed;\n },\n getPosition,\n [Symbol.dispose](): void {\n this.dispose();\n },\n update,\n };\n}\n\n// ── CSS Anchor Positioning ────────────────────────────────────────────────────\n\nfunction isCssAnchorPositioningSupported(): boolean {\n return typeof CSS !== 'undefined' && CSS.supports('anchor-name', '--orbit');\n}\n\nlet anchorCounter = 0;\n\n/**\n * Maps a placement to the CSS `position-area` value.\n * https://drafts.csswg.org/css-anchor-position/#position-area\n */\nconst POSITION_AREA: Record<Placement, string> = {\n bottom: 'block-end center',\n 'bottom-end': 'block-end span-inline-end',\n 'bottom-start': 'block-end span-inline-start',\n left: 'inline-start center',\n 'left-end': 'inline-start span-block-end',\n 'left-start': 'inline-start span-block-start',\n right: 'inline-end center',\n 'right-end': 'inline-end span-block-end',\n 'right-start': 'inline-end span-block-start',\n top: 'block-start center',\n 'top-end': 'block-start span-inline-end',\n 'top-start': 'block-start span-inline-start',\n};\n\n/** Applies a set of CSS properties to an element and returns a cleanup that restores them. */\nfunction withStyles(el: HTMLElement, props: Record<string, string>): () => void {\n const saved: Record<string, string | undefined> = {};\n\n for (const prop of Object.keys(props)) {\n const prev = el.style.getPropertyValue(prop);\n\n saved[prop] = prev !== '' ? prev : undefined;\n el.style.setProperty(prop, props[prop]);\n }\n\n return () => {\n for (const prop of Object.keys(props)) {\n const prev = saved[prop];\n\n if (prev !== undefined) {\n el.style.setProperty(prop, prev);\n } else {\n el.style.removeProperty(prop);\n }\n }\n };\n}\n\nfunction setupCssAnchorPositioning(\n reference: HTMLElement,\n floating: HTMLElement,\n placement: Placement,\n fallbacks: string,\n): () => void {\n const name = `--orbit-${++anchorCounter}`;\n\n const cleanupRef = withStyles(reference, { 'anchor-name': name });\n const cleanupFloat = withStyles(floating, {\n position: 'fixed',\n 'position-anchor': name,\n 'position-area': POSITION_AREA[placement],\n 'position-try-fallbacks': fallbacks,\n });\n\n return () => {\n cleanupRef();\n cleanupFloat();\n };\n}\n\nexport interface CssAnchorHandle extends FloatHandle {\n /** Always `true` — position is managed natively by CSS Anchor Positioning. */\n readonly cssAnchor: true;\n}\n\n/**\n * Uses CSS Anchor Positioning to let the browser handle repositioning natively.\n * No JavaScript positioning loop — the browser manages placement via `position-try-fallbacks`.\n *\n * Requires both elements to be `HTMLElement`. Falls back to `float()` for complex cases\n * (e.g. middleware pipelines, custom apply callbacks).\n *\n * @experimental CSS Anchor Positioning support varies by browser. Check `isCssAnchorSupported()`\n * before using in production.\n *\n * @example\n * ```ts\n * import { floatWithAnchor } from '@vielzeug/orbit';\n *\n * const handle = floatWithAnchor(trigger, tooltip, { placement: 'top' });\n * // on hide:\n * handle.dispose();\n * ```\n */\nexport function floatWithAnchor(\n reference: HTMLElement,\n floating: HTMLElement,\n {\n fallbacks = 'flip-block, flip-inline, flip-block flip-inline',\n placement = 'bottom',\n }: { fallbacks?: string; placement?: Placement } = {},\n): CssAnchorHandle {\n const cleanupFn = setupCssAnchorPositioning(reference, floating, placement, fallbacks);\n const base = makeHandle(\n () => cleanupFn(),\n () => null,\n () => {},\n );\n\n return Object.assign(base, { cssAnchor: true as const });\n}\n\n/**\n * Returns `true` when the browser supports CSS Anchor Positioning.\n * Use to guard `floatWithAnchor()` calls in production.\n */\nexport { isCssAnchorPositioningSupported as isCssAnchorSupported };\n\n// ── float() ───────────────────────────────────────────────────────────────────\n\n/**\n * Options for `float()`. Extends `ComputePositionOptions` so all positioning\n * options (`placement`, `middleware`, `boundary`, `padding`, `containingBlock`)\n * are inherited directly.\n */\nexport interface FloatOptions extends ComputePositionOptions {\n /**\n * Custom callback to apply the computed position to the DOM.\n * Called once per position update with the full `ComputePositionResult`.\n * Defaults to writing `left` / `top` on the floating element (requires `position: fixed`).\n */\n apply?: (result: ComputePositionResult) => void;\n /**\n * Options for the auto-update loop. Omit to use defaults.\n * Pass `false` to disable auto-updating (position is computed once on call).\n */\n autoUpdate?: AutoUpdateOptions | false;\n}\n\nfunction applyDefault(result: ComputePositionResult, floating: HTMLElement): void {\n floating.style.left = `${result.x}px`;\n floating.style.top = `${result.y}px`;\n}\n\n/**\n * High-level API: positions the floating element and continuously keeps it updated.\n *\n * For CSS Anchor Positioning (browser-native, no JS loop), use {@link floatWithAnchor} instead.\n *\n * Returns a {@link FloatHandle} with `dispose()`, `update()`, and `getPosition()`.\n * Always call `dispose()` on teardown to remove listeners.\n *\n * @example\n * ```ts\n * const handle = float(trigger, tooltip, {\n * placement: 'top',\n * middleware: [offset(8), flip(), shift({ padding: 6 })],\n * });\n * // on hide:\n * handle.dispose();\n * ```\n */\nexport function float(\n reference: ReferenceElement,\n floating: HTMLElement,\n {\n apply,\n autoUpdate: autoUpdateOptions = {},\n boundary,\n containingBlock,\n middleware,\n padding,\n placement = 'bottom',\n }: FloatOptions = {},\n): FloatHandle {\n let lastPosition: ComputePositionResult | null = null;\n const applyFn = apply ?? ((result) => applyDefault(result, floating));\n\n function update(): void {\n const result = computePosition(reference, floating, { boundary, containingBlock, middleware, padding, placement });\n\n lastPosition = result;\n applyFn(result);\n }\n\n if (autoUpdateOptions === false) {\n update();\n\n return makeHandle(\n () => {},\n () => lastPosition,\n update,\n );\n }\n\n const cleanupFn = autoUpdate(reference, floating, update, autoUpdateOptions);\n\n return makeHandle(\n () => cleanupFn(),\n () => lastPosition,\n update,\n );\n}\n"],"mappings":"6DAWA,SAAgB,EACd,EACA,EACA,EACa,CACb,IAAM,EAAa,IAAI,gBACnB,EAAW,GAEf,MAAO,CACL,IAAI,gBAAiB,CACnB,OAAO,EAAW,MACpB,EACA,SAAU,CACJ,IAEJ,EAAW,GACX,EAAW,MAAM,EACjB,EAAW,EACb,EACA,IAAI,UAAW,CACb,OAAO,CACT,EACA,cACA,CAAC,OAAO,UAAiB,CACvB,KAAK,QAAQ,CACf,EACA,QACF,CACF,CAIA,SAAS,GAA2C,CAClD,OAAO,OAAO,IAAQ,KAAe,IAAI,SAAS,cAAe,SAAS,CAC5E,CAEA,IAAI,EAAgB,EAMd,EAA2C,CAC/C,OAAQ,mBACR,aAAc,4BACd,eAAgB,8BAChB,KAAM,sBACN,WAAY,8BACZ,aAAc,gCACd,MAAO,oBACP,YAAa,4BACb,cAAe,8BACf,IAAK,qBACL,UAAW,8BACX,YAAa,+BACf,EAGA,SAAS,EAAW,EAAiB,EAA2C,CAC9E,IAAM,EAA4C,CAAC,EAEnD,IAAK,IAAM,KAAQ,OAAO,KAAK,CAAK,EAAG,CACrC,IAAM,EAAO,EAAG,MAAM,iBAAiB,CAAI,EAE3C,EAAM,GAAQ,IAAS,GAAY,IAAA,GAAP,EAC5B,EAAG,MAAM,YAAY,EAAM,EAAM,EAAK,CACxC,CAEA,UAAa,CACX,IAAK,IAAM,KAAQ,OAAO,KAAK,CAAK,EAAG,CACrC,IAAM,EAAO,EAAM,GAEf,IAAS,IAAA,GAGX,EAAG,MAAM,eAAe,CAAI,EAF5B,EAAG,MAAM,YAAY,EAAM,CAAI,CAInC,CACF,CACF,CAEA,SAAS,EACP,EACA,EACA,EACA,EACY,CACZ,IAAM,EAAO,WAAW,EAAE,IAEpB,EAAa,EAAW,EAAW,CAAE,cAAe,CAAK,CAAC,EAC1D,EAAe,EAAW,EAAU,CACxC,SAAU,QACV,kBAAmB,EACnB,gBAAiB,EAAc,GAC/B,yBAA0B,CAC5B,CAAC,EAED,UAAa,CACX,EAAW,EACX,EAAa,CACf,CACF,CA0BA,SAAgB,EACd,EACA,EACA,CACE,YAAY,kDACZ,YAAY,UACqC,CAAC,EACnC,CACjB,IAAM,EAAY,EAA0B,EAAW,EAAU,EAAW,CAAS,EAC/E,EAAO,MACL,EAAU,MACV,SACA,CAAC,CACT,EAEA,OAAO,OAAO,OAAO,EAAM,CAAE,UAAW,EAAc,CAAC,CACzD,CA6BA,SAAS,EAAa,EAA+B,EAA6B,CAChF,EAAS,MAAM,KAAO,GAAG,EAAO,EAAE,IAClC,EAAS,MAAM,IAAM,GAAG,EAAO,EAAE,GACnC,CAoBA,SAAgB,EACd,EACA,EACA,CACE,QACA,WAAY,EAAoB,CAAC,EACjC,WACA,kBACA,aACA,UACA,YAAY,UACI,CAAC,EACN,CACb,IAAI,EAA6C,KAC3C,EAAU,IAAW,GAAW,EAAa,EAAQ,CAAQ,GAEnE,SAAS,GAAe,CACtB,IAAM,EAAS,EAAA,gBAAgB,EAAW,EAAU,CAAE,WAAU,kBAAiB,aAAY,UAAS,WAAU,CAAC,EAEjH,EAAe,EACf,EAAQ,CAAM,CAChB,CAEA,GAAI,IAAsB,GAGxB,OAFA,EAAO,EAEA,MACC,CAAC,MACD,EACN,CACF,EAGF,IAAM,EAAY,EAAA,WAAW,EAAW,EAAU,EAAQ,CAAiB,EAE3E,OAAO,MACC,EAAU,MACV,EACN,CACF,CACF"}