@embedpdf/core-ui 3.0.0-next.0

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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs","names":["makeGroup"],"sources":["../src/schema.ts","../src/transforms.ts","../src/helpers.ts","../src/solver.ts","../src/projection.ts","../src/shortcuts.ts"],"sourcesContent":["/**\n * @embedpdf/core-ui — the structure-only schema vocabulary.\n *\n * The schema contains ONLY what a designer decides and the runtime cannot\n * compute: order, grouping, importance, and each item's degradation ladder.\n * Everything the runtime CAN compute is banned from it by construction:\n * no breakpoints, no show/hide lists, no locale overrides, no dividers, no\n * spacers, no hand-written overflow menus. Fit is measured and solved at\n * runtime (see solver.ts); the overflow menu is derived (see projection.ts).\n */\n\n/** Presentation ladder for a command button, richest first. */\nexport type Variant = 'icon+label' | 'icon' | 'label';\n\n/**\n * Who yields space first. 1 = first to degrade/overflow · 3 = default ·\n * 5 = pinned: may still degrade variants, but NEVER leaves the bar.\n */\nexport type Importance = 1 | 2 | 3 | 4 | 5;\n\nexport const PINNED: Importance = 5;\n\nexport interface BarItem {\n /** The command this button runs — the only required field. */\n readonly command: string;\n /** Degradation ladder, richest first. Default: ['icon']. */\n readonly variants?: readonly Variant[];\n readonly importance?: Importance;\n}\n\n/**\n * An app-rendered slot (e.g. the inline zoom strip). Each named variant is\n * measured like any command button. The ladder MUST terminate in a command\n * (`terminal`) so the item always has a menu form when it overflows — this\n * is what makes the overflow projection total.\n */\nexport interface CustomItem {\n readonly slot: string;\n /** Named presentation variants, richest first. Default: ['default']. */\n readonly variants?: readonly string[];\n /** The command that stands in for this slot in menus (its last resort). */\n readonly terminal: string;\n readonly importance?: Importance;\n}\n\nexport type BarChild = BarItem | CustomItem | string; // string = { command }\n\nexport interface BarGroup {\n readonly id: string;\n /** Titles the group's menu form (labeled submenu / section heading). */\n readonly labelKey?: string;\n /** Presentation hint: 'tabs' renders as a tab strip and projects as radio rows. */\n readonly role?: 'buttons' | 'tabs';\n /**\n * Stage 1 of the GROUP degradation ladder: under pressure, move trailing\n * children (rightmost first, at the CHILD's importance) into a derived\n * group-local disclosure — a trigger rendered inside the group opening a\n * menu of the hidden children. Never sheds the last visible child: below\n * that floor the group `collapse`s (stage 2) or overflows whole. This is\n * v2's `overflow-tabs-button`, computed instead of authored.\n */\n readonly shed?: boolean;\n /**\n * Stage 2: what the WHOLE group degrades to once its children have\n * exhausted their ladders (and shedding, if enabled, has hit its floor): a\n * single menu button or a select-style picker. Groups with neither `shed`\n * nor `collapse` send children to the global overflow menu one by one.\n */\n readonly collapse?: 'menu' | 'select';\n readonly importance?: Importance;\n readonly items: readonly BarChild[];\n}\n\n/**\n * Alignment regions. Separators derive between adjacent visible groups\n * within a section — never across sections, never from schema data.\n *\n * The names are direction-aware (RTL flips start/end) and `center` is a\n * SOFT contract: \"balance this segment in the space left over by start and\n * end\". With symmetric flanks that coincides with true centering; with a\n * heavy flank the segment drifts rather than fights — segments never\n * overlap, matching how every toolbar convention (including v2's\n * spacer-flanked tabs) treats its middle region. Strict geometric centering\n * would be a solver concern (a tighter budget: 2×max(start,end)+center),\n * deliberately not offered until a product needs it.\n */\nexport interface BarSections {\n readonly start?: readonly BarGroup[];\n readonly center?: readonly BarGroup[];\n readonly end?: readonly BarGroup[];\n}\n\nexport interface BarSchema {\n readonly id: string;\n readonly sections: BarSections;\n}\n\n/** A run of command rows; separators derive between sections. */\nexport interface MenuSection {\n /** Optional section heading (i18n key). */\n readonly labelKey?: string;\n readonly items: readonly string[];\n}\n\nexport interface MenuSchema {\n readonly id: string;\n readonly sections: readonly MenuSection[];\n}\n\n/**\n * The shell FRAME — region arrangement and visibility. Regions are a FIXED\n * vocabulary (each carries semantics the shell must own: the toolbar's\n * measurement physics, the document gate, aria landmarks); what's YOURS is\n * where they sit, whether they show, and — through the region slots — what\n * fills them. Part of the chrome value because it is structure: owned, never\n * merged. Free-form layout is deliberately not offered — wanting a different\n * frame architecture is what headless is for.\n */\nexport interface FrameSchema {\n /** Where the main bar lives. Its mode band rides the CONTENT side (below a\n * top bar, above a bottom bar). Default: 'top'. */\n readonly toolbar?: 'top' | 'bottom';\n /** Document tab strip: 'multiple' shows it only with >1 tab. A hidden\n * region hides its SLOT too — visibility outranks slotted content.\n * Default: 'always'. */\n readonly tabs?: 'always' | 'multiple' | 'never';\n /** The header row — a socket only: the chrome ships no header of its own,\n * so it renders nothing until a `slot=\"header\"` child fills it. `false`\n * removes the socket, keeping a slotted header out. Default: true. */\n readonly header?: boolean;\n}\n\nexport interface ChromeSchema {\n /** Standalone bars (e.g. the main toolbar). */\n readonly bars: Readonly<Record<string, BarSchema>>;\n /** Secondary bars keyed by tool mode — WHICH one shows is derived from the\n * interaction hub's active tool, never stored. */\n readonly modeBars?: Readonly<Record<string, BarSchema>>;\n /** Named dropdown menus referenced by commands' `menu:` targets. */\n readonly menus?: Readonly<Record<string, MenuSchema>>;\n /** Contextual strips (selection menus) — same BarSchema, same fit engine. */\n readonly strips?: Readonly<Record<string, BarSchema>>;\n /** Region arrangement & visibility. Omitted = the default frame. */\n readonly frame?: FrameSchema;\n}\n\n// ── authoring sugar ───────────────────────────────────────────────────────────\n\nexport function item(command: string, opts?: Omit<BarItem, 'command'>): BarItem {\n return { command, ...opts };\n}\n\nexport function custom(slot: string, opts: Omit<CustomItem, 'slot'>): CustomItem {\n return { slot, ...opts };\n}\n\nexport function group(id: string, items: readonly BarChild[]): BarGroup;\nexport function group(\n id: string,\n opts: Omit<BarGroup, 'id' | 'items'> & { items?: readonly BarChild[] },\n items?: readonly BarChild[],\n): BarGroup;\nexport function group(\n id: string,\n optsOrItems:\n | readonly BarChild[]\n | (Omit<BarGroup, 'id' | 'items'> & { items?: readonly BarChild[] }),\n items?: readonly BarChild[],\n): BarGroup {\n if (Array.isArray(optsOrItems)) return { id, items: optsOrItems as readonly BarChild[] };\n const { items: optItems, ...opts } = optsOrItems as Omit<BarGroup, 'id' | 'items'> & {\n items?: readonly BarChild[];\n };\n return { id, ...opts, items: items ?? optItems ?? [] };\n}\n\n// ── normalized form — what the solver and projection consume ─────────────────\n\nexport type NormalizedUnit =\n | {\n readonly kind: 'command';\n /** Unique within the bar: `${groupId}:${command}`. Measurement + assignment key. */\n readonly key: string;\n readonly command: string;\n readonly variants: readonly string[];\n readonly importance: Importance;\n }\n | {\n readonly kind: 'custom';\n readonly key: string;\n readonly slot: string;\n readonly variants: readonly string[];\n readonly terminal: string;\n readonly importance: Importance;\n };\n\nexport interface NormalizedGroup {\n readonly id: string;\n readonly labelKey?: string;\n readonly role: 'buttons' | 'tabs';\n readonly shed: boolean;\n readonly collapse?: 'menu' | 'select';\n readonly importance: Importance;\n readonly units: readonly NormalizedUnit[];\n}\n\nexport interface NormalizedSection {\n readonly name: 'start' | 'center' | 'end';\n readonly groups: readonly NormalizedGroup[];\n}\n\nexport interface NormalizedBar {\n readonly id: string;\n readonly sections: readonly NormalizedSection[];\n}\n\nexport const DEFAULT_IMPORTANCE: Importance = 3;\nconst DEFAULT_COMMAND_VARIANTS: readonly Variant[] = ['icon'];\nconst DEFAULT_CUSTOM_VARIANTS: readonly string[] = ['default'];\n\nfunction normalizeChild(groupId: string, child: BarChild, seen: Set<string>): NormalizedUnit {\n const asItem: BarItem | CustomItem = typeof child === 'string' ? { command: child } : child;\n const unit: NormalizedUnit =\n 'slot' in asItem\n ? {\n kind: 'custom',\n key: `${groupId}:${asItem.slot}`,\n slot: asItem.slot,\n variants: asItem.variants ?? DEFAULT_CUSTOM_VARIANTS,\n terminal: asItem.terminal,\n importance: asItem.importance ?? DEFAULT_IMPORTANCE,\n }\n : {\n kind: 'command',\n key: `${groupId}:${asItem.command}`,\n command: asItem.command,\n variants: asItem.variants ?? DEFAULT_COMMAND_VARIANTS,\n importance: asItem.importance ?? DEFAULT_IMPORTANCE,\n };\n if (unit.variants.length === 0) throw new Error(`[ui-core] empty variant ladder: ${unit.key}`);\n if (seen.has(unit.key)) throw new Error(`[ui-core] duplicate unit in bar: ${unit.key}`);\n seen.add(unit.key);\n return unit;\n}\n\n/** Resolve shorthands + defaults; validate uniqueness. Solver/projection input. */\nexport function normalizeBar(bar: BarSchema): NormalizedBar {\n const seen = new Set<string>();\n const groupIds = new Set<string>();\n const sections: NormalizedSection[] = [];\n for (const name of ['start', 'center', 'end'] as const) {\n const groups = bar.sections[name];\n if (!groups || groups.length === 0) continue;\n sections.push({\n name,\n groups: groups.map((g) => {\n if (groupIds.has(g.id)) throw new Error(`[ui-core] duplicate group in bar: ${g.id}`);\n groupIds.add(g.id);\n return {\n id: g.id,\n labelKey: g.labelKey,\n role: g.role ?? 'buttons',\n shed: g.shed ?? false,\n collapse: g.collapse,\n importance: g.importance ?? DEFAULT_IMPORTANCE,\n units: g.items.map((c) => normalizeChild(g.id, c, seen)),\n };\n }),\n });\n }\n return { id: bar.id, sections };\n}\n\n/**\n * Drop units whose command is currently invisible (permissions, disabled\n * categories, contextual visibility) BEFORE solving — an invisible unit must\n * not consume budget or appear in the overflow. Groups that empty out vanish\n * naturally in the solver's separator math and in the projection.\n */\nexport function filterBar(\n bar: NormalizedBar,\n keep: (unit: NormalizedUnit) => boolean,\n): NormalizedBar {\n return {\n id: bar.id,\n sections: bar.sections.map((s) => ({\n name: s.name,\n groups: s.groups.map((g) => ({ ...g, units: g.units.filter(keep) })),\n })),\n };\n}\n\n/**\n * Identity + validation. Checks what is checkable without a command registry:\n * bars normalize cleanly, and every `menu` a strip/bar could reference exists\n * is left to `validateChrome` (which also takes the known command ids).\n */\nexport function defineChrome<T extends ChromeSchema>(chrome: T): T {\n for (const bar of Object.values(chrome.bars)) normalizeBar(bar);\n for (const bar of Object.values(chrome.modeBars ?? {})) normalizeBar(bar);\n for (const strip of Object.values(chrome.strips ?? {})) normalizeBar(strip);\n return chrome;\n}\n\n/** Dev-time cross-check: every command referenced by the chrome exists. */\nexport function validateChrome(chrome: ChromeSchema, knownCommands: ReadonlySet<string>): string[] {\n const problems: string[] = [];\n const checkBar = (bar: BarSchema, where: string) => {\n for (const section of normalizeBar(bar).sections)\n for (const g of section.groups)\n for (const u of g.units) {\n const refs = u.kind === 'command' ? [u.command] : [u.terminal];\n for (const c of refs)\n if (!knownCommands.has(c)) problems.push(`${where}: unknown command \"${c}\"`);\n }\n };\n for (const [id, bar] of Object.entries(chrome.bars)) checkBar(bar, `bars.${id}`);\n for (const [id, bar] of Object.entries(chrome.modeBars ?? {})) checkBar(bar, `modeBars.${id}`);\n for (const [id, strip] of Object.entries(chrome.strips ?? {})) checkBar(strip, `strips.${id}`);\n for (const [id, menu] of Object.entries(chrome.menus ?? {}))\n for (const section of menu.sections)\n for (const c of section.items)\n if (!knownCommands.has(c)) problems.push(`menus.${id}: unknown command \"${c}\"`);\n return problems;\n}\n","/**\n * Pure transforms over ChromeSchema — the \"surgical edit\" tier of the\n * customization ladder, between \"pass nothing\" and \"own the whole value\".\n * They are ordinary functions over data: no registry, no merge grammar, no\n * order sensitivity beyond function composition. Anything they can't express\n * is a sign the caller should write the schema value instead.\n *\n * Addressing is by BAR ID across all three bar collections (bars, modeBars,\n * strips). Mode bars may also be addressed by their surface key\n * ('mode:annotate') since that is what appears in `chrome.modeBars`.\n */\nimport {\n group as makeGroup,\n type BarChild,\n type BarGroup,\n type BarSchema,\n type BarSections,\n type ChromeSchema,\n type CustomItem,\n} from './schema';\n\nexport interface AddItemSpec {\n /** Bar id ('main', 'annotate', …) or a modeBars surface key ('mode:annotate'). */\n readonly bar: string;\n readonly section: keyof BarSections;\n /** Target group id. Unknown in the bar → a new group is created at the end\n * of `section`; known but in a DIFFERENT section → error (group ids are\n * bar-unique, so that is a contradiction, not a request). */\n readonly group: string;\n readonly item: BarChild;\n /** Insert position within the group. Default: append. */\n readonly at?: number;\n}\n\nconst SECTION_NAMES: readonly (keyof BarSections)[] = ['start', 'center', 'end'];\n\nconst isCustom = (child: BarChild): child is CustomItem =>\n typeof child !== 'string' && 'slot' in child;\n\nconst commandOf = (child: BarChild): string | null =>\n typeof child === 'string' ? child : isCustom(child) ? null : child.command;\n\n/** Every (collection, key) location whose bar matches `id`. */\nfunction locate(schema: ChromeSchema, id: string): ['bars' | 'modeBars' | 'strips', string][] {\n const hits: ['bars' | 'modeBars' | 'strips', string][] = [];\n for (const coll of ['bars', 'modeBars', 'strips'] as const) {\n for (const [key, bar] of Object.entries(schema[coll] ?? {})) {\n if (bar.id === id || key === id) hits.push([coll, key]);\n }\n }\n return hits;\n}\n\nfunction withBar(\n schema: ChromeSchema,\n coll: 'bars' | 'modeBars' | 'strips',\n key: string,\n bar: BarSchema,\n): ChromeSchema {\n return { ...schema, [coll]: { ...schema[coll], [key]: bar } };\n}\n\n/** Insert `spec.item` into a group of one bar. See AddItemSpec for semantics. */\nexport function addItem(schema: ChromeSchema, spec: AddItemSpec): ChromeSchema {\n const hits = locate(schema, spec.bar);\n if (hits.length === 0)\n throw new Error(`[ui-core] addItem: no bar \"${spec.bar}\" in bars/modeBars/strips`);\n if (hits.length > 1)\n throw new Error(\n `[ui-core] addItem: bar id \"${spec.bar}\" is ambiguous (${hits.map(([c]) => c).join(', ')})`,\n );\n const [coll, key] = hits[0];\n const bar = schema[coll]![key];\n\n for (const name of SECTION_NAMES) {\n if (name === spec.section) continue;\n if (bar.sections[name]?.some((g) => g.id === spec.group))\n throw new Error(\n `[ui-core] addItem: group \"${spec.group}\" lives in section \"${name}\", not \"${spec.section}\"`,\n );\n }\n\n const groups = bar.sections[spec.section] ?? [];\n const idx = groups.findIndex((g) => g.id === spec.group);\n const nextGroups =\n idx === -1\n ? [...groups, makeGroup(spec.group, [spec.item])]\n : groups.map((g, i) => {\n if (i !== idx) return g;\n const items = [...g.items];\n items.splice(spec.at ?? items.length, 0, spec.item);\n return { ...g, items };\n });\n\n return withBar(schema, coll, key, {\n ...bar,\n sections: { ...bar.sections, [spec.section]: nextGroups },\n });\n}\n\n/**\n * Purge commands (or custom slots, by slot name) from every bar, mode bar,\n * strip, and menu. Groups and menu sections that empty out are dropped;\n * emptied menus keep their key (commands may still target them) with no rows.\n */\nexport function removeItems(schema: ChromeSchema, ids: readonly string[]): ChromeSchema {\n const gone = new Set(ids);\n const keep = (child: BarChild): boolean => {\n const cmd = commandOf(child);\n return cmd !== null ? !gone.has(cmd) : !gone.has((child as CustomItem).slot);\n };\n\n const filterGroups = (groups: readonly BarGroup[] | undefined) =>\n groups?.map((g) => ({ ...g, items: g.items.filter(keep) })).filter((g) => g.items.length > 0);\n\n const filterBarSchema = (bar: BarSchema): BarSchema => ({\n ...bar,\n sections: Object.fromEntries(\n SECTION_NAMES.flatMap((name) => {\n const groups = filterGroups(bar.sections[name]);\n return groups && groups.length > 0 ? [[name, groups]] : [];\n }),\n ),\n });\n\n const filterColl = <T extends Readonly<Record<string, BarSchema>> | undefined>(coll: T): T =>\n coll &&\n (Object.fromEntries(Object.entries(coll).map(([k, b]) => [k, filterBarSchema(b)])) as T);\n\n return {\n ...schema,\n bars: filterColl(schema.bars)!,\n modeBars: filterColl(schema.modeBars),\n strips: filterColl(schema.strips),\n menus:\n schema.menus &&\n Object.fromEntries(\n Object.entries(schema.menus).map(([k, menu]) => [\n k,\n {\n ...menu,\n sections: menu.sections\n .map((s) => ({ ...s, items: s.items.filter((c) => !gone.has(c)) }))\n .filter((s) => s.items.length > 0),\n },\n ]),\n ),\n };\n}\n\n/**\n * Swap a command in place everywhere it appears — bars, mode bars, strips,\n * and (when the replacement is itself a plain command) menu rows.\n */\nexport function replaceItem(schema: ChromeSchema, id: string, item: BarChild): ChromeSchema {\n const replacementCommand = commandOf(item);\n const swap = (child: BarChild): BarChild => (commandOf(child) === id ? item : child);\n\n const mapBar = (bar: BarSchema): BarSchema => ({\n ...bar,\n sections: Object.fromEntries(\n SECTION_NAMES.flatMap((name) => {\n const groups = bar.sections[name];\n return groups ? [[name, groups.map((g) => ({ ...g, items: g.items.map(swap) }))]] : [];\n }),\n ),\n });\n\n const mapColl = <T extends Readonly<Record<string, BarSchema>> | undefined>(coll: T): T =>\n coll && (Object.fromEntries(Object.entries(coll).map(([k, b]) => [k, mapBar(b)])) as T);\n\n return {\n ...schema,\n bars: mapColl(schema.bars)!,\n modeBars: mapColl(schema.modeBars),\n strips: mapColl(schema.strips),\n menus:\n replacementCommand === null\n ? schema.menus\n : schema.menus &&\n Object.fromEntries(\n Object.entries(schema.menus).map(([k, menu]) => [\n k,\n {\n ...menu,\n sections: menu.sections.map((s) => ({\n ...s,\n items: s.items.map((c) => (c === id ? replacementCommand : c)),\n })),\n },\n ]),\n ),\n };\n}\n","/**\n * The helpers bundle handed to `chrome: (base, h) => …` transforms — the\n * surgical edits plus the authoring sugar, so simple customizations need no\n * imports at all. One object, frozen shape: it IS public API (the vanilla\n * snippet passes it across the config boundary), so additions are features\n * and removals are breaking.\n */\nimport { custom, defineChrome, group, item } from './schema';\nimport { addItem, removeItems, replaceItem } from './transforms';\n\nexport const chromeHelpers = {\n addItem,\n removeItems,\n replaceItem,\n item,\n group,\n custom,\n defineChrome,\n} as const;\n\nexport type ChromeHelpers = typeof chromeHelpers;\n","/**\n * The fit solver — pure. Given a normalized bar, measured widths, and the\n * container budget, decide what every unit renders as: a variant, shed into\n * its group's disclosure, part of a collapsed group, or the overflow menu.\n *\n * Deterministic degradation policy, applied while over budget:\n * 1. among all available steps, take the one owned by the LOWEST-importance\n * unit/group; ties prefer variant < shed < group-collapse < overflow;\n * remaining ties degrade the RIGHTMOST first (end of bar yields first).\n * 2. a unit's variant steps run out before it may shed or overflow.\n * 3. a `shed` group moves children (at the CHILD's importance) into a\n * group-local disclosure, but never below ONE visible child — the floor.\n * 4. a group with `collapse` collapses only after every child sits on its\n * last variant AND shedding (if enabled) has hit its floor; once\n * collapsed it degrades further as ONE unit (the whole group overflows\n * together — a select can't half-overflow). A shed group WITHOUT\n * `collapse` overflows whole at the floor instead.\n * 5. pinned (importance 5) units/groups may degrade variants but never\n * shed, collapse away, or overflow. Everything else can ALWAYS reach the\n * overflow menu, so any bar fits any width whose pinned floor fits.\n *\n * So the full group ladder mirrors the item ladder:\n * items: richest variant → … → smallest variant → (shed |) overflow\n * groups: all children → shed to floor → collapsed control → overflow\n *\n * The overflow trigger occupies space only when something overflowed: solve\n * once without it; if anything overflowed, solve again with the trigger's\n * width reserved (a smaller budget can only overflow MORE, so two passes\n * reach the fixpoint). A group's disclosure trigger is budgeted the same way,\n * inside `measure`, whenever that group has shed children.\n *\n * Missing measurements count as width 0 and are reported via `complete:\n * false` — callers render the first frame from an incomplete solve and\n * re-solve when the ResizeObserver delivers real numbers.\n */\nimport type { NormalizedBar, NormalizedGroup, NormalizedUnit } from './schema';\nimport { PINNED } from './schema';\n\nexport interface FitMetrics {\n /** Width of unit `key` rendered at `variant`; undefined = not yet measured. */\n unit(key: string, variant: string): number | undefined;\n /** Width of group `id` rendered in its collapsed form ('menu' | 'select'). */\n groupCollapsed(groupId: string): number | undefined;\n /** Width of group `id`'s disclosure trigger (shed groups only). */\n groupTrigger(groupId: string): number | undefined;\n /** Width of the overflow trigger button. */\n readonly overflowTrigger: number;\n /** Gap between adjacent visible units. */\n readonly gap: number;\n /** Width of a derived separator between adjacent visible groups (with its gaps). */\n readonly separator: number;\n}\n\nexport type UnitAssignment =\n | { readonly kind: 'variant'; readonly variant: string }\n | { readonly kind: 'shed' } // hidden behind its group's disclosure trigger\n | { readonly kind: 'collapsed' } // hidden behind its group's collapsed control\n | { readonly kind: 'overflow' };\n\nexport interface GroupAssignment {\n /** How many children sit behind the group's disclosure trigger. */\n readonly shedCount: number;\n /** The group renders as its single collapsed control. */\n readonly collapsed: boolean;\n /** No part of the group is visible in the bar. */\n readonly overflowed: boolean;\n}\n\nexport interface FitResult {\n readonly units: ReadonlyMap<string, UnitAssignment>;\n readonly groups: ReadonlyMap<string, GroupAssignment>;\n readonly hasOverflow: boolean;\n /** Total visible width at this assignment (diagnostics + tests). */\n readonly width: number;\n /** False when any consulted measurement was missing (treated as 0). */\n readonly complete: boolean;\n}\n\n// ── internal mutable solve state ──────────────────────────────────────────────\n\ninterface UnitState {\n unit: NormalizedUnit;\n group: GroupState;\n /** Index into unit.variants (0 = richest). */\n variantIndex: number;\n shed: boolean;\n overflowed: boolean;\n /** Position in bar order — rightmost-first tie-breaking. */\n position: number;\n}\n\ninterface GroupState {\n group: NormalizedGroup;\n section: 'start' | 'center' | 'end';\n collapsed: boolean;\n overflowed: boolean;\n units: UnitState[];\n}\n\ntype Step =\n | { type: 'variant'; importance: number; position: number; unit: UnitState }\n | { type: 'shed'; importance: number; position: number; unit: UnitState }\n | { type: 'collapse'; importance: number; position: number; group: GroupState }\n | { type: 'overflow-unit'; importance: number; position: number; unit: UnitState }\n | { type: 'overflow-group'; importance: number; position: number; group: GroupState };\n\n/** variant < shed < collapse < overflow when importance ties. */\nconst STEP_RANK: Record<Step['type'], number> = {\n variant: 0,\n shed: 1,\n collapse: 2,\n 'overflow-unit': 3,\n 'overflow-group': 3,\n};\n\nfunction buildState(bar: NormalizedBar): GroupState[] {\n const groups: GroupState[] = [];\n let position = 0;\n for (const section of bar.sections) {\n for (const g of section.groups) {\n const gs: GroupState = {\n group: g,\n section: section.name,\n collapsed: false,\n overflowed: false,\n units: [],\n };\n for (const u of g.units) {\n gs.units.push({\n unit: u,\n group: gs,\n variantIndex: 0,\n shed: false,\n overflowed: false,\n position,\n });\n position += 1;\n }\n groups.push(gs);\n }\n }\n return groups;\n}\n\nfunction nextStep(groups: GroupState[]): Step | null {\n let best: Step | null = null;\n const consider = (step: Step) => {\n if (\n !best ||\n step.importance < best.importance ||\n (step.importance === best.importance &&\n (STEP_RANK[step.type] < STEP_RANK[best.type] ||\n (STEP_RANK[step.type] === STEP_RANK[best.type] && step.position > best.position)))\n ) {\n best = step;\n }\n };\n\n for (const gs of groups) {\n if (gs.overflowed) continue;\n const groupPosition = gs.units.length ? gs.units[gs.units.length - 1].position : 0;\n\n if (gs.collapsed) {\n // A collapsed group degrades as one unit: overflow it whole.\n if (gs.group.importance < PINNED)\n consider({\n type: 'overflow-group',\n importance: gs.group.importance,\n position: groupPosition,\n group: gs,\n });\n continue;\n }\n\n let childrenExhausted = true;\n const visibleCount = gs.units.filter((u) => !u.overflowed && !u.shed).length;\n for (const us of gs.units) {\n if (us.overflowed || us.shed) continue;\n if (us.variantIndex < us.unit.variants.length - 1) {\n childrenExhausted = false;\n consider({\n type: 'variant',\n importance: us.unit.importance,\n position: us.position,\n unit: us,\n });\n } else if (us.unit.importance < PINNED) {\n if (gs.group.shed && visibleCount > 1) {\n // Stage 1: move the child behind the group's disclosure trigger —\n // never below one visible child (the floor).\n consider({\n type: 'shed',\n importance: us.unit.importance,\n position: us.position,\n unit: us,\n });\n } else if (!gs.group.shed && !gs.group.collapse) {\n // Plain group: children go to the GLOBAL overflow individually.\n consider({\n type: 'overflow-unit',\n importance: us.unit.importance,\n position: us.position,\n unit: us,\n });\n }\n }\n }\n\n // Stage 2 (terminal for the expanded form): available only once variants\n // are exhausted AND shedding — if enabled — sits at its floor.\n const shedExhausted = !gs.group.shed || visibleCount <= 1;\n if (childrenExhausted && shedExhausted && gs.group.importance < PINNED) {\n if (gs.group.collapse) {\n consider({\n type: 'collapse',\n importance: gs.group.importance,\n position: groupPosition,\n group: gs,\n });\n } else if (gs.group.shed) {\n // Shed group without a collapsed form: at the floor the WHOLE group\n // (visible + shed children) moves to the global overflow together.\n consider({\n type: 'overflow-group',\n importance: gs.group.importance,\n position: groupPosition,\n group: gs,\n });\n }\n }\n }\n return best;\n}\n\nfunction applyStep(step: Step): void {\n switch (step.type) {\n case 'variant':\n step.unit.variantIndex += 1;\n return;\n case 'shed':\n step.unit.shed = true;\n return;\n case 'collapse':\n step.group.collapsed = true;\n return;\n case 'overflow-unit': {\n step.unit.overflowed = true;\n if (step.unit.group.units.every((u) => u.overflowed)) step.unit.group.overflowed = true;\n return;\n }\n case 'overflow-group': {\n step.group.overflowed = true;\n for (const u of step.group.units) u.overflowed = true;\n return;\n }\n }\n}\n\ninterface Measured {\n width: number;\n complete: boolean;\n}\n\n/**\n * Visible width of the current assignment: unit widths + gaps + derived\n * separators. Gaps are counted between ALL adjacent visible units, including\n * across section boundaries — deliberately conservative: the adapter's layout\n * spaces sections with collapsing auto margins, so the cross-section gap\n * allowance (≤ 2×gap) is slack those margins absorb, never an overlap risk.\n */\nfunction measure(groups: GroupState[], metrics: FitMetrics, hasTrigger: boolean): Measured {\n let width = 0;\n let complete = true;\n let visibleUnits = 0;\n\n // Separators derive between adjacent visible groups within a section.\n const visibleBySection = new Map<string, number>();\n\n for (const gs of groups) {\n if (gs.overflowed) continue;\n if (gs.collapsed) {\n const w = metrics.groupCollapsed(gs.group.id);\n if (w === undefined) complete = false;\n width += w ?? 0;\n visibleUnits += 1;\n visibleBySection.set(gs.section, (visibleBySection.get(gs.section) ?? 0) + 1);\n continue;\n }\n let groupVisible = false;\n let shedCount = 0;\n for (const us of gs.units) {\n if (us.overflowed) continue;\n if (us.shed) {\n shedCount += 1;\n continue;\n }\n const w = metrics.unit(us.unit.key, us.unit.variants[us.variantIndex]);\n if (w === undefined) complete = false;\n width += w ?? 0;\n visibleUnits += 1;\n groupVisible = true;\n }\n if (shedCount > 0) {\n // The group's disclosure trigger takes real space, like any unit.\n const w = metrics.groupTrigger(gs.group.id);\n if (w === undefined) complete = false;\n width += w ?? 0;\n visibleUnits += 1;\n groupVisible = true;\n }\n if (groupVisible) visibleBySection.set(gs.section, (visibleBySection.get(gs.section) ?? 0) + 1);\n }\n\n if (hasTrigger) {\n width += metrics.overflowTrigger;\n visibleUnits += 1;\n }\n if (visibleUnits > 1) width += metrics.gap * (visibleUnits - 1);\n for (const count of visibleBySection.values())\n if (count > 1) width += metrics.separator * (count - 1);\n\n return { width, complete };\n}\n\nfunction anyOverflow(groups: GroupState[]): boolean {\n return groups.some((gs) => gs.units.some((u) => u.overflowed));\n}\n\nfunction solvePass(\n bar: NormalizedBar,\n metrics: FitMetrics,\n budget: number,\n hasTrigger: boolean,\n): { groups: GroupState[]; measured: Measured } {\n const groups = buildState(bar);\n let measured = measure(groups, metrics, hasTrigger);\n while (measured.width > budget) {\n const step = nextStep(groups);\n if (!step) break; // pinned floor — nothing left to shed\n applyStep(step);\n measured = measure(groups, metrics, hasTrigger);\n }\n return { groups, measured };\n}\n\nexport function solve(bar: NormalizedBar, metrics: FitMetrics, containerWidth: number): FitResult {\n // Pass 1: assume no trigger. If nothing overflows, done.\n let pass = solvePass(bar, metrics, containerWidth, false);\n if (anyOverflow(pass.groups)) {\n // Pass 2: same budget, trigger now takes real space in `measure`. The step\n // sequence is budget-independent, so pass 2 degrades strictly further than\n // pass 1 — overflow can't disappear, and the trigger stays justified.\n pass = solvePass(bar, metrics, containerWidth, true);\n }\n\n const units = new Map<string, UnitAssignment>();\n const groupAssignments = new Map<string, GroupAssignment>();\n for (const gs of pass.groups) {\n // Overflow ≻ collapsed ≻ shed: a group that shed a few children and THEN\n // collapsed (or overflowed) subsumes them into the later, stronger state.\n const shedCount = gs.units.filter((u) => u.shed && !u.overflowed && !gs.collapsed).length;\n groupAssignments.set(gs.group.id, {\n shedCount,\n collapsed: gs.collapsed,\n overflowed: gs.overflowed,\n });\n for (const us of gs.units) {\n units.set(\n us.unit.key,\n us.overflowed\n ? { kind: 'overflow' }\n : gs.collapsed\n ? { kind: 'collapsed' }\n : us.shed\n ? { kind: 'shed' }\n : { kind: 'variant', variant: us.unit.variants[us.variantIndex] },\n );\n }\n }\n return {\n units,\n groups: groupAssignments,\n hasOverflow: anyOverflow(pass.groups),\n width: pass.measured.width,\n complete: pass.measured.complete,\n };\n}\n","/**\n * Overflow projection — pure. The overflow menu is never authored: it is the\n * complement of the visible set, projected into menu form. The projection is\n * TOTAL because every unit has a canonical menu form by construction:\n *\n * command → command row (label/icon/active resolve live)\n * command with a `menu` target → submenu row pointing at that menu\n * custom item → its `terminal` command's form\n * group → section (renderers separate sections)\n * group with `labelKey` → labeled section (title or nested submenu —\n * presentation is the renderer's choice)\n * `role: 'tabs'` group → section marked radio\n *\n * Groups project in bar order; a partially-overflowed group projects only its\n * overflowed units; empty sections vanish. This is what replaces every\n * hand-written overflow/action menu in v2 — same information, one source.\n */\nimport type { NormalizedBar, NormalizedGroup, NormalizedUnit } from './schema';\nimport type { FitResult } from './solver';\n\nexport type OverflowRow =\n /** A plain command row. The renderer resolves label/icon/active from the registry. */\n | { readonly type: 'command'; readonly command: string }\n /** A command that opens a menu — renders as `label ▸` nesting that menu. */\n | { readonly type: 'submenu'; readonly command: string; readonly menu: string };\n\nexport interface OverflowSection {\n /** From the group's labelKey — render as a section title or a nested submenu. */\n readonly labelKey?: string;\n /** 'radio' when the group is a tab strip: exactly one row is active. */\n readonly role?: 'radio';\n readonly rows: readonly OverflowRow[];\n}\n\n/**\n * The one fact projection needs about a command: does it open a menu?\n * (Label, icon, and active state stay live in the renderer.) Return null for\n * unknown commands — they project as plain rows and resolve at render time.\n */\nexport type ResolveMenuTarget = (commandId: string) => { menu?: string } | null;\n\nfunction projectUnit(unit: NormalizedUnit, resolve: ResolveMenuTarget): OverflowRow {\n // A custom item's menu form is its terminal command's form.\n const command = unit.kind === 'custom' ? unit.terminal : unit.command;\n const menu = resolve(command)?.menu;\n return menu ? { type: 'submenu', command, menu } : { type: 'command', command };\n}\n\nexport function projectOverflow(\n bar: NormalizedBar,\n fit: FitResult,\n resolve: ResolveMenuTarget,\n): OverflowSection[] {\n const sections: OverflowSection[] = [];\n for (const section of bar.sections) {\n for (const group of section.groups) {\n // Shed units are NOT here: they're reachable through the group's own\n // disclosure trigger (projectShed). Only true overflow leaves the group.\n const rows = group.units\n .filter((u) => fit.units.get(u.key)?.kind === 'overflow')\n .map((u) => projectUnit(u, resolve));\n if (rows.length === 0) continue;\n sections.push({\n labelKey: group.labelKey,\n role: group.role === 'tabs' ? 'radio' : undefined,\n rows,\n });\n }\n }\n return sections;\n}\n\n/**\n * The content of a group's disclosure trigger: its shed units, in bar order,\n * in menu form — same totality rules as the global overflow. This is v2's\n * hand-written `mode-tabs-overflow-menu`, derived.\n */\nexport function projectShed(\n group: NormalizedGroup,\n fit: FitResult,\n resolve: ResolveMenuTarget,\n): OverflowRow[] {\n return group.units\n .filter((u) => fit.units.get(u.key)?.kind === 'shed')\n .map((u) => projectUnit(u, resolve));\n}\n\n/** One strip group: a separator boundary, its visible commands in bar order. */\nexport interface StripGroup {\n readonly id: string;\n readonly labelKey?: string;\n readonly commands: readonly string[];\n}\n\n/**\n * Strip projection — a bar projected for UN-measured rendering (a contextual\n * strip anchored to a selection has no fit pressure to solve). The schema\n * declares what COULD appear; `visible` (the command registry's runtime truth)\n * decides what DOES: hidden commands drop out, groups that empty out vanish,\n * and an all-hidden bar projects to [] — \"render nothing\" falls out. Custom\n * units project through their `terminal` command, same totality rule as the\n * overflow. Upgrading a strip to measured/overflowing rendering later is a\n * renderer swap (<Toolbar>), never a schema change.\n */\nexport function projectStrip(\n bar: NormalizedBar,\n visible: (command: string) => boolean,\n): StripGroup[] {\n const groups: StripGroup[] = [];\n for (const section of bar.sections) {\n for (const group of section.groups) {\n const commands = group.units\n .map((u) => (u.kind === 'custom' ? u.terminal : u.command))\n .filter(visible);\n if (commands.length === 0) continue;\n groups.push({ id: group.id, labelKey: group.labelKey, commands });\n }\n }\n return groups;\n}\n","/**\n * Shortcut parsing + matching — pure. No `navigator`: platform is an input\n * (`isMac`), decided by the embedder, same rule as plugin-i18n's locale.\n *\n * Grammar: modifiers and one key joined by '+', e.g. 'Mod+K', 'Ctrl+=',\n * 'Shift+Alt+D', 'Meta+NumpadAdd'. 'Mod' is ⌘ on mac and Ctrl elsewhere.\n * Keys longer than one character (F1, Escape, NumpadAdd, ArrowLeft) match\n * `event.key` OR `event.code` case-insensitively, so numpad shortcuts work.\n */\n\nexport interface ParsedShortcut {\n readonly key: string; // lowercase\n readonly mod: boolean; // platform-resolved at match time\n readonly ctrl: boolean;\n readonly meta: boolean;\n readonly alt: boolean;\n readonly shift: boolean;\n}\n\n/** The subset of KeyboardEvent the matcher reads — keeps this module DOM-free. */\nexport interface KeyStroke {\n readonly key: string;\n readonly code?: string;\n readonly ctrlKey: boolean;\n readonly metaKey: boolean;\n readonly altKey: boolean;\n readonly shiftKey: boolean;\n}\n\nconst MODIFIERS = new Set([\n 'mod',\n 'ctrl',\n 'control',\n 'meta',\n 'cmd',\n 'command',\n 'alt',\n 'option',\n 'shift',\n]);\n\nexport function parseShortcut(shortcut: string): ParsedShortcut {\n const tokens = shortcut.split('+').map((t) => t.trim());\n // 'Ctrl+=' splits to ['Ctrl', '', ''] — an empty tail means the key IS '+'.\n const keyToken = tokens[tokens.length - 1] === '' ? '+' : tokens[tokens.length - 1];\n const parsed = {\n key: keyToken.toLowerCase(),\n mod: false,\n ctrl: false,\n meta: false,\n alt: false,\n shift: false,\n };\n for (const token of tokens.slice(0, -1)) {\n const t = token.toLowerCase();\n if (t === '') continue; // artifact of a literal '+' key\n if (!MODIFIERS.has(t))\n throw new Error(`[ui-core] unknown modifier \"${token}\" in \"${shortcut}\"`);\n if (t === 'mod') parsed.mod = true;\n else if (t === 'ctrl' || t === 'control') parsed.ctrl = true;\n else if (t === 'meta' || t === 'cmd' || t === 'command') parsed.meta = true;\n else if (t === 'alt' || t === 'option') parsed.alt = true;\n else parsed.shift = true;\n }\n if (parsed.key === '') throw new Error(`[ui-core] empty key in shortcut \"${shortcut}\"`);\n return parsed;\n}\n\nexport function matchShortcut(\n parsed: ParsedShortcut,\n stroke: KeyStroke,\n opts: { isMac: boolean },\n): boolean {\n const wantCtrl = parsed.ctrl || (parsed.mod && !opts.isMac);\n const wantMeta = parsed.meta || (parsed.mod && opts.isMac);\n if (stroke.ctrlKey !== wantCtrl) return false;\n if (stroke.metaKey !== wantMeta) return false;\n if (stroke.altKey !== parsed.alt) return false;\n // Shift changes what `key` IS for printable characters ('=' vs '+'), so only\n // enforce declared shift; an undeclared shift is rejected for non-printables.\n if (parsed.shift && !stroke.shiftKey) return false;\n if (!parsed.shift && stroke.shiftKey && parsed.key.length > 1) return false;\n\n const key = stroke.key.toLowerCase();\n if (key === parsed.key) return true;\n // Long names ('numpadadd', 'f1', …) may be codes rather than keys.\n return (\n parsed.key.length > 1 && stroke.code !== undefined && stroke.code.toLowerCase() === parsed.key\n );\n}\n\n/** Display form for menu rows: '⌘K' on mac, 'Ctrl+K' elsewhere. */\nexport function formatShortcut(shortcut: string, opts: { isMac: boolean }): string {\n const parsed = parseShortcut(shortcut);\n const key = parsed.key.length === 1 ? parsed.key.toUpperCase() : capitalize(parsed.key);\n if (opts.isMac) {\n const mods = [\n parsed.ctrl ? '⌃' : '',\n parsed.alt ? '⌥' : '',\n parsed.shift ? '⇧' : '',\n parsed.meta || parsed.mod ? '⌘' : '',\n ].join('');\n return `${mods}${key}`;\n }\n const mods = [\n parsed.ctrl || parsed.mod ? 'Ctrl' : '',\n parsed.meta ? 'Meta' : '',\n parsed.alt ? 'Alt' : '',\n parsed.shift ? 'Shift' : '',\n ].filter(Boolean);\n return [...mods, key].join('+');\n}\n\nfunction capitalize(s: string): string {\n return s.charAt(0).toUpperCase() + s.slice(1);\n}\n"],"mappings":"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"}
@@ -0,0 +1,364 @@
1
+ //#region src/schema.d.ts
2
+ /**
3
+ * @embedpdf/core-ui — the structure-only schema vocabulary.
4
+ *
5
+ * The schema contains ONLY what a designer decides and the runtime cannot
6
+ * compute: order, grouping, importance, and each item's degradation ladder.
7
+ * Everything the runtime CAN compute is banned from it by construction:
8
+ * no breakpoints, no show/hide lists, no locale overrides, no dividers, no
9
+ * spacers, no hand-written overflow menus. Fit is measured and solved at
10
+ * runtime (see solver.ts); the overflow menu is derived (see projection.ts).
11
+ */
12
+ /** Presentation ladder for a command button, richest first. */
13
+ type Variant = 'icon+label' | 'icon' | 'label';
14
+ /**
15
+ * Who yields space first. 1 = first to degrade/overflow · 3 = default ·
16
+ * 5 = pinned: may still degrade variants, but NEVER leaves the bar.
17
+ */
18
+ type Importance = 1 | 2 | 3 | 4 | 5;
19
+ declare const PINNED: Importance;
20
+ interface BarItem {
21
+ /** The command this button runs — the only required field. */
22
+ readonly command: string;
23
+ /** Degradation ladder, richest first. Default: ['icon']. */
24
+ readonly variants?: readonly Variant[];
25
+ readonly importance?: Importance;
26
+ }
27
+ /**
28
+ * An app-rendered slot (e.g. the inline zoom strip). Each named variant is
29
+ * measured like any command button. The ladder MUST terminate in a command
30
+ * (`terminal`) so the item always has a menu form when it overflows — this
31
+ * is what makes the overflow projection total.
32
+ */
33
+ interface CustomItem {
34
+ readonly slot: string;
35
+ /** Named presentation variants, richest first. Default: ['default']. */
36
+ readonly variants?: readonly string[];
37
+ /** The command that stands in for this slot in menus (its last resort). */
38
+ readonly terminal: string;
39
+ readonly importance?: Importance;
40
+ }
41
+ type BarChild = BarItem | CustomItem | string;
42
+ interface BarGroup {
43
+ readonly id: string;
44
+ /** Titles the group's menu form (labeled submenu / section heading). */
45
+ readonly labelKey?: string;
46
+ /** Presentation hint: 'tabs' renders as a tab strip and projects as radio rows. */
47
+ readonly role?: 'buttons' | 'tabs';
48
+ /**
49
+ * Stage 1 of the GROUP degradation ladder: under pressure, move trailing
50
+ * children (rightmost first, at the CHILD's importance) into a derived
51
+ * group-local disclosure — a trigger rendered inside the group opening a
52
+ * menu of the hidden children. Never sheds the last visible child: below
53
+ * that floor the group `collapse`s (stage 2) or overflows whole. This is
54
+ * v2's `overflow-tabs-button`, computed instead of authored.
55
+ */
56
+ readonly shed?: boolean;
57
+ /**
58
+ * Stage 2: what the WHOLE group degrades to once its children have
59
+ * exhausted their ladders (and shedding, if enabled, has hit its floor): a
60
+ * single menu button or a select-style picker. Groups with neither `shed`
61
+ * nor `collapse` send children to the global overflow menu one by one.
62
+ */
63
+ readonly collapse?: 'menu' | 'select';
64
+ readonly importance?: Importance;
65
+ readonly items: readonly BarChild[];
66
+ }
67
+ /**
68
+ * Alignment regions. Separators derive between adjacent visible groups
69
+ * within a section — never across sections, never from schema data.
70
+ *
71
+ * The names are direction-aware (RTL flips start/end) and `center` is a
72
+ * SOFT contract: "balance this segment in the space left over by start and
73
+ * end". With symmetric flanks that coincides with true centering; with a
74
+ * heavy flank the segment drifts rather than fights — segments never
75
+ * overlap, matching how every toolbar convention (including v2's
76
+ * spacer-flanked tabs) treats its middle region. Strict geometric centering
77
+ * would be a solver concern (a tighter budget: 2×max(start,end)+center),
78
+ * deliberately not offered until a product needs it.
79
+ */
80
+ interface BarSections {
81
+ readonly start?: readonly BarGroup[];
82
+ readonly center?: readonly BarGroup[];
83
+ readonly end?: readonly BarGroup[];
84
+ }
85
+ interface BarSchema {
86
+ readonly id: string;
87
+ readonly sections: BarSections;
88
+ }
89
+ /** A run of command rows; separators derive between sections. */
90
+ interface MenuSection {
91
+ /** Optional section heading (i18n key). */
92
+ readonly labelKey?: string;
93
+ readonly items: readonly string[];
94
+ }
95
+ interface MenuSchema {
96
+ readonly id: string;
97
+ readonly sections: readonly MenuSection[];
98
+ }
99
+ /**
100
+ * The shell FRAME — region arrangement and visibility. Regions are a FIXED
101
+ * vocabulary (each carries semantics the shell must own: the toolbar's
102
+ * measurement physics, the document gate, aria landmarks); what's YOURS is
103
+ * where they sit, whether they show, and — through the region slots — what
104
+ * fills them. Part of the chrome value because it is structure: owned, never
105
+ * merged. Free-form layout is deliberately not offered — wanting a different
106
+ * frame architecture is what headless is for.
107
+ */
108
+ interface FrameSchema {
109
+ /** Where the main bar lives. Its mode band rides the CONTENT side (below a
110
+ * top bar, above a bottom bar). Default: 'top'. */
111
+ readonly toolbar?: 'top' | 'bottom';
112
+ /** Document tab strip: 'multiple' shows it only with >1 tab. A hidden
113
+ * region hides its SLOT too — visibility outranks slotted content.
114
+ * Default: 'always'. */
115
+ readonly tabs?: 'always' | 'multiple' | 'never';
116
+ /** The header row — a socket only: the chrome ships no header of its own,
117
+ * so it renders nothing until a `slot="header"` child fills it. `false`
118
+ * removes the socket, keeping a slotted header out. Default: true. */
119
+ readonly header?: boolean;
120
+ }
121
+ interface ChromeSchema {
122
+ /** Standalone bars (e.g. the main toolbar). */
123
+ readonly bars: Readonly<Record<string, BarSchema>>;
124
+ /** Secondary bars keyed by tool mode — WHICH one shows is derived from the
125
+ * interaction hub's active tool, never stored. */
126
+ readonly modeBars?: Readonly<Record<string, BarSchema>>;
127
+ /** Named dropdown menus referenced by commands' `menu:` targets. */
128
+ readonly menus?: Readonly<Record<string, MenuSchema>>;
129
+ /** Contextual strips (selection menus) — same BarSchema, same fit engine. */
130
+ readonly strips?: Readonly<Record<string, BarSchema>>;
131
+ /** Region arrangement & visibility. Omitted = the default frame. */
132
+ readonly frame?: FrameSchema;
133
+ }
134
+ declare function item(command: string, opts?: Omit<BarItem, 'command'>): BarItem;
135
+ declare function custom(slot: string, opts: Omit<CustomItem, 'slot'>): CustomItem;
136
+ declare function group(id: string, items: readonly BarChild[]): BarGroup;
137
+ declare function group(id: string, opts: Omit<BarGroup, 'id' | 'items'> & {
138
+ items?: readonly BarChild[];
139
+ }, items?: readonly BarChild[]): BarGroup;
140
+ type NormalizedUnit = {
141
+ readonly kind: 'command';
142
+ /** Unique within the bar: `${groupId}:${command}`. Measurement + assignment key. */
143
+ readonly key: string;
144
+ readonly command: string;
145
+ readonly variants: readonly string[];
146
+ readonly importance: Importance;
147
+ } | {
148
+ readonly kind: 'custom';
149
+ readonly key: string;
150
+ readonly slot: string;
151
+ readonly variants: readonly string[];
152
+ readonly terminal: string;
153
+ readonly importance: Importance;
154
+ };
155
+ interface NormalizedGroup {
156
+ readonly id: string;
157
+ readonly labelKey?: string;
158
+ readonly role: 'buttons' | 'tabs';
159
+ readonly shed: boolean;
160
+ readonly collapse?: 'menu' | 'select';
161
+ readonly importance: Importance;
162
+ readonly units: readonly NormalizedUnit[];
163
+ }
164
+ interface NormalizedSection {
165
+ readonly name: 'start' | 'center' | 'end';
166
+ readonly groups: readonly NormalizedGroup[];
167
+ }
168
+ interface NormalizedBar {
169
+ readonly id: string;
170
+ readonly sections: readonly NormalizedSection[];
171
+ }
172
+ declare const DEFAULT_IMPORTANCE: Importance;
173
+ /** Resolve shorthands + defaults; validate uniqueness. Solver/projection input. */
174
+ declare function normalizeBar(bar: BarSchema): NormalizedBar;
175
+ /**
176
+ * Drop units whose command is currently invisible (permissions, disabled
177
+ * categories, contextual visibility) BEFORE solving — an invisible unit must
178
+ * not consume budget or appear in the overflow. Groups that empty out vanish
179
+ * naturally in the solver's separator math and in the projection.
180
+ */
181
+ declare function filterBar(bar: NormalizedBar, keep: (unit: NormalizedUnit) => boolean): NormalizedBar;
182
+ /**
183
+ * Identity + validation. Checks what is checkable without a command registry:
184
+ * bars normalize cleanly, and every `menu` a strip/bar could reference exists
185
+ * is left to `validateChrome` (which also takes the known command ids).
186
+ */
187
+ declare function defineChrome<T extends ChromeSchema>(chrome: T): T;
188
+ /** Dev-time cross-check: every command referenced by the chrome exists. */
189
+ declare function validateChrome(chrome: ChromeSchema, knownCommands: ReadonlySet<string>): string[];
190
+ //#endregion
191
+ //#region src/transforms.d.ts
192
+ interface AddItemSpec {
193
+ /** Bar id ('main', 'annotate', …) or a modeBars surface key ('mode:annotate'). */
194
+ readonly bar: string;
195
+ readonly section: keyof BarSections;
196
+ /** Target group id. Unknown in the bar → a new group is created at the end
197
+ * of `section`; known but in a DIFFERENT section → error (group ids are
198
+ * bar-unique, so that is a contradiction, not a request). */
199
+ readonly group: string;
200
+ readonly item: BarChild;
201
+ /** Insert position within the group. Default: append. */
202
+ readonly at?: number;
203
+ }
204
+ /** Insert `spec.item` into a group of one bar. See AddItemSpec for semantics. */
205
+ declare function addItem(schema: ChromeSchema, spec: AddItemSpec): ChromeSchema;
206
+ /**
207
+ * Purge commands (or custom slots, by slot name) from every bar, mode bar,
208
+ * strip, and menu. Groups and menu sections that empty out are dropped;
209
+ * emptied menus keep their key (commands may still target them) with no rows.
210
+ */
211
+ declare function removeItems(schema: ChromeSchema, ids: readonly string[]): ChromeSchema;
212
+ /**
213
+ * Swap a command in place everywhere it appears — bars, mode bars, strips,
214
+ * and (when the replacement is itself a plain command) menu rows.
215
+ */
216
+ declare function replaceItem(schema: ChromeSchema, id: string, item: BarChild): ChromeSchema;
217
+ //#endregion
218
+ //#region src/helpers.d.ts
219
+ declare const chromeHelpers: {
220
+ readonly addItem: typeof addItem;
221
+ readonly removeItems: typeof removeItems;
222
+ readonly replaceItem: typeof replaceItem;
223
+ readonly item: typeof item;
224
+ readonly group: typeof group;
225
+ readonly custom: typeof custom;
226
+ readonly defineChrome: typeof defineChrome;
227
+ };
228
+ type ChromeHelpers = typeof chromeHelpers;
229
+ //#endregion
230
+ //#region src/solver.d.ts
231
+ interface FitMetrics {
232
+ /** Width of unit `key` rendered at `variant`; undefined = not yet measured. */
233
+ unit(key: string, variant: string): number | undefined;
234
+ /** Width of group `id` rendered in its collapsed form ('menu' | 'select'). */
235
+ groupCollapsed(groupId: string): number | undefined;
236
+ /** Width of group `id`'s disclosure trigger (shed groups only). */
237
+ groupTrigger(groupId: string): number | undefined;
238
+ /** Width of the overflow trigger button. */
239
+ readonly overflowTrigger: number;
240
+ /** Gap between adjacent visible units. */
241
+ readonly gap: number;
242
+ /** Width of a derived separator between adjacent visible groups (with its gaps). */
243
+ readonly separator: number;
244
+ }
245
+ type UnitAssignment = {
246
+ readonly kind: 'variant';
247
+ readonly variant: string;
248
+ } | {
249
+ readonly kind: 'shed';
250
+ } | {
251
+ readonly kind: 'collapsed';
252
+ } | {
253
+ readonly kind: 'overflow';
254
+ };
255
+ interface GroupAssignment {
256
+ /** How many children sit behind the group's disclosure trigger. */
257
+ readonly shedCount: number;
258
+ /** The group renders as its single collapsed control. */
259
+ readonly collapsed: boolean;
260
+ /** No part of the group is visible in the bar. */
261
+ readonly overflowed: boolean;
262
+ }
263
+ interface FitResult {
264
+ readonly units: ReadonlyMap<string, UnitAssignment>;
265
+ readonly groups: ReadonlyMap<string, GroupAssignment>;
266
+ readonly hasOverflow: boolean;
267
+ /** Total visible width at this assignment (diagnostics + tests). */
268
+ readonly width: number;
269
+ /** False when any consulted measurement was missing (treated as 0). */
270
+ readonly complete: boolean;
271
+ }
272
+ declare function solve(bar: NormalizedBar, metrics: FitMetrics, containerWidth: number): FitResult;
273
+ //#endregion
274
+ //#region src/projection.d.ts
275
+ type OverflowRow =
276
+ /** A plain command row. The renderer resolves label/icon/active from the registry. */
277
+ {
278
+ readonly type: 'command';
279
+ readonly command: string;
280
+ } |
281
+ /** A command that opens a menu — renders as `label ▸` nesting that menu. */
282
+ {
283
+ readonly type: 'submenu';
284
+ readonly command: string;
285
+ readonly menu: string;
286
+ };
287
+ interface OverflowSection {
288
+ /** From the group's labelKey — render as a section title or a nested submenu. */
289
+ readonly labelKey?: string;
290
+ /** 'radio' when the group is a tab strip: exactly one row is active. */
291
+ readonly role?: 'radio';
292
+ readonly rows: readonly OverflowRow[];
293
+ }
294
+ /**
295
+ * The one fact projection needs about a command: does it open a menu?
296
+ * (Label, icon, and active state stay live in the renderer.) Return null for
297
+ * unknown commands — they project as plain rows and resolve at render time.
298
+ */
299
+ type ResolveMenuTarget = (commandId: string) => {
300
+ menu?: string;
301
+ } | null;
302
+ declare function projectOverflow(bar: NormalizedBar, fit: FitResult, resolve: ResolveMenuTarget): OverflowSection[];
303
+ /**
304
+ * The content of a group's disclosure trigger: its shed units, in bar order,
305
+ * in menu form — same totality rules as the global overflow. This is v2's
306
+ * hand-written `mode-tabs-overflow-menu`, derived.
307
+ */
308
+ declare function projectShed(group: NormalizedGroup, fit: FitResult, resolve: ResolveMenuTarget): OverflowRow[];
309
+ /** One strip group: a separator boundary, its visible commands in bar order. */
310
+ interface StripGroup {
311
+ readonly id: string;
312
+ readonly labelKey?: string;
313
+ readonly commands: readonly string[];
314
+ }
315
+ /**
316
+ * Strip projection — a bar projected for UN-measured rendering (a contextual
317
+ * strip anchored to a selection has no fit pressure to solve). The schema
318
+ * declares what COULD appear; `visible` (the command registry's runtime truth)
319
+ * decides what DOES: hidden commands drop out, groups that empty out vanish,
320
+ * and an all-hidden bar projects to [] — "render nothing" falls out. Custom
321
+ * units project through their `terminal` command, same totality rule as the
322
+ * overflow. Upgrading a strip to measured/overflowing rendering later is a
323
+ * renderer swap (<Toolbar>), never a schema change.
324
+ */
325
+ declare function projectStrip(bar: NormalizedBar, visible: (command: string) => boolean): StripGroup[];
326
+ //#endregion
327
+ //#region src/shortcuts.d.ts
328
+ /**
329
+ * Shortcut parsing + matching — pure. No `navigator`: platform is an input
330
+ * (`isMac`), decided by the embedder, same rule as plugin-i18n's locale.
331
+ *
332
+ * Grammar: modifiers and one key joined by '+', e.g. 'Mod+K', 'Ctrl+=',
333
+ * 'Shift+Alt+D', 'Meta+NumpadAdd'. 'Mod' is ⌘ on mac and Ctrl elsewhere.
334
+ * Keys longer than one character (F1, Escape, NumpadAdd, ArrowLeft) match
335
+ * `event.key` OR `event.code` case-insensitively, so numpad shortcuts work.
336
+ */
337
+ interface ParsedShortcut {
338
+ readonly key: string;
339
+ readonly mod: boolean;
340
+ readonly ctrl: boolean;
341
+ readonly meta: boolean;
342
+ readonly alt: boolean;
343
+ readonly shift: boolean;
344
+ }
345
+ /** The subset of KeyboardEvent the matcher reads — keeps this module DOM-free. */
346
+ interface KeyStroke {
347
+ readonly key: string;
348
+ readonly code?: string;
349
+ readonly ctrlKey: boolean;
350
+ readonly metaKey: boolean;
351
+ readonly altKey: boolean;
352
+ readonly shiftKey: boolean;
353
+ }
354
+ declare function parseShortcut(shortcut: string): ParsedShortcut;
355
+ declare function matchShortcut(parsed: ParsedShortcut, stroke: KeyStroke, opts: {
356
+ isMac: boolean;
357
+ }): boolean;
358
+ /** Display form for menu rows: '⌘K' on mac, 'Ctrl+K' elsewhere. */
359
+ declare function formatShortcut(shortcut: string, opts: {
360
+ isMac: boolean;
361
+ }): string;
362
+ //#endregion
363
+ export { type AddItemSpec, type BarChild, type BarGroup, type BarItem, type BarSchema, type BarSections, type ChromeHelpers, type ChromeSchema, type CustomItem, DEFAULT_IMPORTANCE, type FitMetrics, type FitResult, type FrameSchema, type GroupAssignment, type Importance, type KeyStroke, type MenuSchema, type MenuSection, type NormalizedBar, type NormalizedGroup, type NormalizedSection, type NormalizedUnit, type OverflowRow, type OverflowSection, PINNED, type ParsedShortcut, type ResolveMenuTarget, type StripGroup, type UnitAssignment, type Variant, addItem, chromeHelpers, custom, defineChrome, filterBar, formatShortcut, group, item, matchShortcut, normalizeBar, parseShortcut, projectOverflow, projectShed, projectStrip, removeItems, replaceItem, solve, validateChrome };
364
+ //# sourceMappingURL=index.d.cts.map