//#region src/core/idPath.d.ts /** * Canonical DOM-id generation from structural paths. * * Every render pipeline (React headless, HTML sync, HTML stream) needs to * derive stable DOM ids from the same path so `aria-controls`, `aria-labelledby`, * and `htmlFor` references resolve consistently across pipelines. * * Previously each pipeline carried its own copy with subtly different * normalisation (raw path in one place, dot/bracket-collapsed in another, * whitelist-collapsed in a third). The streaming renderer's tab panel ids * silently diverged from the sync renderer's because of that drift. * * Pipelines should import the helpers below rather than re-deriving them. */ /** * Normalise a structural path into the id segment used after the `sc-` * prefix. Whitelist-based: any run of characters outside `[A-Za-z0-9_-]` * collapses to a single hyphen, with trailing hyphens stripped. * * Whitelist (not blacklist) so unexpected characters from free-text sources * — `meta.description`, label-derived suffixes, encoded JSON Pointers — * cannot leak into ids and break CSS selectors or aria associations. * * Non-ASCII inputs (e.g. CJK property names like `名前`, accented Latin * like `café`, emoji like `🦄`) collapse under the whitelist to a short * or empty string and would silently collide on `sc-`. To keep ids * deterministic AND unique per input, the normaliser appends a short * hash suffix derived from the original string whenever the whitelisted * collapse: * * - produces an empty string, OR * - dropped non-structural characters from the input (i.e. anything * besides the path joiners `.`, `[`, `]` and ASCII whitespace). * * Structural separator runs do NOT trigger the disambiguator so * canonical paths like `user.preferences` and `tags[0]` keep their * historic readable form (`user-preferences`, `tags-0`). * * The hash is a 32-bit FNV-1a variant rendered in base-36. It is * deterministic (same input → same output), short (≤ 7 characters), and * non-cryptographic — collision resistance is good enough for DOM ids, * and a cryptographic primitive is unnecessary and not universally * available (no `crypto` global in every JS runtime that consumes the * library). * * The leading character is guaranteed to be an ASCII letter so the full * `sc-` id is always a valid CSS identifier and `querySelector` * target. Empty-collapse inputs receive a synthetic `u` (for "unicode") * prefix on the hash so the id never starts with a digit. */ declare function normaliseIdSegment(value: string): string; /** * Build the canonical `sc-`-prefixed DOM id for a structural path. Use * this as the base id for an input element; derived ids (panel, tab, * hint) compose suffixes onto the returned string. * * An empty `path` is permitted — it surfaces as the bare prefix `sc-` * so a leaf renderer at the schema root (e.g. * `renderToHtml(z.string())`) still emits a usable id without throwing. * Container renderers always thread a non-empty path through * `renderChild`, so the empty-id case can never produce sibling * collisions inside a structured form. */ declare function fieldDomId(path: string): string; /** * Derive the constraint-hint element id for a given field id. * The hint element is wired to inputs via `aria-describedby`. */ declare function hintIdFor(fieldId: string): string; /** * Derive the tab panel id for a discriminated-union container at `path`. * Used by every renderer that emits a WAI-ARIA tabs widget so that the * `aria-controls` on each tab and the `id` on the matching panel match. */ declare function panelIdFor(path: string): string; /** * Derive the id for tab `i` within a discriminated-union container at `path`. * Used to pair `aria-labelledby` on the active panel with the active tab's * `id` across all renderers. */ declare function tabIdFor(path: string, index: number): string; /** * Append a child path suffix to a parent path. When the suffix is omitted * (e.g. transparent wrappers like union options), the parent path is * returned unchanged so the child inherits the parent's id. * * Bracketed array indices like `[0]` append directly so `tags` + `[0]` * becomes `tags[0]` rather than `tags.[0]` — matching the canonical form * used by `core/fieldPath.ts` `resolvePath`, which already parses bracket * notation when navigating WalkedField trees. * * This is the single authoritative implementation. The copies in * `react/SchemaComponent.tsx`, `html/a11y.ts`, `solid/SchemaComponent.tsx`, * and `vue/idPrefix.ts` are kept for backward compatibility but delegate * here. */ declare function joinPath(parent: string, suffix: string | undefined): string; /** * Normalise a framework `useId()`-style value into a DOM-id-safe prefix. * Framework `useId` implementations often return values containing `:` or * other characters that are invalid in CSS selectors. This function replaces * any run of non-alphanumeric characters with a single hyphen and trims * leading/trailing hyphens. * * Throws when the sanitised result is empty so callers receive an actionable * error rather than a silent empty-string id. */ declare function sanitisePrefix(value: string): string; //#endregion export { fieldDomId, hintIdFor, joinPath, normaliseIdSegment, panelIdFor, sanitisePrefix, tabIdFor };