@oddsquad/vite-plugin-lit 0.2.0 → 0.2.2

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.
@@ -157,14 +157,39 @@ if (hot !== undefined && typeof window !== 'undefined') {
157
157
  }
158
158
  };
159
159
  // -------------------------------------------------------------------------
160
+ // SPA navigation: a route change swaps the component tree without any HMR
161
+ // or panel event, so the snapshot went stale until a manual refresh. Push a
162
+ // deduped tree after each navigation — twice, since routes typically
163
+ // lazy-load and render async. Redundant while the live observer watches.
164
+ // -------------------------------------------------------------------------
165
+ const onNavigation = () => {
166
+ if (observer !== null)
167
+ return;
168
+ for (const delay of [150, 1000]) {
169
+ setTimeout(pushTreeIfChanged, delay);
170
+ }
171
+ };
172
+ window.addEventListener('popstate', onNavigation);
173
+ window.addEventListener('hashchange', onNavigation);
174
+ for (const method of ['pushState', 'replaceState']) {
175
+ const original = history[method].bind(history);
176
+ history[method] = (...args) => {
177
+ original(...args);
178
+ onNavigation();
179
+ };
180
+ }
181
+ // -------------------------------------------------------------------------
160
182
  // Command dispatch
161
183
  // -------------------------------------------------------------------------
162
184
  hot.on(INSPECT_CMD_CHANNEL, (data) => {
163
185
  const cmd = data;
164
186
  switch (cmd.type) {
165
- case 'tree':
166
- send({ type: 'tree', roots: buildTree() });
187
+ case 'tree': {
188
+ const roots = buildTree();
189
+ lastTreeJson = JSON.stringify(roots);
190
+ send({ type: 'tree', roots });
167
191
  break;
192
+ }
168
193
  case 'details': {
169
194
  const el = elementById(cmd.id);
170
195
  if (el !== undefined) {
@@ -1 +1 @@
1
- {"version":3,"file":"install.js","sourceRoot":"","sources":["../../../../../packages/labs/vite-plugin-lit/src/lib/runtime/inspector/install.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: BSD-3-Clause\n */\n\n/**\n * Components inspector runtime.\n *\n * Injected into the host page (alongside the timeline runtime) when the\n * DevTools panel is enabled. Answers the panel's tree/details requests over the\n * Vite HMR channel, keeps a watched element's details fresh as it updates, and\n * outlines elements the panel hovers in its tree.\n */\n\nimport {elementById} from '../timeline/identity.js';\nimport {buildTree, collectDetails} from './collect.js';\nimport {\n INSPECT_CMD_CHANNEL,\n INSPECT_DATA_CHANNEL,\n type InspectorCommand,\n type InspectorMessage,\n} from '../../../types/inspector.js';\n\ntype ViteHot = {\n send: (event: string, data: unknown) => void;\n on: (event: string, handler: (data: unknown) => void) => void;\n};\n\nconst hot = (import.meta as {hot?: ViteHot}).hot;\n\nif (hot !== undefined && typeof window !== 'undefined') {\n const send = (msg: InspectorMessage): void => {\n try {\n hot.send(INSPECT_DATA_CHANNEL, msg);\n } catch {\n // HMR channel temporarily unavailable; the panel can re-request.\n }\n };\n\n // -------------------------------------------------------------------------\n // Live-watch: re-push details whenever the watched element finishes updating.\n // We wrap the instance's `updated` (not the prototype) so the hook is scoped\n // to one element and trivially removable, and it works without the timeline's\n // recording gate.\n // -------------------------------------------------------------------------\n\n type Updatable = Element & {\n updated?: (changed: unknown) => void;\n };\n // Hold the watched element via a WeakRef so an active watch doesn't keep a\n // removed element alive: the override and `restore` only reach `el` through\n // the ref, leaving the DOM as its sole strong root.\n let watched: {ref: WeakRef<Updatable>; restore: () => void} | null = null;\n\n const unwatch = (): void => {\n watched?.restore();\n watched = null;\n };\n\n const watch = (id: number): void => {\n unwatch();\n const el = elementById(id) as Updatable | undefined;\n if (el === undefined) {\n send({type: 'gone', id});\n return;\n }\n const hadOwn = Object.prototype.hasOwnProperty.call(el, 'updated');\n const prev = el.updated;\n const ref = new WeakRef(el);\n el.updated = function (changed: unknown) {\n prev?.call(this, changed);\n const cur = ref.deref();\n if (cur !== undefined) {\n send({type: 'details', details: collectDetails(cur)});\n }\n };\n watched = {\n ref,\n restore: () => {\n const cur = ref.deref();\n if (cur === undefined) return;\n if (hadOwn) cur.updated = prev;\n else delete cur.updated;\n },\n };\n // Push an immediate snapshot so the panel doesn't wait for the next update.\n send({type: 'details', details: collectDetails(el)});\n };\n\n // -------------------------------------------------------------------------\n // Highlight box: a lightweight fixed-position outline drawn over an element\n // the panel hovers in its tree. Independent of the source overlay so it works\n // whether or not that feature is enabled.\n // -------------------------------------------------------------------------\n\n let highlightBox: HTMLElement | null = null;\n\n const showHighlight = (el: Element): void => {\n if (highlightBox === null) {\n highlightBox = document.createElement('div');\n highlightBox.setAttribute('data-lit-devtools-highlight', '');\n Object.assign(highlightBox.style, {\n position: 'fixed',\n zIndex: '2147483646',\n pointerEvents: 'none',\n background: 'rgba(77, 99, 255, 0.25)',\n outline: '1px solid #4d63ff',\n borderRadius: '2px',\n transition: 'all 80ms ease-out',\n } satisfies Partial<CSSStyleDeclaration>);\n document.body.append(highlightBox);\n }\n const r = el.getBoundingClientRect();\n Object.assign(highlightBox.style, {\n display: 'block',\n left: `${r.left}px`,\n top: `${r.top}px`,\n width: `${r.width}px`,\n height: `${r.height}px`,\n });\n };\n\n const clearHighlight = (): void => {\n if (highlightBox !== null) highlightBox.style.display = 'none';\n };\n\n // -------------------------------------------------------------------------\n // Opt-in live tree: watch the DOM (light + every shadow root) and push a\n // fresh tree when the component hierarchy actually changes. Off by default.\n // childList-only (no attributes), so cosmetic changes — including our own\n // highlight box toggling — don't churn; identical rebuilds are also deduped.\n // -------------------------------------------------------------------------\n\n let observer: MutationObserver | null = null;\n let observeTimer: ReturnType<typeof setTimeout> | undefined;\n let lastTreeJson = '';\n\n /** Re-attach the observer to the body and every shadow root in the page. */\n const syncObserverTargets = (obs: MutationObserver): void => {\n obs.disconnect();\n obs.observe(document.body, {childList: true, subtree: true});\n const walk = (root: ParentNode): void => {\n for (const el of root.querySelectorAll('*')) {\n if (el.shadowRoot !== null) {\n obs.observe(el.shadowRoot, {childList: true, subtree: true});\n walk(el.shadowRoot);\n }\n }\n };\n walk(document);\n };\n\n const pushTreeIfChanged = (): void => {\n const roots = buildTree();\n const json = JSON.stringify(roots);\n if (json === lastTreeJson) return;\n lastTreeJson = json;\n send({type: 'tree', roots});\n };\n\n const onMutation = (): void => {\n if (observeTimer !== undefined) clearTimeout(observeTimer);\n observeTimer = setTimeout(() => {\n observeTimer = undefined;\n if (observer !== null) syncObserverTargets(observer);\n pushTreeIfChanged();\n }, 100);\n };\n\n const setObserving = (enabled: boolean): void => {\n if (enabled) {\n if (observer === null) observer = new MutationObserver(onMutation);\n lastTreeJson = '';\n syncObserverTargets(observer);\n pushTreeIfChanged();\n } else if (observer !== null) {\n observer.disconnect();\n observer = null;\n if (observeTimer !== undefined) {\n clearTimeout(observeTimer);\n observeTimer = undefined;\n }\n }\n };\n\n // -------------------------------------------------------------------------\n // Command dispatch\n // -------------------------------------------------------------------------\n\n hot.on(INSPECT_CMD_CHANNEL, (data) => {\n const cmd = data as InspectorCommand;\n switch (cmd.type) {\n case 'tree':\n send({type: 'tree', roots: buildTree()});\n break;\n case 'details': {\n const el = elementById(cmd.id);\n if (el !== undefined) {\n send({type: 'details', details: collectDetails(el)});\n } else {\n send({type: 'gone', id: cmd.id});\n }\n break;\n }\n case 'watch':\n if (cmd.id === null) unwatch();\n else watch(cmd.id);\n break;\n case 'highlight': {\n if (cmd.id === null) {\n clearHighlight();\n break;\n }\n const el = elementById(cmd.id);\n if (el !== undefined) showHighlight(el);\n else clearHighlight();\n break;\n }\n case 'observe':\n setObserving(cmd.enabled);\n break;\n }\n });\n\n // Announce readiness so a panel that loaded first re-requests the tree.\n send({type: 'ready'});\n}\n"]}
1
+ {"version":3,"file":"install.js","sourceRoot":"","sources":["../../../../../packages/labs/vite-plugin-lit/src/lib/runtime/inspector/install.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: BSD-3-Clause\n */\n\n/**\n * Components inspector runtime.\n *\n * Injected into the host page (alongside the timeline runtime) when the\n * DevTools panel is enabled. Answers the panel's tree/details requests over the\n * Vite HMR channel, keeps a watched element's details fresh as it updates, and\n * outlines elements the panel hovers in its tree.\n */\n\nimport {elementById} from '../timeline/identity.js';\nimport {buildTree, collectDetails} from './collect.js';\nimport {\n INSPECT_CMD_CHANNEL,\n INSPECT_DATA_CHANNEL,\n type InspectorCommand,\n type InspectorMessage,\n} from '../../../types/inspector.js';\n\ntype ViteHot = {\n send: (event: string, data: unknown) => void;\n on: (event: string, handler: (data: unknown) => void) => void;\n};\n\nconst hot = (import.meta as {hot?: ViteHot}).hot;\n\nif (hot !== undefined && typeof window !== 'undefined') {\n const send = (msg: InspectorMessage): void => {\n try {\n hot.send(INSPECT_DATA_CHANNEL, msg);\n } catch {\n // HMR channel temporarily unavailable; the panel can re-request.\n }\n };\n\n // -------------------------------------------------------------------------\n // Live-watch: re-push details whenever the watched element finishes updating.\n // We wrap the instance's `updated` (not the prototype) so the hook is scoped\n // to one element and trivially removable, and it works without the timeline's\n // recording gate.\n // -------------------------------------------------------------------------\n\n type Updatable = Element & {\n updated?: (changed: unknown) => void;\n };\n // Hold the watched element via a WeakRef so an active watch doesn't keep a\n // removed element alive: the override and `restore` only reach `el` through\n // the ref, leaving the DOM as its sole strong root.\n let watched: {ref: WeakRef<Updatable>; restore: () => void} | null = null;\n\n const unwatch = (): void => {\n watched?.restore();\n watched = null;\n };\n\n const watch = (id: number): void => {\n unwatch();\n const el = elementById(id) as Updatable | undefined;\n if (el === undefined) {\n send({type: 'gone', id});\n return;\n }\n const hadOwn = Object.prototype.hasOwnProperty.call(el, 'updated');\n const prev = el.updated;\n const ref = new WeakRef(el);\n el.updated = function (changed: unknown) {\n prev?.call(this, changed);\n const cur = ref.deref();\n if (cur !== undefined) {\n send({type: 'details', details: collectDetails(cur)});\n }\n };\n watched = {\n ref,\n restore: () => {\n const cur = ref.deref();\n if (cur === undefined) return;\n if (hadOwn) cur.updated = prev;\n else delete cur.updated;\n },\n };\n // Push an immediate snapshot so the panel doesn't wait for the next update.\n send({type: 'details', details: collectDetails(el)});\n };\n\n // -------------------------------------------------------------------------\n // Highlight box: a lightweight fixed-position outline drawn over an element\n // the panel hovers in its tree. Independent of the source overlay so it works\n // whether or not that feature is enabled.\n // -------------------------------------------------------------------------\n\n let highlightBox: HTMLElement | null = null;\n\n const showHighlight = (el: Element): void => {\n if (highlightBox === null) {\n highlightBox = document.createElement('div');\n highlightBox.setAttribute('data-lit-devtools-highlight', '');\n Object.assign(highlightBox.style, {\n position: 'fixed',\n zIndex: '2147483646',\n pointerEvents: 'none',\n background: 'rgba(77, 99, 255, 0.25)',\n outline: '1px solid #4d63ff',\n borderRadius: '2px',\n transition: 'all 80ms ease-out',\n } satisfies Partial<CSSStyleDeclaration>);\n document.body.append(highlightBox);\n }\n const r = el.getBoundingClientRect();\n Object.assign(highlightBox.style, {\n display: 'block',\n left: `${r.left}px`,\n top: `${r.top}px`,\n width: `${r.width}px`,\n height: `${r.height}px`,\n });\n };\n\n const clearHighlight = (): void => {\n if (highlightBox !== null) highlightBox.style.display = 'none';\n };\n\n // -------------------------------------------------------------------------\n // Opt-in live tree: watch the DOM (light + every shadow root) and push a\n // fresh tree when the component hierarchy actually changes. Off by default.\n // childList-only (no attributes), so cosmetic changes — including our own\n // highlight box toggling — don't churn; identical rebuilds are also deduped.\n // -------------------------------------------------------------------------\n\n let observer: MutationObserver | null = null;\n let observeTimer: ReturnType<typeof setTimeout> | undefined;\n let lastTreeJson = '';\n\n /** Re-attach the observer to the body and every shadow root in the page. */\n const syncObserverTargets = (obs: MutationObserver): void => {\n obs.disconnect();\n obs.observe(document.body, {childList: true, subtree: true});\n const walk = (root: ParentNode): void => {\n for (const el of root.querySelectorAll('*')) {\n if (el.shadowRoot !== null) {\n obs.observe(el.shadowRoot, {childList: true, subtree: true});\n walk(el.shadowRoot);\n }\n }\n };\n walk(document);\n };\n\n const pushTreeIfChanged = (): void => {\n const roots = buildTree();\n const json = JSON.stringify(roots);\n if (json === lastTreeJson) return;\n lastTreeJson = json;\n send({type: 'tree', roots});\n };\n\n const onMutation = (): void => {\n if (observeTimer !== undefined) clearTimeout(observeTimer);\n observeTimer = setTimeout(() => {\n observeTimer = undefined;\n if (observer !== null) syncObserverTargets(observer);\n pushTreeIfChanged();\n }, 100);\n };\n\n const setObserving = (enabled: boolean): void => {\n if (enabled) {\n if (observer === null) observer = new MutationObserver(onMutation);\n lastTreeJson = '';\n syncObserverTargets(observer);\n pushTreeIfChanged();\n } else if (observer !== null) {\n observer.disconnect();\n observer = null;\n if (observeTimer !== undefined) {\n clearTimeout(observeTimer);\n observeTimer = undefined;\n }\n }\n };\n\n // -------------------------------------------------------------------------\n // SPA navigation: a route change swaps the component tree without any HMR\n // or panel event, so the snapshot went stale until a manual refresh. Push a\n // deduped tree after each navigation — twice, since routes typically\n // lazy-load and render async. Redundant while the live observer watches.\n // -------------------------------------------------------------------------\n\n const onNavigation = (): void => {\n if (observer !== null) return;\n for (const delay of [150, 1000]) {\n setTimeout(pushTreeIfChanged, delay);\n }\n };\n window.addEventListener('popstate', onNavigation);\n window.addEventListener('hashchange', onNavigation);\n for (const method of ['pushState', 'replaceState'] as const) {\n const original = history[method].bind(history);\n history[method] = (...args: Parameters<History['pushState']>) => {\n original(...args);\n onNavigation();\n };\n }\n\n // -------------------------------------------------------------------------\n // Command dispatch\n // -------------------------------------------------------------------------\n\n hot.on(INSPECT_CMD_CHANNEL, (data) => {\n const cmd = data as InspectorCommand;\n switch (cmd.type) {\n case 'tree': {\n const roots = buildTree();\n lastTreeJson = JSON.stringify(roots);\n send({type: 'tree', roots});\n break;\n }\n case 'details': {\n const el = elementById(cmd.id);\n if (el !== undefined) {\n send({type: 'details', details: collectDetails(el)});\n } else {\n send({type: 'gone', id: cmd.id});\n }\n break;\n }\n case 'watch':\n if (cmd.id === null) unwatch();\n else watch(cmd.id);\n break;\n case 'highlight': {\n if (cmd.id === null) {\n clearHighlight();\n break;\n }\n const el = elementById(cmd.id);\n if (el !== undefined) showHighlight(el);\n else clearHighlight();\n break;\n }\n case 'observe':\n setObserving(cmd.enabled);\n break;\n }\n });\n\n // Announce readiness so a panel that loaded first re-requests the tree.\n send({type: 'ready'});\n}\n"]}
package/lib/tokens.d.ts CHANGED
@@ -8,7 +8,7 @@
8
8
  * {@link injectTokens}. Prefer importing `tokens` for Lit components so the
9
9
  * semantic aliases are inherited from `:root`.
10
10
  */
11
- export declare const tokenCSS = "\n /* ---- Brand \u00B7 the Lit flame ---- */\n --lit-devtools-lit-blue: #324fff;\n --lit-devtools-lit-blue-bright: #4d63ff;\n --lit-devtools-lit-indigo: #2a2c9d;\n --lit-devtools-lit-dark-blue: #283198;\n --lit-devtools-lit-cyan: #00ffff;\n --lit-devtools-lit-dark-cyan: #00e8ff;\n\n /* ---- Neutral ink scale (0 = near-black, 13 = white) ---- */\n --lit-devtools-ink-0: hsl(0 0% 1%);\n --lit-devtools-ink-1: hsl(0 0% 5%);\n --lit-devtools-ink-2: hsl(0 0% 7%);\n --lit-devtools-ink-3: hsl(0 0% 11%);\n --lit-devtools-ink-4: hsl(0 0% 13%);\n --lit-devtools-ink-5: hsl(0 0% 16%);\n --lit-devtools-ink-6: hsl(0 0% 21%);\n --lit-devtools-ink-7: hsl(0 0% 28%);\n --lit-devtools-ink-8: hsl(0 0% 38%);\n --lit-devtools-ink-9: hsl(0 0% 57%);\n --lit-devtools-ink-10: hsl(0 0% 63%);\n --lit-devtools-ink-11: hsl(0 0% 78%);\n --lit-devtools-ink-12: hsl(0 0% 89%);\n --lit-devtools-ink-13: hsl(0 0% 100%);\n\n /* ---- Typography ---- */\n --lit-devtools-font-sans: system-ui, -apple-system, 'Segoe UI', sans-serif;\n --lit-devtools-font-mono: ui-monospace, 'SF Mono', Menlo, Consolas, monospace;\n\n --lit-devtools-weight-regular: 400;\n --lit-devtools-weight-medium: 500;\n --lit-devtools-weight-semibold: 600;\n --lit-devtools-weight-bold: 700;\n --lit-devtools-weight-extrabold: 800;\n\n --lit-devtools-text-2xs: 11px;\n --lit-devtools-text-xs: 12px;\n --lit-devtools-text-sm: 13px;\n --lit-devtools-text-md: 14px;\n --lit-devtools-text-base:16px;\n\n --lit-devtools-leading-tight: 1.15;\n --lit-devtools-leading-snug: 1.3;\n --lit-devtools-leading-normal: 1.5;\n\n --lit-devtools-tracking-tight: -0.02em;\n --lit-devtools-tracking-snug: -0.01em;\n --lit-devtools-tracking-normal: 0;\n --lit-devtools-tracking-wide: 0.02em;\n --lit-devtools-tracking-caps: 0.06em;\n\n /* ---- Spacing (4px base) ---- */\n --lit-devtools-space-0: 0;\n --lit-devtools-space-1: 2px;\n --lit-devtools-space-2: 4px;\n --lit-devtools-space-3: 6px;\n --lit-devtools-space-4: 8px;\n --lit-devtools-space-5: 12px;\n --lit-devtools-space-6: 16px;\n --lit-devtools-space-7: 20px;\n --lit-devtools-space-8: 24px;\n --lit-devtools-space-9: 32px;\n\n /* ---- Radius ---- */\n --lit-devtools-radius-xs: 3px;\n --lit-devtools-radius-sm: 5px;\n --lit-devtools-radius-md: 8px;\n --lit-devtools-radius-lg: 12px;\n --lit-devtools-radius-xl: 16px;\n --lit-devtools-radius-pill: 999px;\n\n /* ---- Elevation ---- */\n --lit-devtools-shadow-xs: 0 1px 2px hsl(0 0% 0% / 0.30);\n --lit-devtools-shadow-sm: 0 1px 5px hsl(0 0% 0% / 0.35);\n --lit-devtools-shadow-md: 0 4px 14px hsl(0 0% 0% / 0.40);\n --lit-devtools-shadow-lg: 0 12px 32px hsl(0 0% 0% / 0.50);\n --lit-devtools-shadow-xl: 0 24px 64px hsl(0 0% 0% / 0.55);\n --lit-devtools-shadow-window: 0 24px 80px hsl(0 0% 0% / 0.6),\n 0 0 0 1px hsl(0 0% 100% / 0.06);\n --lit-devtools-ring: 0 0 0 2px var(--lit-devtools-accent-ring);\n\n /* ---- Motion ---- */\n --lit-devtools-ease-standard: cubic-bezier(0.2, 0, 0, 1);\n --lit-devtools-dur-fast: 140ms;\n --lit-devtools-dur-normal: 220ms;\n\n\n /* ---- DARK \u00B7 DevTools theme ---- */\n --lit-devtools-accent: var(--lit-devtools-lit-blue-bright);\n --lit-devtools-accent-hover: #6478ff;\n --lit-devtools-accent-pressed: #3d54f0;\n --lit-devtools-accent-soft: hsla(232 100% 65% / 0.16);\n --lit-devtools-accent-ring: hsla(232 100% 65% / 0.45);\n --lit-devtools-on-accent: #ffffff;\n --lit-devtools-accent-cyan: var(--lit-devtools-lit-dark-cyan);\n\n --lit-devtools-bg: var(--lit-devtools-ink-0);\n --lit-devtools-surface: var(--lit-devtools-ink-2);\n --lit-devtools-surface-low: var(--lit-devtools-ink-1);\n --lit-devtools-surface-container: var(--lit-devtools-ink-4);\n --lit-devtools-surface-container-high: var(--lit-devtools-ink-5);\n --lit-devtools-surface-elevated: var(--lit-devtools-ink-6);\n --lit-devtools-surface-hover: hsl(0 0% 100% / 0.04);\n --lit-devtools-surface-active: hsl(0 0% 100% / 0.07);\n\n --lit-devtools-text: var(--lit-devtools-ink-12);\n --lit-devtools-text-strong: var(--lit-devtools-ink-13);\n --lit-devtools-text-secondary: var(--lit-devtools-ink-10);\n --lit-devtools-text-muted: var(--lit-devtools-ink-8);\n --lit-devtools-text-link: var(--lit-devtools-lit-blue-bright);\n\n --lit-devtools-border: var(--lit-devtools-ink-6);\n --lit-devtools-border-strong: var(--lit-devtools-ink-7);\n --lit-devtools-border-subtle: hsl(0 0% 100% / 0.06);\n\n --lit-devtools-success: hsl(158 74% 53%);\n --lit-devtools-success-soft: hsl(158 74% 53% / 0.15);\n --lit-devtools-warning: #f4bf4f;\n --lit-devtools-warning-soft: hsl(43 88% 63% / 0.15);\n --lit-devtools-error: #ff6b6b;\n --lit-devtools-error-soft: hsl(0 100% 71% / 0.15);\n --lit-devtools-info: var(--lit-devtools-lit-dark-cyan);\n --lit-devtools-info-soft: hsl(187 100% 47% / 0.15);\n\n --lit-devtools-selection-bg: var(--lit-devtools-accent);\n --lit-devtools-on-selection: #ffffff;\n\n color-scheme: dark;\n";
11
+ export declare const tokenCSS = "\n /* ---- Brand \u00B7 the Lit flame ---- */\n --lit-devtools-lit-blue: #324fff;\n --lit-devtools-lit-blue-bright: #4d63ff;\n --lit-devtools-lit-indigo: #2a2c9d;\n --lit-devtools-lit-dark-blue: #283198;\n --lit-devtools-lit-cyan: #00ffff;\n --lit-devtools-lit-dark-cyan: #00e8ff;\n\n /* ---- Neutral ink scale (0 = near-black, 13 = white) ---- */\n --lit-devtools-ink-0: hsl(0 0% 1%);\n --lit-devtools-ink-1: hsl(0 0% 5%);\n --lit-devtools-ink-2: hsl(0 0% 7%);\n --lit-devtools-ink-3: hsl(0 0% 11%);\n --lit-devtools-ink-4: hsl(0 0% 13%);\n --lit-devtools-ink-5: hsl(0 0% 16%);\n --lit-devtools-ink-6: hsl(0 0% 21%);\n --lit-devtools-ink-7: hsl(0 0% 28%);\n --lit-devtools-ink-8: hsl(0 0% 38%);\n --lit-devtools-ink-9: hsl(0 0% 57%);\n --lit-devtools-ink-10: hsl(0 0% 63%);\n --lit-devtools-ink-11: hsl(0 0% 78%);\n --lit-devtools-ink-12: hsl(0 0% 89%);\n --lit-devtools-ink-13: hsl(0 0% 100%);\n\n /* ---- Typography ---- */\n --lit-devtools-font-sans: system-ui, -apple-system, 'Segoe UI', sans-serif;\n --lit-devtools-font-mono: ui-monospace, 'SF Mono', Menlo, Consolas, monospace;\n\n --lit-devtools-weight-regular: 400;\n --lit-devtools-weight-medium: 500;\n --lit-devtools-weight-semibold: 600;\n --lit-devtools-weight-bold: 700;\n --lit-devtools-weight-extrabold: 800;\n\n --lit-devtools-text-2xs: 11px;\n --lit-devtools-text-xs: 12px;\n --lit-devtools-text-sm: 13px;\n --lit-devtools-text-md: 14px;\n --lit-devtools-text-base:16px;\n\n --lit-devtools-leading-tight: 1.15;\n --lit-devtools-leading-snug: 1.3;\n --lit-devtools-leading-normal: 1.5;\n\n --lit-devtools-tracking-tight: -0.02em;\n --lit-devtools-tracking-snug: -0.01em;\n --lit-devtools-tracking-normal: 0;\n --lit-devtools-tracking-wide: 0.02em;\n --lit-devtools-tracking-caps: 0.06em;\n\n /* ---- Spacing (4px base) ---- */\n --lit-devtools-space-0: 0;\n --lit-devtools-space-1: 2px;\n --lit-devtools-space-2: 4px;\n --lit-devtools-space-3: 6px;\n --lit-devtools-space-4: 8px;\n --lit-devtools-space-5: 12px;\n --lit-devtools-space-6: 16px;\n --lit-devtools-space-7: 20px;\n --lit-devtools-space-8: 24px;\n --lit-devtools-space-9: 32px;\n\n /* ---- Radius ---- */\n --lit-devtools-radius-xs: 3px;\n --lit-devtools-radius-sm: 5px;\n --lit-devtools-radius-md: 8px;\n --lit-devtools-radius-lg: 12px;\n --lit-devtools-radius-xl: 16px;\n --lit-devtools-radius-pill: 999px;\n\n /* ---- Elevation ---- */\n --lit-devtools-shadow-xs: 0 1px 2px hsl(0 0% 0% / 0.30);\n --lit-devtools-shadow-sm: 0 1px 5px hsl(0 0% 0% / 0.35);\n --lit-devtools-shadow-md: 0 4px 14px hsl(0 0% 0% / 0.40);\n --lit-devtools-shadow-lg: 0 12px 32px hsl(0 0% 0% / 0.50);\n --lit-devtools-shadow-xl: 0 24px 64px hsl(0 0% 0% / 0.55);\n --lit-devtools-shadow-window: 0 24px 80px hsl(0 0% 0% / 0.6),\n 0 0 0 1px hsl(0 0% 100% / 0.06);\n --lit-devtools-ring: 0 0 0 2px var(--lit-devtools-accent-ring);\n\n /* ---- Motion ---- */\n --lit-devtools-ease-standard: cubic-bezier(0.2, 0, 0, 1);\n --lit-devtools-dur-fast: 140ms;\n --lit-devtools-dur-normal: 220ms;\n\n\n /* ---- DARK \u00B7 DevTools theme ---- */\n --lit-devtools-accent: var(--lit-devtools-lit-blue-bright);\n --lit-devtools-accent-hover: #6478ff;\n --lit-devtools-accent-pressed: #3d54f0;\n --lit-devtools-accent-soft: hsla(232 100% 65% / 0.16);\n --lit-devtools-accent-ring: hsla(232 100% 65% / 0.45);\n --lit-devtools-on-accent: #ffffff;\n --lit-devtools-accent-cyan: var(--lit-devtools-lit-dark-cyan);\n\n --lit-devtools-bg: var(--lit-devtools-ink-0);\n --lit-devtools-surface: var(--lit-devtools-ink-2);\n --lit-devtools-surface-low: var(--lit-devtools-ink-1);\n --lit-devtools-surface-container: var(--lit-devtools-ink-4);\n --lit-devtools-surface-container-high: var(--lit-devtools-ink-5);\n --lit-devtools-surface-elevated: var(--lit-devtools-ink-6);\n --lit-devtools-surface-hover: hsl(0 0% 100% / 0.04);\n --lit-devtools-surface-active: hsl(0 0% 100% / 0.07);\n\n --lit-devtools-text: var(--lit-devtools-ink-12);\n --lit-devtools-text-strong: var(--lit-devtools-ink-13);\n --lit-devtools-text-secondary: var(--lit-devtools-ink-10);\n --lit-devtools-text-muted: var(--lit-devtools-ink-8);\n --lit-devtools-text-link: var(--lit-devtools-lit-blue-bright);\n\n --lit-devtools-border: var(--lit-devtools-ink-6);\n --lit-devtools-border-strong: var(--lit-devtools-ink-7);\n --lit-devtools-border-subtle: hsl(0 0% 100% / 0.06);\n\n --lit-devtools-success: hsl(158 74% 53%);\n --lit-devtools-success-soft: hsl(158 74% 53% / 0.15);\n --lit-devtools-warning: #f4bf4f;\n --lit-devtools-warning-soft: hsl(43 88% 63% / 0.15);\n --lit-devtools-error: #ff6b6b;\n --lit-devtools-error-soft: hsl(0 100% 71% / 0.15);\n --lit-devtools-info: var(--lit-devtools-lit-dark-cyan);\n --lit-devtools-info-soft: hsl(187 100% 47% / 0.15);\n\n --lit-devtools-selection-bg: var(--lit-devtools-accent);\n --lit-devtools-on-selection: #ffffff;\n";
12
12
  /**
13
13
  * Lit `css` template for use in panel component shadow roots.
14
14
  *
@@ -24,6 +24,28 @@ export declare const tokenCSS = "\n /* ---- Brand \u00B7 the Lit flame ---- */\
24
24
  * \`lit-devtools-panel.ts\` so all components inherit the same dark/light theme.
25
25
  */
26
26
  export declare const tokens: import("lit").CSSResult;
27
+ /**
28
+ * Options for {@link injectTokens} / {@link tokenStyleText}.
29
+ */
30
+ export interface InjectTokensOptions {
31
+ /**
32
+ * Also declare `color-scheme` on `:root`. Only safe when the devtools OWN
33
+ * the target document (the panel iframe / standalone panel page). Never set
34
+ * this when injecting into the host page: `color-scheme` on the embedder's
35
+ * `:root` makes the UA repaint the canvas dark for apps that don't declare
36
+ * an opaque background. Defaults to `false`.
37
+ */
38
+ colorScheme?: boolean;
39
+ }
40
+ /**
41
+ * Builds the token stylesheet text injected by {@link injectTokens}.
42
+ *
43
+ * By default the sheet defines custom properties only — inert for the host
44
+ * page. With `colorScheme: true` it additionally declares `color-scheme` so
45
+ * the owning document's UA surfaces (canvas, form controls, scrollbars)
46
+ * follow the devtools theme.
47
+ */
48
+ export declare const tokenStyleText: ({ colorScheme, }?: InjectTokensOptions) => string;
27
49
  /**
28
50
  * Injects `:root { … }` into the page `<head>` once.
29
51
  *
@@ -33,6 +55,8 @@ export declare const tokens: import("lit").CSSResult;
33
55
  *
34
56
  * The injected stylesheet reacts to `prefers-color-scheme` and to
35
57
  * `.color-scheme-light` / `.color-scheme-dark` classes on the document root.
58
+ * It never sets `color-scheme` on the host page; the panel opts in via
59
+ * {@link InjectTokensOptions.colorScheme} for its own document.
36
60
  */
37
- export declare const injectTokens: () => void;
61
+ export declare const injectTokens: (options?: InjectTokensOptions) => void;
38
62
  //# sourceMappingURL=tokens.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["../../../packages/labs/vite-plugin-lit/src/lib/tokens.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AA2MH;;;;GAIG;AACH,eAAO,MAAM,QAAQ,+uKAAqC,CAAC;AAE3D;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,MAAM,yBAIlB,CAAC;AAIF;;;;;;;;;GASG;AACH,eAAO,MAAM,YAAY,QAAO,IAuB/B,CAAC"}
1
+ {"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["../../../packages/labs/vite-plugin-lit/src/lib/tokens.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AA2MH;;;;GAIG;AACH,eAAO,MAAM,QAAQ,stKAAqC,CAAC;AAE3D;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,MAAM,yBAIlB,CAAC;AAIF;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC;;;;;;OAMG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,cAAc,GAAI,mBAE5B,mBAAwB,KAAG,MAwB7B,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,YAAY,GAAI,UAAU,mBAAmB,KAAG,IAO5D,CAAC"}
package/lib/tokens.js CHANGED
@@ -153,9 +153,8 @@ const darkThemeCSS = `
153
153
 
154
154
  --lit-devtools-selection-bg: var(--lit-devtools-accent);
155
155
  --lit-devtools-on-selection: #ffffff;
156
-
157
- color-scheme: dark;
158
156
  `;
157
+ const darkSchemeCSS = `color-scheme: dark;`;
159
158
  const lightThemeCSS = `
160
159
  /* ---- LIGHT · lit.dev website theme ---- */
161
160
  --lit-devtools-accent: var(--lit-devtools-lit-blue);
@@ -196,9 +195,8 @@ const lightThemeCSS = `
196
195
 
197
196
  --lit-devtools-selection-bg: var(--lit-devtools-accent);
198
197
  --lit-devtools-on-selection: #ffffff;
199
-
200
- color-scheme: light;
201
198
  `;
199
+ const lightSchemeCSS = `color-scheme: light;`;
202
200
  /**
203
201
  * Default dark theme tokens as a flat string, primarily for use by
204
202
  * {@link injectTokens}. Prefer importing `tokens` for Lit components so the
@@ -226,38 +224,57 @@ export const tokens = css `
226
224
  `;
227
225
  let _injected = false;
228
226
  /**
229
- * Injects `:root { … }` into the page `<head>` once.
230
- *
231
- * CSS custom properties defined on `:root` cascade through shadow DOM
232
- * boundaries, so this makes every `var(--lit-devtools-accent)` etc. resolve inside both
233
- * runtime elements (indicator, source-overlay) and Lit panel components.
227
+ * Builds the token stylesheet text injected by {@link injectTokens}.
234
228
  *
235
- * The injected stylesheet reacts to `prefers-color-scheme` and to
236
- * `.color-scheme-light` / `.color-scheme-dark` classes on the document root.
229
+ * By default the sheet defines custom properties only — inert for the host
230
+ * page. With `colorScheme: true` it additionally declares `color-scheme` so
231
+ * the owning document's UA surfaces (canvas, form controls, scrollbars)
232
+ * follow the devtools theme.
237
233
  */
238
- export const injectTokens = () => {
239
- if (_injected)
240
- return;
241
- _injected = true;
242
- const style = document.createElement('style');
243
- style.setAttribute('data-lit-devtools-tokens', '');
244
- style.textContent = `
234
+ export const tokenStyleText = ({ colorScheme = false, } = {}) => {
235
+ const dark = colorScheme
236
+ ? `${darkThemeCSS}\n ${darkSchemeCSS}`
237
+ : darkThemeCSS;
238
+ const light = colorScheme
239
+ ? `${lightThemeCSS}\n ${lightSchemeCSS}`
240
+ : lightThemeCSS;
241
+ return `
245
242
  :root {
246
243
  ${baseTokenCSS}
247
- ${darkThemeCSS}
244
+ ${dark}
248
245
  }
249
246
  @media (prefers-color-scheme: light) {
250
247
  :root {
251
- ${lightThemeCSS}
248
+ ${light}
252
249
  }
253
250
  }
254
251
  :root.color-scheme-light {
255
- ${lightThemeCSS}
252
+ ${light}
256
253
  }
257
254
  :root.color-scheme-dark {
258
- ${darkThemeCSS}
255
+ ${dark}
259
256
  }
260
257
  `;
258
+ };
259
+ /**
260
+ * Injects `:root { … }` into the page `<head>` once.
261
+ *
262
+ * CSS custom properties defined on `:root` cascade through shadow DOM
263
+ * boundaries, so this makes every `var(--lit-devtools-accent)` etc. resolve inside both
264
+ * runtime elements (indicator, source-overlay) and Lit panel components.
265
+ *
266
+ * The injected stylesheet reacts to `prefers-color-scheme` and to
267
+ * `.color-scheme-light` / `.color-scheme-dark` classes on the document root.
268
+ * It never sets `color-scheme` on the host page; the panel opts in via
269
+ * {@link InjectTokensOptions.colorScheme} for its own document.
270
+ */
271
+ export const injectTokens = (options) => {
272
+ if (_injected)
273
+ return;
274
+ _injected = true;
275
+ const style = document.createElement('style');
276
+ style.setAttribute('data-lit-devtools-tokens', '');
277
+ style.textContent = tokenStyleText(options);
261
278
  document.head.prepend(style);
262
279
  };
263
280
  //# sourceMappingURL=tokens.js.map
package/lib/tokens.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"tokens.js","sourceRoot":"","sources":["../../../packages/labs/vite-plugin-lit/src/lib/tokens.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAC,GAAG,EAAE,SAAS,EAAC,MAAM,KAAK,CAAC;AAEnC;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,MAAM,YAAY,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqFpB,CAAC;AAEF,MAAM,YAAY,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA0CpB,CAAC;AAEF,MAAM,aAAa,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA0CrB,CAAC;AAEF;;;;GAIG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG,GAAG,YAAY,KAAK,YAAY,EAAE,CAAC;AAE3D;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG,GAAG,CAAA;;MAEnB,SAAS,CAAC,YAAY,CAAC;;CAE5B,CAAC;AAEF,IAAI,SAAS,GAAG,KAAK,CAAC;AAEtB;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,GAAS,EAAE;IACrC,IAAI,SAAS;QAAE,OAAO;IACtB,SAAS,GAAG,IAAI,CAAC;IACjB,MAAM,KAAK,GAAG,QAAQ,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;IAC9C,KAAK,CAAC,YAAY,CAAC,0BAA0B,EAAE,EAAE,CAAC,CAAC;IACnD,KAAK,CAAC,WAAW,GAAG;;QAEd,YAAY;QACZ,YAAY;;;;UAIV,aAAa;;;;QAIf,aAAa;;;QAGb,YAAY;;GAEjB,CAAC;IACF,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAC/B,CAAC,CAAC","sourcesContent":["/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: BSD-3-Clause\n */\n\nimport {css, unsafeCSS} from 'lit';\n\n/**\n * Design token CSS custom properties for the Lit DevTools.\n *\n * Two entry points:\n * - **`tokens`** — Lit `css` template that defines the theme-agnostic base\n * tokens on `:host`. Semantic color aliases (`--lit-devtools-bg`, `--lit-devtools-surface`, `--lit-devtools-text`,\n * etc.) are inherited from `:root`, where {@link injectTokens} installs them.\n * Use as `static styles = [tokens, css`…`]`.\n * - **`injectTokens()`** — injects `:root { … }` into the page `<head>` once.\n * This makes semantic aliases available to every devtools surface, both\n * runtime elements (indicator, source-overlay) that build their shadow DOM\n * via `innerHTML` and Lit panel components that inherit from `:root`.\n * The injected stylesheet reacts to `prefers-color-scheme` and to\n * `.color-scheme-light` / `.color-scheme-dark` classes on `:root`.\n *\n * Sourced from the lit-design skill (`tokens/colors.css`). Defaults to the\n * dark DevTools theme; the light lit.dev website palette is applied when the\n * OS/browser requests a light color scheme or when `:root` has the matching\n * theme class.\n *\n * Fonts are system stacks (no webfonts). For the branded Manrope + Roboto Mono\n * see the lit-design skill's `fonts/` directory.\n */\n\nconst baseTokenCSS = `\n /* ---- Brand · the Lit flame ---- */\n --lit-devtools-lit-blue: #324fff;\n --lit-devtools-lit-blue-bright: #4d63ff;\n --lit-devtools-lit-indigo: #2a2c9d;\n --lit-devtools-lit-dark-blue: #283198;\n --lit-devtools-lit-cyan: #00ffff;\n --lit-devtools-lit-dark-cyan: #00e8ff;\n\n /* ---- Neutral ink scale (0 = near-black, 13 = white) ---- */\n --lit-devtools-ink-0: hsl(0 0% 1%);\n --lit-devtools-ink-1: hsl(0 0% 5%);\n --lit-devtools-ink-2: hsl(0 0% 7%);\n --lit-devtools-ink-3: hsl(0 0% 11%);\n --lit-devtools-ink-4: hsl(0 0% 13%);\n --lit-devtools-ink-5: hsl(0 0% 16%);\n --lit-devtools-ink-6: hsl(0 0% 21%);\n --lit-devtools-ink-7: hsl(0 0% 28%);\n --lit-devtools-ink-8: hsl(0 0% 38%);\n --lit-devtools-ink-9: hsl(0 0% 57%);\n --lit-devtools-ink-10: hsl(0 0% 63%);\n --lit-devtools-ink-11: hsl(0 0% 78%);\n --lit-devtools-ink-12: hsl(0 0% 89%);\n --lit-devtools-ink-13: hsl(0 0% 100%);\n\n /* ---- Typography ---- */\n --lit-devtools-font-sans: system-ui, -apple-system, 'Segoe UI', sans-serif;\n --lit-devtools-font-mono: ui-monospace, 'SF Mono', Menlo, Consolas, monospace;\n\n --lit-devtools-weight-regular: 400;\n --lit-devtools-weight-medium: 500;\n --lit-devtools-weight-semibold: 600;\n --lit-devtools-weight-bold: 700;\n --lit-devtools-weight-extrabold: 800;\n\n --lit-devtools-text-2xs: 11px;\n --lit-devtools-text-xs: 12px;\n --lit-devtools-text-sm: 13px;\n --lit-devtools-text-md: 14px;\n --lit-devtools-text-base:16px;\n\n --lit-devtools-leading-tight: 1.15;\n --lit-devtools-leading-snug: 1.3;\n --lit-devtools-leading-normal: 1.5;\n\n --lit-devtools-tracking-tight: -0.02em;\n --lit-devtools-tracking-snug: -0.01em;\n --lit-devtools-tracking-normal: 0;\n --lit-devtools-tracking-wide: 0.02em;\n --lit-devtools-tracking-caps: 0.06em;\n\n /* ---- Spacing (4px base) ---- */\n --lit-devtools-space-0: 0;\n --lit-devtools-space-1: 2px;\n --lit-devtools-space-2: 4px;\n --lit-devtools-space-3: 6px;\n --lit-devtools-space-4: 8px;\n --lit-devtools-space-5: 12px;\n --lit-devtools-space-6: 16px;\n --lit-devtools-space-7: 20px;\n --lit-devtools-space-8: 24px;\n --lit-devtools-space-9: 32px;\n\n /* ---- Radius ---- */\n --lit-devtools-radius-xs: 3px;\n --lit-devtools-radius-sm: 5px;\n --lit-devtools-radius-md: 8px;\n --lit-devtools-radius-lg: 12px;\n --lit-devtools-radius-xl: 16px;\n --lit-devtools-radius-pill: 999px;\n\n /* ---- Elevation ---- */\n --lit-devtools-shadow-xs: 0 1px 2px hsl(0 0% 0% / 0.30);\n --lit-devtools-shadow-sm: 0 1px 5px hsl(0 0% 0% / 0.35);\n --lit-devtools-shadow-md: 0 4px 14px hsl(0 0% 0% / 0.40);\n --lit-devtools-shadow-lg: 0 12px 32px hsl(0 0% 0% / 0.50);\n --lit-devtools-shadow-xl: 0 24px 64px hsl(0 0% 0% / 0.55);\n --lit-devtools-shadow-window: 0 24px 80px hsl(0 0% 0% / 0.6),\n 0 0 0 1px hsl(0 0% 100% / 0.06);\n --lit-devtools-ring: 0 0 0 2px var(--lit-devtools-accent-ring);\n\n /* ---- Motion ---- */\n --lit-devtools-ease-standard: cubic-bezier(0.2, 0, 0, 1);\n --lit-devtools-dur-fast: 140ms;\n --lit-devtools-dur-normal: 220ms;\n`;\n\nconst darkThemeCSS = `\n /* ---- DARK · DevTools theme ---- */\n --lit-devtools-accent: var(--lit-devtools-lit-blue-bright);\n --lit-devtools-accent-hover: #6478ff;\n --lit-devtools-accent-pressed: #3d54f0;\n --lit-devtools-accent-soft: hsla(232 100% 65% / 0.16);\n --lit-devtools-accent-ring: hsla(232 100% 65% / 0.45);\n --lit-devtools-on-accent: #ffffff;\n --lit-devtools-accent-cyan: var(--lit-devtools-lit-dark-cyan);\n\n --lit-devtools-bg: var(--lit-devtools-ink-0);\n --lit-devtools-surface: var(--lit-devtools-ink-2);\n --lit-devtools-surface-low: var(--lit-devtools-ink-1);\n --lit-devtools-surface-container: var(--lit-devtools-ink-4);\n --lit-devtools-surface-container-high: var(--lit-devtools-ink-5);\n --lit-devtools-surface-elevated: var(--lit-devtools-ink-6);\n --lit-devtools-surface-hover: hsl(0 0% 100% / 0.04);\n --lit-devtools-surface-active: hsl(0 0% 100% / 0.07);\n\n --lit-devtools-text: var(--lit-devtools-ink-12);\n --lit-devtools-text-strong: var(--lit-devtools-ink-13);\n --lit-devtools-text-secondary: var(--lit-devtools-ink-10);\n --lit-devtools-text-muted: var(--lit-devtools-ink-8);\n --lit-devtools-text-link: var(--lit-devtools-lit-blue-bright);\n\n --lit-devtools-border: var(--lit-devtools-ink-6);\n --lit-devtools-border-strong: var(--lit-devtools-ink-7);\n --lit-devtools-border-subtle: hsl(0 0% 100% / 0.06);\n\n --lit-devtools-success: hsl(158 74% 53%);\n --lit-devtools-success-soft: hsl(158 74% 53% / 0.15);\n --lit-devtools-warning: #f4bf4f;\n --lit-devtools-warning-soft: hsl(43 88% 63% / 0.15);\n --lit-devtools-error: #ff6b6b;\n --lit-devtools-error-soft: hsl(0 100% 71% / 0.15);\n --lit-devtools-info: var(--lit-devtools-lit-dark-cyan);\n --lit-devtools-info-soft: hsl(187 100% 47% / 0.15);\n\n --lit-devtools-selection-bg: var(--lit-devtools-accent);\n --lit-devtools-on-selection: #ffffff;\n\n color-scheme: dark;\n`;\n\nconst lightThemeCSS = `\n /* ---- LIGHT · lit.dev website theme ---- */\n --lit-devtools-accent: var(--lit-devtools-lit-blue);\n --lit-devtools-accent-hover: #1f3bff;\n --lit-devtools-accent-pressed: #2a2c9d;\n --lit-devtools-accent-soft: hsla(232 100% 60% / 0.12);\n --lit-devtools-accent-ring: hsla(232 100% 60% / 0.40);\n --lit-devtools-on-accent: #ffffff;\n --lit-devtools-accent-cyan: var(--lit-devtools-lit-dark-cyan);\n\n --lit-devtools-bg: #f4f4f4;\n --lit-devtools-surface: #ffffff;\n --lit-devtools-surface-low: #f3f3f3;\n --lit-devtools-surface-container: #ffffff;\n --lit-devtools-surface-container-high: #e8e8e8;\n --lit-devtools-surface-elevated: #ffffff;\n --lit-devtools-surface-hover: hsl(0 0% 0% / 0.04);\n --lit-devtools-surface-active: hsl(0 0% 0% / 0.07);\n\n --lit-devtools-text: #242424;\n --lit-devtools-text-strong: #000000;\n --lit-devtools-text-secondary: #6e6e6e;\n --lit-devtools-text-muted: #949494;\n --lit-devtools-text-link: #005dc7;\n\n --lit-devtools-border: #e2e2e2;\n --lit-devtools-border-strong: #c6c6c6;\n --lit-devtools-border-subtle: hsl(0 0% 0% / 0.07);\n\n --lit-devtools-success: #00865b;\n --lit-devtools-success-soft: hsl(158 100% 26% / 0.10);\n --lit-devtools-warning: #b26a00;\n --lit-devtools-warning-soft: hsl(40 100% 35% / 0.10);\n --lit-devtools-error: #ba1a1a;\n --lit-devtools-error-soft: hsl(0 75% 42% / 0.10);\n --lit-devtools-info: #005dc7;\n --lit-devtools-info-soft: hsl(210 100% 39% / 0.10);\n\n --lit-devtools-selection-bg: var(--lit-devtools-accent);\n --lit-devtools-on-selection: #ffffff;\n\n color-scheme: light;\n`;\n\n/**\n * Default dark theme tokens as a flat string, primarily for use by\n * {@link injectTokens}. Prefer importing `tokens` for Lit components so the\n * semantic aliases are inherited from `:root`.\n */\nexport const tokenCSS = `${baseTokenCSS}\\n${darkThemeCSS}`;\n\n/**\n * Lit `css` template for use in panel component shadow roots.\n *\n * ```ts\n * import {tokens} from '../lib/tokens.js';\n * // ...\n * static override styles = [tokens, css`…`];\n * ```\n *\n * This installs the theme-agnostic base tokens on `:host`. Semantic aliases\n * (`--lit-devtools-bg`, `--lit-devtools-text`, etc.) are inherited from `:root`, where they are installed\n * by {@link injectTokens}. The panel iframe calls `injectTokens()` from\n * \\`lit-devtools-panel.ts\\` so all components inherit the same dark/light theme.\n */\nexport const tokens = css`\n :host {\n ${unsafeCSS(baseTokenCSS)}\n }\n`;\n\nlet _injected = false;\n\n/**\n * Injects `:root { … }` into the page `<head>` once.\n *\n * CSS custom properties defined on `:root` cascade through shadow DOM\n * boundaries, so this makes every `var(--lit-devtools-accent)` etc. resolve inside both\n * runtime elements (indicator, source-overlay) and Lit panel components.\n *\n * The injected stylesheet reacts to `prefers-color-scheme` and to\n * `.color-scheme-light` / `.color-scheme-dark` classes on the document root.\n */\nexport const injectTokens = (): void => {\n if (_injected) return;\n _injected = true;\n const style = document.createElement('style');\n style.setAttribute('data-lit-devtools-tokens', '');\n style.textContent = `\n :root {\n ${baseTokenCSS}\n ${darkThemeCSS}\n }\n @media (prefers-color-scheme: light) {\n :root {\n ${lightThemeCSS}\n }\n }\n :root.color-scheme-light {\n ${lightThemeCSS}\n }\n :root.color-scheme-dark {\n ${darkThemeCSS}\n }\n `;\n document.head.prepend(style);\n};\n"]}
1
+ {"version":3,"file":"tokens.js","sourceRoot":"","sources":["../../../packages/labs/vite-plugin-lit/src/lib/tokens.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAC,GAAG,EAAE,SAAS,EAAC,MAAM,KAAK,CAAC;AAEnC;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,MAAM,YAAY,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqFpB,CAAC;AAEF,MAAM,YAAY,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAwCpB,CAAC;AAEF,MAAM,aAAa,GAAG,qBAAqB,CAAC;AAE5C,MAAM,aAAa,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAwCrB,CAAC;AAEF,MAAM,cAAc,GAAG,sBAAsB,CAAC;AAE9C;;;;GAIG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG,GAAG,YAAY,KAAK,YAAY,EAAE,CAAC;AAE3D;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG,GAAG,CAAA;;MAEnB,SAAS,CAAC,YAAY,CAAC;;CAE5B,CAAC;AAEF,IAAI,SAAS,GAAG,KAAK,CAAC;AAgBtB;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,EAC7B,WAAW,GAAG,KAAK,MACI,EAAE,EAAU,EAAE;IACrC,MAAM,IAAI,GAAG,WAAW;QACtB,CAAC,CAAC,GAAG,YAAY,OAAO,aAAa,EAAE;QACvC,CAAC,CAAC,YAAY,CAAC;IACjB,MAAM,KAAK,GAAG,WAAW;QACvB,CAAC,CAAC,GAAG,aAAa,OAAO,cAAc,EAAE;QACzC,CAAC,CAAC,aAAa,CAAC;IAClB,OAAO;;QAED,YAAY;QACZ,IAAI;;;;UAIF,KAAK;;;;QAIP,KAAK;;;QAGL,IAAI;;GAET,CAAC;AACJ,CAAC,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,OAA6B,EAAQ,EAAE;IAClE,IAAI,SAAS;QAAE,OAAO;IACtB,SAAS,GAAG,IAAI,CAAC;IACjB,MAAM,KAAK,GAAG,QAAQ,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;IAC9C,KAAK,CAAC,YAAY,CAAC,0BAA0B,EAAE,EAAE,CAAC,CAAC;IACnD,KAAK,CAAC,WAAW,GAAG,cAAc,CAAC,OAAO,CAAC,CAAC;IAC5C,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAC/B,CAAC,CAAC","sourcesContent":["/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: BSD-3-Clause\n */\n\nimport {css, unsafeCSS} from 'lit';\n\n/**\n * Design token CSS custom properties for the Lit DevTools.\n *\n * Two entry points:\n * - **`tokens`** — Lit `css` template that defines the theme-agnostic base\n * tokens on `:host`. Semantic color aliases (`--lit-devtools-bg`, `--lit-devtools-surface`, `--lit-devtools-text`,\n * etc.) are inherited from `:root`, where {@link injectTokens} installs them.\n * Use as `static styles = [tokens, css`…`]`.\n * - **`injectTokens()`** — injects `:root { … }` into the page `<head>` once.\n * This makes semantic aliases available to every devtools surface, both\n * runtime elements (indicator, source-overlay) that build their shadow DOM\n * via `innerHTML` and Lit panel components that inherit from `:root`.\n * The injected stylesheet reacts to `prefers-color-scheme` and to\n * `.color-scheme-light` / `.color-scheme-dark` classes on `:root`.\n *\n * Sourced from the lit-design skill (`tokens/colors.css`). Defaults to the\n * dark DevTools theme; the light lit.dev website palette is applied when the\n * OS/browser requests a light color scheme or when `:root` has the matching\n * theme class.\n *\n * Fonts are system stacks (no webfonts). For the branded Manrope + Roboto Mono\n * see the lit-design skill's `fonts/` directory.\n */\n\nconst baseTokenCSS = `\n /* ---- Brand · the Lit flame ---- */\n --lit-devtools-lit-blue: #324fff;\n --lit-devtools-lit-blue-bright: #4d63ff;\n --lit-devtools-lit-indigo: #2a2c9d;\n --lit-devtools-lit-dark-blue: #283198;\n --lit-devtools-lit-cyan: #00ffff;\n --lit-devtools-lit-dark-cyan: #00e8ff;\n\n /* ---- Neutral ink scale (0 = near-black, 13 = white) ---- */\n --lit-devtools-ink-0: hsl(0 0% 1%);\n --lit-devtools-ink-1: hsl(0 0% 5%);\n --lit-devtools-ink-2: hsl(0 0% 7%);\n --lit-devtools-ink-3: hsl(0 0% 11%);\n --lit-devtools-ink-4: hsl(0 0% 13%);\n --lit-devtools-ink-5: hsl(0 0% 16%);\n --lit-devtools-ink-6: hsl(0 0% 21%);\n --lit-devtools-ink-7: hsl(0 0% 28%);\n --lit-devtools-ink-8: hsl(0 0% 38%);\n --lit-devtools-ink-9: hsl(0 0% 57%);\n --lit-devtools-ink-10: hsl(0 0% 63%);\n --lit-devtools-ink-11: hsl(0 0% 78%);\n --lit-devtools-ink-12: hsl(0 0% 89%);\n --lit-devtools-ink-13: hsl(0 0% 100%);\n\n /* ---- Typography ---- */\n --lit-devtools-font-sans: system-ui, -apple-system, 'Segoe UI', sans-serif;\n --lit-devtools-font-mono: ui-monospace, 'SF Mono', Menlo, Consolas, monospace;\n\n --lit-devtools-weight-regular: 400;\n --lit-devtools-weight-medium: 500;\n --lit-devtools-weight-semibold: 600;\n --lit-devtools-weight-bold: 700;\n --lit-devtools-weight-extrabold: 800;\n\n --lit-devtools-text-2xs: 11px;\n --lit-devtools-text-xs: 12px;\n --lit-devtools-text-sm: 13px;\n --lit-devtools-text-md: 14px;\n --lit-devtools-text-base:16px;\n\n --lit-devtools-leading-tight: 1.15;\n --lit-devtools-leading-snug: 1.3;\n --lit-devtools-leading-normal: 1.5;\n\n --lit-devtools-tracking-tight: -0.02em;\n --lit-devtools-tracking-snug: -0.01em;\n --lit-devtools-tracking-normal: 0;\n --lit-devtools-tracking-wide: 0.02em;\n --lit-devtools-tracking-caps: 0.06em;\n\n /* ---- Spacing (4px base) ---- */\n --lit-devtools-space-0: 0;\n --lit-devtools-space-1: 2px;\n --lit-devtools-space-2: 4px;\n --lit-devtools-space-3: 6px;\n --lit-devtools-space-4: 8px;\n --lit-devtools-space-5: 12px;\n --lit-devtools-space-6: 16px;\n --lit-devtools-space-7: 20px;\n --lit-devtools-space-8: 24px;\n --lit-devtools-space-9: 32px;\n\n /* ---- Radius ---- */\n --lit-devtools-radius-xs: 3px;\n --lit-devtools-radius-sm: 5px;\n --lit-devtools-radius-md: 8px;\n --lit-devtools-radius-lg: 12px;\n --lit-devtools-radius-xl: 16px;\n --lit-devtools-radius-pill: 999px;\n\n /* ---- Elevation ---- */\n --lit-devtools-shadow-xs: 0 1px 2px hsl(0 0% 0% / 0.30);\n --lit-devtools-shadow-sm: 0 1px 5px hsl(0 0% 0% / 0.35);\n --lit-devtools-shadow-md: 0 4px 14px hsl(0 0% 0% / 0.40);\n --lit-devtools-shadow-lg: 0 12px 32px hsl(0 0% 0% / 0.50);\n --lit-devtools-shadow-xl: 0 24px 64px hsl(0 0% 0% / 0.55);\n --lit-devtools-shadow-window: 0 24px 80px hsl(0 0% 0% / 0.6),\n 0 0 0 1px hsl(0 0% 100% / 0.06);\n --lit-devtools-ring: 0 0 0 2px var(--lit-devtools-accent-ring);\n\n /* ---- Motion ---- */\n --lit-devtools-ease-standard: cubic-bezier(0.2, 0, 0, 1);\n --lit-devtools-dur-fast: 140ms;\n --lit-devtools-dur-normal: 220ms;\n`;\n\nconst darkThemeCSS = `\n /* ---- DARK · DevTools theme ---- */\n --lit-devtools-accent: var(--lit-devtools-lit-blue-bright);\n --lit-devtools-accent-hover: #6478ff;\n --lit-devtools-accent-pressed: #3d54f0;\n --lit-devtools-accent-soft: hsla(232 100% 65% / 0.16);\n --lit-devtools-accent-ring: hsla(232 100% 65% / 0.45);\n --lit-devtools-on-accent: #ffffff;\n --lit-devtools-accent-cyan: var(--lit-devtools-lit-dark-cyan);\n\n --lit-devtools-bg: var(--lit-devtools-ink-0);\n --lit-devtools-surface: var(--lit-devtools-ink-2);\n --lit-devtools-surface-low: var(--lit-devtools-ink-1);\n --lit-devtools-surface-container: var(--lit-devtools-ink-4);\n --lit-devtools-surface-container-high: var(--lit-devtools-ink-5);\n --lit-devtools-surface-elevated: var(--lit-devtools-ink-6);\n --lit-devtools-surface-hover: hsl(0 0% 100% / 0.04);\n --lit-devtools-surface-active: hsl(0 0% 100% / 0.07);\n\n --lit-devtools-text: var(--lit-devtools-ink-12);\n --lit-devtools-text-strong: var(--lit-devtools-ink-13);\n --lit-devtools-text-secondary: var(--lit-devtools-ink-10);\n --lit-devtools-text-muted: var(--lit-devtools-ink-8);\n --lit-devtools-text-link: var(--lit-devtools-lit-blue-bright);\n\n --lit-devtools-border: var(--lit-devtools-ink-6);\n --lit-devtools-border-strong: var(--lit-devtools-ink-7);\n --lit-devtools-border-subtle: hsl(0 0% 100% / 0.06);\n\n --lit-devtools-success: hsl(158 74% 53%);\n --lit-devtools-success-soft: hsl(158 74% 53% / 0.15);\n --lit-devtools-warning: #f4bf4f;\n --lit-devtools-warning-soft: hsl(43 88% 63% / 0.15);\n --lit-devtools-error: #ff6b6b;\n --lit-devtools-error-soft: hsl(0 100% 71% / 0.15);\n --lit-devtools-info: var(--lit-devtools-lit-dark-cyan);\n --lit-devtools-info-soft: hsl(187 100% 47% / 0.15);\n\n --lit-devtools-selection-bg: var(--lit-devtools-accent);\n --lit-devtools-on-selection: #ffffff;\n`;\n\nconst darkSchemeCSS = `color-scheme: dark;`;\n\nconst lightThemeCSS = `\n /* ---- LIGHT · lit.dev website theme ---- */\n --lit-devtools-accent: var(--lit-devtools-lit-blue);\n --lit-devtools-accent-hover: #1f3bff;\n --lit-devtools-accent-pressed: #2a2c9d;\n --lit-devtools-accent-soft: hsla(232 100% 60% / 0.12);\n --lit-devtools-accent-ring: hsla(232 100% 60% / 0.40);\n --lit-devtools-on-accent: #ffffff;\n --lit-devtools-accent-cyan: var(--lit-devtools-lit-dark-cyan);\n\n --lit-devtools-bg: #f4f4f4;\n --lit-devtools-surface: #ffffff;\n --lit-devtools-surface-low: #f3f3f3;\n --lit-devtools-surface-container: #ffffff;\n --lit-devtools-surface-container-high: #e8e8e8;\n --lit-devtools-surface-elevated: #ffffff;\n --lit-devtools-surface-hover: hsl(0 0% 0% / 0.04);\n --lit-devtools-surface-active: hsl(0 0% 0% / 0.07);\n\n --lit-devtools-text: #242424;\n --lit-devtools-text-strong: #000000;\n --lit-devtools-text-secondary: #6e6e6e;\n --lit-devtools-text-muted: #949494;\n --lit-devtools-text-link: #005dc7;\n\n --lit-devtools-border: #e2e2e2;\n --lit-devtools-border-strong: #c6c6c6;\n --lit-devtools-border-subtle: hsl(0 0% 0% / 0.07);\n\n --lit-devtools-success: #00865b;\n --lit-devtools-success-soft: hsl(158 100% 26% / 0.10);\n --lit-devtools-warning: #b26a00;\n --lit-devtools-warning-soft: hsl(40 100% 35% / 0.10);\n --lit-devtools-error: #ba1a1a;\n --lit-devtools-error-soft: hsl(0 75% 42% / 0.10);\n --lit-devtools-info: #005dc7;\n --lit-devtools-info-soft: hsl(210 100% 39% / 0.10);\n\n --lit-devtools-selection-bg: var(--lit-devtools-accent);\n --lit-devtools-on-selection: #ffffff;\n`;\n\nconst lightSchemeCSS = `color-scheme: light;`;\n\n/**\n * Default dark theme tokens as a flat string, primarily for use by\n * {@link injectTokens}. Prefer importing `tokens` for Lit components so the\n * semantic aliases are inherited from `:root`.\n */\nexport const tokenCSS = `${baseTokenCSS}\\n${darkThemeCSS}`;\n\n/**\n * Lit `css` template for use in panel component shadow roots.\n *\n * ```ts\n * import {tokens} from '../lib/tokens.js';\n * // ...\n * static override styles = [tokens, css`…`];\n * ```\n *\n * This installs the theme-agnostic base tokens on `:host`. Semantic aliases\n * (`--lit-devtools-bg`, `--lit-devtools-text`, etc.) are inherited from `:root`, where they are installed\n * by {@link injectTokens}. The panel iframe calls `injectTokens()` from\n * \\`lit-devtools-panel.ts\\` so all components inherit the same dark/light theme.\n */\nexport const tokens = css`\n :host {\n ${unsafeCSS(baseTokenCSS)}\n }\n`;\n\nlet _injected = false;\n\n/**\n * Options for {@link injectTokens} / {@link tokenStyleText}.\n */\nexport interface InjectTokensOptions {\n /**\n * Also declare `color-scheme` on `:root`. Only safe when the devtools OWN\n * the target document (the panel iframe / standalone panel page). Never set\n * this when injecting into the host page: `color-scheme` on the embedder's\n * `:root` makes the UA repaint the canvas dark for apps that don't declare\n * an opaque background. Defaults to `false`.\n */\n colorScheme?: boolean;\n}\n\n/**\n * Builds the token stylesheet text injected by {@link injectTokens}.\n *\n * By default the sheet defines custom properties only — inert for the host\n * page. With `colorScheme: true` it additionally declares `color-scheme` so\n * the owning document's UA surfaces (canvas, form controls, scrollbars)\n * follow the devtools theme.\n */\nexport const tokenStyleText = ({\n colorScheme = false,\n}: InjectTokensOptions = {}): string => {\n const dark = colorScheme\n ? `${darkThemeCSS}\\n ${darkSchemeCSS}`\n : darkThemeCSS;\n const light = colorScheme\n ? `${lightThemeCSS}\\n ${lightSchemeCSS}`\n : lightThemeCSS;\n return `\n :root {\n ${baseTokenCSS}\n ${dark}\n }\n @media (prefers-color-scheme: light) {\n :root {\n ${light}\n }\n }\n :root.color-scheme-light {\n ${light}\n }\n :root.color-scheme-dark {\n ${dark}\n }\n `;\n};\n\n/**\n * Injects `:root { … }` into the page `<head>` once.\n *\n * CSS custom properties defined on `:root` cascade through shadow DOM\n * boundaries, so this makes every `var(--lit-devtools-accent)` etc. resolve inside both\n * runtime elements (indicator, source-overlay) and Lit panel components.\n *\n * The injected stylesheet reacts to `prefers-color-scheme` and to\n * `.color-scheme-light` / `.color-scheme-dark` classes on the document root.\n * It never sets `color-scheme` on the host page; the panel opts in via\n * {@link InjectTokensOptions.colorScheme} for its own document.\n */\nexport const injectTokens = (options?: InjectTokensOptions): void => {\n if (_injected) return;\n _injected = true;\n const style = document.createElement('style');\n style.setAttribute('data-lit-devtools-tokens', '');\n style.textContent = tokenStyleText(options);\n document.head.prepend(style);\n};\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oddsquad/vite-plugin-lit",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "description": "Vite plugin providing true HMR for Lit components, plus CSS helpers and a DevTools panel",
5
5
  "license": "BSD-3-Clause",
6
6
  "author": "Oddsquad (based on @lit-labs/vite-hmr by Google LLC)",
@@ -1 +1 @@
1
- {"version":3,"file":"lit-devtools-panel.d.ts","sourceRoot":"","sources":["../../../packages/labs/vite-plugin-lit/src/panel/lit-devtools-panel.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAC,UAAU,EAAqB,MAAM,KAAK,CAAC;AAOnD,OAAO,oBAAoB,CAAC;AAS5B,OAAO,sBAAsB,CAAC;AAE9B,OAAO,wBAAwB,CAAC;AAChC,OAAO,0BAA0B,CAAC;AAqClC;;;;GAIG;AACH,qBACa,gBAAiB,SAAQ,UAAU;IAC9C,OAAgB,MAAM,4BA2CpB;IAEO,OAAO,CAAC,IAAI,CAAgB;IAEX,OAAO,CAAC,eAAe,CAAC,CAAiB;IAEnE,OAAO,CAAC,YAAY;IAIpB,yEAAyE;IACzE,OAAO,CAAC,iBAAiB;IAMzB;;;;;OAKG;IACH,OAAO,CAAC,oBAAoB;IA4BnB,MAAM;CAwBhB;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,oBAAoB,EAAE,gBAAgB,CAAC;KACxC;CACF"}
1
+ {"version":3,"file":"lit-devtools-panel.d.ts","sourceRoot":"","sources":["../../../packages/labs/vite-plugin-lit/src/panel/lit-devtools-panel.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAC,UAAU,EAAqB,MAAM,KAAK,CAAC;AAOnD,OAAO,oBAAoB,CAAC;AAW5B,OAAO,sBAAsB,CAAC;AAE9B,OAAO,wBAAwB,CAAC;AAChC,OAAO,0BAA0B,CAAC;AAqClC;;;;GAIG;AACH,qBACa,gBAAiB,SAAQ,UAAU;IAC9C,OAAgB,MAAM,4BA2CpB;IAEO,OAAO,CAAC,IAAI,CAAgB;IAEX,OAAO,CAAC,eAAe,CAAC,CAAiB;IAEnE,OAAO,CAAC,YAAY;IAIpB,yEAAyE;IACzE,OAAO,CAAC,iBAAiB;IAMzB;;;;;OAKG;IACH,OAAO,CAAC,oBAAoB;IA4BnB,MAAM;CAwBhB;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,oBAAoB,EAAE,gBAAgB,CAAC;KACxC;CACF"}
@@ -16,7 +16,9 @@ import { applyColorScheme, readColorSchemePreference, } from '../lib/color-schem
16
16
  import './timeline-view.js';
17
17
  // Install the shared design tokens on the panel iframe's :root before the
18
18
  // views render. Panel components inherit the semantic aliases from :root.
19
- injectTokens();
19
+ // The panel owns this document, so it also declares `color-scheme` (host-page
20
+ // injections must not — see `injectTokens`).
21
+ injectTokens({ colorScheme: true });
20
22
  // Own the color-scheme class once the panel module is live: re-assert the
21
23
  // saved preference (the Settings tab mounts lazily, so it can't). `auto` needs
22
24
  // no JS — the tokens' `prefers-color-scheme` @media rule resolves it live.
@@ -1 +1 @@
1
- {"version":3,"file":"lit-devtools-panel.js","sourceRoot":"","sources":["../../../packages/labs/vite-plugin-lit/src/panel/lit-devtools-panel.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: BSD-3-Clause\n */\n\nimport {LitElement, html, css, nothing} from 'lit';\nimport {customElement, query, state} from 'lit/decorators.js';\nimport {tokens, injectTokens} from '../lib/tokens.js';\nimport {\n applyColorScheme,\n readColorSchemePreference,\n} from '../lib/color-scheme.js';\nimport './timeline-view.js';\n\n// Install the shared design tokens on the panel iframe's :root before the\n// views render. Panel components inherit the semantic aliases from :root.\ninjectTokens();\n// Own the color-scheme class once the panel module is live: re-assert the\n// saved preference (the Settings tab mounts lazily, so it can't). `auto` needs\n// no JS — the tokens' `prefers-color-scheme` @media rule resolves it live.\napplyColorScheme(readColorSchemePreference());\nimport './components-view.js';\nimport type {ComponentsView} from './components-view.js';\nimport './devtools-settings.js';\nimport '../lib/segmented-tabs.js';\nimport type {TabItem} from '../lib/segmented-tabs.js';\nimport {CUBE_ICON, CLOCK_ICON, GEAR_ICON} from '../lib/icons.js';\n\n/**\n * Tabs hosted by the panel. The Timeline is the first; this list is the\n * extension point for future Lit DevTools views.\n */\nconst TABS: readonly TabItem[] = [\n {id: 'components', label: 'Components', icon: CUBE_ICON},\n {id: 'timeline', label: 'Timeline', icon: CLOCK_ICON},\n {id: 'settings', label: 'Settings', icon: GEAR_ICON},\n];\n\n/** Inline Lit logo mark. */\nconst LIT_LOGO_SVG = html`<svg\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"-32 0 320 320\"\n width=\"20\"\n height=\"20\"\n aria-hidden=\"true\"\n>\n <path\n fill=\"#00e8ff\"\n d=\"m64 192l25.926-44.727l38.233-19.114l63.974 63.974l10.833 61.754L192 320l-64-64l-38.074-25.615z\"\n />\n <path\n fill=\"#283198\"\n d=\"M128 256V128l64-64v128zM0 256l64 64l9.202-60.602L64 192l-37.542 23.71z\"\n />\n <path\n fill=\"#324fff\"\n d=\"M64 192V64l64-64v128zm128 128V192l64-64v128zM0 256V128l64 64z\"\n />\n <path fill=\"#0ff\" d=\"M64 320V192l64 64z\" />\n</svg>`;\n\n/**\n * Root of the Lit DevTools panel — a tabbed shell. Each tab's view is kept\n * mounted and merely hidden when inactive, so the Timeline keeps recording\n * (and holds its events) while another tab is in front.\n */\n@customElement('lit-devtools-panel')\nexport class LitDevtoolsPanel extends LitElement {\n static override styles = [\n tokens,\n css`\n :host {\n display: flex;\n flex-direction: column;\n height: 100vh;\n font-family: var(--lit-devtools-font-sans);\n font-size: var(--lit-devtools-text-sm);\n background: var(--lit-devtools-bg);\n color: var(--lit-devtools-text);\n overflow: hidden;\n }\n header {\n display: flex;\n align-items: center;\n gap: var(--lit-devtools-space-6);\n padding: 0 var(--lit-devtools-space-5);\n border-bottom: 1px solid var(--lit-devtools-border);\n background: var(--lit-devtools-surface-low);\n flex-shrink: 0;\n }\n .brand {\n display: flex;\n align-items: center;\n gap: var(--lit-devtools-space-4);\n color: var(--lit-devtools-text-strong);\n font-weight: var(--lit-devtools-weight-bold);\n font-size: var(--lit-devtools-text-xs);\n letter-spacing: var(--lit-devtools-tracking-caps);\n text-transform: uppercase;\n padding: var(--lit-devtools-space-5) 0;\n }\n .brand svg {\n display: block;\n }\n .view {\n display: flex;\n flex-direction: column;\n flex: 1;\n overflow: hidden;\n }\n `,\n ];\n\n @state() private _tab = 'components';\n\n @query('components-view') private _componentsView?: ComponentsView;\n\n private _onTabChange(e: CustomEvent<{value: string}>) {\n this._tab = e.detail.value;\n }\n\n /** A timeline event's \"inspect\" link — open the Components tab on it. */\n private _onInspectElement(e: CustomEvent<{id: number}>) {\n this._tab = 'components';\n // The view is always mounted, so it can select without waiting for render.\n this._componentsView?.selectById(e.detail.id);\n }\n\n /**\n * A component was picked via the overlay inspector — switch to the Components\n * tab and request the parent DevTools shell to bring this dock entry to the\n * front, so the user can see the picked element without having to manually\n * open the Lit panel first.\n */\n private _onInspectorActivate() {\n this._tab = 'components';\n // The panel iframe is same-origin with the Vite DevTools shell — the\n // parent exposes its DevTools client context on\n // window.__VITE_DEVTOOLS_CLIENT_CONTEXT__ (set by @vitejs/devtools's\n // inject.ts). Ask it to select the Lit dock entry so the panel becomes\n // visible.\n try {\n const parent = window.parent;\n if (\n parent &&\n parent !== window &&\n '__VITE_DEVTOOLS_CLIENT_CONTEXT__' in parent\n ) {\n const ctx = (\n parent as unknown as Record<\n string,\n | undefined\n | {docks?: {switchEntry?: (id: string) => Promise<boolean>}}\n >\n ).__VITE_DEVTOOLS_CLIENT_CONTEXT__;\n ctx?.docks?.switchEntry?.('lit-devtools');\n }\n } catch {\n // Cross-origin or not running inside the DevTools shell — ignore.\n }\n }\n\n override render() {\n return html`\n <header>\n <span class=\"brand\">${LIT_LOGO_SVG} Lit DevTools</span>\n <segmented-tabs\n .items=${TABS}\n .value=${this._tab}\n @change=${this._onTabChange}\n ></segmented-tabs>\n </header>\n <div class=\"view\" @inspect-element=${this._onInspectElement}>\n <timeline-view ?hidden=${this._tab !== 'timeline'}></timeline-view>\n <!-- Kept mounted (like the timeline) so an overlay inspect-pick can\n arrive and switch us here even while another tab is in front. -->\n <components-view\n ?hidden=${this._tab !== 'components'}\n @inspector-activate=${this._onInspectorActivate}\n ></components-view>\n ${this._tab === 'settings'\n ? html`<devtools-settings></devtools-settings>`\n : nothing}\n </div>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'lit-devtools-panel': LitDevtoolsPanel;\n }\n}\n"]}
1
+ {"version":3,"file":"lit-devtools-panel.js","sourceRoot":"","sources":["../../../packages/labs/vite-plugin-lit/src/panel/lit-devtools-panel.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: BSD-3-Clause\n */\n\nimport {LitElement, html, css, nothing} from 'lit';\nimport {customElement, query, state} from 'lit/decorators.js';\nimport {tokens, injectTokens} from '../lib/tokens.js';\nimport {\n applyColorScheme,\n readColorSchemePreference,\n} from '../lib/color-scheme.js';\nimport './timeline-view.js';\n\n// Install the shared design tokens on the panel iframe's :root before the\n// views render. Panel components inherit the semantic aliases from :root.\n// The panel owns this document, so it also declares `color-scheme` (host-page\n// injections must not — see `injectTokens`).\ninjectTokens({colorScheme: true});\n// Own the color-scheme class once the panel module is live: re-assert the\n// saved preference (the Settings tab mounts lazily, so it can't). `auto` needs\n// no JS — the tokens' `prefers-color-scheme` @media rule resolves it live.\napplyColorScheme(readColorSchemePreference());\nimport './components-view.js';\nimport type {ComponentsView} from './components-view.js';\nimport './devtools-settings.js';\nimport '../lib/segmented-tabs.js';\nimport type {TabItem} from '../lib/segmented-tabs.js';\nimport {CUBE_ICON, CLOCK_ICON, GEAR_ICON} from '../lib/icons.js';\n\n/**\n * Tabs hosted by the panel. The Timeline is the first; this list is the\n * extension point for future Lit DevTools views.\n */\nconst TABS: readonly TabItem[] = [\n {id: 'components', label: 'Components', icon: CUBE_ICON},\n {id: 'timeline', label: 'Timeline', icon: CLOCK_ICON},\n {id: 'settings', label: 'Settings', icon: GEAR_ICON},\n];\n\n/** Inline Lit logo mark. */\nconst LIT_LOGO_SVG = html`<svg\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"-32 0 320 320\"\n width=\"20\"\n height=\"20\"\n aria-hidden=\"true\"\n>\n <path\n fill=\"#00e8ff\"\n d=\"m64 192l25.926-44.727l38.233-19.114l63.974 63.974l10.833 61.754L192 320l-64-64l-38.074-25.615z\"\n />\n <path\n fill=\"#283198\"\n d=\"M128 256V128l64-64v128zM0 256l64 64l9.202-60.602L64 192l-37.542 23.71z\"\n />\n <path\n fill=\"#324fff\"\n d=\"M64 192V64l64-64v128zm128 128V192l64-64v128zM0 256V128l64 64z\"\n />\n <path fill=\"#0ff\" d=\"M64 320V192l64 64z\" />\n</svg>`;\n\n/**\n * Root of the Lit DevTools panel — a tabbed shell. Each tab's view is kept\n * mounted and merely hidden when inactive, so the Timeline keeps recording\n * (and holds its events) while another tab is in front.\n */\n@customElement('lit-devtools-panel')\nexport class LitDevtoolsPanel extends LitElement {\n static override styles = [\n tokens,\n css`\n :host {\n display: flex;\n flex-direction: column;\n height: 100vh;\n font-family: var(--lit-devtools-font-sans);\n font-size: var(--lit-devtools-text-sm);\n background: var(--lit-devtools-bg);\n color: var(--lit-devtools-text);\n overflow: hidden;\n }\n header {\n display: flex;\n align-items: center;\n gap: var(--lit-devtools-space-6);\n padding: 0 var(--lit-devtools-space-5);\n border-bottom: 1px solid var(--lit-devtools-border);\n background: var(--lit-devtools-surface-low);\n flex-shrink: 0;\n }\n .brand {\n display: flex;\n align-items: center;\n gap: var(--lit-devtools-space-4);\n color: var(--lit-devtools-text-strong);\n font-weight: var(--lit-devtools-weight-bold);\n font-size: var(--lit-devtools-text-xs);\n letter-spacing: var(--lit-devtools-tracking-caps);\n text-transform: uppercase;\n padding: var(--lit-devtools-space-5) 0;\n }\n .brand svg {\n display: block;\n }\n .view {\n display: flex;\n flex-direction: column;\n flex: 1;\n overflow: hidden;\n }\n `,\n ];\n\n @state() private _tab = 'components';\n\n @query('components-view') private _componentsView?: ComponentsView;\n\n private _onTabChange(e: CustomEvent<{value: string}>) {\n this._tab = e.detail.value;\n }\n\n /** A timeline event's \"inspect\" link — open the Components tab on it. */\n private _onInspectElement(e: CustomEvent<{id: number}>) {\n this._tab = 'components';\n // The view is always mounted, so it can select without waiting for render.\n this._componentsView?.selectById(e.detail.id);\n }\n\n /**\n * A component was picked via the overlay inspector — switch to the Components\n * tab and request the parent DevTools shell to bring this dock entry to the\n * front, so the user can see the picked element without having to manually\n * open the Lit panel first.\n */\n private _onInspectorActivate() {\n this._tab = 'components';\n // The panel iframe is same-origin with the Vite DevTools shell — the\n // parent exposes its DevTools client context on\n // window.__VITE_DEVTOOLS_CLIENT_CONTEXT__ (set by @vitejs/devtools's\n // inject.ts). Ask it to select the Lit dock entry so the panel becomes\n // visible.\n try {\n const parent = window.parent;\n if (\n parent &&\n parent !== window &&\n '__VITE_DEVTOOLS_CLIENT_CONTEXT__' in parent\n ) {\n const ctx = (\n parent as unknown as Record<\n string,\n | undefined\n | {docks?: {switchEntry?: (id: string) => Promise<boolean>}}\n >\n ).__VITE_DEVTOOLS_CLIENT_CONTEXT__;\n ctx?.docks?.switchEntry?.('lit-devtools');\n }\n } catch {\n // Cross-origin or not running inside the DevTools shell — ignore.\n }\n }\n\n override render() {\n return html`\n <header>\n <span class=\"brand\">${LIT_LOGO_SVG} Lit DevTools</span>\n <segmented-tabs\n .items=${TABS}\n .value=${this._tab}\n @change=${this._onTabChange}\n ></segmented-tabs>\n </header>\n <div class=\"view\" @inspect-element=${this._onInspectElement}>\n <timeline-view ?hidden=${this._tab !== 'timeline'}></timeline-view>\n <!-- Kept mounted (like the timeline) so an overlay inspect-pick can\n arrive and switch us here even while another tab is in front. -->\n <components-view\n ?hidden=${this._tab !== 'components'}\n @inspector-activate=${this._onInspectorActivate}\n ></components-view>\n ${this._tab === 'settings'\n ? html`<devtools-settings></devtools-settings>`\n : nothing}\n </div>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'lit-devtools-panel': LitDevtoolsPanel;\n }\n}\n"]}