/** * The handful of harness surfaces a chord can only reach through the DOM, and * the addresses that make reaching them defensible. * * ## Why this module exists at all * * Most of what a keybinding wants to do has a service behind it: the layout * columns, the session list, the workspace registry and the mode switch all * publish a face a plugin may call. Three do not. The settings dialog's open * state and its selected page are, in the harness's own words, "component-local * viewing state"; the sidebar's session search is a `useState` inside * `ui-workspace`. Those packages ship inside the harness, which this repository * does not edit, so there is no seam to add and no version in which asking * nicely works. * * The choice is therefore between driving them from the outside and not binding * them at all. This module drives them, and confines every selector to one file * so the cost of that choice is countable. * * ## What makes these addresses better than the usual DOM scraping * * Every anchor below is a **contract the framework emits**, not a class name or * a shape that happens to render today: * * - `[data-slot=""]` is written by the slot outlet itself * (`dsh-client-web-react`), on every slot, unconditionally. A slot key is * part of the published SlotMap — renaming one is a breaking change the * harness announces. * - `data-sidebar-collapsed` / `data-details-collapsed` are the frame's own * state attributes, and are what its stylesheet reads. They cannot drift from * the truth without the layout visibly breaking first. * - `role="dialog"` / `aria-modal` / `aria-expanded` / `aria-haspopup` are * accessibility contracts. A refactor that drops them is a bug in its own * right, so depending on them makes this module fail in the same direction as * a screen reader rather than in a direction nobody notices. * * What is deliberately NOT used: CSS-module class names (hashed per build), * visible text (localized), and DOM order within a region (renders in whatever * order registrations resolved). The one place order is unavoidable — picking * one settings page out of the nav rail — reads its index from the slot * registry rather than guessing it, so the id, not the position, is the thing * being matched. * * Every function here answers `undefined` rather than throwing. A surface that * is not on screen is the ordinary case: a composition without `ui-workspace` * has no search box, and a press before the frame mounts has nothing to press. * @module @omdsh-plugins/omdsh-shortcuts/src/client/anchors */ /** How long a press waits for a surface it just asked to appear, in ms. */ const APPEAR_TIMEOUT = 1500 /** How often it looks, in ms. One animation frame, near enough. */ const APPEAR_INTERVAL = 16 /** * The nearest `