import { Effect } from 'effect'; import { ElementNotFound } from './error.js'; /** * Focuses an element matching the given selector after the next render has * committed. * * Use `Dom.focus` inside a Command for focus that's caused by a Message * dispatching: a dialog opening, an input becoming the active step in a * form, returning focus to a trigger button after a popover closes, * keyboard navigation across a stable layout. The Command fires from * `update`'s return; the focus runs after the next render commits, so the * element is in place by the time `.focus()` runs. * * Do not use `OnMount` for focus. The cause of focus-on-open is the * Message, not the element appearing. Mount is for per-instance lifecycle * effects bound to a VNode existing where the live element handle is * needed (positioning, portaling, observer attachment, library setup). * * Section headings, articles, and other non-natively-focusable elements * are common URL fragment targets, but `.focus()` is a no-op on them * without a `tabindex`. Pass `makeFocusable: true` to inject * `tabindex="-1"` on the target if it has none, making programmatic * focus actually land. Pass `preventScroll: true` to suppress the * browser's default scroll-on-focus, useful when the focus call follows * a deliberate scroll that should not be undone. The two options compose * with `scrollIntoViewAfterPaint` for URL-fragment-navigation * accessibility: scroll the section into view, then focus the same * selector so keyboard users start Tab navigation from the target. * * Fails with `ElementNotFound` if the selector does not match an `HTMLElement`. * * @example * ```typescript * Dom.focus('#email-input') * Dom.focus('#section', { preventScroll: true, makeFocusable: true }) * ``` */ export declare const focus: (selector: string, options?: Readonly<{ preventScroll?: boolean; makeFocusable?: boolean; }>) => Effect.Effect; /** * Opens a dialog element using `show()` with high z-index, focus trapping, * and Escape key handling. Uses `show()` instead of `showModal()` so that * DevTools (and any other high-z-index overlay) remains interactive. The * Dialog component provides its own backdrop, scroll locking, and transitions. * Fails with `ElementNotFound` if the selector does not match an `HTMLDialogElement`. * * Pass `focusSelector` to focus an element inside the dialog when it opens. * * Records the element that had focus when the dialog opened so `closeModal` * can return focus there, the way `showModal()` would natively. * * @example * ```typescript * Dom.showModal('#my-dialog') * Dom.showModal('#my-dialog', { focusSelector: '#search-input' }) * ``` */ export declare const showModal: (selector: string, options?: Readonly<{ focusSelector?: string; }>) => Effect.Effect; /** * Closes a dialog element using `.close()`. * Cleans up the keyboard handlers installed by `showModal` and restores focus to * the element that was focused before the dialog opened (the trigger, or the * dialog beneath it when closing a stacked dialog). * Fails with `ElementNotFound` if the selector does not match an `HTMLDialogElement`. * * @example * ```typescript * Dom.closeModal('#my-dialog') * ``` */ export declare const closeModal: (selector: string) => Effect.Effect; /** * Programmatically clicks an element matching the given selector. * Fails with `ElementNotFound` if the selector does not match an `HTMLElement`. * * @example * ```typescript * Dom.clickElement('#menu-item-2') * ``` */ export declare const clickElement: (selector: string) => Effect.Effect; /** * Scrolls an element into view by selector. Resolves the selector after * `Render.afterCommit`. Defaults to `{ block: 'nearest' }`; pass a different * `block` for use cases like URL-fragment landing where `'start'` is right. * For a target the same Message just brought into the DOM, * `scrollIntoViewAfterPaint` is the right choice. * * Fails with `ElementNotFound` if the selector does not match an `HTMLElement`. * * @example * ```typescript * Dom.scrollIntoView('#active-item') * Dom.scrollIntoView('#section-2', { block: 'start' }) * ``` */ export declare const scrollIntoView: (selector: string, options?: Readonly<{ block?: ScrollLogicalPosition; }>) => Effect.Effect; /** * Like `scrollIntoView`, but waits for `Render.afterPaint` instead of * `Render.afterCommit` before resolving the selector. * * Reach for this when the target was just brought into the DOM by the same * Message that dispatches the scroll, such as a routing flow landing at a * URL fragment. The two-frame wait gives the runtime time to commit the new * Model and the browser time to lay it out before the scroll runs. For a * target that's already on screen, `scrollIntoView` is the lighter choice. * * Defaults to `{ block: 'nearest' }`; pass `{ block: 'start' }` for URL * fragment landings where the target should sit at the top of the viewport. * * Fails with `ElementNotFound` if the selector does not match an `HTMLElement`. * * @example * ```typescript * Dom.scrollIntoViewAfterPaint('#overview') * Dom.scrollIntoViewAfterPaint(`#${hash}`, { block: 'start' }) * ``` */ export declare const scrollIntoViewAfterPaint: (selector: string, options?: Readonly<{ block?: ScrollLogicalPosition; }>) => Effect.Effect; /** * Like `scrollIntoViewAfterPaint`, but skips the scroll if the element is * already fully visible within its scroll container. * * Defaults to `{ block: 'center' }`; pass a different `block` when the * target should land at a specific position when it does need to scroll. * * `when` selects the timing gate. `'Paint'` (the default) waits for * `Render.afterPaint`, so the scroll lands after the target is on screen. * `'Commit'` waits for `Render.afterCommit` instead, so the scroll lands in * the same frame the DOM patch applies, before the browser paints. Use * `'Commit'` when the target is brought into view and scrolled by the same * Message (such as a menu opening), so it appears already scrolled rather * than visibly jumping. * * Fails with `ElementNotFound` if the selector does not match an `HTMLElement`. * * @example * ```typescript * Dom.scrollIntoViewIfNotVisible('#active-nav-link') * Dom.scrollIntoViewIfNotVisible('#active-nav-link', { block: 'nearest' }) * Dom.scrollIntoViewIfNotVisible('#active-nav-link', { when: 'Commit' }) * ``` */ export declare const scrollIntoViewIfNotVisible: (selector: string, options?: Readonly<{ block?: ScrollLogicalPosition; when?: "Paint" | "Commit"; }>) => Effect.Effect; /** Direction for focus advancement: forward or backward in tab order. */ export type FocusDirection = 'Next' | 'Previous'; /** * Focuses the next or previous focusable element in the document relative to the element matching the given selector. * Fails with `ElementNotFound` if the selector does not match an `HTMLElement`. * * @example * ```typescript * Dom.advanceFocus('#menu-button', 'Next') * ``` */ export declare const advanceFocus: (selector: string, direction: FocusDirection) => Effect.Effect; //# sourceMappingURL=dom.d.ts.map