/** * floating-container.ts * * Shared low-level utility for creating a `position:fixed` container element * that lives on `document.body` (or a custom target). * * All portal-style primitives in this library (`portal`, `popup`, * `cascading-popup-list`, etc.) ultimately need the same three operations: * 1. Create a fixed-position div with a z-index above everything else. * 2. Lazily attach it to the DOM exactly once — only when content needs to * be shown, never eagerly on component mount. * 3. Remove it cleanly when the component unmounts or the panel closes. * * Centralising this here ensures every floating surface shares identical * defaults, avoids the "orphaned div" bug that comes from eagerly calling * `document.body.appendChild` at mount time, and gives one place to tweak * z-index, default styles, or target element logic across the whole library. * * ─── Usage ──────────────────────────────────────────────────────────────────── * * ```ts * // Create (not yet in DOM) * const { el, attach, detach, isAttached } = createFloatingContainer(); * * // Lazily attach when you actually need to show something * attach(); * el.style.top = "100px"; * el.style.left = "200px"; * litRender(myTemplate, el); * * // Detach when done * detach(); * ``` * * Apply extra styles at creation time: * ```ts * const { el, attach, detach } = createFloatingContainer({ * style: { * minWidth: "10rem", * background: "var(--md-color-surface)", * border: "0.06rem solid var(--md-color-border)", * borderRadius: "var(--md-radius-sm)", * boxShadow: "var(--md-shadow-dropdown)", * overflow: "hidden", * }, * }); * ``` */ export interface FloatingContainerOptions { /** * Extra CSS properties merged onto the container element at creation time. * These are applied on top of the mandatory base styles * (`position:fixed`, `z-index`, `display:none`). */ style?: Partial; /** * Where to mount the container. * Accepts an `Element` directly, a CSS selector string, or omit/`null` to * default to `document.body`. * * @default document.body */ target?: Element | string | null; /** * Override the default `z-index` value. * * @default "9999" */ zIndex?: string | number; } export interface FloatingContainer { /** * The raw `
` element. You can read/write styles, measure, and render * lit-html templates into this element directly. It is NOT in the DOM until * `attach()` is called. */ readonly el: HTMLDivElement; /** * Append `el` to the target (default: `document.body`) if it is not already * attached. Safe to call multiple times — subsequent calls are no-ops. */ attach(): void; /** * Remove `el` from the DOM. Safe to call when already detached — it is a * no-op in that case. After calling `detach()` you may call `attach()` * again to re-insert the same element. */ detach(): void; /** * Returns `true` when `el` is currently in the DOM (i.e. `attach()` has * been called and `detach()` has not been called since). */ isAttached(): boolean; } /** * Create a reusable floating container element. * * The element is created synchronously but is **not** appended to the DOM. * Call `attach()` exactly when you need to make it visible or measure it. * Call `detach()` (or `el.remove()`) to clean up. * * This function is intentionally pure — it does NOT call `onCleanup()` or * any other framework hook. The caller is responsible for calling `detach()` * at the right time (e.g. inside `onCleanup` / `onCleanup` of an `eleHook` * or `htmlHook` lifecycle). * * @example * // Inside an eleHook mountFn: * const fc = createFloatingContainer({ style: { minWidth: "160px" } }); * * const open = () => { * fc.attach(); * litRender(content, fc.el); * position(anchor, fc.el); * fc.el.style.display = "block"; * }; * * const close = () => { * fc.el.style.display = "none"; * }; * * return { * onCleanup() { * fc.detach(); * }, * }; */ export declare function createFloatingContainer(opts?: FloatingContainerOptions): FloatingContainer; //# sourceMappingURL=floating-container.d.ts.map