@2lab.ai/ui 0.0.0-stage → 0.2.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.
- package/README.md +55 -2
- package/dist/agent-inbox.js +1061 -0
- package/dist/agent-inbox.js.map +1 -0
- package/dist/agent-queue.js +1610 -0
- package/dist/agent-queue.js.map +1 -0
- package/dist/agent-run.js +859 -0
- package/dist/agent-run.js.map +1 -0
- package/dist/ai-answer.js +687 -0
- package/dist/ai-answer.js.map +1 -0
- package/dist/components/agent-inbox/agent-inbox.d.ts +158 -0
- package/dist/components/agent-inbox/index.d.ts +2 -0
- package/dist/components/agent-inbox/styles.d.ts +6 -0
- package/dist/components/agent-queue/agent-queue.d.ts +41 -0
- package/dist/components/agent-queue/index.d.ts +6 -0
- package/dist/components/agent-queue/logic.d.ts +261 -0
- package/dist/components/agent-queue/strings.d.ts +473 -0
- package/dist/components/agent-queue/styles.d.ts +8 -0
- package/dist/components/agent-run/agent-run.d.ts +273 -0
- package/dist/components/agent-run/index.d.ts +2 -0
- package/dist/components/agent-run/styles.d.ts +6 -0
- package/dist/components/ai-answer/ai-answer.d.ts +92 -0
- package/dist/components/ai-answer/index.d.ts +2 -0
- package/dist/components/ai-answer/styles.d.ts +2 -0
- package/dist/components/context-window/context-window.d.ts +156 -0
- package/dist/components/context-window/index.d.ts +2 -0
- package/dist/components/context-window/styles.d.ts +2 -0
- package/dist/components/memory-panel/index.d.ts +2 -0
- package/dist/components/memory-panel/memory-panel.d.ts +101 -0
- package/dist/components/memory-panel/styles.d.ts +2 -0
- package/dist/components/model-picker/index.d.ts +2 -0
- package/dist/components/model-picker/model-picker.d.ts +136 -0
- package/dist/components/model-picker/morph.d.ts +9 -0
- package/dist/components/model-picker/styles.d.ts +6 -0
- package/dist/components/tool-call-card/index.d.ts +7 -0
- package/dist/components/tool-call-card/logic.d.ts +87 -0
- package/dist/components/tool-call-card/strings.d.ts +94 -0
- package/dist/components/tool-call-card/styles.d.ts +5 -0
- package/dist/components/tool-call-card/tool-call-card.d.ts +49 -0
- package/dist/components/tool-call-card/tool-call-group.d.ts +32 -0
- package/dist/context-window.js +384 -0
- package/dist/context-window.js.map +1 -0
- package/dist/core/element.d.ts +41 -0
- package/dist/core/format.d.ts +14 -0
- package/dist/core/html.d.ts +10 -0
- package/dist/core/tokens.d.ts +14 -0
- package/dist/format-BBGWXPzk.js +51 -0
- package/dist/format-BBGWXPzk.js.map +1 -0
- package/dist/html-elD6Bb_u.js +175 -0
- package/dist/html-elD6Bb_u.js.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.js +129 -0
- package/dist/index.js.map +1 -0
- package/dist/memory-panel.js +1255 -0
- package/dist/memory-panel.js.map +1 -0
- package/dist/model-picker.js +858 -0
- package/dist/model-picker.js.map +1 -0
- package/dist/tokens.css +4 -0
- package/dist/tool-call-card.js +1046 -0
- package/dist/tool-call-card.js.map +1 -0
- package/package.json +79 -4
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model-picker.js","sources":["../src/components/model-picker/morph.ts","../src/components/model-picker/styles.ts","../src/components/model-picker/model-picker.ts"],"sourcesContent":["/**\n * Bring a live subtree in line with freshly rendered markup, keeping every node whose place did not change —\n * so focus, a running transition (the menu's open/close, the effort thumb) and live-region text nodes survive\n * a re-render. Ported from the soma-work dashboard's `morphInnerHtml` (spec 12).\n *\n * Children pair up in order. A node with `data-mk` pairs only with the node of the same key (a row that stands\n * for one model never turns into another model's row); unkeyed nodes pair by tag + id + first class.\n */\nexport function morphInto(el: Element, html: string): void {\n const tpl = document.createElement('template');\n tpl.innerHTML = html;\n morphChildren(el, tpl.content);\n}\n\nfunction keyOf(n: Node): string {\n if (n.nodeType !== 1) return `#${n.nodeType}`;\n const e = n as Element;\n const k = e.getAttribute('data-mk');\n if (k !== null) return `${e.tagName}|@${k}`;\n const c = e.getAttribute('class') || '';\n const sp = c.indexOf(' ');\n return `${e.tagName}|${e.id}.${sp < 0 ? c : c.slice(0, sp)}`;\n}\n\nfunction keyLater(n: Node | null, key: string): boolean {\n for (; n; n = n.nextSibling) if (keyOf(n) === key) return true;\n return false;\n}\n\nfunction morphNode(a: Node, b: Node): void {\n if (a.nodeType !== 1) {\n if (a.nodeValue !== b.nodeValue) a.nodeValue = b.nodeValue;\n return;\n }\n const ae = a as Element;\n const be = b as Element;\n for (let i = ae.attributes.length - 1; i >= 0; i--) {\n const name = ae.attributes[i].name;\n if (!be.hasAttribute(name)) ae.removeAttribute(name);\n }\n for (let i = 0; i < be.attributes.length; i++) {\n const at = be.attributes[i];\n if (ae.getAttribute(at.name) !== at.value) ae.setAttribute(at.name, at.value);\n }\n morphChildren(ae, be);\n}\n\nfunction morphChildren(a: Node, b: Node): void {\n let cur = a.firstChild;\n let next = b.firstChild;\n while (next) {\n // A live node the fresh markup no longer has goes first, so the nodes after it still pair with their own.\n if (cur && keyOf(cur) !== keyOf(next) && !keyLater(next, keyOf(cur))) {\n const dropped = cur;\n cur = cur.nextSibling;\n a.removeChild(dropped);\n continue;\n }\n const after: ChildNode | null = next.nextSibling;\n if (cur && keyOf(cur) === keyOf(next)) {\n morphNode(cur, next);\n cur = cur.nextSibling;\n } else {\n a.insertBefore(next, cur);\n }\n next = after;\n }\n while (cur) {\n const gone = cur;\n cur = cur.nextSibling;\n a.removeChild(gone);\n }\n}\n","/**\n * Ported from the soma-work dashboard (\"MODEL · EFFORT MENU\", .prd/affectui/re-model-picker.md D1, D2, D13–D15).\n * The dashboard's own --mp-well / --mp-bar / --mp-bar-off pairs (dark #2e2e33 · #5a5a62 · #35353b, light #f1f1f3 ·\n * #c9c9d0 · #e6e6ea) are derived from the card and text tokens, so both themes follow any page palette.\n */\nexport const styles = `\n:host { --mp-well: color-mix(in srgb, var(--ib-text) 6%, var(--ib-card)); --mp-bar: color-mix(in srgb, var(--ib-text) 24%, var(--ib-card));\n --mp-bar-off: color-mix(in srgb, var(--ib-text) 9%, var(--ib-card));\n display: inline-block; max-width: 100%; vertical-align: middle; }\n.mp { display: flex; flex-direction: column; align-items: flex-start; gap: 4px; min-width: 0; max-width: 100%; }\n.mp-trigger { display: inline-flex; align-items: center; gap: 6px; max-width: 100%; min-width: 0; min-height: 30px; padding: 0 9px 0 5px; font: inherit; font-size: 13px; font-weight: 500; color: var(--ib-text); background: var(--ib-seg); border: 1px solid var(--ib-card-border); border-radius: 8px; cursor: pointer; white-space: nowrap; transition: background-color var(--dur-press) var(--ease-out); }\n.mp-trigger:not([aria-disabled=\"true\"]):hover, .mp-trigger[aria-expanded=\"true\"] { background: var(--mp-well); }\n.mp-trigger:focus-visible { outline: 2px solid var(--border-focus); outline-offset: 2px; }\n.mp-trigger[aria-busy=\"true\"] { cursor: progress; }\n.mp-trigger[aria-disabled=\"true\"] { cursor: default; background: transparent; border-color: transparent; }\n.mp-trigger[aria-disabled=\"true\"] .mp-chev { display: none; }\n.mp-trigger .mp-glyph { width: 18px; height: 18px; border-radius: 5px; font-size: 10px; }\n.mp-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; }\n.mp-level { flex: none; font-weight: 400; color: var(--ib-text-2); }\n.mp-chev { flex: none; width: 6px; height: 6px; margin: 0 1px 0 2px; border-right: 1.5px solid var(--ib-muted); border-bottom: 1.5px solid var(--ib-muted); transform: translateY(-2px) rotate(45deg); transition: transform 300ms var(--ease-out); }\n.mp-trigger[aria-expanded=\"true\"] .mp-chev { transform: translateY(1px) rotate(225deg); }\n.mp-glyph { display: inline-grid; flex: none; place-items: center; width: 22px; height: 22px; border-radius: 6px; background: var(--ib-card); box-shadow: inset 0 0 0 1px var(--ib-card-border); font-size: 10.5px; font-weight: 600; line-height: 1; color: var(--ib-text); }\n.mp-note { max-width: 100%; font-size: 12px; line-height: 17px; color: var(--ib-text-2); overflow-wrap: anywhere; }\n.mp-note.is-error { color: var(--st-fail-text); }\n.mp-note:empty { display: none; }\n/* A fixed 100px box at 0,0: tells the menu its containing block's origin and scale (transformed ancestors). */\n.mp-probe { position: fixed; left: 0; top: 0; width: 100px; height: 0; visibility: hidden; pointer-events: none; }\n/* The menu: position fixed (an ancestor's overflow clip never cuts it), placed from the trigger in script. */\n.mp-pop { position: fixed; z-index: 150; left: 0; top: 0; box-sizing: border-box; width: min(336px, calc(100vw - 32px)); max-height: calc(100vh - 24px); overflow-y: auto; overscroll-behavior: contain; container: mp / inline-size; padding: 4px; border-radius: 16px; background: var(--ib-col); box-shadow: 0 0 0 1px var(--ib-card-border), var(--ib-shadow-raised); color: var(--ib-text-2); font-size: 13px; line-height: 20px; text-align: left; white-space: normal; transform-origin: top left; opacity: 0; visibility: hidden; pointer-events: none; transform: translateY(-4px) scale(0.96); transition: opacity 160ms ease, transform 220ms var(--ease-out), visibility 0s linear 220ms; }\n.mp-pop[data-side=\"top\"] { transform-origin: bottom left; transform: translateY(4px) scale(0.96); }\n.mp-pop.is-open { opacity: 1; visibility: visible; transform: none; pointer-events: auto; transition: opacity 200ms ease, transform var(--dur-move) var(--ease-out), visibility 0s; }\n.mp-card { padding: 6px; border-radius: 12px; background: var(--ib-card); box-shadow: 0 0 0 1px var(--ib-card-border), var(--ib-shadow); }\n.mp-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; height: 24px; padding: 0 10px; font-size: 11px; line-height: 16px; color: var(--ib-muted); }\n.mp-head-t { min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }\n.mp-cols, .mp-bars { display: grid; flex: none; grid-template-columns: repeat(3, 36px); gap: 8px; }\n.mp-cols { font-size: 10px; letter-spacing: -0.01em; }\n.mp-cols > span { display: flex; justify-content: center; white-space: nowrap; }\n.mp-wait { margin: 0 10px 4px; font-size: 12px; line-height: 17px; color: var(--st-wait); overflow-wrap: anywhere; }\n.mp-list { display: grid; gap: 1px; border-radius: 10px; outline: none; }\n.mp-opt { display: grid; grid-template-columns: 22px minmax(0, 1fr) auto; grid-template-areas: \"g t b\" \"g d d\"; align-items: center; column-gap: 10px; min-height: 48px; padding: 6px 10px; border-radius: 10px; cursor: pointer; transition: background-color var(--dur-press) ease, opacity 220ms ease; }\n.mp-opt > .mp-glyph { grid-area: g; }\n.mp-opt > .mp-bars { grid-area: b; }\n.mp-opt[aria-disabled=\"true\"] { cursor: default; }\n.mp-list[aria-disabled=\"true\"] .mp-opt:not([aria-selected=\"true\"]) .mp-title { color: var(--ib-text-2); }\n.mp-list[data-pointing] .mp-opt[data-active] { background: var(--mp-well); }\n.mp-list[data-pointing] .mp-opt:not([data-active]) { opacity: 0.5; }\n.mp-list:focus-visible .mp-opt[data-active] { background: var(--mp-well); box-shadow: inset 0 0 0 1.5px var(--border-focus); }\n.mp-title { grid-area: t; display: flex; align-items: center; gap: 4px; min-width: 0; font-weight: 500; color: var(--ib-text); }\n.mp-title-name { min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }\n.mp-check { flex: none; font-size: 12px; line-height: 1; color: var(--accent); animation: mp-pop 320ms var(--ease-out) both; }\n.mp-desc { grid-area: d; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden; font-size: 12px; line-height: 17px; color: var(--ib-muted); overflow-wrap: anywhere; }\n.mp-meter { display: grid; grid-template-columns: repeat(5, 1fr); gap: 2px; height: 5px; }\n.mp-meter.is-none { display: block; height: auto; font-size: 11px; line-height: 1; text-align: center; color: var(--ib-muted); }\n.mp-seg { border-radius: 1.5px; background: var(--mp-bar-off); transition: background-color 180ms ease; }\n.mp-seg[data-on] { background: var(--mp-bar); }\n.mp-opt[data-lit] .mp-seg[data-on] { background: var(--accent); transition-delay: calc(var(--c) * 70ms + var(--s) * 45ms); animation: mp-fill 360ms var(--ease-out) both; animation-delay: calc(var(--c) * 70ms + var(--s) * 45ms); }\n.mp-settings { margin-top: 6px; padding: 6px 10px 4px; border-top: 1px solid var(--ib-card-border); }\n.mp-effort-head { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; min-height: 22px; }\n.mp-effort-label { flex: none; font-size: 12.5px; color: var(--ib-text-2); }\n.mp-effort-cap { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 12px; color: var(--st-wait); }\n.mp-seg-ctl { position: relative; display: grid; grid-template-columns: repeat(var(--n), minmax(0, 1fr)); margin-top: 4px; padding: 2px; border-radius: 9px; background: var(--ib-seg); box-shadow: inset 0 0 0 1px var(--ib-card-border); }\n.mp-thumb { position: absolute; top: 2px; bottom: 2px; left: 2px; width: calc((100% - 4px) / var(--n)); border-radius: 7px; background: var(--ib-seg-on); box-shadow: 0 0 0 1px var(--ib-card-border), 0 1px 2px color-mix(in srgb, #000 12%, transparent); transform: translateX(calc(var(--i) * 100%)); transition: transform var(--dur-move) var(--ease-out); }\n.mp-seg-btn { position: relative; min-width: 0; min-height: 26px; padding: 0 2px; font: inherit; font-size: 12px; font-weight: 500; color: var(--ib-muted); background: none; border: 0; border-radius: 7px; cursor: pointer; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; transition: color 200ms ease; }\n.mp-seg-btn[aria-checked=\"true\"], .mp-seg-btn:hover { color: var(--ib-text); }\n.mp-seg-btn:focus-visible { outline: 2px solid var(--border-focus); outline-offset: -2px; }\n.mp-seg-ctl[aria-disabled=\"true\"] .mp-seg-btn { cursor: progress; }\n.mp-err { margin: 6px 10px 2px; font-size: 12px; line-height: 17px; color: var(--st-fail-text); overflow-wrap: anywhere; }\n.mp-err:empty { display: none; }\n.mp-foot { display: flex; align-items: center; gap: 6px; min-height: 38px; padding: 4px 6px 0 10px; }\n.mp-caption { flex: 1; min-width: 0; overflow: hidden; font-size: 12px; color: var(--ib-muted); white-space: nowrap; text-overflow: ellipsis; font-variant-numeric: tabular-nums; }\n.mp-caption b { font-weight: 500; color: var(--ib-text); }\n.mp-keys { display: flex; flex: none; gap: 2px; }\n.mp-keys kbd { display: grid; place-items: center; min-width: 18px; height: 18px; padding: 0 3px; border-radius: 5px; background: var(--ib-card); box-shadow: 0 0 0 1px var(--ib-card-border); font-family: inherit; font-size: 10.5px; line-height: 1; color: var(--ib-muted); }\n@keyframes mp-pop { from { opacity: 0; transform: scale(0.6); } }\n@keyframes mp-fill { 0% { transform: scaleY(1); } 45% { transform: scaleY(1.6); } 100% { transform: scaleY(1); } }\n@container mp (max-width: 300px) {\n .mp-opt .mp-glyph, .mp-keys { display: none; }\n .mp-opt { grid-template-columns: minmax(0, 1fr) auto; grid-template-areas: \"t b\" \"d d\"; }\n}\n/* Touch / narrow: the dashboard's own block — trigger and levels ≥44px, rows ≥54px, no key hints. */\n@media (pointer: coarse), (max-width: 639px) {\n .mp-trigger, .mp-seg-btn { min-height: 44px; }\n .mp-opt { min-height: 54px; }\n .mp-keys { display: none; }\n}\n/* The global rule shortens durations; scale, the staggered fill and the check pop stop here too. */\n@media (prefers-reduced-motion: reduce) {\n .mp-pop, .mp-pop[data-side=\"top\"] { transform: none; }\n .mp-opt[data-lit] .mp-seg[data-on] { animation: none; transition-delay: 0s; }\n .mp-check { animation: none; }\n}\n`;\n","import { define, prefersReducedMotion, UiElement } from '../../core/element';\nimport { esc, escAttr } from '../../core/html';\nimport { morphInto } from './morph';\nimport { styles } from './styles';\n\n/** USD per million tokens. */\nexport interface ModelPrice {\n input: number;\n output: number;\n}\n\n/** One model the session can switch to. */\nexport interface PickerModel {\n /** What `ui-change` carries back (the host's switch key, e.g. `opus[1m]` or a full model id). */\n id: string;\n /** Display name, e.g. `Opus 5.5 (1M)`. */\n label: string;\n /** Compact name for the description line and the avatar letter (defaults: id / label). */\n short?: string;\n /** Context window in tokens. */\n window?: number;\n /** The model's own auto-compact threshold in tokens. */\n autoCompactAt?: number;\n /** Price per million tokens; `null` / missing = unknown (never guessed). */\n price?: ModelPrice | null;\n /** Effort levels this model runs, in order. Missing = the five standard levels; `[]` = no effort control. */\n effortLevels?: string[];\n /** Override the 5-segment meters (0–5, 0 draws \"—\"). By default they are measured against the largest in the list. */\n bars?: { window?: number; compaction?: number; cost?: number };\n}\n\nexport interface ModelPickerValue {\n /** The session's model id. When it is not in `models` it is shown as a first, unselectable row. */\n model: string;\n /** The effort level that was set. */\n effort?: string;\n /** The level that actually runs when the model caps the set one (e.g. set Max → runs High). */\n effectiveEffort?: string;\n}\n\nexport interface ModelPickerData {\n models: PickerModel[];\n value: ModelPickerValue;\n /** Tokens in the session's context now: a row whose auto-compact point is below it says it switches after compaction. */\n contextTokens?: number;\n /** `true` = read-only; a string = read-only with that reason (tooltip + description). */\n disabled?: boolean | string;\n /** A write in flight. `model`: rows locked (a string replaces the \"Switching model…\" line); `effort`: levels locked. */\n busy?: { model?: boolean | string; effort?: boolean };\n /** Last write failed — announced with role=\"alert\" (inside the open menu, or under the trigger). */\n error?: string;\n}\n\n/** `ui-change` detail. */\nexport interface ModelPickerChange {\n model: string;\n effort?: string;\n /** Which of the two the person changed. */\n changed: 'model' | 'effort';\n}\n\nexport type ModelMenuSide = 'top' | 'bottom';\nexport type ModelMeters = [window: number, compaction: number, cost: number];\n\n/** The standard effort levels, in order (the dashboard's MODEL_EFFORT_LEVELS). */\nexport const MODEL_EFFORT_LEVELS = ['low', 'medium', 'high', 'xhigh', 'max'];\nconst EFFORT_LABELS: Record<string, string> = {\n low: 'Low',\n medium: 'Medium',\n high: 'High',\n xhigh: 'Extra high',\n max: 'Max',\n};\nconst EFFORT_SHORT: Record<string, string> = { low: 'Low', medium: 'Medium', high: 'High', xhigh: 'XHigh', max: 'Max' };\nconst ROLL_MS = 560;\nconst WATCH_MS = 150;\n\nconst STRINGS = {\n en: {\n model: 'Model',\n trigger: (name: string, level: string) => `Model ${name}${level ? `, effort ${level}` : ''} — change`,\n dialog: 'Model and effort for this session',\n head: 'This session model',\n cols: ['Window', 'Compact', 'Cost'],\n list: 'Models',\n after: 'switches after compaction',\n outside: 'Current · not in the switch list',\n outsideTray: 'Not in the switch list · price unknown',\n outsideSr: 'Not in the switch list, price unknown',\n win: (w: string) => `window ${w}`,\n winSr: (w: string) => `window ${w}`,\n tray: (i: string, o: string) => `Input ${i} · Output ${o} / M`,\n noPrice: 'Price —',\n priceWords: (i: string, o: string) => `input ${i} · output ${o} per million tokens`,\n noPriceWords: 'price unknown',\n switching: 'Switching model…',\n effort: 'Effort',\n cap: (set: string, runs: string) => `Set ${set} → this model runs ${runs}`,\n },\n ko: {\n model: '모델',\n trigger: (name: string, level: string) => `모델 ${name}${level ? `, effort ${level}` : ''} — 바꾸기`,\n dialog: '이 세션의 모델 · effort',\n head: '이 세션 모델',\n cols: ['창', '압축', '비용'],\n list: '모델',\n after: 'compact 후 전환',\n outside: '현재 · 전환 목록 밖',\n outsideTray: '전환 목록 밖 모델 · 가격 정보 없음',\n outsideSr: '전환 목록 밖 모델, 가격 정보 없음',\n win: (w: string) => `창 ${w}`,\n winSr: (w: string) => `창 ${w}`,\n tray: (i: string, o: string) => `입력 ${i} · 출력 ${o} / M`,\n noPrice: '가격 정보 없음',\n priceWords: (i: string, o: string) => `입력 ${i} · 출력 ${o} / 백만 토큰`,\n noPriceWords: '가격 정보 없음',\n switching: '모델 전환 중…',\n effort: 'Effort',\n cap: (set: string, runs: string) => `설정 ${set} → 이 모델은 ${runs}까지 실행`,\n },\n};\ntype Strings = (typeof STRINGS)['en'];\n\nconst CHECK = '✓';\n\nconst num = (v: unknown): number => {\n const n = Number(v);\n return Number.isFinite(n) ? n : 0;\n};\n\n/** Filled segments of a 5-segment meter: `v` against the largest of the list, at least 1; 0 when unknown. */\nexport function meterSegments(v: unknown, max: unknown): number {\n const a = num(v);\n const m = num(max);\n if (!(a > 0) || !(m > 0)) return 0;\n return Math.max(1, Math.min(5, Math.round((5 * a) / m)));\n}\n\nfunction barOr(v: unknown, fallback: number): number {\n if (v === undefined || v === null) return fallback;\n return Math.max(0, Math.min(5, Math.round(num(v))));\n}\n\n/** A price both of whose numbers are real, else null (unknown stays unknown). */\nexport function validModelPrice(p: ModelPrice | null | undefined): ModelPrice | null {\n if (!p) return null;\n const input = Number(p.input);\n const output = Number(p.output);\n return Number.isFinite(input) && Number.isFinite(output) && input >= 0 && output >= 0 ? { input, output } : null;\n}\n\n/** Window · compaction · cost meters per model: the host's `bars`, else against the list's largest value. */\nexport function modelMeters(models: PickerModel[]): ModelMeters[] {\n let win = 0;\n let ac = 0;\n let out = 0;\n for (const m of models) {\n win = Math.max(win, num(m.window));\n ac = Math.max(ac, num(m.autoCompactAt));\n out = Math.max(out, validModelPrice(m.price)?.output ?? 0);\n }\n return models.map((m) => {\n const p = validModelPrice(m.price);\n return [\n barOr(m.bars?.window, meterSegments(m.window, win)),\n barOr(m.bars?.compaction, meterSegments(m.autoCompactAt, ac)),\n barOr(m.bars?.cost, p ? meterSegments(p.output, out) : 0),\n ];\n });\n}\n\n/** Token counts the way the dashboard's model menu shows them: 950 · 450.0K · 1.0M. */\nexport function fmtModelTokens(n: unknown): string {\n let v = Math.max(0, num(n));\n if (v < 999.5) return String(Math.round(v));\n for (const unit of ['K', 'M', 'B', 'T']) {\n v /= 1000;\n if (v < 999.95) return `${v.toFixed(1)}${unit}`;\n }\n return '999.9T+';\n}\n\n/** Dollars, whole when the target is whole: $5, $2.50 (a rolling value keeps its target's form). */\nexport function fmtModelPrice(v: unknown, ref?: unknown): string {\n const n = num(v);\n const t = ref === undefined ? n : num(ref);\n return `$${Math.round(t) === t ? String(Math.round(n)) : n.toFixed(2)}`;\n}\n\n/** The effort levels a model runs: its own list (deduped), the standard five when it has none, [] = no control. */\nexport function modelEffortLevels(model?: PickerModel | null): string[] {\n if (!model || !Array.isArray(model.effortLevels)) return MODEL_EFFORT_LEVELS.slice();\n const out: string[] = [];\n for (const l of model.effortLevels) {\n const s = String(l ?? '');\n if (s && !out.includes(s)) out.push(s);\n }\n return out;\n}\n\nexport function modelEffortLabel(level?: string): string {\n return level ? (EFFORT_LABELS[level] ?? level) : '';\n}\n\n/** The avatar letter: first character of the short name (or label), upper-cased. */\nexport function modelGlyph(m: { short?: string; label?: string; id?: string }): string {\n const src = String(m.short || m.label || m.id || '?');\n return (Array.from(src)[0] ?? '?').toUpperCase();\n}\n\n/** Below this much room on the chosen side the menu covers its trigger instead of turning into a short scroller. */\nconst MIN_ROOM = 180;\n\n/**\n * Where the menu goes (viewport px): under (`bottom`) or over (`top`) the trigger, flipped when that side\n * has no room and the other has more, left edge on the trigger's, kept 12px inside the viewport. When the\n * chosen side is too short for the whole menu it gets that side's height and scrolls (`maxHeight`), so the\n * trigger stays visible; only when even that is under 180px does it slide over the trigger.\n */\nexport function placeModelMenu(\n r: { top: number; bottom: number; left: number },\n w: number,\n h: number,\n vw: number,\n vh: number,\n side: ModelMenuSide = 'bottom',\n): { left: number; top: number; side: ModelMenuSide; maxHeight: number } {\n const gap = 6;\n const edge = 12;\n const below = vh - r.bottom - gap - edge;\n const above = r.top - gap - edge;\n const s: ModelMenuSide =\n side === 'top' ? (h > above && below > above ? 'bottom' : 'top') : h > below && above > below ? 'top' : 'bottom';\n const room = s === 'top' ? above : below;\n const full = Math.max(0, vh - 2 * edge);\n const fit = h > room && room >= MIN_ROOM ? room : Math.min(h, full);\n const left = Math.max(edge, Math.min(r.left, vw - edge - w));\n let top = s === 'top' ? r.top - gap - fit : r.bottom + gap;\n top = Math.max(edge, Math.min(top, vh - edge - fit));\n return {\n left: Math.round(left),\n top: Math.round(top),\n side: s,\n maxHeight: Math.floor(h > room && room >= MIN_ROOM ? room : full),\n };\n}\n\nexport interface AnchorSpot {\n left: number;\n top: number;\n}\n\nfunction flatParent(n: Element): Element | null {\n if (n.assignedSlot) return n.assignedSlot;\n const p = n.parentNode;\n if (!p) return null;\n if (p.nodeType === 11) return (p as ShadowRoot).host ?? null;\n return p.nodeType === 1 ? (p as Element) : null;\n}\n\n/**\n * The trigger's place in its layout: its viewport position plus the scroll offsets of every ancestor up to\n * (and including) the first `position: fixed` one, crossing shadow roots. Scrolling leaves it unchanged —\n * also a page scroll under a fixed panel — so only a layout move (a card that changed column) changes it.\n */\nexport function anchorSpot(el: Element): AnchorSpot {\n const r = el.getBoundingClientRect();\n let x = r.left;\n let y = r.top;\n for (let n = flatParent(el); n; n = flatParent(n)) {\n x += n.scrollLeft || 0;\n y += n.scrollTop || 0;\n if (getComputedStyle(n).position === 'fixed') break;\n }\n return { left: x, top: y };\n}\n\n/** The anchor moved more than 2px in its layout. */\nexport function anchorMoved(at: AnchorSpot | null, now: AnchorSpot | null): boolean {\n if (!at || !now) return false;\n return Math.abs(now.left - at.left) > 2 || Math.abs(now.top - at.top) > 2;\n}\n\ninterface Opt {\n /** The model id; '' for the session's own model when it is outside the list. */\n key: string;\n model: PickerModel;\n listed: boolean;\n meters: ModelMeters;\n}\n\n/** The rows: the session's model first when it is not in the list (current, not selectable), then the list. */\nfunction pickerOptions(d: ModelPickerData): Opt[] {\n const seen = new Set<string>();\n const models: PickerModel[] = [];\n for (const m of Array.isArray(d.models) ? d.models : []) {\n if (!m || typeof m.id !== 'string' || !m.id || seen.has(m.id)) continue;\n seen.add(m.id);\n models.push(m);\n }\n const meters = modelMeters(models);\n const cur = d.value?.model ?? '';\n const out: Opt[] = [];\n if (cur && !seen.has(cur)) out.push({ key: '', model: { id: cur, label: cur }, listed: false, meters: [0, 0, 0] });\n models.forEach((m, i) => {\n out.push({ key: m.id, model: m, listed: true, meters: meters[i] });\n });\n return out;\n}\n\nfunction currentIndex(opts: Opt[], cur: string): number {\n if (!cur) return -1;\n return opts.findIndex((o) => o.key === '' || o.key === cur);\n}\n\n/**\n * `<ui-model-picker>` — one trigger (avatar · model · effort · chevron) that opens the session's model menu:\n * every model with its window, auto-compact point and cost as 5-segment meters, the effort levels that model\n * runs, and a tray with the price. Picking a model or a level sends a cancelable `ui-change`.\n */\nexport class UiModelPicker extends UiElement<ModelPickerData> {\n static override styles = [styles];\n static get observedAttributes() {\n return ['lang', 'open', 'side'];\n }\n\n #open = false;\n #reflecting = false;\n #activeKey: string | null = null;\n #pointing = false;\n #shown: ModelPrice | null = null;\n #raf = 0;\n #placeRaf = 0;\n #watch = 0;\n #attached = false;\n #at: AnchorSpot | null = null;\n #last: AnchorSpot | null = null;\n #pos: { left: number; top: number; side: ModelMenuSide; maxHeight: number } | null = null;\n\n constructor() {\n super();\n this.root.addEventListener('click', (e) => this.#onClick(e));\n this.root.addEventListener('keydown', (e) => this.#onKey(e as KeyboardEvent));\n this.root.addEventListener('pointerover', (e) => this.#onPointer(e as PointerEvent));\n this.root.addEventListener('pointerout', (e) => this.#onPointerOut(e as PointerEvent));\n }\n\n /** Whether the menu is open. Setting it opens/closes without moving focus and without `ui-open-change`. */\n get open(): boolean {\n return this.#open;\n }\n\n set open(v: boolean) {\n this.#setOpen(!!v, { user: false });\n }\n\n attributeChangedCallback(name: string, _old: string | null, value: string | null): void {\n if (name === 'open') {\n if (!this.#reflecting) this.#setOpen(value !== null, { user: false });\n return;\n }\n this.requestRender();\n }\n\n override connectedCallback(): void {\n super.connectedCallback();\n if (this.#open) this.#attach();\n }\n\n override disconnectedCallback(): void {\n this.#detach();\n }\n\n get #t(): Strings {\n return this.getAttribute('lang') === 'ko' ? STRINGS.ko : STRINGS.en;\n }\n\n get #side(): ModelMenuSide {\n return this.getAttribute('side') === 'top' ? 'top' : 'bottom';\n }\n\n #off(): boolean {\n return !!this.data?.disabled;\n }\n\n #opts(): Opt[] {\n return this.data ? pickerOptions(this.data) : [];\n }\n\n /** The active row: the model last pointed at while it is still listed, else the session's model. */\n #activeIndex(opts: Opt[], cur: number): number {\n const i = this.#activeKey === null ? -1 : opts.findIndex((o) => o.key === this.#activeKey);\n return i >= 0 ? i : Math.max(cur, 0);\n }\n\n // ── open / close ──────────────────────────────────────────────────────────\n\n #setOpen(v: boolean, o: { user: boolean; focusList?: boolean; returnFocus?: boolean }): void {\n if (v === this.#open) {\n if (v && o.focusList) this.#focusList();\n return;\n }\n if (v) {\n if (this.#off()) {\n this.#reflect(false); // a read-only picker never opens, also not by attribute\n return;\n }\n // Every open starts on the session's model, unlit.\n this.#open = true;\n this.#activeKey = null;\n this.#pointing = false;\n this.#shown = null;\n this.#at = null;\n this.#last = null;\n this.#reflect(true);\n if (this.isConnected) {\n this.renderNow();\n if (!this.#open) return; // it closed itself while placing (the trigger is off-screen)\n this.#attach();\n if (o.focusList) this.#focusList();\n }\n } else {\n // Focus goes home first, while the menu is still open (no focus lost when it turns inert under it).\n if (o.returnFocus) this.$('.mp-trigger')?.focus();\n this.#open = false;\n this.#pointing = false;\n this.#at = null;\n this.#last = null;\n this.#reflect(false);\n this.#detach();\n if (this.isConnected) this.renderNow();\n }\n if (o.user) this.emit('ui-open-change', { open: v });\n }\n\n #reflect(v: boolean): void {\n if (this.hasAttribute('open') === v) return;\n this.#reflecting = true;\n this.toggleAttribute('open', v);\n this.#reflecting = false;\n }\n\n #focusList(): void {\n this.$('.mp-list')?.focus({ preventScroll: true });\n }\n\n readonly #onOutside = (e: Event): void => {\n if (this.#open && !e.composedPath().includes(this)) this.#setOpen(false, { user: true });\n };\n\n readonly #onViewport = (): void => this.#queuePlace();\n\n readonly #tick = (): void => {\n if (!this.#open) return;\n const trig = this.$('.mp-trigger');\n if (!trig) return;\n if (!this.#at) {\n this.#place();\n return;\n }\n const r = trig.getBoundingClientRect();\n if ((!r.width && !r.height) || anchorMoved(this.#at, anchorSpot(trig))) {\n // The anchor left its place (another column, a reflow): close instead of pointing at the old spot.\n this.#setOpen(false, { user: true });\n return;\n }\n // A scroll the document never heard of (inside another shadow root) still moves the menu along.\n if (!this.#last || r.left !== this.#last.left || r.top !== this.#last.top) this.#place();\n };\n\n #attach(): void {\n if (this.#attached || !this.#open || !this.isConnected) return;\n this.#attached = true;\n document.addEventListener('pointerdown', this.#onOutside, true);\n document.addEventListener('focusin', this.#onOutside);\n document.addEventListener('scroll', this.#onViewport, { capture: true, passive: true });\n window.addEventListener('resize', this.#onViewport);\n this.#watch = window.setInterval(this.#tick, WATCH_MS);\n this.#queuePlace();\n }\n\n #detach(): void {\n if (this.#attached) {\n document.removeEventListener('pointerdown', this.#onOutside, true);\n document.removeEventListener('focusin', this.#onOutside);\n document.removeEventListener('scroll', this.#onViewport, { capture: true });\n window.removeEventListener('resize', this.#onViewport);\n this.#attached = false;\n }\n clearInterval(this.#watch);\n this.#watch = 0;\n if (this.#placeRaf) cancelAnimationFrame(this.#placeRaf);\n this.#placeRaf = 0;\n if (this.#raf) cancelAnimationFrame(this.#raf);\n this.#raf = 0;\n }\n\n #queuePlace(): void {\n if (!this.#open || this.#placeRaf || typeof requestAnimationFrame !== 'function') return;\n this.#placeRaf = requestAnimationFrame(() => {\n this.#placeRaf = 0;\n this.#place();\n });\n }\n\n /**\n * Fixed positioning from the trigger's rect. The menu is `position: fixed`, so the open card's clip never\n * cuts it; when an ancestor is a containing block for fixed elements (a transform, a filter) the probe —\n * a fixed 100px box at 0,0 — tells its origin and scale and the viewport position is mapped into it.\n */\n #place(): void {\n if (!this.#open || !this.isConnected) return;\n const trig = this.$('.mp-trigger');\n const pop = this.$('.mp-pop');\n const probe = this.$('.mp-probe');\n if (!trig || !pop) return;\n const r = trig.getBoundingClientRect();\n if (!r.width && !r.height) {\n if (this.#at) this.#setOpen(false, { user: true });\n return; // not laid out yet — the watch tries again\n }\n const vw = document.documentElement.clientWidth || window.innerWidth;\n const vh = window.innerHeight;\n if (r.bottom < 0 || r.top > vh || r.right < 0 || r.left > vw) {\n this.#setOpen(false, { user: true });\n return;\n }\n const o = probe?.getBoundingClientRect();\n const k = o && o.width > 0 ? o.width / 100 : 1;\n const ox = o?.left ?? 0;\n const oy = o?.top ?? 0;\n // scrollHeight: the whole menu, also while a max-height from the last placement caps it.\n const p = placeModelMenu(r, pop.offsetWidth * k, pop.scrollHeight * k, vw, vh, this.#side);\n this.#pos = {\n left: Math.round((p.left - ox) / k),\n top: Math.round((p.top - oy) / k),\n side: p.side,\n maxHeight: Math.floor(p.maxHeight / k),\n };\n pop.style.left = `${this.#pos.left}px`;\n pop.style.top = `${this.#pos.top}px`;\n pop.style.maxHeight = `${this.#pos.maxHeight}px`;\n pop.setAttribute('data-side', p.side);\n this.#last = { left: r.left, top: r.top };\n if (!this.#at) this.#at = anchorSpot(trig);\n }\n\n // ── picks ─────────────────────────────────────────────────────────────────\n\n /** A row picks its model — by id, never by position. The current row only closes; locked rows do nothing. */\n #pickKey(key: string): void {\n const d = this.data;\n if (!d || this.#off()) return;\n const opts = this.#opts();\n const i = opts.findIndex((o) => o.key === key);\n if (i < 0) return;\n if (i === currentIndex(opts, d.value?.model ?? '')) {\n this.#setOpen(false, { user: true, returnFocus: true });\n return;\n }\n const o = opts[i];\n if (!o.listed || d.busy?.model) return;\n this.#setOpen(false, { user: true, returnFocus: true });\n const detail: ModelPickerChange = { model: o.model.id, effort: d.value?.effort, changed: 'model' };\n // Optimistic value on top of the LATEST data: a listener may have set busy/error synchronously; if it set a\n // value of its own, that value wins.\n if (this.emit('ui-change', detail) && this.data && this.data.value === d.value)\n this.data = { ...this.data, value: { model: o.model.id, effort: d.value?.effort } };\n }\n\n /** A level keeps the menu open (it is a setting of the same choice). */\n #pickEffort(level: string): void {\n const d = this.data;\n if (!d || this.#off() || d.busy?.effort || !level || level === d.value?.effort) return;\n const model = d.value?.model ?? '';\n const detail: ModelPickerChange = { model, effort: level, changed: 'effort' };\n if (this.emit('ui-change', detail) && this.data && this.data.value === d.value)\n this.data = { ...this.data, value: { model, effort: level } };\n }\n\n // ── input ─────────────────────────────────────────────────────────────────\n\n #onClick(e: Event): void {\n const t = e.target as Element | null;\n if (!t?.closest) return;\n if (t.closest('.mp-trigger')) {\n if (this.#off()) return;\n const opening = !this.#open;\n this.#setOpen(opening, { user: true, focusList: opening, returnFocus: !opening });\n return;\n }\n if (!this.#open) return;\n const opt = t.closest('.mp-opt');\n if (opt) {\n this.#pickKey(opt.getAttribute('data-k') ?? '');\n return;\n }\n const b = t.closest('.mp-seg-btn');\n if (b && b.parentElement?.getAttribute('aria-disabled') !== 'true')\n this.#pickEffort(b.getAttribute('data-effort') ?? '');\n }\n\n #onKey(e: KeyboardEvent): void {\n const t = e.target as HTMLElement | null;\n if (!t?.closest) return;\n if (t.closest('.mp-trigger')) {\n this.#triggerKey(e);\n return;\n }\n if (!t.closest('.mp-pop') || !this.#open) return;\n // Every key inside the menu stays in it (no page shortcut, no outer Escape).\n e.stopPropagation();\n const onList = t.classList.contains('mp-list');\n if (e.key === 'Escape') {\n e.preventDefault();\n this.#setOpen(false, { user: true, returnFocus: true });\n } else if (e.key === 'Tab') {\n // Two stops, moved by the menu itself: the list and the checked level. Tab cycles between them.\n e.preventDefault();\n const level = this.$('.mp-seg-btn[tabindex=\"0\"]');\n const list = this.$('.mp-list');\n (onList ? (level ?? list) : list)?.focus();\n } else if (onList) {\n this.#listKey(e);\n } else {\n const radio = t.closest<HTMLElement>('.mp-seg-btn');\n if (radio) this.#effortKey(e, radio);\n }\n }\n\n /** ↓ / ↑ on the trigger open the menu (Enter and Space are the button's own click); Esc closes it. */\n #triggerKey(e: KeyboardEvent): void {\n if (e.key === 'Escape' && this.#open) {\n e.preventDefault();\n e.stopPropagation();\n this.#setOpen(false, { user: true, returnFocus: true });\n return;\n }\n if (e.key !== 'ArrowDown' && e.key !== 'ArrowUp') return;\n e.preventDefault();\n if (this.#off()) return;\n this.#setOpen(true, { user: true, focusList: true });\n }\n\n /** ↑ ↓ (wrapping) · Home · End point at a row; Enter · Space pick it. */\n #listKey(e: KeyboardEvent): void {\n const opts = this.#opts();\n const n = opts.length;\n if (!n) return;\n const k = e.key;\n const cur = currentIndex(opts, this.data?.value?.model ?? '');\n if (k === 'ArrowDown' || k === 'ArrowUp' || k === 'Home' || k === 'End') {\n e.preventDefault();\n const i = k === 'Home' ? 0 : k === 'End' ? n - 1 : this.#activeIndex(opts, cur) + (k === 'ArrowDown' ? 1 : -1);\n this.#activeKey = opts[((i % n) + n) % n].key;\n this.#pointing = true;\n this.renderNow();\n // A menu capped to the room it has scrolls: keep the active row in view.\n this.$('.mp-opt[data-active]')?.scrollIntoView?.({ block: 'nearest' });\n } else if (k === 'Enter' || k === ' ') {\n e.preventDefault();\n this.#pickKey(opts[this.#activeIndex(opts, cur)].key);\n }\n }\n\n /** Effort: the arrows move and select at once (radio pattern); Home · End. */\n #effortKey(e: KeyboardEvent, radio: HTMLElement): void {\n const group = radio.parentElement;\n if (!group) return;\n const btns = Array.from(group.querySelectorAll<HTMLElement>('.mp-seg-btn'));\n const n = btns.length;\n const i = btns.indexOf(radio);\n const k = e.key;\n const j =\n k === 'ArrowRight' || k === 'ArrowDown'\n ? i + 1\n : k === 'ArrowLeft' || k === 'ArrowUp'\n ? i - 1\n : k === 'Home'\n ? 0\n : k === 'End'\n ? n - 1\n : null;\n if (j === null || !n) return;\n e.preventDefault();\n if (group.getAttribute('aria-disabled') === 'true') return;\n const next = btns[((j % n) + n) % n];\n next.focus();\n this.#pickEffort(next.getAttribute('data-effort') ?? '');\n }\n\n /** The mouse points at a row: it lights, the others step back; leaving the list lets go. */\n #onPointer(e: PointerEvent): void {\n if (!this.#open || (e.pointerType && e.pointerType !== 'mouse')) return;\n const opt = (e.target as Element | null)?.closest?.('.mp-opt');\n if (!opt) return;\n const key = opt.getAttribute('data-k') ?? '';\n if (this.#pointing && this.#activeKey === key) return;\n this.#activeKey = key;\n this.#pointing = true;\n this.renderNow();\n }\n\n #onPointerOut(e: PointerEvent): void {\n if (!this.#open || !this.#pointing || (e.pointerType && e.pointerType !== 'mouse')) return;\n const list = this.$('.mp-list');\n const to = e.relatedTarget as Node | null;\n if (!list || !list.contains(e.target as Node) || (to && list.contains(to))) return;\n this.#pointing = false;\n this.renderNow();\n }\n\n // ── render ────────────────────────────────────────────────────────────────\n\n /** Patch the live tree instead of replacing it: the open/close transition, the thumb and focus survive. */\n protected override update(): void {\n morphInto(this.content, this.render());\n this.updated();\n }\n\n protected render(): string {\n const d = this.data;\n if (!d) return '';\n const t = this.#t;\n const v = d.value ?? { model: '' };\n const opts = pickerOptions(d);\n const cur = currentIndex(opts, v.model ?? '');\n const curOpt = cur >= 0 ? opts[cur] : null;\n const open = this.#open;\n const off = !!d.disabled;\n const why = typeof d.disabled === 'string' ? d.disabled : '';\n const busy = !!(d.busy?.model || d.busy?.effort);\n const name = curOpt ? curOpt.model.label || curOpt.model.id : t.model;\n const level = modelEffortLabel(v.effectiveEffort || v.effort);\n const pending = typeof d.busy?.model === 'string' ? d.busy.model : '';\n\n const trigger = `<button type=\"button\" class=\"mp-trigger\" part=\"trigger\" data-key=\"mp-trigger\" aria-haspopup=\"dialog\" aria-expanded=\"${\n open ? 'true' : 'false'\n }\" aria-controls=\"mp-menu\" aria-label=\"${escAttr(t.trigger(name, level))}\"${busy ? ' aria-busy=\"true\"' : ''}${\n off ? ` aria-disabled=\"true\"${why ? ` title=\"${escAttr(why)}\" aria-describedby=\"mp-why\"` : ''}` : ''\n }><span class=\"mp-glyph\" aria-hidden=\"true\">${esc(modelGlyph(curOpt ? curOpt.model : { label: name }))}</span><span class=\"mp-name\">${esc(\n name,\n )}</span>${level ? `<span class=\"mp-level\">· ${esc(level)}</span>` : ''}<span class=\"mp-chev\" aria-hidden=\"true\"></span></button>`;\n\n return `<div class=\"mp\">${trigger}${why ? `<span class=\"sr-only\" id=\"mp-why\">${esc(why)}</span>` : ''}\n<div class=\"mp-note\" role=\"status\">${!open && pending ? esc(pending) : ''}</div>\n<div class=\"mp-note is-error\" role=\"alert\">${!open && d.error ? esc(d.error) : ''}</div>\n<i class=\"mp-probe\" aria-hidden=\"true\"></i>${this.#menu(d, opts, cur, t)}</div>`;\n }\n\n #menu(d: ModelPickerData, opts: Opt[], cur: number, t: Strings): string {\n const open = this.#open;\n const active = opts.length ? this.#activeIndex(opts, cur) : -1;\n const lit = this.#pointing ? active : cur;\n const used = num(d.contextTokens);\n const locked = !!d.busy?.model;\n const wait = typeof d.busy?.model === 'string' && d.busy.model ? d.busy.model : t.switching;\n const pos = this.#pos;\n let rows = '';\n opts.forEach((o, i) => {\n const m = o.model;\n const isCur = i === cur;\n const name = m.label || m.id;\n const ac = num(m.autoCompactAt);\n const win = num(m.window);\n const price = validModelPrice(m.price);\n const desc = o.listed\n ? [\n m.short || m.id,\n ac > 0 ? `autocompact ${fmtModelTokens(ac)}` : '',\n !isCur && ac > 0 && used > ac ? t.after : '',\n ]\n .filter(Boolean)\n .join(' · ')\n : t.outside;\n const facts = o.listed\n ? [\n win > 0 ? t.winSr(fmtModelTokens(win)) : '',\n price ? t.priceWords(fmtModelPrice(price.input), fmtModelPrice(price.output)) : t.noPriceWords,\n ]\n .filter(Boolean)\n .join(', ')\n : '';\n const label = `${name}, ${desc}${facts ? `. ${facts}` : ''}`;\n rows += `<div class=\"mp-opt\" id=\"mp-opt-${i}\" role=\"option\" data-mk=\"opt:${escAttr(o.key)}\" data-k=\"${escAttr(o.key)}\" aria-selected=\"${\n isCur ? 'true' : 'false'\n }\"${locked || !o.listed ? ' aria-disabled=\"true\"' : ''}${i === active ? ' data-active=\"\"' : ''}${\n i === lit ? ' data-lit=\"\"' : ''\n } aria-label=\"${escAttr(label)}\"><span class=\"mp-glyph\" aria-hidden=\"true\">${esc(modelGlyph(m))}</span><span class=\"mp-title\"><span class=\"mp-title-name\">${esc(\n name,\n )}</span>${isCur ? `<span class=\"mp-check\" aria-hidden=\"true\">${CHECK}</span>` : ''}</span>${meters(o.meters)}<span class=\"mp-desc\">${esc(desc)}</span></div>`;\n });\n const tray = this.#tray(lit >= 0 ? opts[lit] : undefined, t);\n return `<div class=\"mp-pop${open ? ' is-open' : ''}\" part=\"menu\" id=\"mp-menu\" role=\"dialog\" aria-label=\"${escAttr(t.dialog)}\"${\n open ? '' : ' inert'\n } data-side=\"${pos?.side ?? this.#side}\"${\n pos ? ` style=\"left:${pos.left}px;top:${pos.top}px;max-height:${pos.maxHeight}px\"` : ''\n }><div class=\"mp-card\"><div class=\"mp-head\" aria-hidden=\"true\"><span class=\"mp-head-t\">${esc(\n t.head,\n )}</span><span class=\"mp-cols\">${t.cols.map((c) => `<span>${esc(c)}</span>`).join('')}</span></div>${\n locked ? `<div class=\"mp-wait\" id=\"mp-wait\">${esc(wait)}</div>` : ''\n }<div class=\"mp-list\" role=\"listbox\" aria-label=\"${escAttr(t.list)}\" tabindex=\"0\" data-key=\"mp-list\"${\n active >= 0 ? ` aria-activedescendant=\"mp-opt-${active}\"` : ''\n }${locked ? ' aria-disabled=\"true\" aria-describedby=\"mp-wait\"' : ''}${this.#pointing ? ' data-pointing=\"\"' : ''}>${rows}</div>${this.#effort(\n d,\n cur >= 0 ? opts[cur] : undefined,\n t,\n )}<div class=\"mp-err\" role=\"alert\">${open && d.error ? esc(d.error) : ''}</div></div><div class=\"mp-foot\"><span class=\"mp-caption\" aria-hidden=\"true\">${\n tray.html\n }</span><span class=\"mp-keys\" aria-hidden=\"true\"><kbd>↑↓</kbd><kbd>↵</kbd></span><span class=\"sr-only mp-sr\" aria-live=\"polite\">${esc(\n tray.sr,\n )}</span></div></div>`;\n }\n\n /** Effort as a radiogroup with one tab stop; checked = the level that runs; only the model's levels. */\n #effort(d: ModelPickerData, cur: Opt | undefined, t: Strings): string {\n const levels = modelEffortLevels(cur?.listed ? cur.model : null);\n if (!levels.length) return '';\n const v = d.value ?? { model: '' };\n const on = v.effectiveEffort || v.effort || '';\n const idx = levels.indexOf(on);\n const capped = !!(v.effectiveEffort && v.effort && v.effectiveEffort !== v.effort);\n const busy = !!d.busy?.effort;\n let btns = '';\n levels.forEach((l, i) => {\n const checked = l === on;\n btns += `<button type=\"button\" class=\"mp-seg-btn\" role=\"radio\" data-mk=\"eff:${escAttr(l)}\" data-key=\"eff:${escAttr(\n l,\n )}\" data-effort=\"${escAttr(l)}\" aria-checked=\"${checked ? 'true' : 'false'}\" tabindex=\"${\n checked || (idx < 0 && i === 0) ? '0' : '-1'\n }\" aria-label=\"${escAttr(modelEffortLabel(l))}\">${esc(EFFORT_SHORT[l] ?? l)}</button>`;\n });\n return `<div class=\"mp-settings\"><div class=\"mp-effort-head\"><span class=\"mp-effort-label\" id=\"mp-effort-label\">${esc(\n t.effort,\n )}</span>${capped ? `<span class=\"mp-effort-cap\">${esc(t.cap(modelEffortLabel(v.effort), modelEffortLabel(v.effectiveEffort)))}</span>` : ''}</div><div class=\"mp-seg-ctl\" role=\"radiogroup\" aria-labelledby=\"mp-effort-label\"${\n busy ? ' aria-disabled=\"true\" aria-busy=\"true\"' : ''\n } style=\"--i:${Math.max(0, idx)};--n:${levels.length}\">${idx >= 0 ? '<span class=\"mp-thumb\" aria-hidden=\"true\"></span>' : ''}${btns}</div></div>`;\n }\n\n /** The tray of the lit row, and the sentence the live region reads once. */\n #tray(o: Opt | undefined, t: Strings): { html: string; sr: string } {\n if (!o) return { html: '', sr: '' };\n if (!o.listed) return { html: esc(t.outsideTray), sr: t.outsideSr };\n const m = o.model;\n const p = validModelPrice(m.price);\n const win = num(m.window) > 0 ? fmtModelTokens(m.window) : '';\n const html = [\n p\n ? t.tray(\n `<b class=\"mp-roll\" data-roll=\"input\">${fmtModelPrice(p.input)}</b>`,\n `<b class=\"mp-roll\" data-roll=\"output\">${fmtModelPrice(p.output)}</b>`,\n )\n : esc(t.noPrice),\n win ? esc(t.win(win)) : '',\n ]\n .filter(Boolean)\n .join(' · ');\n const sr = `${m.label || m.id}: ${[\n p ? t.priceWords(fmtModelPrice(p.input), fmtModelPrice(p.output)) : t.noPriceWords,\n win ? t.winSr(win) : '',\n ]\n .filter(Boolean)\n .join(', ')}`;\n return { html, sr };\n }\n\n protected override updated(): void {\n if (!this.#open) {\n if (this.#raf) cancelAnimationFrame(this.#raf);\n this.#raf = 0;\n return;\n }\n if (this.#off()) {\n this.#setOpen(false, { user: true });\n return;\n }\n this.#place();\n this.#rollTray();\n }\n\n /** The tray's prices roll from what is shown to the lit row's (560ms, ease-out quart); reduced motion jumps. */\n #rollTray(): void {\n if (this.#raf) cancelAnimationFrame(this.#raf);\n this.#raf = 0;\n const opts = this.#opts();\n const cur = currentIndex(opts, this.data?.value?.model ?? '');\n const lit = this.#pointing ? this.#activeIndex(opts, cur) : cur;\n const o = lit >= 0 ? opts[lit] : undefined;\n const to = o?.listed ? validModelPrice(o.model.price) : null;\n const from = this.#shown;\n this.#shown = to;\n if (!to || !from || (from.input === to.input && from.output === to.output)) return;\n if (prefersReducedMotion() || typeof requestAnimationFrame !== 'function') return;\n const els = this.$$('.mp-roll');\n const t0 = performance.now();\n const step = (now: number) => {\n const p = Math.min(1, Math.max(0, (now - t0) / ROLL_MS));\n const e = 1 - (1 - p) ** 4;\n const at = {\n input: from.input + (to.input - from.input) * e,\n output: from.output + (to.output - from.output) * e,\n };\n this.#shown = p < 1 ? at : to;\n for (const el of els) {\n const k = el.getAttribute('data-roll') === 'input' ? 'input' : 'output';\n el.textContent = fmtModelPrice(at[k], to[k]);\n }\n this.#raf = p < 1 ? requestAnimationFrame(step) : 0;\n };\n step(t0);\n }\n}\n\nfunction meters(vals: ModelMeters): string {\n let html = '<span class=\"mp-bars\" aria-hidden=\"true\">';\n vals.forEach((v, c) => {\n if (!v) {\n html += '<span class=\"mp-meter is-none\">—</span>';\n return;\n }\n html += `<span class=\"mp-meter\" style=\"--c:${c}\">`;\n for (let k = 0; k < 5; k++) html += `<span class=\"mp-seg\" style=\"--s:${k}\"${k < v ? ' data-on=\"\"' : ''}></span>`;\n html += '</span>';\n });\n return `${html}</span>`;\n}\n\ndefine('ui-model-picker', UiModelPicker);\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'ui-model-picker': UiModelPicker;\n }\n}\n"],"names":["meters","o"],"mappings":"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"}
|
package/dist/tokens.css
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
/* @2lab.ai/ui design tokens — data-theme="dark|light" on any ancestor switches */
|
|
2
|
+
:root, [data-theme="light"] { --ui-ease: cubic-bezier(0.2,0.8,0.2,1); --ui-ease-out: cubic-bezier(0.23, 1, 0.32, 1); --ui-ease-in-out: cubic-bezier(0.77, 0, 0.175, 1); --ui-dur-press: 160ms; --ui-dur-expand: 240ms; --ui-dur-move: 320ms; --ui-dur-fade: 180ms; --ui-radius: 10px; --ui-font: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", "Apple SD Gothic Neo", Pretendard, sans-serif; --ui-mono: 'SF Mono', 'Fira Code', ui-monospace, Menlo, monospace; --ui-bg: #f7f7f7; --ui-surface: #ffffff; --ui-surface-raised: #f1f1f1; --ui-border: #e4e4e4; --ui-border-focus: #4d9de0; --ui-text: #18181a; --ui-text-secondary: #57575d; --ui-text-tertiary: #68686f; --ui-accent: #1f6dc2; --ui-accent-hover: #1a5ca6; --ui-green: #14783b; --ui-yellow: #a16207; --ui-red: #b91c1c; --ui-purple: #7c3aed; --ui-orange: #c2410c; --ui-ib-col: #efefef; --ui-ib-card: #ffffff; --ui-ib-card-dim: #f8f8f8; --ui-ib-card-border: #e3e3e3; --ui-ib-pill: #e2e2e2; --ui-ib-text: #161616; --ui-ib-text-2: #555558; --ui-ib-muted: #65656b; --ui-ib-seg: #ebebeb; --ui-ib-seg-on: #ffffff; --ui-ib-spark: #5b7fe0; --ui-ib-shadow: 0 1px 2px rgba(0,0,0,0.06); --ui-ib-shadow-raised: 0 14px 30px rgba(0,0,0,0.14), 0 3px 8px rgba(0,0,0,0.08); --ui-st-wait: #c2780a; --ui-st-run: #2f63e0; --ui-st-done: #137a3e; --ui-st-fail: #d43a3a; --ui-st-fail-text: #c02f2f; color-scheme: light; }
|
|
3
|
+
[data-theme="dark"] { --ui-bg: #1c1c1f; --ui-surface: #232327; --ui-surface-raised: #2a2a2f; --ui-border: #34343a; --ui-border-focus: #4d9de0; --ui-text: #ededf0; --ui-text-secondary: #a8a8b0; --ui-text-tertiary: #93939b; --ui-accent: #4d9de0; --ui-accent-hover: #3b82c4; --ui-green: #3ecf8e; --ui-yellow: #f6c90e; --ui-red: #f26b6b; --ui-purple: #a78bfa; --ui-orange: #f97316; --ui-ib-col: #18181b; --ui-ib-card: #242428; --ui-ib-card-dim: #1f1f23; --ui-ib-card-border: #34343a; --ui-ib-pill: #2f2f35; --ui-ib-text: #f2f2f3; --ui-ib-text-2: #b4b4bb; --ui-ib-muted: #93939b; --ui-ib-seg: #161619; --ui-ib-seg-on: #2e2e33; --ui-ib-spark: #7b9cf0; --ui-ib-shadow: 0 1px 2px rgba(0,0,0,0.35); --ui-ib-shadow-raised: 0 14px 32px rgba(0,0,0,0.5), 0 3px 8px rgba(0,0,0,0.35); --ui-st-wait: #f5a524; --ui-st-run: #6b93f2; --ui-st-done: #3fb968; --ui-st-fail: #f26b6b; --ui-st-fail-text: #f26b6b; color-scheme: dark; }
|
|
4
|
+
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) { --ui-bg: #1c1c1f; --ui-surface: #232327; --ui-surface-raised: #2a2a2f; --ui-border: #34343a; --ui-border-focus: #4d9de0; --ui-text: #ededf0; --ui-text-secondary: #a8a8b0; --ui-text-tertiary: #93939b; --ui-accent: #4d9de0; --ui-accent-hover: #3b82c4; --ui-green: #3ecf8e; --ui-yellow: #f6c90e; --ui-red: #f26b6b; --ui-purple: #a78bfa; --ui-orange: #f97316; --ui-ib-col: #18181b; --ui-ib-card: #242428; --ui-ib-card-dim: #1f1f23; --ui-ib-card-border: #34343a; --ui-ib-pill: #2f2f35; --ui-ib-text: #f2f2f3; --ui-ib-text-2: #b4b4bb; --ui-ib-muted: #93939b; --ui-ib-seg: #161619; --ui-ib-seg-on: #2e2e33; --ui-ib-spark: #7b9cf0; --ui-ib-shadow: 0 1px 2px rgba(0,0,0,0.35); --ui-ib-shadow-raised: 0 14px 32px rgba(0,0,0,0.5), 0 3px 8px rgba(0,0,0,0.35); --ui-st-wait: #f5a524; --ui-st-run: #6b93f2; --ui-st-done: #3fb968; --ui-st-fail: #f26b6b; --ui-st-fail-text: #f26b6b; color-scheme: dark; } }
|