@oddsquad/vite-plugin-lit 0.0.3 → 0.0.5

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.
Files changed (175) hide show
  1. package/index.d.ts +3 -2
  2. package/index.d.ts.map +1 -1
  3. package/index.js +1 -1
  4. package/index.js.map +1 -1
  5. package/lib/color-scheme.d.ts +30 -0
  6. package/lib/color-scheme.d.ts.map +1 -0
  7. package/lib/color-scheme.js +41 -0
  8. package/lib/color-scheme.js.map +1 -0
  9. package/lib/icons.d.ts +18 -0
  10. package/lib/icons.d.ts.map +1 -0
  11. package/lib/icons.js +23 -0
  12. package/lib/icons.js.map +1 -0
  13. package/lib/plugin.d.ts +71 -6
  14. package/lib/plugin.d.ts.map +1 -1
  15. package/lib/plugin.js +522 -21
  16. package/lib/plugin.js.map +1 -1
  17. package/lib/runtime/css.d.ts +94 -0
  18. package/lib/runtime/css.d.ts.map +1 -0
  19. package/lib/runtime/css.js +112 -0
  20. package/lib/runtime/css.js.map +1 -0
  21. package/lib/runtime/edge-panel.d.ts +18 -0
  22. package/lib/runtime/edge-panel.d.ts.map +1 -0
  23. package/lib/runtime/edge-panel.js +130 -0
  24. package/lib/runtime/edge-panel.js.map +1 -0
  25. package/lib/runtime/fonts.d.ts +18 -0
  26. package/lib/runtime/fonts.d.ts.map +1 -0
  27. package/lib/runtime/fonts.js +18 -0
  28. package/lib/runtime/fonts.js.map +1 -0
  29. package/lib/runtime/indicator.d.ts +7 -0
  30. package/lib/runtime/indicator.d.ts.map +1 -0
  31. package/lib/runtime/indicator.js +141 -0
  32. package/lib/runtime/indicator.js.map +1 -0
  33. package/lib/runtime/inspector/collect.d.ts +17 -0
  34. package/lib/runtime/inspector/collect.d.ts.map +1 -0
  35. package/lib/runtime/inspector/collect.js +132 -0
  36. package/lib/runtime/inspector/collect.js.map +1 -0
  37. package/lib/runtime/inspector/install.d.ts +7 -0
  38. package/lib/runtime/inspector/install.d.ts.map +1 -0
  39. package/lib/runtime/inspector/install.js +204 -0
  40. package/lib/runtime/inspector/install.js.map +1 -0
  41. package/lib/runtime/inspector/serialize.d.ts +10 -0
  42. package/lib/runtime/inspector/serialize.d.ts.map +1 -0
  43. package/lib/runtime/inspector/serialize.js +133 -0
  44. package/lib/runtime/inspector/serialize.js.map +1 -0
  45. package/lib/runtime/intern.d.ts.map +1 -1
  46. package/lib/runtime/intern.js +1 -1
  47. package/lib/runtime/intern.js.map +1 -1
  48. package/lib/runtime/overrides.d.ts +25 -0
  49. package/lib/runtime/overrides.d.ts.map +1 -0
  50. package/lib/runtime/overrides.js +33 -0
  51. package/lib/runtime/overrides.js.map +1 -0
  52. package/lib/runtime/patch.d.ts +6 -15
  53. package/lib/runtime/patch.d.ts.map +1 -1
  54. package/lib/runtime/patch.js +81 -28
  55. package/lib/runtime/patch.js.map +1 -1
  56. package/lib/runtime/source-meta.d.ts +16 -0
  57. package/lib/runtime/source-meta.d.ts.map +1 -0
  58. package/lib/runtime/source-meta.js +8 -0
  59. package/lib/runtime/source-meta.js.map +1 -0
  60. package/lib/runtime/source-overlay/editors.d.ts +9 -0
  61. package/lib/runtime/source-overlay/editors.d.ts.map +1 -0
  62. package/lib/runtime/source-overlay/editors.js +40 -0
  63. package/lib/runtime/source-overlay/editors.js.map +1 -0
  64. package/lib/runtime/source-overlay/mask-path.d.ts +7 -0
  65. package/lib/runtime/source-overlay/mask-path.d.ts.map +1 -0
  66. package/lib/runtime/source-overlay/mask-path.js +26 -0
  67. package/lib/runtime/source-overlay/mask-path.js.map +1 -0
  68. package/lib/runtime/source-overlay/overlay-element.d.ts +18 -0
  69. package/lib/runtime/source-overlay/overlay-element.d.ts.map +1 -0
  70. package/lib/runtime/source-overlay/overlay-element.js +381 -0
  71. package/lib/runtime/source-overlay/overlay-element.js.map +1 -0
  72. package/lib/runtime/source-overlay/source-host.d.ts +14 -0
  73. package/lib/runtime/source-overlay/source-host.d.ts.map +1 -0
  74. package/lib/runtime/source-overlay/source-host.js +94 -0
  75. package/lib/runtime/source-overlay/source-host.js.map +1 -0
  76. package/lib/runtime/source-overlay/template.d.ts +7 -0
  77. package/lib/runtime/source-overlay/template.d.ts.map +1 -0
  78. package/lib/runtime/source-overlay/template.js +125 -0
  79. package/lib/runtime/source-overlay/template.js.map +1 -0
  80. package/lib/runtime/source-overlay.d.ts +7 -0
  81. package/lib/runtime/source-overlay.d.ts.map +1 -0
  82. package/lib/runtime/source-overlay.js +11 -0
  83. package/lib/runtime/source-overlay.js.map +1 -0
  84. package/lib/runtime/timeline/clock.d.ts +10 -0
  85. package/lib/runtime/timeline/clock.d.ts.map +1 -0
  86. package/lib/runtime/timeline/clock.js +22 -0
  87. package/lib/runtime/timeline/clock.js.map +1 -0
  88. package/lib/runtime/timeline/identity.d.ts +37 -0
  89. package/lib/runtime/timeline/identity.d.ts.map +1 -0
  90. package/lib/runtime/timeline/identity.js +73 -0
  91. package/lib/runtime/timeline/identity.js.map +1 -0
  92. package/lib/runtime/timeline/input.d.ts +16 -0
  93. package/lib/runtime/timeline/input.d.ts.map +1 -0
  94. package/lib/runtime/timeline/input.js +87 -0
  95. package/lib/runtime/timeline/input.js.map +1 -0
  96. package/lib/runtime/timeline/install.d.ts +7 -0
  97. package/lib/runtime/timeline/install.d.ts.map +1 -0
  98. package/lib/runtime/timeline/install.js +69 -0
  99. package/lib/runtime/timeline/install.js.map +1 -0
  100. package/lib/runtime/timeline/lifecycle.d.ts +27 -0
  101. package/lib/runtime/timeline/lifecycle.d.ts.map +1 -0
  102. package/lib/runtime/timeline/lifecycle.js +225 -0
  103. package/lib/runtime/timeline/lifecycle.js.map +1 -0
  104. package/lib/runtime/timeline/public-api.d.ts +28 -0
  105. package/lib/runtime/timeline/public-api.d.ts.map +1 -0
  106. package/lib/runtime/timeline/public-api.js +44 -0
  107. package/lib/runtime/timeline/public-api.js.map +1 -0
  108. package/lib/runtime/timeline/render.d.ts +39 -0
  109. package/lib/runtime/timeline/render.d.ts.map +1 -0
  110. package/lib/runtime/timeline/render.js +109 -0
  111. package/lib/runtime/timeline/render.js.map +1 -0
  112. package/lib/runtime/timeline/transport.d.ts +42 -0
  113. package/lib/runtime/timeline/transport.d.ts.map +1 -0
  114. package/lib/runtime/timeline/transport.js +86 -0
  115. package/lib/runtime/timeline/transport.js.map +1 -0
  116. package/lib/segmented-tabs.d.ts +33 -0
  117. package/lib/segmented-tabs.d.ts.map +1 -0
  118. package/lib/segmented-tabs.js +129 -0
  119. package/lib/segmented-tabs.js.map +1 -0
  120. package/lib/source-meta.d.ts +26 -0
  121. package/lib/source-meta.d.ts.map +1 -0
  122. package/lib/source-meta.js +129 -0
  123. package/lib/source-meta.js.map +1 -0
  124. package/lib/timeline-plugin.d.ts +72 -0
  125. package/lib/timeline-plugin.d.ts.map +1 -0
  126. package/lib/timeline-plugin.js +376 -0
  127. package/lib/timeline-plugin.js.map +1 -0
  128. package/lib/tokens.d.ts +38 -0
  129. package/lib/tokens.d.ts.map +1 -0
  130. package/lib/tokens.js +263 -0
  131. package/lib/tokens.js.map +1 -0
  132. package/lib/transform.d.ts +5 -5
  133. package/lib/transform.d.ts.map +1 -1
  134. package/lib/transform.js +3 -3
  135. package/lib/transform.js.map +1 -1
  136. package/lib/types.d.ts +34 -0
  137. package/lib/types.d.ts.map +1 -0
  138. package/lib/types.js +7 -0
  139. package/lib/types.js.map +1 -0
  140. package/lib/wrap-table.d.ts.map +1 -1
  141. package/lib/wrap-table.js.map +1 -1
  142. package/package.json +18 -4
  143. package/panel/components-view.d.ts +60 -0
  144. package/panel/components-view.d.ts.map +1 -0
  145. package/panel/components-view.js +581 -0
  146. package/panel/components-view.js.map +1 -0
  147. package/panel/devtools-settings.d.ts +41 -0
  148. package/panel/devtools-settings.d.ts.map +1 -0
  149. package/panel/devtools-settings.js +463 -0
  150. package/panel/devtools-settings.js.map +1 -0
  151. package/panel/index.html +29 -0
  152. package/panel/lit-devtools-panel.d.ts +37 -0
  153. package/panel/lit-devtools-panel.d.ts.map +1 -0
  154. package/panel/lit-devtools-panel.js +183 -0
  155. package/panel/lit-devtools-panel.js.map +1 -0
  156. package/panel/timeline-event-list.d.ts +43 -0
  157. package/panel/timeline-event-list.d.ts.map +1 -0
  158. package/panel/timeline-event-list.js +416 -0
  159. package/panel/timeline-event-list.js.map +1 -0
  160. package/panel/timeline-layers.d.ts +25 -0
  161. package/panel/timeline-layers.d.ts.map +1 -0
  162. package/panel/timeline-layers.js +96 -0
  163. package/panel/timeline-layers.js.map +1 -0
  164. package/panel/timeline-view.d.ts +38 -0
  165. package/panel/timeline-view.d.ts.map +1 -0
  166. package/panel/timeline-view.js +234 -0
  167. package/panel/timeline-view.js.map +1 -0
  168. package/types/inspector.d.ts +130 -0
  169. package/types/inspector.d.ts.map +1 -0
  170. package/types/inspector.js +16 -0
  171. package/types/inspector.js.map +1 -0
  172. package/types/timeline.d.ts +98 -0
  173. package/types/timeline.d.ts.map +1 -0
  174. package/types/timeline.js +39 -0
  175. package/types/timeline.js.map +1 -0
@@ -0,0 +1,141 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Google LLC
4
+ * SPDX-License-Identifier: BSD-3-Clause
5
+ */
6
+ /**
7
+ * Custom element for the HMR update indicator.
8
+ * Injected by the Vite plugin as an external module so that
9
+ * `import.meta.hot` is available.
10
+ */
11
+ import { FONT_MONO_VAR } from './fonts.js';
12
+ import { FLAME_ICON } from '../icons.js';
13
+ import { subscribeOverride } from './overrides.js';
14
+ import { observeEdgeInsets } from './edge-panel.js';
15
+ import { injectTokens } from '../tokens.js';
16
+ /**
17
+ * True when an HMR batch is purely a stylesheet swap — every update is either
18
+ * a `css-update` or a `js-update` whose accepted module is a `.css` source
19
+ * (the shared-sheet queries `?css-sheet`/`?raw`/`?url` all accept a `.css`
20
+ * path). Such a batch restyles adopted sheets in place with no re-render.
21
+ *
22
+ * Heuristic: keyed on the accepted path ending in `.css`. Robust for this
23
+ * plugin's own queries; a user hand-wiring `import.meta.hot.accept` on a raw
24
+ * `.css` would also read as a style swap, which is the intended grouping. An
25
+ * empty/missing payload can't be classified, so it counts as a re-render
26
+ * rather than being silently dropped.
27
+ */
28
+ function isStyleSwap(data) {
29
+ const updates = data?.updates;
30
+ if (!Array.isArray(updates) || updates.length === 0)
31
+ return false;
32
+ return updates.every((u) => {
33
+ if (u.type === 'css-update')
34
+ return true;
35
+ if (u.type === 'js-update') {
36
+ return (u.acceptedPath ?? u.path ?? '').split('?')[0].endsWith('.css');
37
+ }
38
+ return false;
39
+ });
40
+ }
41
+ class LitDevtoolsIndicator extends HTMLElement {
42
+ #initialized = false;
43
+ #count = 0;
44
+ #container;
45
+ #countEl = null;
46
+ constructor() {
47
+ super();
48
+ const root = this.attachShadow({ mode: 'closed' });
49
+ // `--idle-op` is the at-rest opacity: 0 (invisible until a pulse) without a
50
+ // count, .5 (count stays legible) with one. The count display and idle
51
+ // opacity are both driven by the `.with-count` class so the panel can
52
+ // toggle the count on/off live (see #setCount).
53
+ root.innerHTML = `
54
+ <style>
55
+ @keyframes pulse{0%{opacity:var(--idle-op,0)}15%{opacity:1}80%{opacity:1}100%{opacity:var(--idle-op,0)}}
56
+ :host{
57
+ position:fixed;inset:0;display:grid;
58
+ z-index:2147483647;pointer-events:none;
59
+ /* Base padding plus the inset the Vite DevTools edge panel occupies
60
+ on each edge (set from JS), so the indicator never sits on it. */
61
+ padding:
62
+ calc(var(--lit-devtools-hmr-indicator-padding,16px) + var(--edge-top,0px))
63
+ calc(var(--lit-devtools-hmr-indicator-padding,16px) + var(--edge-right,0px))
64
+ calc(var(--lit-devtools-hmr-indicator-padding,16px) + var(--edge-bottom,0px))
65
+ calc(var(--lit-devtools-hmr-indicator-padding,16px) + var(--edge-left,0px))
66
+ }
67
+ #container{
68
+ place-self:var(--lit-devtools-hmr-indicator-align,end end);
69
+ display:flex;align-items:stretch;
70
+ background:var(--lit-devtools-surface-elevated);color:var(--lit-devtools-text-strong);
71
+ backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);
72
+ border-radius:var(--lit-devtools-radius-md);
73
+ font:12px/1 ${FONT_MONO_VAR};font-variant-numeric:tabular-nums;
74
+ overflow:hidden;opacity:var(--idle-op,0)
75
+ }
76
+ #container.with-count{--idle-op:.5}
77
+ #container.active{animation:pulse 2.5s ease-out forwards}
78
+ #icon{display:flex;align-items:center;justify-content:center;padding:0 10px}
79
+ #icon svg{width:16px;height:16px;display:block;fill:currentColor}
80
+ #indicator{
81
+ display:flex;align-items:center;gap:6px;
82
+ padding:7px 12px;
83
+ border-left:1px solid var(--lit-devtools-border-subtle)
84
+ }
85
+ .dot{width:8px;height:8px;border-radius:50%;background:var(--lit-devtools-success);flex-shrink:0}
86
+ /* Style-only swaps (shared adopted stylesheet hot-swap, no re-render)
87
+ pulse in the calmer info color and don't bump the count. */
88
+ #container.style-swap .dot{background:var(--lit-devtools-info)}
89
+ .count{display:none}
90
+ #container.with-count .count{display:inline}
91
+ </style>
92
+ <div id="container"><span id="icon">${FLAME_ICON}</span><span id="indicator"><span class="dot"></span><span class="count">0</span></span></div>
93
+ `;
94
+ this.#container = root.getElementById('container');
95
+ this.#countEl = root.querySelector('.count');
96
+ this.#setCount(this.hasAttribute('count'));
97
+ }
98
+ /** Show/hide the cumulative update count (and the at-rest opacity). */
99
+ #setCount(enabled) {
100
+ this.#container.classList.toggle('with-count', enabled);
101
+ }
102
+ connectedCallback() {
103
+ if (this.#initialized)
104
+ return;
105
+ this.#initialized = true;
106
+ injectTokens();
107
+ const hot = import.meta.hot;
108
+ hot?.on('vite:afterUpdate', (data) => {
109
+ // Count only updates that actually re-render/re-execute a component;
110
+ // a pure shared-stylesheet swap (?css-sheet / ?raw / ?url adopted sheet)
111
+ // restyles in place without re-rendering, so it pulses but doesn't count.
112
+ const styleSwap = isStyleSwap(data);
113
+ if (!styleSwap && this.#countEl !== null) {
114
+ this.#countEl.textContent = String(++this.#count);
115
+ }
116
+ this.#container.classList.toggle('style-swap', styleSwap);
117
+ this.#container.classList.remove('active');
118
+ void this.#container.offsetWidth;
119
+ this.#container.classList.add('active');
120
+ });
121
+ // Let the DevTools panel hide/show the indicator and its count live (and
122
+ // across reloads).
123
+ subscribeOverride(hot, (o) => {
124
+ if (o.hmrIndicatorVisible !== undefined) {
125
+ this.style.display = o.hmrIndicatorVisible ? '' : 'none';
126
+ }
127
+ if (o.hmrIndicatorCount !== undefined) {
128
+ this.#setCount(o.hmrIndicatorCount);
129
+ }
130
+ });
131
+ // Stay clear of the Vite DevTools edge panel.
132
+ observeEdgeInsets((insets) => {
133
+ this.style.setProperty('--edge-top', `${insets.top}px`);
134
+ this.style.setProperty('--edge-right', `${insets.right}px`);
135
+ this.style.setProperty('--edge-bottom', `${insets.bottom}px`);
136
+ this.style.setProperty('--edge-left', `${insets.left}px`);
137
+ });
138
+ }
139
+ }
140
+ customElements.define('lit-devtools-hmr-indicator', LitDevtoolsIndicator);
141
+ //# sourceMappingURL=indicator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"indicator.js","sourceRoot":"","sources":["../../../../packages/labs/vite-plugin-lit/src/lib/runtime/indicator.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 * Custom element for the HMR update indicator.\n * Injected by the Vite plugin as an external module so that\n * `import.meta.hot` is available.\n */\n\nimport {FONT_MONO_VAR} from './fonts.js';\nimport {FLAME_ICON} from '../icons.js';\nimport {subscribeOverride} from './overrides.js';\nimport {observeEdgeInsets} from './edge-panel.js';\nimport {injectTokens} from '../tokens.js';\n\n/** One entry of a Vite `vite:afterUpdate` payload. */\ninterface ViteUpdate {\n type?: string;\n path?: string;\n acceptedPath?: string;\n}\n\n/**\n * True when an HMR batch is purely a stylesheet swap — every update is either\n * a `css-update` or a `js-update` whose accepted module is a `.css` source\n * (the shared-sheet queries `?css-sheet`/`?raw`/`?url` all accept a `.css`\n * path). Such a batch restyles adopted sheets in place with no re-render.\n *\n * Heuristic: keyed on the accepted path ending in `.css`. Robust for this\n * plugin's own queries; a user hand-wiring `import.meta.hot.accept` on a raw\n * `.css` would also read as a style swap, which is the intended grouping. An\n * empty/missing payload can't be classified, so it counts as a re-render\n * rather than being silently dropped.\n */\nfunction isStyleSwap(data: unknown): boolean {\n const updates = (data as {updates?: ViteUpdate[]} | undefined)?.updates;\n if (!Array.isArray(updates) || updates.length === 0) return false;\n return updates.every((u) => {\n if (u.type === 'css-update') return true;\n if (u.type === 'js-update') {\n return (u.acceptedPath ?? u.path ?? '').split('?')[0].endsWith('.css');\n }\n return false;\n });\n}\n\nclass LitDevtoolsIndicator extends HTMLElement {\n #initialized = false;\n #count = 0;\n #container: HTMLElement;\n #countEl: HTMLElement | null = null;\n\n constructor() {\n super();\n const root = this.attachShadow({mode: 'closed'});\n // `--idle-op` is the at-rest opacity: 0 (invisible until a pulse) without a\n // count, .5 (count stays legible) with one. The count display and idle\n // opacity are both driven by the `.with-count` class so the panel can\n // toggle the count on/off live (see #setCount).\n root.innerHTML = `\n <style>\n @keyframes pulse{0%{opacity:var(--idle-op,0)}15%{opacity:1}80%{opacity:1}100%{opacity:var(--idle-op,0)}}\n :host{\n position:fixed;inset:0;display:grid;\n z-index:2147483647;pointer-events:none;\n /* Base padding plus the inset the Vite DevTools edge panel occupies\n on each edge (set from JS), so the indicator never sits on it. */\n padding:\n calc(var(--lit-devtools-hmr-indicator-padding,16px) + var(--edge-top,0px))\n calc(var(--lit-devtools-hmr-indicator-padding,16px) + var(--edge-right,0px))\n calc(var(--lit-devtools-hmr-indicator-padding,16px) + var(--edge-bottom,0px))\n calc(var(--lit-devtools-hmr-indicator-padding,16px) + var(--edge-left,0px))\n }\n #container{\n place-self:var(--lit-devtools-hmr-indicator-align,end end);\n display:flex;align-items:stretch;\n background:var(--lit-devtools-surface-elevated);color:var(--lit-devtools-text-strong);\n backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);\n border-radius:var(--lit-devtools-radius-md);\n font:12px/1 ${FONT_MONO_VAR};font-variant-numeric:tabular-nums;\n overflow:hidden;opacity:var(--idle-op,0)\n }\n #container.with-count{--idle-op:.5}\n #container.active{animation:pulse 2.5s ease-out forwards}\n #icon{display:flex;align-items:center;justify-content:center;padding:0 10px}\n #icon svg{width:16px;height:16px;display:block;fill:currentColor}\n #indicator{\n display:flex;align-items:center;gap:6px;\n padding:7px 12px;\n border-left:1px solid var(--lit-devtools-border-subtle)\n }\n .dot{width:8px;height:8px;border-radius:50%;background:var(--lit-devtools-success);flex-shrink:0}\n /* Style-only swaps (shared adopted stylesheet hot-swap, no re-render)\n pulse in the calmer info color and don't bump the count. */\n #container.style-swap .dot{background:var(--lit-devtools-info)}\n .count{display:none}\n #container.with-count .count{display:inline}\n </style>\n <div id=\"container\"><span id=\"icon\">${FLAME_ICON}</span><span id=\"indicator\"><span class=\"dot\"></span><span class=\"count\">0</span></span></div>\n `;\n this.#container = root.getElementById('container')!;\n this.#countEl = root.querySelector('.count');\n this.#setCount(this.hasAttribute('count'));\n }\n\n /** Show/hide the cumulative update count (and the at-rest opacity). */\n #setCount(enabled: boolean) {\n this.#container.classList.toggle('with-count', enabled);\n }\n\n connectedCallback() {\n if (this.#initialized) return;\n this.#initialized = true;\n injectTokens();\n const hot = (\n import.meta as {\n hot?: {on: (event: string, cb: (data?: unknown) => void) => void};\n }\n ).hot;\n hot?.on('vite:afterUpdate', (data) => {\n // Count only updates that actually re-render/re-execute a component;\n // a pure shared-stylesheet swap (?css-sheet / ?raw / ?url adopted sheet)\n // restyles in place without re-rendering, so it pulses but doesn't count.\n const styleSwap = isStyleSwap(data);\n if (!styleSwap && this.#countEl !== null) {\n this.#countEl.textContent = String(++this.#count);\n }\n this.#container.classList.toggle('style-swap', styleSwap);\n this.#container.classList.remove('active');\n void this.#container.offsetWidth;\n this.#container.classList.add('active');\n });\n // Let the DevTools panel hide/show the indicator and its count live (and\n // across reloads).\n subscribeOverride(hot, (o) => {\n if (o.hmrIndicatorVisible !== undefined) {\n this.style.display = o.hmrIndicatorVisible ? '' : 'none';\n }\n if (o.hmrIndicatorCount !== undefined) {\n this.#setCount(o.hmrIndicatorCount);\n }\n });\n // Stay clear of the Vite DevTools edge panel.\n observeEdgeInsets((insets) => {\n this.style.setProperty('--edge-top', `${insets.top}px`);\n this.style.setProperty('--edge-right', `${insets.right}px`);\n this.style.setProperty('--edge-bottom', `${insets.bottom}px`);\n this.style.setProperty('--edge-left', `${insets.left}px`);\n });\n }\n}\n\ncustomElements.define('lit-devtools-hmr-indicator', LitDevtoolsIndicator);\n"]}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Google LLC
4
+ * SPDX-License-Identifier: BSD-3-Clause
5
+ */
6
+ import type { InspectorDetails, InspectorTreeNode } from '../../../types/inspector.js';
7
+ /**
8
+ * An element worth showing in the tree: an upgraded custom element that
9
+ * duck-types as a ReactiveElement. Catches Lit components regardless of whether
10
+ * the source-meta transform touched them, while skipping devtools' own UI.
11
+ */
12
+ export declare const isInspectable: (el: Element) => boolean;
13
+ /** Build the full component render tree rooted at the document body. */
14
+ export declare const buildTree: () => InspectorTreeNode[];
15
+ /** Snapshot one element's reactive properties, attributes, and flags. */
16
+ export declare const collectDetails: (el: Element) => InspectorDetails;
17
+ //# sourceMappingURL=collect.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"collect.d.ts","sourceRoot":"","sources":["../../../../../packages/labs/vite-plugin-lit/src/lib/runtime/inspector/collect.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAUH,OAAO,KAAK,EAEV,gBAAgB,EAEhB,iBAAiB,EAClB,MAAM,6BAA6B,CAAC;AAsCrC;;;;GAIG;AACH,eAAO,MAAM,aAAa,GAAI,IAAI,OAAO,KAAG,OAO3C,CAAC;AA2CF,wEAAwE;AACxE,eAAO,MAAM,SAAS,QAAO,iBAAiB,EAI7C,CAAC;AAWF,yEAAyE;AACzE,eAAO,MAAM,cAAc,GAAI,IAAI,OAAO,KAAG,gBA6C5C,CAAC"}
@@ -0,0 +1,132 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Google LLC
4
+ * SPDX-License-Identifier: BSD-3-Clause
5
+ */
6
+ /**
7
+ * Walks the page to build the component render tree and to snapshot a single
8
+ * element's reactive state for the inspector panel. Runs entirely in the page;
9
+ * the results are sent over the transport as plain JSON.
10
+ */
11
+ import { idOf } from '../timeline/identity.js';
12
+ import { serialize, typeTag } from './serialize.js';
13
+ const SOURCE_META_KEY = Symbol.for('@lit-labs/vite-plugin-lit#source');
14
+ const metaOf = (el) => el.constructor[SOURCE_META_KEY];
15
+ const sourceOf = (el) => {
16
+ const meta = metaOf(el);
17
+ return meta === undefined
18
+ ? undefined
19
+ : { file: meta.filePath, line: meta.lineNumber };
20
+ };
21
+ /**
22
+ * An element worth showing in the tree: an upgraded custom element that
23
+ * duck-types as a ReactiveElement. Catches Lit components regardless of whether
24
+ * the source-meta transform touched them, while skipping devtools' own UI.
25
+ */
26
+ export const isInspectable = (el) => {
27
+ const tag = el.tagName.toLowerCase();
28
+ if (!tag.includes('-'))
29
+ return false;
30
+ if (tag === 'lit-source-overlay' || tag.startsWith('lit-devtools-')) {
31
+ return false;
32
+ }
33
+ return typeof el.requestUpdate === 'function';
34
+ };
35
+ const nodeFor = (el, children) => {
36
+ const meta = metaOf(el);
37
+ return {
38
+ id: idOf(el),
39
+ tagName: el.tagName.toLowerCase(),
40
+ componentName: meta?.componentName,
41
+ source: meta === undefined
42
+ ? undefined
43
+ : { file: meta.filePath, line: meta.lineNumber },
44
+ children,
45
+ };
46
+ };
47
+ /**
48
+ * Visits `el`: if it's inspectable it becomes a node whose children are the
49
+ * inspectables nested in its shadow + light DOM; otherwise we descend, pushing
50
+ * any inspectables we find into the current `sink` (so non-component wrappers
51
+ * are flattened away).
52
+ */
53
+ const visit = (el, sink) => {
54
+ if (isInspectable(el)) {
55
+ const children = [];
56
+ descend(el, children);
57
+ sink.push(nodeFor(el, children));
58
+ }
59
+ else {
60
+ descend(el, sink);
61
+ }
62
+ };
63
+ const descend = (el, sink) => {
64
+ const shadow = el.shadowRoot;
65
+ if (shadow !== null) {
66
+ for (const child of shadow.children)
67
+ visit(child, sink);
68
+ }
69
+ for (const child of el.children)
70
+ visit(child, sink);
71
+ };
72
+ /** Build the full component render tree rooted at the document body. */
73
+ export const buildTree = () => {
74
+ const roots = [];
75
+ for (const child of document.body.children)
76
+ visit(child, roots);
77
+ return roots;
78
+ };
79
+ const attributeName = (key, decl) => {
80
+ if (decl.attribute === false)
81
+ return false;
82
+ if (typeof decl.attribute === 'string')
83
+ return decl.attribute;
84
+ return String(key).toLowerCase();
85
+ };
86
+ /** Snapshot one element's reactive properties, attributes, and flags. */
87
+ export const collectDetails = (el) => {
88
+ const re = el;
89
+ const declarations = re.constructor.elementProperties;
90
+ const properties = [];
91
+ if (declarations !== undefined) {
92
+ for (const [key, decl] of declarations) {
93
+ // Reading a reactive property runs its accessor, which may throw; one bad
94
+ // getter must not take out the whole details snapshot.
95
+ let value;
96
+ let threw = false;
97
+ try {
98
+ value = el[key];
99
+ }
100
+ catch {
101
+ threw = true;
102
+ }
103
+ properties.push({
104
+ name: typeof key === 'symbol' ? key.toString() : String(key),
105
+ value: threw ? '[getter threw]' : serialize(value),
106
+ type: threw ? 'error' : typeTag(value),
107
+ attribute: attributeName(key, decl),
108
+ reflects: decl.reflect === true,
109
+ state: decl.state === true,
110
+ });
111
+ }
112
+ }
113
+ const attributes = Array.from(el.attributes, (a) => ({
114
+ name: a.name,
115
+ value: a.value,
116
+ }));
117
+ const meta = metaOf(el);
118
+ return {
119
+ id: idOf(el),
120
+ tagName: el.tagName.toLowerCase(),
121
+ componentName: meta?.componentName,
122
+ source: sourceOf(el),
123
+ attributes,
124
+ properties,
125
+ flags: {
126
+ hasUpdated: re.hasUpdated === true,
127
+ isUpdatePending: re.isUpdatePending === true,
128
+ hasShadowRoot: el.shadowRoot !== null,
129
+ },
130
+ };
131
+ };
132
+ //# sourceMappingURL=collect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"collect.js","sourceRoot":"","sources":["../../../../../packages/labs/vite-plugin-lit/src/lib/runtime/inspector/collect.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 * Walks the page to build the component render tree and to snapshot a single\n * element's reactive state for the inspector panel. Runs entirely in the page;\n * the results are sent over the transport as plain JSON.\n */\n\nimport {idOf} from '../timeline/identity.js';\nimport {serialize, typeTag} from './serialize.js';\nimport type {\n ElementSource,\n InspectorDetails,\n InspectorProp,\n InspectorTreeNode,\n} from '../../../types/inspector.js';\n\nconst SOURCE_META_KEY = Symbol.for('@lit-labs/vite-plugin-lit#source');\n\ninterface LitSourceMeta {\n filePath: string;\n lineNumber: number;\n componentName: string;\n}\n\n/** Subset of ReactiveElement's `PropertyDeclaration` we read. */\ninterface PropertyDeclaration {\n attribute?: boolean | string;\n reflect?: boolean;\n state?: boolean;\n}\n\n/** Subset of a ReactiveElement instance/constructor we duck-type against. */\ninterface ReactiveElementLike extends Element {\n requestUpdate?: unknown;\n hasUpdated?: boolean;\n isUpdatePending?: boolean;\n constructor: {\n elementProperties?: Map<PropertyKey, PropertyDeclaration>;\n [SOURCE_META_KEY]?: LitSourceMeta;\n };\n}\n\nconst metaOf = (el: Element): LitSourceMeta | undefined =>\n (el as ReactiveElementLike).constructor[SOURCE_META_KEY];\n\nconst sourceOf = (el: Element): ElementSource | undefined => {\n const meta = metaOf(el);\n return meta === undefined\n ? undefined\n : {file: meta.filePath, line: meta.lineNumber};\n};\n\n/**\n * An element worth showing in the tree: an upgraded custom element that\n * duck-types as a ReactiveElement. Catches Lit components regardless of whether\n * the source-meta transform touched them, while skipping devtools' own UI.\n */\nexport const isInspectable = (el: Element): boolean => {\n const tag = el.tagName.toLowerCase();\n if (!tag.includes('-')) return false;\n if (tag === 'lit-source-overlay' || tag.startsWith('lit-devtools-')) {\n return false;\n }\n return typeof (el as ReactiveElementLike).requestUpdate === 'function';\n};\n\nconst nodeFor = (\n el: Element,\n children: InspectorTreeNode[]\n): InspectorTreeNode => {\n const meta = metaOf(el);\n return {\n id: idOf(el),\n tagName: el.tagName.toLowerCase(),\n componentName: meta?.componentName,\n source:\n meta === undefined\n ? undefined\n : {file: meta.filePath, line: meta.lineNumber},\n children,\n };\n};\n\n/**\n * Visits `el`: if it's inspectable it becomes a node whose children are the\n * inspectables nested in its shadow + light DOM; otherwise we descend, pushing\n * any inspectables we find into the current `sink` (so non-component wrappers\n * are flattened away).\n */\nconst visit = (el: Element, sink: InspectorTreeNode[]): void => {\n if (isInspectable(el)) {\n const children: InspectorTreeNode[] = [];\n descend(el, children);\n sink.push(nodeFor(el, children));\n } else {\n descend(el, sink);\n }\n};\n\nconst descend = (el: Element, sink: InspectorTreeNode[]): void => {\n const shadow = el.shadowRoot;\n if (shadow !== null) {\n for (const child of shadow.children) visit(child, sink);\n }\n for (const child of el.children) visit(child, sink);\n};\n\n/** Build the full component render tree rooted at the document body. */\nexport const buildTree = (): InspectorTreeNode[] => {\n const roots: InspectorTreeNode[] = [];\n for (const child of document.body.children) visit(child, roots);\n return roots;\n};\n\nconst attributeName = (\n key: PropertyKey,\n decl: PropertyDeclaration\n): string | false => {\n if (decl.attribute === false) return false;\n if (typeof decl.attribute === 'string') return decl.attribute;\n return String(key).toLowerCase();\n};\n\n/** Snapshot one element's reactive properties, attributes, and flags. */\nexport const collectDetails = (el: Element): InspectorDetails => {\n const re = el as ReactiveElementLike;\n const declarations = re.constructor.elementProperties;\n const properties: InspectorProp[] = [];\n if (declarations !== undefined) {\n for (const [key, decl] of declarations) {\n // Reading a reactive property runs its accessor, which may throw; one bad\n // getter must not take out the whole details snapshot.\n let value: unknown;\n let threw = false;\n try {\n value = (el as unknown as Record<PropertyKey, unknown>)[key];\n } catch {\n threw = true;\n }\n properties.push({\n name: typeof key === 'symbol' ? key.toString() : String(key),\n value: threw ? '[getter threw]' : serialize(value),\n type: threw ? 'error' : typeTag(value),\n attribute: attributeName(key, decl),\n reflects: decl.reflect === true,\n state: decl.state === true,\n });\n }\n }\n\n const attributes = Array.from(el.attributes, (a) => ({\n name: a.name,\n value: a.value,\n }));\n\n const meta = metaOf(el);\n return {\n id: idOf(el),\n tagName: el.tagName.toLowerCase(),\n componentName: meta?.componentName,\n source: sourceOf(el),\n attributes,\n properties,\n flags: {\n hasUpdated: re.hasUpdated === true,\n isUpdatePending: re.isUpdatePending === true,\n hasShadowRoot: el.shadowRoot !== null,\n },\n };\n};\n"]}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Google LLC
4
+ * SPDX-License-Identifier: BSD-3-Clause
5
+ */
6
+ export {};
7
+ //# sourceMappingURL=install.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../../../../../packages/labs/vite-plugin-lit/src/lib/runtime/inspector/install.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
@@ -0,0 +1,204 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Google LLC
4
+ * SPDX-License-Identifier: BSD-3-Clause
5
+ */
6
+ /**
7
+ * Components inspector runtime.
8
+ *
9
+ * Injected into the host page (alongside the timeline runtime) when the
10
+ * DevTools panel is enabled. Answers the panel's tree/details requests over the
11
+ * Vite HMR channel, keeps a watched element's details fresh as it updates, and
12
+ * outlines elements the panel hovers in its tree.
13
+ */
14
+ import { elementById } from '../timeline/identity.js';
15
+ import { buildTree, collectDetails } from './collect.js';
16
+ import { INSPECT_CMD_CHANNEL, INSPECT_DATA_CHANNEL, } from '../../../types/inspector.js';
17
+ const hot = import.meta.hot;
18
+ if (hot !== undefined && typeof window !== 'undefined') {
19
+ const send = (msg) => {
20
+ try {
21
+ hot.send(INSPECT_DATA_CHANNEL, msg);
22
+ }
23
+ catch {
24
+ // HMR channel temporarily unavailable; the panel can re-request.
25
+ }
26
+ };
27
+ // Hold the watched element via a WeakRef so an active watch doesn't keep a
28
+ // removed element alive: the override and `restore` only reach `el` through
29
+ // the ref, leaving the DOM as its sole strong root.
30
+ let watched = null;
31
+ const unwatch = () => {
32
+ watched?.restore();
33
+ watched = null;
34
+ };
35
+ const watch = (id) => {
36
+ unwatch();
37
+ const el = elementById(id);
38
+ if (el === undefined) {
39
+ send({ type: 'gone', id });
40
+ return;
41
+ }
42
+ const hadOwn = Object.prototype.hasOwnProperty.call(el, 'updated');
43
+ const prev = el.updated;
44
+ const ref = new WeakRef(el);
45
+ el.updated = function (changed) {
46
+ prev?.call(this, changed);
47
+ const cur = ref.deref();
48
+ if (cur !== undefined) {
49
+ send({ type: 'details', details: collectDetails(cur) });
50
+ }
51
+ };
52
+ watched = {
53
+ ref,
54
+ restore: () => {
55
+ const cur = ref.deref();
56
+ if (cur === undefined)
57
+ return;
58
+ if (hadOwn)
59
+ cur.updated = prev;
60
+ else
61
+ delete cur.updated;
62
+ },
63
+ };
64
+ // Push an immediate snapshot so the panel doesn't wait for the next update.
65
+ send({ type: 'details', details: collectDetails(el) });
66
+ };
67
+ // -------------------------------------------------------------------------
68
+ // Highlight box: a lightweight fixed-position outline drawn over an element
69
+ // the panel hovers in its tree. Independent of the source overlay so it works
70
+ // whether or not that feature is enabled.
71
+ // -------------------------------------------------------------------------
72
+ let highlightBox = null;
73
+ const showHighlight = (el) => {
74
+ if (highlightBox === null) {
75
+ highlightBox = document.createElement('div');
76
+ highlightBox.setAttribute('data-lit-devtools-highlight', '');
77
+ Object.assign(highlightBox.style, {
78
+ position: 'fixed',
79
+ zIndex: '2147483646',
80
+ pointerEvents: 'none',
81
+ background: 'rgba(77, 99, 255, 0.25)',
82
+ outline: '1px solid #4d63ff',
83
+ borderRadius: '2px',
84
+ transition: 'all 80ms ease-out',
85
+ });
86
+ document.body.append(highlightBox);
87
+ }
88
+ const r = el.getBoundingClientRect();
89
+ Object.assign(highlightBox.style, {
90
+ display: 'block',
91
+ left: `${r.left}px`,
92
+ top: `${r.top}px`,
93
+ width: `${r.width}px`,
94
+ height: `${r.height}px`,
95
+ });
96
+ };
97
+ const clearHighlight = () => {
98
+ if (highlightBox !== null)
99
+ highlightBox.style.display = 'none';
100
+ };
101
+ // -------------------------------------------------------------------------
102
+ // Opt-in live tree: watch the DOM (light + every shadow root) and push a
103
+ // fresh tree when the component hierarchy actually changes. Off by default.
104
+ // childList-only (no attributes), so cosmetic changes — including our own
105
+ // highlight box toggling — don't churn; identical rebuilds are also deduped.
106
+ // -------------------------------------------------------------------------
107
+ let observer = null;
108
+ let observeTimer;
109
+ let lastTreeJson = '';
110
+ /** Re-attach the observer to the body and every shadow root in the page. */
111
+ const syncObserverTargets = (obs) => {
112
+ obs.disconnect();
113
+ obs.observe(document.body, { childList: true, subtree: true });
114
+ const walk = (root) => {
115
+ for (const el of root.querySelectorAll('*')) {
116
+ if (el.shadowRoot !== null) {
117
+ obs.observe(el.shadowRoot, { childList: true, subtree: true });
118
+ walk(el.shadowRoot);
119
+ }
120
+ }
121
+ };
122
+ walk(document);
123
+ };
124
+ const pushTreeIfChanged = () => {
125
+ const roots = buildTree();
126
+ const json = JSON.stringify(roots);
127
+ if (json === lastTreeJson)
128
+ return;
129
+ lastTreeJson = json;
130
+ send({ type: 'tree', roots });
131
+ };
132
+ const onMutation = () => {
133
+ if (observeTimer !== undefined)
134
+ clearTimeout(observeTimer);
135
+ observeTimer = setTimeout(() => {
136
+ observeTimer = undefined;
137
+ if (observer !== null)
138
+ syncObserverTargets(observer);
139
+ pushTreeIfChanged();
140
+ }, 100);
141
+ };
142
+ const setObserving = (enabled) => {
143
+ if (enabled) {
144
+ if (observer === null)
145
+ observer = new MutationObserver(onMutation);
146
+ lastTreeJson = '';
147
+ syncObserverTargets(observer);
148
+ pushTreeIfChanged();
149
+ }
150
+ else if (observer !== null) {
151
+ observer.disconnect();
152
+ observer = null;
153
+ if (observeTimer !== undefined) {
154
+ clearTimeout(observeTimer);
155
+ observeTimer = undefined;
156
+ }
157
+ }
158
+ };
159
+ // -------------------------------------------------------------------------
160
+ // Command dispatch
161
+ // -------------------------------------------------------------------------
162
+ hot.on(INSPECT_CMD_CHANNEL, (data) => {
163
+ const cmd = data;
164
+ switch (cmd.type) {
165
+ case 'tree':
166
+ send({ type: 'tree', roots: buildTree() });
167
+ break;
168
+ case 'details': {
169
+ const el = elementById(cmd.id);
170
+ if (el !== undefined) {
171
+ send({ type: 'details', details: collectDetails(el) });
172
+ }
173
+ else {
174
+ send({ type: 'gone', id: cmd.id });
175
+ }
176
+ break;
177
+ }
178
+ case 'watch':
179
+ if (cmd.id === null)
180
+ unwatch();
181
+ else
182
+ watch(cmd.id);
183
+ break;
184
+ case 'highlight': {
185
+ if (cmd.id === null) {
186
+ clearHighlight();
187
+ break;
188
+ }
189
+ const el = elementById(cmd.id);
190
+ if (el !== undefined)
191
+ showHighlight(el);
192
+ else
193
+ clearHighlight();
194
+ break;
195
+ }
196
+ case 'observe':
197
+ setObserving(cmd.enabled);
198
+ break;
199
+ }
200
+ });
201
+ // Announce readiness so a panel that loaded first re-requests the tree.
202
+ send({ type: 'ready' });
203
+ }
204
+ //# sourceMappingURL=install.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"install.js","sourceRoot":"","sources":["../../../../../packages/labs/vite-plugin-lit/src/lib/runtime/inspector/install.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;;;;GAOG;AAEH,OAAO,EAAC,WAAW,EAAC,MAAM,yBAAyB,CAAC;AACpD,OAAO,EAAC,SAAS,EAAE,cAAc,EAAC,MAAM,cAAc,CAAC;AACvD,OAAO,EACL,mBAAmB,EACnB,oBAAoB,GAGrB,MAAM,6BAA6B,CAAC;AAOrC,MAAM,GAAG,GAAI,MAAM,CAAC,IAAwB,CAAC,GAAG,CAAC;AAEjD,IAAI,GAAG,KAAK,SAAS,IAAI,OAAO,MAAM,KAAK,WAAW,EAAE,CAAC;IACvD,MAAM,IAAI,GAAG,CAAC,GAAqB,EAAQ,EAAE;QAC3C,IAAI,CAAC;YACH,GAAG,CAAC,IAAI,CAAC,oBAAoB,EAAE,GAAG,CAAC,CAAC;QACtC,CAAC;QAAC,MAAM,CAAC;YACP,iEAAiE;QACnE,CAAC;IACH,CAAC,CAAC;IAYF,2EAA2E;IAC3E,4EAA4E;IAC5E,oDAAoD;IACpD,IAAI,OAAO,GAA0D,IAAI,CAAC;IAE1E,MAAM,OAAO,GAAG,GAAS,EAAE;QACzB,OAAO,EAAE,OAAO,EAAE,CAAC;QACnB,OAAO,GAAG,IAAI,CAAC;IACjB,CAAC,CAAC;IAEF,MAAM,KAAK,GAAG,CAAC,EAAU,EAAQ,EAAE;QACjC,OAAO,EAAE,CAAC;QACV,MAAM,EAAE,GAAG,WAAW,CAAC,EAAE,CAA0B,CAAC;QACpD,IAAI,EAAE,KAAK,SAAS,EAAE,CAAC;YACrB,IAAI,CAAC,EAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAC,CAAC,CAAC;YACzB,OAAO;QACT,CAAC;QACD,MAAM,MAAM,GAAG,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,CAAC,CAAC;QACnE,MAAM,IAAI,GAAG,EAAE,CAAC,OAAO,CAAC;QACxB,MAAM,GAAG,GAAG,IAAI,OAAO,CAAC,EAAE,CAAC,CAAC;QAC5B,EAAE,CAAC,OAAO,GAAG,UAAU,OAAgB;YACrC,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;YAC1B,MAAM,GAAG,GAAG,GAAG,CAAC,KAAK,EAAE,CAAC;YACxB,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;gBACtB,IAAI,CAAC,EAAC,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,cAAc,CAAC,GAAG,CAAC,EAAC,CAAC,CAAC;YACxD,CAAC;QACH,CAAC,CAAC;QACF,OAAO,GAAG;YACR,GAAG;YACH,OAAO,EAAE,GAAG,EAAE;gBACZ,MAAM,GAAG,GAAG,GAAG,CAAC,KAAK,EAAE,CAAC;gBACxB,IAAI,GAAG,KAAK,SAAS;oBAAE,OAAO;gBAC9B,IAAI,MAAM;oBAAE,GAAG,CAAC,OAAO,GAAG,IAAI,CAAC;;oBAC1B,OAAO,GAAG,CAAC,OAAO,CAAC;YAC1B,CAAC;SACF,CAAC;QACF,4EAA4E;QAC5E,IAAI,CAAC,EAAC,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,cAAc,CAAC,EAAE,CAAC,EAAC,CAAC,CAAC;IACvD,CAAC,CAAC;IAEF,4EAA4E;IAC5E,4EAA4E;IAC5E,8EAA8E;IAC9E,0CAA0C;IAC1C,4EAA4E;IAE5E,IAAI,YAAY,GAAuB,IAAI,CAAC;IAE5C,MAAM,aAAa,GAAG,CAAC,EAAW,EAAQ,EAAE;QAC1C,IAAI,YAAY,KAAK,IAAI,EAAE,CAAC;YAC1B,YAAY,GAAG,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;YAC7C,YAAY,CAAC,YAAY,CAAC,6BAA6B,EAAE,EAAE,CAAC,CAAC;YAC7D,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC,KAAK,EAAE;gBAChC,QAAQ,EAAE,OAAO;gBACjB,MAAM,EAAE,YAAY;gBACpB,aAAa,EAAE,MAAM;gBACrB,UAAU,EAAE,yBAAyB;gBACrC,OAAO,EAAE,mBAAmB;gBAC5B,YAAY,EAAE,KAAK;gBACnB,UAAU,EAAE,mBAAmB;aACO,CAAC,CAAC;YAC1C,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;QACrC,CAAC;QACD,MAAM,CAAC,GAAG,EAAE,CAAC,qBAAqB,EAAE,CAAC;QACrC,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC,KAAK,EAAE;YAChC,OAAO,EAAE,OAAO;YAChB,IAAI,EAAE,GAAG,CAAC,CAAC,IAAI,IAAI;YACnB,GAAG,EAAE,GAAG,CAAC,CAAC,GAAG,IAAI;YACjB,KAAK,EAAE,GAAG,CAAC,CAAC,KAAK,IAAI;YACrB,MAAM,EAAE,GAAG,CAAC,CAAC,MAAM,IAAI;SACxB,CAAC,CAAC;IACL,CAAC,CAAC;IAEF,MAAM,cAAc,GAAG,GAAS,EAAE;QAChC,IAAI,YAAY,KAAK,IAAI;YAAE,YAAY,CAAC,KAAK,CAAC,OAAO,GAAG,MAAM,CAAC;IACjE,CAAC,CAAC;IAEF,4EAA4E;IAC5E,yEAAyE;IACzE,4EAA4E;IAC5E,0EAA0E;IAC1E,6EAA6E;IAC7E,4EAA4E;IAE5E,IAAI,QAAQ,GAA4B,IAAI,CAAC;IAC7C,IAAI,YAAuD,CAAC;IAC5D,IAAI,YAAY,GAAG,EAAE,CAAC;IAEtB,4EAA4E;IAC5E,MAAM,mBAAmB,GAAG,CAAC,GAAqB,EAAQ,EAAE;QAC1D,GAAG,CAAC,UAAU,EAAE,CAAC;QACjB,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,EAAE,EAAC,SAAS,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAC,CAAC,CAAC;QAC7D,MAAM,IAAI,GAAG,CAAC,IAAgB,EAAQ,EAAE;YACtC,KAAK,MAAM,EAAE,IAAI,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,EAAE,CAAC;gBAC5C,IAAI,EAAE,CAAC,UAAU,KAAK,IAAI,EAAE,CAAC;oBAC3B,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,EAAE,EAAC,SAAS,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAC,CAAC,CAAC;oBAC7D,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC;gBACtB,CAAC;YACH,CAAC;QACH,CAAC,CAAC;QACF,IAAI,CAAC,QAAQ,CAAC,CAAC;IACjB,CAAC,CAAC;IAEF,MAAM,iBAAiB,GAAG,GAAS,EAAE;QACnC,MAAM,KAAK,GAAG,SAAS,EAAE,CAAC;QAC1B,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QACnC,IAAI,IAAI,KAAK,YAAY;YAAE,OAAO;QAClC,YAAY,GAAG,IAAI,CAAC;QACpB,IAAI,CAAC,EAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAC,CAAC,CAAC;IAC9B,CAAC,CAAC;IAEF,MAAM,UAAU,GAAG,GAAS,EAAE;QAC5B,IAAI,YAAY,KAAK,SAAS;YAAE,YAAY,CAAC,YAAY,CAAC,CAAC;QAC3D,YAAY,GAAG,UAAU,CAAC,GAAG,EAAE;YAC7B,YAAY,GAAG,SAAS,CAAC;YACzB,IAAI,QAAQ,KAAK,IAAI;gBAAE,mBAAmB,CAAC,QAAQ,CAAC,CAAC;YACrD,iBAAiB,EAAE,CAAC;QACtB,CAAC,EAAE,GAAG,CAAC,CAAC;IACV,CAAC,CAAC;IAEF,MAAM,YAAY,GAAG,CAAC,OAAgB,EAAQ,EAAE;QAC9C,IAAI,OAAO,EAAE,CAAC;YACZ,IAAI,QAAQ,KAAK,IAAI;gBAAE,QAAQ,GAAG,IAAI,gBAAgB,CAAC,UAAU,CAAC,CAAC;YACnE,YAAY,GAAG,EAAE,CAAC;YAClB,mBAAmB,CAAC,QAAQ,CAAC,CAAC;YAC9B,iBAAiB,EAAE,CAAC;QACtB,CAAC;aAAM,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;YAC7B,QAAQ,CAAC,UAAU,EAAE,CAAC;YACtB,QAAQ,GAAG,IAAI,CAAC;YAChB,IAAI,YAAY,KAAK,SAAS,EAAE,CAAC;gBAC/B,YAAY,CAAC,YAAY,CAAC,CAAC;gBAC3B,YAAY,GAAG,SAAS,CAAC;YAC3B,CAAC;QACH,CAAC;IACH,CAAC,CAAC;IAEF,4EAA4E;IAC5E,mBAAmB;IACnB,4EAA4E;IAE5E,GAAG,CAAC,EAAE,CAAC,mBAAmB,EAAE,CAAC,IAAI,EAAE,EAAE;QACnC,MAAM,GAAG,GAAG,IAAwB,CAAC;QACrC,QAAQ,GAAG,CAAC,IAAI,EAAE,CAAC;YACjB,KAAK,MAAM;gBACT,IAAI,CAAC,EAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,EAAC,CAAC,CAAC;gBACzC,MAAM;YACR,KAAK,SAAS,CAAC,CAAC,CAAC;gBACf,MAAM,EAAE,GAAG,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;gBAC/B,IAAI,EAAE,KAAK,SAAS,EAAE,CAAC;oBACrB,IAAI,CAAC,EAAC,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,cAAc,CAAC,EAAE,CAAC,EAAC,CAAC,CAAC;gBACvD,CAAC;qBAAM,CAAC;oBACN,IAAI,CAAC,EAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,GAAG,CAAC,EAAE,EAAC,CAAC,CAAC;gBACnC,CAAC;gBACD,MAAM;YACR,CAAC;YACD,KAAK,OAAO;gBACV,IAAI,GAAG,CAAC,EAAE,KAAK,IAAI;oBAAE,OAAO,EAAE,CAAC;;oBAC1B,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;gBACnB,MAAM;YACR,KAAK,WAAW,CAAC,CAAC,CAAC;gBACjB,IAAI,GAAG,CAAC,EAAE,KAAK,IAAI,EAAE,CAAC;oBACpB,cAAc,EAAE,CAAC;oBACjB,MAAM;gBACR,CAAC;gBACD,MAAM,EAAE,GAAG,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;gBAC/B,IAAI,EAAE,KAAK,SAAS;oBAAE,aAAa,CAAC,EAAE,CAAC,CAAC;;oBACnC,cAAc,EAAE,CAAC;gBACtB,MAAM;YACR,CAAC;YACD,KAAK,SAAS;gBACZ,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;gBAC1B,MAAM;QACV,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,wEAAwE;IACxE,IAAI,CAAC,EAAC,IAAI,EAAE,OAAO,EAAC,CAAC,CAAC;AACxB,CAAC","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"]}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Google LLC
4
+ * SPDX-License-Identifier: BSD-3-Clause
5
+ */
6
+ /** A short type label for the details table's "type" column. */
7
+ export declare const typeTag: (value: unknown) => string;
8
+ /** Produce a readable one-line preview of `value`. Never throws. */
9
+ export declare const serialize: (value: unknown) => string;
10
+ //# sourceMappingURL=serialize.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"serialize.d.ts","sourceRoot":"","sources":["../../../../../packages/labs/vite-plugin-lit/src/lib/runtime/inspector/serialize.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAaH,gEAAgE;AAChE,eAAO,MAAM,OAAO,GAAI,OAAO,OAAO,KAAG,MAWxC,CAAC;AAwFF,oEAAoE;AACpE,eAAO,MAAM,SAAS,GAAI,OAAO,OAAO,KAAG,MAM1C,CAAC"}