Files
dating-app-frontend/.claude/skills/impeccable/scripts/live-ui-core.mjs
2026-06-08 13:23:20 +03:00

180 lines
5.4 KiB
JavaScript

/**
* Framework-neutral Impeccable live chrome contract.
*
* The production browser bundle is intentionally plain DOM so Svelte, React,
* Vue, and static adapters can all mount the same chrome. This module is the
* testable contract/inventory for that bundle; live-browser.js mirrors these
* values at runtime because it is served as a standalone script.
*/
export const LIVE_CHROME_MOUNT_CONTRACT = Object.freeze([
'root',
'transport',
'state',
'actions',
]);
export const LIVE_UI_SURFACES = Object.freeze([
{
key: 'global-bottom-bar',
ids: [
'impeccable-live-global-bar',
'impeccable-live-global-bar-brand',
'impeccable-live-pick-toggle',
'impeccable-live-insert-toggle',
'impeccable-live-detect-toggle',
'impeccable-live-detect-badge',
'impeccable-live-design-toggle',
'impeccable-live-page-chat',
'impeccable-live-page-chat-input',
'impeccable-live-page-chat-voice',
],
states: ['rest', 'hover', 'focus-visible', 'pressed', 'active', 'tooltip'],
},
{
key: 'pending-copy-edit-dock',
ids: ['impeccable-live-pending-dock'],
states: ['closed', 'open', 'hover', 'pressed', 'loading', 'rollback', 'keep-fixing'],
},
{
key: 'element-selection-chrome',
ids: [
'impeccable-live-highlight',
'impeccable-live-tooltip',
'impeccable-live-bar',
'impeccable-live-configure-input-wrap',
'impeccable-live-input',
'impeccable-live-configure-voice',
],
states: ['rest', 'hover', 'focus-visible', 'pressed', 'disabled'],
},
{
key: 'action-picker',
ids: ['impeccable-live-picker'],
states: ['closed', 'open', 'option-hover', 'option-focus'],
},
{
key: 'edit-chrome',
ids: ['impeccable-live-edit-badge'],
states: ['enabled', 'disabled', 'editing', 'cancel', 'save', 'edited-content'],
},
{
key: 'generating-row',
ids: ['impeccable-live-bar', 'impeccable-live-shader'],
states: ['action-label', 'animated-dots', 'generating', 'done'],
},
{
key: 'variant-cycling-row',
ids: ['impeccable-live-bar', 'impeccable-live-params-panel'],
states: ['variant-1', 'variant-2', 'variant-3', 'left-disabled', 'right-disabled', 'dot-click', 'accept', 'discard'],
},
{
key: 'variant-params-panel',
ids: ['impeccable-live-params-panel'],
states: ['closed', 'open-above', 'open-below', 'range', 'steps', 'toggle'],
},
{
key: 'saving-confirmed-rows',
ids: ['impeccable-live-bar'],
states: ['saving', 'applying-variant', 'confirmed'],
},
{
key: 'insert-mode-chrome',
ids: [
'impeccable-live-insert-line',
'impeccable-live-insert-placeholder',
'impeccable-live-placeholder-resize',
'impeccable-live-insert-input',
'impeccable-live-insert-voice',
'impeccable-live-insert-create',
'impeccable-live-insert-create-tooltip',
],
states: ['toggle-active', 'line', 'placeholder', 'resize', 'enabled', 'disabled', 'tooltip'],
},
{
key: 'annotation-chrome',
ids: [
'impeccable-live-annot',
'impeccable-live-annot-svg',
'impeccable-live-annot-pins',
'impeccable-live-annot-clear',
],
states: ['overlay', 'drawing', 'pin', 'pin-edit', 'clear'],
},
{
key: 'design-system-panel',
ids: ['impeccable-live-design-host'],
states: ['closed', 'open', 'tabs', 'token-tiles', 'copy'],
},
{
key: 'toasts-and-errors',
ids: ['impeccable-live-toast'],
states: ['normal', 'error', 'no-variants-mounted'],
},
{
key: 'css-isolation-boundary',
ids: ['impeccable-live-root'],
states: ['shadow-root', 'style-tags', 'hostile-css'],
},
]);
export const LIVE_UI_COMPONENT_IDS = Object.freeze([
...new Set(LIVE_UI_SURFACES.flatMap((surface) => surface.ids)),
]);
export function resolveLiveUiRoot(env = globalThis) {
const doc = env?.document;
const explicit = env?.__IMPECCABLE_LIVE_UI_ROOT__
|| env?.window?.__IMPECCABLE_LIVE_UI_ROOT__;
if (explicit && typeof explicit.appendChild === 'function') return explicit;
return doc?.body || null;
}
export function getLiveUiElementById(id, env = globalThis) {
const doc = env?.document;
const root = resolveLiveUiRoot(env);
if (!id) return null;
if (root?.getElementById) {
const found = root.getElementById(id);
if (found) return found;
}
if (root?.querySelector) {
const found = root.querySelector('#' + escapeCssIdent(id));
if (found) return found;
}
return doc?.getElementById?.(id) || null;
}
export function appendToLiveUiRoot(el, env = globalThis) {
const root = resolveLiveUiRoot(env);
if (!root) throw new Error('Impeccable live UI root is not available');
root.appendChild(el);
return el;
}
export function appendStyleToLiveUiRoot(styleEl, env = globalThis) {
const doc = env?.document;
const root = resolveLiveUiRoot(env);
if (root && root !== doc?.body) {
root.appendChild(styleEl);
} else {
(doc?.head || doc?.body || root).appendChild(styleEl);
}
return styleEl;
}
export function activeElementDeep(doc = globalThis.document) {
let active = doc?.activeElement || null;
while (active?.shadowRoot?.activeElement) {
active = active.shadowRoot.activeElement;
}
return active;
}
function escapeCssIdent(value) {
if (typeof CSS !== 'undefined' && typeof CSS.escape === 'function') {
return CSS.escape(String(value));
}
return String(value).replace(/([ !"#$%&'()*+,./:;<=>?@[\\\]^`{|}~])/g, '\\$1');
}