@oddsquad/vite-plugin-lit 0.2.2 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (210) hide show
  1. package/CHANGELOG.md +64 -0
  2. package/LICENSE +28 -0
  3. package/README.md +153 -0
  4. package/bin.mjs +154 -0
  5. package/client.d.ts +61 -0
  6. package/dist/client/assets/browser-agent-rpc-BXhoSh1z-BvWe4sTJ.js +69 -0
  7. package/dist/client/assets/browser-agent-rpc-BXhoSh1z-BvWe4sTJ.js.map +1 -0
  8. package/dist/client/assets/index-CFrVgNfS.js +9740 -0
  9. package/dist/client/assets/index-CFrVgNfS.js.map +1 -0
  10. package/{panel → dist/client}/index.html +1 -0
  11. package/index.d.ts.map +1 -1
  12. package/index.js +2 -2
  13. package/index.js.map +1 -1
  14. package/lib/color-scheme.d.ts.map +1 -1
  15. package/lib/color-scheme.js +17 -21
  16. package/lib/color-scheme.js.map +1 -1
  17. package/lib/devframe/definition.d.ts +45 -0
  18. package/lib/devframe/definition.d.ts.map +1 -0
  19. package/lib/devframe/definition.js +547 -0
  20. package/lib/devframe/definition.js.map +1 -0
  21. package/lib/devframe/icon.d.ts +8 -0
  22. package/lib/devframe/icon.d.ts.map +1 -0
  23. package/lib/devframe/icon.js +21 -0
  24. package/lib/devframe/icon.js.map +1 -0
  25. package/lib/devframe/paths.d.ts +12 -0
  26. package/lib/devframe/paths.d.ts.map +1 -0
  27. package/lib/devframe/paths.js +38 -0
  28. package/lib/devframe/paths.js.map +1 -0
  29. package/lib/devframe/protocol.d.ts +218 -0
  30. package/lib/devframe/protocol.d.ts.map +1 -0
  31. package/lib/devframe/protocol.js +76 -0
  32. package/lib/devframe/protocol.js.map +1 -0
  33. package/lib/devframe/source.d.ts +49 -0
  34. package/lib/devframe/source.d.ts.map +1 -0
  35. package/lib/devframe/source.js +23 -0
  36. package/lib/devframe/source.js.map +1 -0
  37. package/lib/devframe/vite.d.ts +116 -0
  38. package/lib/devframe/vite.d.ts.map +1 -0
  39. package/lib/devframe/vite.js +291 -0
  40. package/lib/devframe/vite.js.map +1 -0
  41. package/lib/http.d.ts +29 -0
  42. package/lib/http.d.ts.map +1 -0
  43. package/lib/http.js +35 -0
  44. package/lib/http.js.map +1 -0
  45. package/lib/icons.d.ts +2 -0
  46. package/lib/icons.d.ts.map +1 -1
  47. package/lib/icons.js +10 -4
  48. package/lib/icons.js.map +1 -1
  49. package/lib/plugin.d.ts +15 -4
  50. package/lib/plugin.d.ts.map +1 -1
  51. package/lib/plugin.js +640 -574
  52. package/lib/plugin.js.map +1 -1
  53. package/lib/runtime/css.d.ts +2 -16
  54. package/lib/runtime/css.d.ts.map +1 -1
  55. package/lib/runtime/css.js +43 -36
  56. package/lib/runtime/css.js.map +1 -1
  57. package/lib/runtime/edge-panel.d.ts.map +1 -1
  58. package/lib/runtime/edge-panel.js +82 -91
  59. package/lib/runtime/edge-panel.js.map +1 -1
  60. package/lib/runtime/fonts.d.ts.map +1 -1
  61. package/lib/runtime/fonts.js +1 -1
  62. package/lib/runtime/fonts.js.map +1 -1
  63. package/lib/runtime/indicator.d.ts.map +1 -1
  64. package/lib/runtime/indicator.js +71 -74
  65. package/lib/runtime/indicator.js.map +1 -1
  66. package/lib/runtime/inspector/collect.d.ts.map +1 -1
  67. package/lib/runtime/inspector/collect.js +83 -90
  68. package/lib/runtime/inspector/collect.js.map +1 -1
  69. package/lib/runtime/inspector/highlight.d.ts +16 -0
  70. package/lib/runtime/inspector/highlight.d.ts.map +1 -0
  71. package/lib/runtime/inspector/highlight.js +66 -0
  72. package/lib/runtime/inspector/highlight.js.map +1 -0
  73. package/lib/runtime/inspector/install.d.ts.map +1 -1
  74. package/lib/runtime/inspector/install.js +180 -205
  75. package/lib/runtime/inspector/install.js.map +1 -1
  76. package/lib/runtime/inspector/serialize.d.ts.map +1 -1
  77. package/lib/runtime/inspector/serialize.js +86 -107
  78. package/lib/runtime/inspector/serialize.js.map +1 -1
  79. package/lib/runtime/intern.d.ts.map +1 -1
  80. package/lib/runtime/intern.js +31 -29
  81. package/lib/runtime/intern.js.map +1 -1
  82. package/lib/runtime/overrides.d.ts.map +1 -1
  83. package/lib/runtime/overrides.js +14 -13
  84. package/lib/runtime/overrides.js.map +1 -1
  85. package/lib/runtime/patch.d.ts +8 -0
  86. package/lib/runtime/patch.d.ts.map +1 -1
  87. package/lib/runtime/patch.js +321 -282
  88. package/lib/runtime/patch.js.map +1 -1
  89. package/lib/runtime/source-meta.d.ts.map +1 -1
  90. package/lib/runtime/source-meta.js +1 -1
  91. package/lib/runtime/source-meta.js.map +1 -1
  92. package/lib/runtime/source-overlay/editors.d.ts.map +1 -1
  93. package/lib/runtime/source-overlay/editors.js +27 -27
  94. package/lib/runtime/source-overlay/editors.js.map +1 -1
  95. package/lib/runtime/source-overlay/mask-path.d.ts.map +1 -1
  96. package/lib/runtime/source-overlay/mask-path.js +15 -15
  97. package/lib/runtime/source-overlay/mask-path.js.map +1 -1
  98. package/lib/runtime/source-overlay/overlay-element.d.ts.map +1 -1
  99. package/lib/runtime/source-overlay/overlay-element.js +347 -356
  100. package/lib/runtime/source-overlay/overlay-element.js.map +1 -1
  101. package/lib/runtime/source-overlay/source-host.d.ts.map +1 -1
  102. package/lib/runtime/source-overlay/source-host.js +64 -71
  103. package/lib/runtime/source-overlay/source-host.js.map +1 -1
  104. package/lib/runtime/source-overlay/template.d.ts.map +1 -1
  105. package/lib/runtime/source-overlay/template.js +3 -3
  106. package/lib/runtime/source-overlay/template.js.map +1 -1
  107. package/lib/runtime/source-overlay.d.ts.map +1 -1
  108. package/lib/runtime/source-overlay.js +5 -2
  109. package/lib/runtime/source-overlay.js.map +1 -1
  110. package/lib/runtime/timeline/clock.d.ts.map +1 -1
  111. package/lib/runtime/timeline/clock.js +2 -2
  112. package/lib/runtime/timeline/clock.js.map +1 -1
  113. package/lib/runtime/timeline/flash.d.ts +39 -0
  114. package/lib/runtime/timeline/flash.d.ts.map +1 -0
  115. package/lib/runtime/timeline/flash.js +169 -0
  116. package/lib/runtime/timeline/flash.js.map +1 -0
  117. package/lib/runtime/timeline/identity.d.ts.map +1 -1
  118. package/lib/runtime/timeline/identity.js +27 -27
  119. package/lib/runtime/timeline/identity.js.map +1 -1
  120. package/lib/runtime/timeline/input.d.ts.map +1 -1
  121. package/lib/runtime/timeline/input.js +54 -67
  122. package/lib/runtime/timeline/input.js.map +1 -1
  123. package/lib/runtime/timeline/install.d.ts.map +1 -1
  124. package/lib/runtime/timeline/install.js +38 -29
  125. package/lib/runtime/timeline/install.js.map +1 -1
  126. package/lib/runtime/timeline/lifecycle.d.ts +8 -0
  127. package/lib/runtime/timeline/lifecycle.d.ts.map +1 -1
  128. package/lib/runtime/timeline/lifecycle.js +149 -133
  129. package/lib/runtime/timeline/lifecycle.js.map +1 -1
  130. package/lib/runtime/timeline/public-api.d.ts.map +1 -1
  131. package/lib/runtime/timeline/public-api.js +9 -9
  132. package/lib/runtime/timeline/public-api.js.map +1 -1
  133. package/lib/runtime/timeline/render.d.ts.map +1 -1
  134. package/lib/runtime/timeline/render.js +70 -75
  135. package/lib/runtime/timeline/render.js.map +1 -1
  136. package/lib/runtime/timeline/transport.d.ts.map +1 -1
  137. package/lib/runtime/timeline/transport.js +39 -43
  138. package/lib/runtime/timeline/transport.js.map +1 -1
  139. package/lib/segmented-tabs.d.ts +3 -1
  140. package/lib/segmented-tabs.d.ts.map +1 -1
  141. package/lib/segmented-tabs.js +136 -107
  142. package/lib/segmented-tabs.js.map +1 -1
  143. package/lib/snapshot.d.ts +28 -0
  144. package/lib/snapshot.d.ts.map +1 -0
  145. package/lib/snapshot.js +57 -0
  146. package/lib/snapshot.js.map +1 -0
  147. package/lib/source-meta.d.ts.map +1 -1
  148. package/lib/source-meta.js +176 -162
  149. package/lib/source-meta.js.map +1 -1
  150. package/lib/timeline/derive.d.ts +152 -0
  151. package/lib/timeline/derive.d.ts.map +1 -0
  152. package/lib/timeline/derive.js +242 -0
  153. package/lib/timeline/derive.js.map +1 -0
  154. package/lib/timeline-plugin.d.ts.map +1 -1
  155. package/lib/timeline-plugin.js +304 -321
  156. package/lib/timeline-plugin.js.map +1 -1
  157. package/lib/tokens.d.ts.map +1 -1
  158. package/lib/tokens.js +17 -18
  159. package/lib/tokens.js.map +1 -1
  160. package/lib/transform.d.ts.map +1 -1
  161. package/lib/transform.js +62 -57
  162. package/lib/transform.js.map +1 -1
  163. package/lib/types.d.ts.map +1 -1
  164. package/lib/types.js +1 -1
  165. package/lib/types.js.map +1 -1
  166. package/lib/wrap-table.d.ts.map +1 -1
  167. package/lib/wrap-table.js +19 -17
  168. package/lib/wrap-table.js.map +1 -1
  169. package/package.json +77 -13
  170. package/types/hmr-incompatibility.d.ts +59 -0
  171. package/types/hmr-incompatibility.d.ts.map +1 -0
  172. package/types/hmr-incompatibility.js +30 -0
  173. package/types/hmr-incompatibility.js.map +1 -0
  174. package/types/in-page.d.ts +49 -0
  175. package/types/in-page.d.ts.map +1 -0
  176. package/types/in-page.js +33 -0
  177. package/types/in-page.js.map +1 -0
  178. package/types/inspector.d.ts.map +1 -1
  179. package/types/inspector.js.map +1 -1
  180. package/types/snapshot.d.ts +44 -0
  181. package/types/snapshot.d.ts.map +1 -0
  182. package/types/snapshot.js +7 -0
  183. package/types/snapshot.js.map +1 -0
  184. package/types/timeline.d.ts +11 -0
  185. package/types/timeline.d.ts.map +1 -1
  186. package/types/timeline.js.map +1 -1
  187. package/panel/components-view.d.ts +0 -60
  188. package/panel/components-view.d.ts.map +0 -1
  189. package/panel/components-view.js +0 -587
  190. package/panel/components-view.js.map +0 -1
  191. package/panel/devtools-settings.d.ts +0 -41
  192. package/panel/devtools-settings.d.ts.map +0 -1
  193. package/panel/devtools-settings.js +0 -463
  194. package/panel/devtools-settings.js.map +0 -1
  195. package/panel/lit-devtools-panel.d.ts +0 -37
  196. package/panel/lit-devtools-panel.d.ts.map +0 -1
  197. package/panel/lit-devtools-panel.js +0 -185
  198. package/panel/lit-devtools-panel.js.map +0 -1
  199. package/panel/timeline-event-list.d.ts +0 -43
  200. package/panel/timeline-event-list.d.ts.map +0 -1
  201. package/panel/timeline-event-list.js +0 -416
  202. package/panel/timeline-event-list.js.map +0 -1
  203. package/panel/timeline-layers.d.ts +0 -25
  204. package/panel/timeline-layers.d.ts.map +0 -1
  205. package/panel/timeline-layers.js +0 -96
  206. package/panel/timeline-layers.js.map +0 -1
  207. package/panel/timeline-view.d.ts +0 -38
  208. package/panel/timeline-view.d.ts.map +0 -1
  209. package/panel/timeline-view.js +0 -234
  210. package/panel/timeline-view.js.map +0 -1
@@ -0,0 +1,169 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Google LLC
4
+ * SPDX-License-Identifier: BSD-3-Clause
5
+ */
6
+ /** Fade length; long enough to catch, short enough not to smear. */
7
+ const DURATION_MS = 450;
8
+ /** How far back the ramp counts updates for one element. */
9
+ const RAMP_WINDOW_MS = 1000;
10
+ /**
11
+ * Outline/fill colours by heat level. Level 0 is also the flat colour used
12
+ * when the ramp is off. Deliberately not the selection blue, so a hovered
13
+ * element and a flashing one read differently.
14
+ */
15
+ const COLORS = [
16
+ 'hsl(158 74% 53%)', // calm — one update
17
+ '#f4bf4f', // warm
18
+ '#f4844f', // hot
19
+ '#ef4444', // on fire
20
+ ];
21
+ /**
22
+ * Heat level for `count` updates of one element inside the ramp window.
23
+ * Exported for the unit test; the thresholds are the whole behaviour.
24
+ */
25
+ export const rampLevel = (count) => {
26
+ if (count >= 8) return 3;
27
+ if (count >= 4) return 2;
28
+ if (count >= 2) return 1;
29
+ return 0;
30
+ };
31
+ let enabled = false;
32
+ let ramp = false;
33
+ let layer = null;
34
+ /** Elements that updated since the last flush, with "was a first update". */
35
+ const pending = new Map();
36
+ let frame = null;
37
+ /** Boxes currently on screen, so a re-flash restarts instead of stacking. */
38
+ const active = new Map();
39
+ /** Recent update timestamps per element, for the ramp. */
40
+ const history = new WeakMap();
41
+ const ensureLayer = () => {
42
+ if (layer === null) {
43
+ layer = document.createElement('div');
44
+ layer.setAttribute('data-lit-devtools-flash-layer', '');
45
+ Object.assign(layer.style, {
46
+ position: 'fixed',
47
+ inset: '0',
48
+ zIndex: '2147483645',
49
+ pointerEvents: 'none',
50
+ overflow: 'hidden',
51
+ });
52
+ document.body.append(layer);
53
+ }
54
+ return layer;
55
+ };
56
+ /** The runtime's own UI (indicator, panels) must not flash itself. */
57
+ const isDevtoolsElement = (el) => el.localName.startsWith('lit-devtools-');
58
+ const recordUpdate = (el, at) => {
59
+ let times = history.get(el);
60
+ if (times === undefined) {
61
+ times = [];
62
+ history.set(el, times);
63
+ }
64
+ times.push(at);
65
+ const cutoff = at - RAMP_WINDOW_MS;
66
+ while (times.length > 0 && times[0] < cutoff) times.shift();
67
+ return times.length;
68
+ };
69
+ const removeBox = (el, anim) => {
70
+ const entry = active.get(el);
71
+ // A newer flash may have replaced this one; only the owner cleans up.
72
+ if (entry === undefined || entry.anim !== anim) return;
73
+ entry.box.remove();
74
+ active.delete(el);
75
+ };
76
+ const paint = (el, rect, level, first) => {
77
+ const color = COLORS[level] ?? COLORS[0];
78
+ let entry = active.get(el);
79
+ if (entry === undefined) {
80
+ const box = document.createElement('div');
81
+ box.setAttribute('data-lit-devtools-flash', '');
82
+ Object.assign(box.style, {
83
+ position: 'absolute',
84
+ boxSizing: 'border-box',
85
+ borderRadius: '2px',
86
+ willChange: 'opacity',
87
+ });
88
+ ensureLayer().append(box);
89
+ entry = {box, anim: box.animate([], {duration: 0})};
90
+ active.set(el, entry);
91
+ } else {
92
+ entry.anim.cancel();
93
+ }
94
+ const {box} = entry;
95
+ box.setAttribute('data-level', String(level));
96
+ Object.assign(box.style, {
97
+ left: `${rect.left}px`,
98
+ top: `${rect.top}px`,
99
+ width: `${rect.width}px`,
100
+ height: `${rect.height}px`,
101
+ outline: `2px solid ${color}`,
102
+ outlineOffset: '-1px',
103
+ background: color,
104
+ });
105
+ // Mounts flash fainter: a page filling in is not the churn we're hunting.
106
+ const peak = first ? 0.35 : 0.75;
107
+ const anim = box.animate(
108
+ [{opacity: peak}, {opacity: peak, offset: 0.3}, {opacity: 0}],
109
+ {duration: DURATION_MS, easing: 'ease-out', fill: 'forwards'}
110
+ );
111
+ entry.anim = anim;
112
+ anim.onfinish = () => removeBox(el, anim);
113
+ anim.oncancel = () => {
114
+ /* replaced by a newer flash; that one owns cleanup */
115
+ };
116
+ };
117
+ const flush = () => {
118
+ frame = null;
119
+ if (!enabled) {
120
+ pending.clear();
121
+ return;
122
+ }
123
+ const now = performance.now();
124
+ for (const [el, first] of pending) {
125
+ if (!el.isConnected) continue;
126
+ const rect = el.getBoundingClientRect();
127
+ // `display: contents` hosts, hidden elements, and off-DOM work have no
128
+ // box worth drawing.
129
+ if (rect.width === 0 || rect.height === 0) continue;
130
+ const count = recordUpdate(el, now);
131
+ paint(el, rect, ramp ? rampLevel(count) : 0, first);
132
+ }
133
+ pending.clear();
134
+ };
135
+ const clearAll = () => {
136
+ pending.clear();
137
+ if (frame !== null) {
138
+ cancelAnimationFrame(frame);
139
+ frame = null;
140
+ }
141
+ for (const {box, anim} of active.values()) {
142
+ anim.cancel();
143
+ box.remove();
144
+ }
145
+ active.clear();
146
+ };
147
+ /** Turn the overlay on or off; off also wipes whatever is mid-fade. */
148
+ export const setFlashEnabled = (on) => {
149
+ if (enabled === on) return;
150
+ enabled = on;
151
+ if (!on) clearAll();
152
+ };
153
+ /** Colour by update frequency instead of the flat colour. */
154
+ export const setFlashRamp = (on) => {
155
+ ramp = on;
156
+ };
157
+ /**
158
+ * The lifecycle layer's update hook. Cheap on the hot path: one Map write and,
159
+ * at most, one `requestAnimationFrame` per frame; all measuring happens in
160
+ * the flush.
161
+ */
162
+ export const flashUpdate = (el, first) => {
163
+ if (!enabled || isDevtoolsElement(el)) return;
164
+ // Several updates of one element in the same frame collapse into one box;
165
+ // it only counts as a mount if every one of them was the first update.
166
+ pending.set(el, (pending.get(el) ?? true) && first);
167
+ if (frame === null) frame = requestAnimationFrame(flush);
168
+ };
169
+ //# sourceMappingURL=flash.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"flash.js","sourceRoot":"","sources":["../../../src/lib/runtime/timeline/flash.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 * \"Flash on update\": a short, non-interactive outline over every Lit element\n * that just finished an update cycle, so re-render churn is visible on the\n * page itself rather than only in the Updates tab.\n *\n * Sibling of the inspector's hover outline, not a reuse of it — many elements\n * can flash in the same frame, and each box has its own fade. Same drawing\n * rules though: one `position: fixed` layer with `pointer-events: none` so the\n * page stays fully interactive underneath.\n *\n * Fed by the lifecycle layer's update hook (see `setUpdateHook` in\n * `lifecycle.ts`), which fires whether or not the timeline is recording. Rects\n * are measured once per animation frame for every element that updated in it,\n * so a tick that updates a hundred components costs one layout, not a hundred.\n *\n * Off by default; the panel turns it on through the settings override.\n */\n\nimport type {UpdateHook} from './lifecycle.js';\n\n/** Fade length; long enough to catch, short enough not to smear. */\nconst DURATION_MS = 450;\n\n/** How far back the ramp counts updates for one element. */\nconst RAMP_WINDOW_MS = 1000;\n\n/**\n * Outline/fill colours by heat level. Level 0 is also the flat colour used\n * when the ramp is off. Deliberately not the selection blue, so a hovered\n * element and a flashing one read differently.\n */\nconst COLORS: readonly string[] = [\n 'hsl(158 74% 53%)', // calm — one update\n '#f4bf4f', // warm\n '#f4844f', // hot\n '#ef4444', // on fire\n];\n\n/**\n * Heat level for `count` updates of one element inside the ramp window.\n * Exported for the unit test; the thresholds are the whole behaviour.\n */\nexport const rampLevel = (count: number): number => {\n if (count >= 8) return 3;\n if (count >= 4) return 2;\n if (count >= 2) return 1;\n return 0;\n};\n\nlet enabled = false;\nlet ramp = false;\n\nlet layer: HTMLElement | null = null;\n\n/** Elements that updated since the last flush, with \"was a first update\". */\nconst pending = new Map<Element, boolean>();\nlet frame: number | null = null;\n\n/** Boxes currently on screen, so a re-flash restarts instead of stacking. */\nconst active = new Map<Element, {box: HTMLElement; anim: Animation}>();\n\n/** Recent update timestamps per element, for the ramp. */\nconst history = new WeakMap<Element, number[]>();\n\nconst ensureLayer = (): HTMLElement => {\n if (layer === null) {\n layer = document.createElement('div');\n layer.setAttribute('data-lit-devtools-flash-layer', '');\n Object.assign(layer.style, {\n position: 'fixed',\n inset: '0',\n zIndex: '2147483645',\n pointerEvents: 'none',\n overflow: 'hidden',\n } satisfies Partial<CSSStyleDeclaration>);\n document.body.append(layer);\n }\n return layer;\n};\n\n/** The runtime's own UI (indicator, panels) must not flash itself. */\nconst isDevtoolsElement = (el: Element): boolean =>\n el.localName.startsWith('lit-devtools-');\n\nconst recordUpdate = (el: Element, at: number): number => {\n let times = history.get(el);\n if (times === undefined) {\n times = [];\n history.set(el, times);\n }\n times.push(at);\n const cutoff = at - RAMP_WINDOW_MS;\n while (times.length > 0 && times[0]! < cutoff) times.shift();\n return times.length;\n};\n\nconst removeBox = (el: Element, anim: Animation): void => {\n const entry = active.get(el);\n // A newer flash may have replaced this one; only the owner cleans up.\n if (entry === undefined || entry.anim !== anim) return;\n entry.box.remove();\n active.delete(el);\n};\n\nconst paint = (\n el: Element,\n rect: DOMRect,\n level: number,\n first: boolean\n): void => {\n const color = COLORS[level] ?? COLORS[0]!;\n let entry = active.get(el);\n if (entry === undefined) {\n const box = document.createElement('div');\n box.setAttribute('data-lit-devtools-flash', '');\n Object.assign(box.style, {\n position: 'absolute',\n boxSizing: 'border-box',\n borderRadius: '2px',\n willChange: 'opacity',\n } satisfies Partial<CSSStyleDeclaration>);\n ensureLayer().append(box);\n entry = {box, anim: box.animate([], {duration: 0})};\n active.set(el, entry);\n } else {\n entry.anim.cancel();\n }\n const {box} = entry;\n box.setAttribute('data-level', String(level));\n Object.assign(box.style, {\n left: `${rect.left}px`,\n top: `${rect.top}px`,\n width: `${rect.width}px`,\n height: `${rect.height}px`,\n outline: `2px solid ${color}`,\n outlineOffset: '-1px',\n background: color,\n } satisfies Partial<CSSStyleDeclaration>);\n // Mounts flash fainter: a page filling in is not the churn we're hunting.\n const peak = first ? 0.35 : 0.75;\n const anim = box.animate(\n [{opacity: peak}, {opacity: peak, offset: 0.3}, {opacity: 0}],\n {duration: DURATION_MS, easing: 'ease-out', fill: 'forwards'}\n );\n entry.anim = anim;\n anim.onfinish = () => removeBox(el, anim);\n anim.oncancel = () => {\n /* replaced by a newer flash; that one owns cleanup */\n };\n};\n\nconst flush = (): void => {\n frame = null;\n if (!enabled) {\n pending.clear();\n return;\n }\n const now = performance.now();\n for (const [el, first] of pending) {\n if (!el.isConnected) continue;\n const rect = el.getBoundingClientRect();\n // `display: contents` hosts, hidden elements, and off-DOM work have no\n // box worth drawing.\n if (rect.width === 0 || rect.height === 0) continue;\n const count = recordUpdate(el, now);\n paint(el, rect, ramp ? rampLevel(count) : 0, first);\n }\n pending.clear();\n};\n\nconst clearAll = (): void => {\n pending.clear();\n if (frame !== null) {\n cancelAnimationFrame(frame);\n frame = null;\n }\n for (const {box, anim} of active.values()) {\n anim.cancel();\n box.remove();\n }\n active.clear();\n};\n\n/** Turn the overlay on or off; off also wipes whatever is mid-fade. */\nexport const setFlashEnabled = (on: boolean): void => {\n if (enabled === on) return;\n enabled = on;\n if (!on) clearAll();\n};\n\n/** Colour by update frequency instead of the flat colour. */\nexport const setFlashRamp = (on: boolean): void => {\n ramp = on;\n};\n\n/**\n * The lifecycle layer's update hook. Cheap on the hot path: one Map write and,\n * at most, one `requestAnimationFrame` per frame; all measuring happens in\n * the flush.\n */\nexport const flashUpdate: UpdateHook = (el, first) => {\n if (!enabled || isDevtoolsElement(el)) return;\n // Several updates of one element in the same frame collapse into one box;\n // it only counts as a mount if every one of them was the first update.\n pending.set(el, (pending.get(el) ?? true) && first);\n if (frame === null) frame = requestAnimationFrame(flush);\n};\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"identity.d.ts","sourceRoot":"","sources":["../../../../../packages/labs/vite-plugin-lit/src/lib/runtime/timeline/identity.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;;;;;;;GAUG;AAEH,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AA8BD,0EAA0E;AAC1E,eAAO,MAAM,IAAI,GAAI,IAAI,MAAM,KAAG,MASjC,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,WAAW,GAAI,IAAI,MAAM,KAAG,OAAO,GAAG,SAOlD,CAAC;AAEF,4EAA4E;AAC5E,eAAO,MAAM,QAAQ,GAAI,IAAI,MAAM,KAAG,aAAa,GAAG,SAQrD,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,WAAW,GAAI,SAAS,OAAO,KAAG,MAAM,EAAE,GAAG,SAKzD,CAAC"}
1
+ {"version":3,"file":"identity.d.ts","sourceRoot":"","sources":["../../../src/lib/runtime/timeline/identity.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;;;;;;;GAUG;AAEH,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AA8BD,0EAA0E;AAC1E,eAAO,MAAM,IAAI,OAAQ,MAAM,KAAG,MASjC,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,WAAW,OAAQ,MAAM,KAAG,OAAO,GAAG,SAOlD,CAAC;AAEF,4EAA4E;AAC5E,eAAO,MAAM,QAAQ,OAAQ,MAAM,KAAG,aAAa,GAAG,SAQrD,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,WAAW,YAAa,OAAO,KAAG,MAAM,EAAE,GAAG,SAKzD,CAAC"}
@@ -21,21 +21,22 @@ const byId = new Map();
21
21
  * page (a list re-rendering thousands of rows) dead entries accumulate for the
22
22
  * whole dev session. Guarded for environments without `FinalizationRegistry`.
23
23
  */
24
- const byIdRegistry = typeof FinalizationRegistry === 'function'
24
+ const byIdRegistry =
25
+ typeof FinalizationRegistry === 'function'
25
26
  ? new FinalizationRegistry((id) => {
26
27
  byId.delete(id);
27
- })
28
+ })
28
29
  : undefined;
29
30
  /** Returns (and memoises) a stable numeric id for an element instance. */
30
31
  export const idOf = (el) => {
31
- let id = ids.get(el);
32
- if (id === undefined) {
33
- id = nextId++;
34
- ids.set(el, id);
35
- byId.set(id, new WeakRef(el));
36
- byIdRegistry?.register(el, id);
37
- }
38
- return id;
32
+ let id = ids.get(el);
33
+ if (id === undefined) {
34
+ id = nextId++;
35
+ ids.set(el, id);
36
+ byId.set(id, new WeakRef(el));
37
+ byIdRegistry?.register(el, id);
38
+ }
39
+ return id;
39
40
  };
40
41
  /**
41
42
  * Resolves an id back to its element instance, or `undefined` if it was never
@@ -43,22 +44,20 @@ export const idOf = (el) => {
43
44
  * id the panel sends (details, watch, highlight).
44
45
  */
45
46
  export const elementById = (id) => {
46
- const el = byId.get(id)?.deref();
47
- if (el === undefined) {
48
- byId.delete(id);
49
- return undefined;
50
- }
51
- return el;
47
+ const el = byId.get(id)?.deref();
48
+ if (el === undefined) {
49
+ byId.delete(id);
50
+ return undefined;
51
+ }
52
+ return el;
52
53
  };
53
54
  /** Reads the file/line source metadata injected by the plugin transform. */
54
55
  export const sourceOf = (el) => {
55
- const ctor = el.constructor;
56
- if (ctor === undefined)
57
- return undefined;
58
- const meta = ctor[SOURCE_META_KEY];
59
- if (meta?.filePath === undefined)
60
- return undefined;
61
- return { file: meta.filePath, line: meta.lineNumber ?? 1 };
56
+ const ctor = el.constructor;
57
+ if (ctor === undefined) return undefined;
58
+ const meta = ctor[SOURCE_META_KEY];
59
+ if (meta?.filePath === undefined) return undefined;
60
+ return {file: meta.filePath, line: meta.lineNumber ?? 1};
62
61
  };
63
62
  /**
64
63
  * Extracts the changed property keys from a PropertyValues argument.
@@ -66,8 +65,9 @@ export const sourceOf = (el) => {
66
65
  * that don't receive a changed-properties argument).
67
66
  */
68
67
  export const changedKeys = (changed) => {
69
- if (!(changed instanceof Map))
70
- return undefined;
71
- return [...changed.keys()].map((k) => typeof k === 'symbol' ? k.toString() : String(k));
68
+ if (!(changed instanceof Map)) return undefined;
69
+ return [...changed.keys()].map((k) =>
70
+ typeof k === 'symbol' ? k.toString() : String(k)
71
+ );
72
72
  };
73
- //# sourceMappingURL=identity.js.map
73
+ //# sourceMappingURL=identity.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"identity.js","sourceRoot":"","sources":["../../../../../packages/labs/vite-plugin-lit/src/lib/runtime/timeline/identity.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAmBH,MAAM,eAAe,GAAG,MAAM,CAAC,GAAG,CAAC,kCAAkC,CAAC,CAAC;AAEvE,kEAAkE;AAClE,MAAM,GAAG,GAAG,IAAI,OAAO,EAAkB,CAAC;AAC1C,IAAI,MAAM,GAAG,CAAC,CAAC;AAEf;;;;GAIG;AACH,MAAM,IAAI,GAAG,IAAI,GAAG,EAA2B,CAAC;AAEhD;;;;;;;GAOG;AACH,MAAM,YAAY,GAChB,OAAO,oBAAoB,KAAK,UAAU;IACxC,CAAC,CAAC,IAAI,oBAAoB,CAAS,CAAC,EAAE,EAAE,EAAE;QACtC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IAClB,CAAC,CAAC;IACJ,CAAC,CAAC,SAAS,CAAC;AAEhB,0EAA0E;AAC1E,MAAM,CAAC,MAAM,IAAI,GAAG,CAAC,EAAU,EAAU,EAAE;IACzC,IAAI,EAAE,GAAG,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IACrB,IAAI,EAAE,KAAK,SAAS,EAAE,CAAC;QACrB,EAAE,GAAG,MAAM,EAAE,CAAC;QACd,GAAG,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;QAChB,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC;QAC9B,YAAY,EAAE,QAAQ,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;IACjC,CAAC;IACD,OAAO,EAAE,CAAC;AACZ,CAAC,CAAC;AAEF;;;;GAIG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,EAAU,EAAuB,EAAE;IAC7D,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC;IACjC,IAAI,EAAE,KAAK,SAAS,EAAE,CAAC;QACrB,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QAChB,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,OAAO,EAAa,CAAC;AACvB,CAAC,CAAC;AAEF,4EAA4E;AAC5E,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,EAAU,EAA6B,EAAE;IAChE,MAAM,IAAI,GAAI,EAA8C,CAAC,WAAW,CAAC;IACzE,IAAI,IAAI,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IACzC,MAAM,IAAI,GAAG,IAAI,CAAC,eAAe,CAEpB,CAAC;IACd,IAAI,IAAI,EAAE,QAAQ,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IACnD,OAAO,EAAC,IAAI,EAAE,IAAI,CAAC,QAAQ,EAAE,IAAI,EAAE,IAAI,CAAC,UAAU,IAAI,CAAC,EAAC,CAAC;AAC3D,CAAC,CAAC;AAEF;;;;GAIG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,OAAgB,EAAwB,EAAE;IACpE,IAAI,CAAC,CAAC,OAAO,YAAY,GAAG,CAAC;QAAE,OAAO,SAAS,CAAC;IAChD,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CACnC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CACjD,CAAC;AACJ,CAAC,CAAC","sourcesContent":["/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: BSD-3-Clause\n */\n\n/**\n * Stable per-instance id and source-meta lookup for the timeline.\n *\n * Assigns monotonic numeric ids to ReactiveElement instances via a WeakMap\n * so we never mutate the elements themselves and ids survive HMR (same\n * instance identity after in-place patching).\n *\n * Source metadata is read from the Symbol injected by the source-meta\n * transform — the same one the source-overlay feature uses — so timeline\n * events can deep-link to the component's definition file.\n */\n\nexport interface ElementSource {\n file: string;\n line: number;\n}\n\nconst SOURCE_META_KEY = Symbol.for('@lit-labs/vite-plugin-lit#source');\n\n/** WeakMap avoids retaining elements after disconnection + GC. */\nconst ids = new WeakMap<object, number>();\nlet nextId = 0;\n\n/**\n * Reverse map for {@link elementById}, so a panel request (which only carries\n * an id) can be resolved back to the live instance. WeakRef-valued so we never\n * keep an element alive past GC; dead entries are pruned on lookup.\n */\nconst byId = new Map<number, WeakRef<object>>();\n\n/**\n * Drops `byId` entries as their elements are garbage-collected. The `WeakRef`\n * already lets the element itself be reclaimed, but the Map slot (id + WeakRef\n * wrapper) would otherwise linger until the next `elementById(id)` lookup —\n * which only happens on a panel request for that specific id, so on a churning\n * page (a list re-rendering thousands of rows) dead entries accumulate for the\n * whole dev session. Guarded for environments without `FinalizationRegistry`.\n */\nconst byIdRegistry =\n typeof FinalizationRegistry === 'function'\n ? new FinalizationRegistry<number>((id) => {\n byId.delete(id);\n })\n : undefined;\n\n/** Returns (and memoises) a stable numeric id for an element instance. */\nexport const idOf = (el: object): number => {\n let id = ids.get(el);\n if (id === undefined) {\n id = nextId++;\n ids.set(el, id);\n byId.set(id, new WeakRef(el));\n byIdRegistry?.register(el, id);\n }\n return id;\n};\n\n/**\n * Resolves an id back to its element instance, or `undefined` if it was never\n * seen or has since been garbage-collected. Used by the inspector to act on the\n * id the panel sends (details, watch, highlight).\n */\nexport const elementById = (id: number): Element | undefined => {\n const el = byId.get(id)?.deref();\n if (el === undefined) {\n byId.delete(id);\n return undefined;\n }\n return el as Element;\n};\n\n/** Reads the file/line source metadata injected by the plugin transform. */\nexport const sourceOf = (el: object): ElementSource | undefined => {\n const ctor = (el as {constructor?: Record<symbol, unknown>}).constructor;\n if (ctor === undefined) return undefined;\n const meta = ctor[SOURCE_META_KEY] as\n | {filePath?: string; lineNumber?: number}\n | undefined;\n if (meta?.filePath === undefined) return undefined;\n return {file: meta.filePath, line: meta.lineNumber ?? 1};\n};\n\n/**\n * Extracts the changed property keys from a PropertyValues argument.\n * Returns undefined when `changed` is not a Map (e.g. for lifecycle hooks\n * that don't receive a changed-properties argument).\n */\nexport const changedKeys = (changed: unknown): string[] | undefined => {\n if (!(changed instanceof Map)) return undefined;\n return [...changed.keys()].map((k) =>\n typeof k === 'symbol' ? k.toString() : String(k)\n );\n};\n"]}
1
+ {"version":3,"file":"identity.js","sourceRoot":"","sources":["../../../src/lib/runtime/timeline/identity.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAmBH,MAAM,eAAe,GAAG,MAAM,CAAC,GAAG,CAAC,kCAAkC,CAAC,CAAC;AAEvE,kEAAkE;AAClE,MAAM,GAAG,GAAG,IAAI,OAAO,EAAkB,CAAC;AAC1C,IAAI,MAAM,GAAG,CAAC,CAAC;AAEf;;;;GAIG;AACH,MAAM,IAAI,GAAG,IAAI,GAAG,EAA2B,CAAC;AAEhD;;;;;;;GAOG;AACH,MAAM,YAAY,GAChB,OAAO,oBAAoB,KAAK,UAAU;IACxC,CAAC,CAAC,IAAI,oBAAoB,CAAS,CAAC,EAAE,EAAE,EAAE;QACtC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IAClB,CAAC,CAAC;IACJ,CAAC,CAAC,SAAS,CAAC;AAEhB,0EAA0E;AAC1E,MAAM,CAAC,MAAM,IAAI,GAAG,CAAC,EAAU,EAAU,EAAE;IACzC,IAAI,EAAE,GAAG,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IACrB,IAAI,EAAE,KAAK,SAAS,EAAE,CAAC;QACrB,EAAE,GAAG,MAAM,EAAE,CAAC;QACd,GAAG,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;QAChB,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC;QAC9B,YAAY,EAAE,QAAQ,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;IACjC,CAAC;IACD,OAAO,EAAE,CAAC;AACZ,CAAC,CAAC;AAEF;;;;GAIG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,EAAU,EAAuB,EAAE;IAC7D,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC;IACjC,IAAI,EAAE,KAAK,SAAS,EAAE,CAAC;QACrB,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QAChB,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,OAAO,EAAa,CAAC;AACvB,CAAC,CAAC;AAEF,4EAA4E;AAC5E,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,EAAU,EAA6B,EAAE;IAChE,MAAM,IAAI,GAAI,EAA8C,CAAC,WAAW,CAAC;IACzE,IAAI,IAAI,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IACzC,MAAM,IAAI,GAAG,IAAI,CAAC,eAAe,CAEpB,CAAC;IACd,IAAI,IAAI,EAAE,QAAQ,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IACnD,OAAO,EAAC,IAAI,EAAE,IAAI,CAAC,QAAQ,EAAE,IAAI,EAAE,IAAI,CAAC,UAAU,IAAI,CAAC,EAAC,CAAC;AAC3D,CAAC,CAAC;AAEF;;;;GAIG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,OAAgB,EAAwB,EAAE;IACpE,IAAI,CAAC,CAAC,OAAO,YAAY,GAAG,CAAC;QAAE,OAAO,SAAS,CAAC;IAChD,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CACnC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CACjD,CAAC;AACJ,CAAC,CAAC","sourcesContent":["/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: BSD-3-Clause\n */\n\n/**\n * Stable per-instance id and source-meta lookup for the timeline.\n *\n * Assigns monotonic numeric ids to ReactiveElement instances via a WeakMap\n * so we never mutate the elements themselves and ids survive HMR (same\n * instance identity after in-place patching).\n *\n * Source metadata is read from the Symbol injected by the source-meta\n * transform — the same one the source-overlay feature uses — so timeline\n * events can deep-link to the component's definition file.\n */\n\nexport interface ElementSource {\n file: string;\n line: number;\n}\n\nconst SOURCE_META_KEY = Symbol.for('@lit-labs/vite-plugin-lit#source');\n\n/** WeakMap avoids retaining elements after disconnection + GC. */\nconst ids = new WeakMap<object, number>();\nlet nextId = 0;\n\n/**\n * Reverse map for {@link elementById}, so a panel request (which only carries\n * an id) can be resolved back to the live instance. WeakRef-valued so we never\n * keep an element alive past GC; dead entries are pruned on lookup.\n */\nconst byId = new Map<number, WeakRef<object>>();\n\n/**\n * Drops `byId` entries as their elements are garbage-collected. The `WeakRef`\n * already lets the element itself be reclaimed, but the Map slot (id + WeakRef\n * wrapper) would otherwise linger until the next `elementById(id)` lookup —\n * which only happens on a panel request for that specific id, so on a churning\n * page (a list re-rendering thousands of rows) dead entries accumulate for the\n * whole dev session. Guarded for environments without `FinalizationRegistry`.\n */\nconst byIdRegistry =\n typeof FinalizationRegistry === 'function'\n ? new FinalizationRegistry<number>((id) => {\n byId.delete(id);\n })\n : undefined;\n\n/** Returns (and memoises) a stable numeric id for an element instance. */\nexport const idOf = (el: object): number => {\n let id = ids.get(el);\n if (id === undefined) {\n id = nextId++;\n ids.set(el, id);\n byId.set(id, new WeakRef(el));\n byIdRegistry?.register(el, id);\n }\n return id;\n};\n\n/**\n * Resolves an id back to its element instance, or `undefined` if it was never\n * seen or has since been garbage-collected. Used by the inspector to act on the\n * id the panel sends (details, watch, highlight).\n */\nexport const elementById = (id: number): Element | undefined => {\n const el = byId.get(id)?.deref();\n if (el === undefined) {\n byId.delete(id);\n return undefined;\n }\n return el as Element;\n};\n\n/** Reads the file/line source metadata injected by the plugin transform. */\nexport const sourceOf = (el: object): ElementSource | undefined => {\n const ctor = (el as {constructor?: Record<symbol, unknown>}).constructor;\n if (ctor === undefined) return undefined;\n const meta = ctor[SOURCE_META_KEY] as\n | {filePath?: string; lineNumber?: number}\n | undefined;\n if (meta?.filePath === undefined) return undefined;\n return {file: meta.filePath, line: meta.lineNumber ?? 1};\n};\n\n/**\n * Extracts the changed property keys from a PropertyValues argument.\n * Returns undefined when `changed` is not a Map (e.g. for lifecycle hooks\n * that don't receive a changed-properties argument).\n */\nexport const changedKeys = (changed: unknown): string[] | undefined => {\n if (!(changed instanceof Map)) return undefined;\n return [...changed.keys()].map((k) =>\n typeof k === 'symbol' ? k.toString() : String(k)\n );\n};\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"input.d.ts","sourceRoot":"","sources":["../../../../../packages/labs/vite-plugin-lit/src/lib/runtime/timeline/input.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;GAGG;AAEH,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,4BAA4B,CAAC;AAG9D,KAAK,MAAM,GAAG,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;AAC7C,KAAK,WAAW,GAAG,MAAM,OAAO,CAAC;AAyEjC,eAAO,MAAM,iBAAiB,GAC5B,MAAM,MAAM,EACZ,WAAW,WAAW,EACtB,cAAc,MAAM,OAAO,KAC1B,IAWF,CAAC;AAEF,eAAO,MAAM,oBAAoB,GAC/B,MAAM,MAAM,EACZ,WAAW,WAAW,EACtB,YAAY,MAAM,OAAO,KACxB,IAWF,CAAC"}
1
+ {"version":3,"file":"input.d.ts","sourceRoot":"","sources":["../../../src/lib/runtime/timeline/input.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;GAGG;AAEH,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,4BAA4B,CAAC;AAG9D,KAAK,MAAM,GAAG,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;AAC7C,KAAK,WAAW,GAAG,MAAM,OAAO,CAAC;AAyEjC,eAAO,MAAM,iBAAiB,SACtB,MAAM,aACD,WAAW,gBACR,MAAM,OAAO,KAC1B,IAWF,CAAC;AAEF,eAAO,MAAM,oBAAoB,SACzB,MAAM,aACD,WAAW,cACV,MAAM,OAAO,KACxB,IAWF,CAAC"}
@@ -3,85 +3,72 @@
3
3
  * Copyright 2026 Google LLC
4
4
  * SPDX-License-Identifier: BSD-3-Clause
5
5
  */
6
- import { now } from './clock.js';
7
- const MOUSE_EVENTS = [
8
- 'mousedown',
9
- 'mouseup',
10
- 'click',
11
- 'dblclick',
12
- ];
6
+ import {now} from './clock.js';
7
+ const MOUSE_EVENTS = ['mousedown', 'mouseup', 'click', 'dblclick'];
13
8
  const KEY_EVENTS = ['keydown', 'keyup'];
14
9
  const mouseHandler = (emit, recording, mouseEnabled) => (e) => {
15
- if (!recording() || !mouseEnabled())
16
- return;
17
- const me = e;
18
- const data = {
19
- type: e.type,
20
- x: Math.round(me.clientX),
21
- y: Math.round(me.clientY),
22
- button: me.button,
23
- };
24
- emit({
25
- layerId: 'mouse',
26
- time: now(),
27
- title: e.type,
28
- subtitle: `(${data.x}, ${data.y})`,
29
- data,
30
- });
10
+ if (!recording() || !mouseEnabled()) return;
11
+ const me = e;
12
+ const data = {
13
+ type: e.type,
14
+ x: Math.round(me.clientX),
15
+ y: Math.round(me.clientY),
16
+ button: me.button,
17
+ };
18
+ emit({
19
+ layerId: 'mouse',
20
+ time: now(),
21
+ title: e.type,
22
+ subtitle: `(${data.x}, ${data.y})`,
23
+ data,
24
+ });
31
25
  };
32
26
  const keyHandler = (emit, recording, keyEnabled) => (e) => {
33
- if (!recording() || !keyEnabled())
34
- return;
35
- const ke = e;
36
- const modifiers = [];
37
- if (ke.ctrlKey)
38
- modifiers.push('Ctrl');
39
- if (ke.metaKey)
40
- modifiers.push('Meta');
41
- if (ke.altKey)
42
- modifiers.push('Alt');
43
- if (ke.shiftKey)
44
- modifiers.push('Shift');
45
- const data = {
46
- type: e.type,
47
- key: ke.key,
48
- code: ke.code,
49
- modifiers,
50
- };
51
- emit({
52
- layerId: 'keyboard',
53
- time: now(),
54
- title: ke.key,
55
- subtitle: modifiers.length ? modifiers.join('+') : undefined,
56
- data,
57
- });
27
+ if (!recording() || !keyEnabled()) return;
28
+ const ke = e;
29
+ const modifiers = [];
30
+ if (ke.ctrlKey) modifiers.push('Ctrl');
31
+ if (ke.metaKey) modifiers.push('Meta');
32
+ if (ke.altKey) modifiers.push('Alt');
33
+ if (ke.shiftKey) modifiers.push('Shift');
34
+ const data = {
35
+ type: e.type,
36
+ key: ke.key,
37
+ code: ke.code,
38
+ modifiers,
39
+ };
40
+ emit({
41
+ layerId: 'keyboard',
42
+ time: now(),
43
+ title: ke.key,
44
+ subtitle: modifiers.length ? modifiers.join('+') : undefined,
45
+ data,
46
+ });
58
47
  };
59
48
  let mouseCleanup = null;
60
49
  let keyCleanup = null;
61
50
  export const installMouseLayer = (emit, recording, mouseEnabled) => {
62
- if (mouseCleanup !== null)
63
- return;
64
- const handler = mouseHandler(emit, recording, mouseEnabled);
51
+ if (mouseCleanup !== null) return;
52
+ const handler = mouseHandler(emit, recording, mouseEnabled);
53
+ for (const type of MOUSE_EVENTS) {
54
+ window.addEventListener(type, handler, {capture: true, passive: true});
55
+ }
56
+ mouseCleanup = () => {
65
57
  for (const type of MOUSE_EVENTS) {
66
- window.addEventListener(type, handler, { capture: true, passive: true });
58
+ window.removeEventListener(type, handler, {capture: true});
67
59
  }
68
- mouseCleanup = () => {
69
- for (const type of MOUSE_EVENTS) {
70
- window.removeEventListener(type, handler, { capture: true });
71
- }
72
- };
60
+ };
73
61
  };
74
62
  export const installKeyboardLayer = (emit, recording, keyEnabled) => {
75
- if (keyCleanup !== null)
76
- return;
77
- const handler = keyHandler(emit, recording, keyEnabled);
63
+ if (keyCleanup !== null) return;
64
+ const handler = keyHandler(emit, recording, keyEnabled);
65
+ for (const type of KEY_EVENTS) {
66
+ window.addEventListener(type, handler, {capture: true, passive: true});
67
+ }
68
+ keyCleanup = () => {
78
69
  for (const type of KEY_EVENTS) {
79
- window.addEventListener(type, handler, { capture: true, passive: true });
70
+ window.removeEventListener(type, handler, {capture: true});
80
71
  }
81
- keyCleanup = () => {
82
- for (const type of KEY_EVENTS) {
83
- window.removeEventListener(type, handler, { capture: true });
84
- }
85
- };
72
+ };
86
73
  };
87
- //# sourceMappingURL=input.js.map
74
+ //# sourceMappingURL=input.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"input.js","sourceRoot":"","sources":["../../../../../packages/labs/vite-plugin-lit/src/lib/runtime/timeline/input.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 * Mouse and keyboard timeline layers — plain window listeners, direct port\n * of the Vue DevTools timeline input capture pattern.\n */\n\nimport type {TimelineEvent} from '../../../types/timeline.js';\nimport {now} from './clock.js';\n\ntype EmitFn = (event: TimelineEvent) => void;\ntype RecordingFn = () => boolean;\n\nconst MOUSE_EVENTS = [\n 'mousedown',\n 'mouseup',\n 'click',\n 'dblclick',\n] as const satisfies readonly string[];\n\nconst KEY_EVENTS = ['keydown', 'keyup'] as const satisfies readonly string[];\n\ninterface MouseData {\n type: string;\n x: number;\n y: number;\n button: number;\n}\n\ninterface KeyData {\n type: string;\n key: string;\n code: string;\n modifiers: string[];\n}\n\nconst mouseHandler =\n (emit: EmitFn, recording: RecordingFn, mouseEnabled: () => boolean) =>\n (e: Event): void => {\n if (!recording() || !mouseEnabled()) return;\n const me = e as MouseEvent;\n const data: MouseData = {\n type: e.type,\n x: Math.round(me.clientX),\n y: Math.round(me.clientY),\n button: me.button,\n };\n emit({\n layerId: 'mouse',\n time: now(),\n title: e.type,\n subtitle: `(${data.x}, ${data.y})`,\n data,\n });\n };\n\nconst keyHandler =\n (emit: EmitFn, recording: RecordingFn, keyEnabled: () => boolean) =>\n (e: Event): void => {\n if (!recording() || !keyEnabled()) return;\n const ke = e as KeyboardEvent;\n const modifiers: string[] = [];\n if (ke.ctrlKey) modifiers.push('Ctrl');\n if (ke.metaKey) modifiers.push('Meta');\n if (ke.altKey) modifiers.push('Alt');\n if (ke.shiftKey) modifiers.push('Shift');\n const data: KeyData = {\n type: e.type,\n key: ke.key,\n code: ke.code,\n modifiers,\n };\n emit({\n layerId: 'keyboard',\n time: now(),\n title: ke.key,\n subtitle: modifiers.length ? modifiers.join('+') : undefined,\n data,\n });\n };\n\nlet mouseCleanup: (() => void) | null = null;\nlet keyCleanup: (() => void) | null = null;\n\nexport const installMouseLayer = (\n emit: EmitFn,\n recording: RecordingFn,\n mouseEnabled: () => boolean\n): void => {\n if (mouseCleanup !== null) return;\n const handler = mouseHandler(emit, recording, mouseEnabled);\n for (const type of MOUSE_EVENTS) {\n window.addEventListener(type, handler, {capture: true, passive: true});\n }\n mouseCleanup = () => {\n for (const type of MOUSE_EVENTS) {\n window.removeEventListener(type, handler, {capture: true});\n }\n };\n};\n\nexport const installKeyboardLayer = (\n emit: EmitFn,\n recording: RecordingFn,\n keyEnabled: () => boolean\n): void => {\n if (keyCleanup !== null) return;\n const handler = keyHandler(emit, recording, keyEnabled);\n for (const type of KEY_EVENTS) {\n window.addEventListener(type, handler, {capture: true, passive: true});\n }\n keyCleanup = () => {\n for (const type of KEY_EVENTS) {\n window.removeEventListener(type, handler, {capture: true});\n }\n };\n};\n"]}
1
+ {"version":3,"file":"input.js","sourceRoot":"","sources":["../../../src/lib/runtime/timeline/input.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 * Mouse and keyboard timeline layers — plain window listeners, direct port\n * of the Vue DevTools timeline input capture pattern.\n */\n\nimport type {TimelineEvent} from '../../../types/timeline.js';\nimport {now} from './clock.js';\n\ntype EmitFn = (event: TimelineEvent) => void;\ntype RecordingFn = () => boolean;\n\nconst MOUSE_EVENTS = [\n 'mousedown',\n 'mouseup',\n 'click',\n 'dblclick',\n] as const satisfies readonly string[];\n\nconst KEY_EVENTS = ['keydown', 'keyup'] as const satisfies readonly string[];\n\ninterface MouseData {\n type: string;\n x: number;\n y: number;\n button: number;\n}\n\ninterface KeyData {\n type: string;\n key: string;\n code: string;\n modifiers: string[];\n}\n\nconst mouseHandler =\n (emit: EmitFn, recording: RecordingFn, mouseEnabled: () => boolean) =>\n (e: Event): void => {\n if (!recording() || !mouseEnabled()) return;\n const me = e as MouseEvent;\n const data: MouseData = {\n type: e.type,\n x: Math.round(me.clientX),\n y: Math.round(me.clientY),\n button: me.button,\n };\n emit({\n layerId: 'mouse',\n time: now(),\n title: e.type,\n subtitle: `(${data.x}, ${data.y})`,\n data,\n });\n };\n\nconst keyHandler =\n (emit: EmitFn, recording: RecordingFn, keyEnabled: () => boolean) =>\n (e: Event): void => {\n if (!recording() || !keyEnabled()) return;\n const ke = e as KeyboardEvent;\n const modifiers: string[] = [];\n if (ke.ctrlKey) modifiers.push('Ctrl');\n if (ke.metaKey) modifiers.push('Meta');\n if (ke.altKey) modifiers.push('Alt');\n if (ke.shiftKey) modifiers.push('Shift');\n const data: KeyData = {\n type: e.type,\n key: ke.key,\n code: ke.code,\n modifiers,\n };\n emit({\n layerId: 'keyboard',\n time: now(),\n title: ke.key,\n subtitle: modifiers.length ? modifiers.join('+') : undefined,\n data,\n });\n };\n\nlet mouseCleanup: (() => void) | null = null;\nlet keyCleanup: (() => void) | null = null;\n\nexport const installMouseLayer = (\n emit: EmitFn,\n recording: RecordingFn,\n mouseEnabled: () => boolean\n): void => {\n if (mouseCleanup !== null) return;\n const handler = mouseHandler(emit, recording, mouseEnabled);\n for (const type of MOUSE_EVENTS) {\n window.addEventListener(type, handler, {capture: true, passive: true});\n }\n mouseCleanup = () => {\n for (const type of MOUSE_EVENTS) {\n window.removeEventListener(type, handler, {capture: true});\n }\n };\n};\n\nexport const installKeyboardLayer = (\n emit: EmitFn,\n recording: RecordingFn,\n keyEnabled: () => boolean\n): void => {\n if (keyCleanup !== null) return;\n const handler = keyHandler(emit, recording, keyEnabled);\n for (const type of KEY_EVENTS) {\n window.addEventListener(type, handler, {capture: true, passive: true});\n }\n keyCleanup = () => {\n for (const type of KEY_EVENTS) {\n window.removeEventListener(type, handler, {capture: true});\n }\n };\n};\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../../../../../packages/labs/vite-plugin-lit/src/lib/runtime/timeline/install.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
1
+ {"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../../../src/lib/runtime/timeline/install.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
@@ -13,20 +13,22 @@
13
13
  * Recording starts off; the panel iframe toggles it via the Vite HMR channel
14
14
  * (Phase 0/1) or devframe shared state (Phase 2+).
15
15
  */
16
- import { emit, setHotClient } from './transport.js';
17
- import { resetClock } from './clock.js';
18
- import { installLifecycleLayer } from './lifecycle.js';
19
- import { installRenderLayer, setRenderDebugEnabled } from './render.js';
20
- import { installMouseLayer, installKeyboardLayer } from './input.js';
16
+ import {emit, setHotClient} from './transport.js';
17
+ import {resetClock} from './clock.js';
18
+ import {installLifecycleLayer, setUpdateHook} from './lifecycle.js';
19
+ import {installRenderLayer, setRenderDebugEnabled} from './render.js';
20
+ import {installMouseLayer, installKeyboardLayer} from './input.js';
21
+ import {flashUpdate, setFlashEnabled, setFlashRamp} from './flash.js';
22
+ import {subscribeOverride} from '../overrides.js';
21
23
  // ---------------------------------------------------------------------------
22
24
  // Recording state — written by the panel toggle, read by all capture layers.
23
25
  // ---------------------------------------------------------------------------
24
26
  const state = {
25
- recordingState: false,
26
- litLifecycleEnabled: true,
27
- litRenderEnabled: true,
28
- mouseEventEnabled: false,
29
- keyboardEventEnabled: false,
27
+ recordingState: false,
28
+ litLifecycleEnabled: true,
29
+ litRenderEnabled: true,
30
+ mouseEventEnabled: false,
31
+ keyboardEventEnabled: false,
30
32
  };
31
33
  const recording = () => state.recordingState;
32
34
  const lifecycleEnabled = () => state.litLifecycleEnabled;
@@ -37,7 +39,7 @@ const keyboardEnabled = () => state.keyboardEventEnabled;
37
39
  // lit-html only pays the per-render CustomEvent dispatch cost while we're
38
40
  // actually capturing the render layer.
39
41
  const syncRenderDebug = () => {
40
- setRenderDebugEnabled(state.recordingState && state.litRenderEnabled);
42
+ setRenderDebugEnabled(state.recordingState && state.litRenderEnabled);
41
43
  };
42
44
  // ---------------------------------------------------------------------------
43
45
  // Capture layer installation
@@ -46,24 +48,31 @@ installLifecycleLayer(emit, recording, lifecycleEnabled);
46
48
  installRenderLayer(emit, recording, renderEnabled);
47
49
  installMouseLayer(emit, recording, mouseEnabled);
48
50
  installKeyboardLayer(emit, recording, keyboardEnabled);
51
+ // Flash-on-update rides the lifecycle wrappers but not the recording gate:
52
+ // it's a page-side visual the panel toggles as a preference, so it follows the
53
+ // settings override (read at boot, pushed live) rather than the layer state.
54
+ setUpdateHook(flashUpdate);
49
55
  const hot = import.meta.hot;
56
+ subscribeOverride(hot, (o) => {
57
+ setFlashEnabled(o.flashUpdates ?? false);
58
+ setFlashRamp(o.flashUpdatesRamp ?? false);
59
+ });
50
60
  if (hot !== undefined) {
51
- setHotClient(hot);
52
- // Panel → app: toggle recording and per-layer flags.
53
- hot.on('lit:timeline:recording-changed', (data) => {
54
- const next = data.recording;
55
- // Re-zero the timeline clock on the rising edge so event times read as
56
- // "ms since recording started" rather than since page load.
57
- if (next && !state.recordingState)
58
- resetClock();
59
- state.recordingState = next;
60
- syncRenderDebug();
61
- });
62
- hot.on('lit:timeline:layers-changed', (data) => {
63
- Object.assign(state, data);
64
- syncRenderDebug();
65
- });
66
- // Announce readiness so the panel can detect the runtime.
67
- hot.send('lit:timeline:runtime-ready', {});
61
+ setHotClient(hot);
62
+ // Panel → app: toggle recording and per-layer flags.
63
+ hot.on('lit:timeline:recording-changed', (data) => {
64
+ const next = data.recording;
65
+ // Re-zero the timeline clock on the rising edge so event times read as
66
+ // "ms since recording started" rather than since page load.
67
+ if (next && !state.recordingState) resetClock();
68
+ state.recordingState = next;
69
+ syncRenderDebug();
70
+ });
71
+ hot.on('lit:timeline:layers-changed', (data) => {
72
+ Object.assign(state, data);
73
+ syncRenderDebug();
74
+ });
75
+ // Announce readiness so the panel can detect the runtime.
76
+ hot.send('lit:timeline:runtime-ready', {});
68
77
  }
69
- //# sourceMappingURL=install.js.map
78
+ //# sourceMappingURL=install.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"install.js","sourceRoot":"","sources":["../../../../../packages/labs/vite-plugin-lit/src/lib/runtime/timeline/install.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;;;;;;GASG;AAEH,OAAO,EAAC,IAAI,EAAE,YAAY,EAAC,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAC,UAAU,EAAC,MAAM,YAAY,CAAC;AACtC,OAAO,EAAC,qBAAqB,EAAC,MAAM,gBAAgB,CAAC;AACrD,OAAO,EAAC,kBAAkB,EAAE,qBAAqB,EAAC,MAAM,aAAa,CAAC;AACtE,OAAO,EAAC,iBAAiB,EAAE,oBAAoB,EAAC,MAAM,YAAY,CAAC;AAGnE,8EAA8E;AAC9E,6EAA6E;AAC7E,8EAA8E;AAE9E,MAAM,KAAK,GAAwB;IACjC,cAAc,EAAE,KAAK;IACrB,mBAAmB,EAAE,IAAI;IACzB,gBAAgB,EAAE,IAAI;IACtB,iBAAiB,EAAE,KAAK;IACxB,oBAAoB,EAAE,KAAK;CAC5B,CAAC;AAEF,MAAM,SAAS,GAAG,GAAY,EAAE,CAAC,KAAK,CAAC,cAAc,CAAC;AACtD,MAAM,gBAAgB,GAAG,GAAY,EAAE,CAAC,KAAK,CAAC,mBAAmB,CAAC;AAClE,MAAM,aAAa,GAAG,GAAY,EAAE,CAAC,KAAK,CAAC,gBAAgB,CAAC;AAC5D,MAAM,YAAY,GAAG,GAAY,EAAE,CAAC,KAAK,CAAC,iBAAiB,CAAC;AAC5D,MAAM,eAAe,GAAG,GAAY,EAAE,CAAC,KAAK,CAAC,oBAAoB,CAAC;AAElE,wEAAwE;AACxE,0EAA0E;AAC1E,uCAAuC;AACvC,MAAM,eAAe,GAAG,GAAS,EAAE;IACjC,qBAAqB,CAAC,KAAK,CAAC,cAAc,IAAI,KAAK,CAAC,gBAAgB,CAAC,CAAC;AACxE,CAAC,CAAC;AAEF,8EAA8E;AAC9E,6BAA6B;AAC7B,8EAA8E;AAE9E,qBAAqB,CAAC,IAAI,EAAE,SAAS,EAAE,gBAAgB,CAAC,CAAC;AACzD,kBAAkB,CAAC,IAAI,EAAE,SAAS,EAAE,aAAa,CAAC,CAAC;AACnD,iBAAiB,CAAC,IAAI,EAAE,SAAS,EAAE,YAAY,CAAC,CAAC;AACjD,oBAAoB,CAAC,IAAI,EAAE,SAAS,EAAE,eAAe,CAAC,CAAC;AAYvD,MAAM,GAAG,GAAI,MAAM,CAAC,IAAwB,CAAC,GAAG,CAAC;AAEjD,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;IACtB,YAAY,CAAC,GAAG,CAAC,CAAC;IAElB,qDAAqD;IACrD,GAAG,CAAC,EAAE,CAAC,gCAAgC,EAAE,CAAC,IAAI,EAAE,EAAE;QAChD,MAAM,IAAI,GAAI,IAA6B,CAAC,SAAS,CAAC;QACtD,uEAAuE;QACvE,4DAA4D;QAC5D,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,cAAc;YAAE,UAAU,EAAE,CAAC;QAChD,KAAK,CAAC,cAAc,GAAG,IAAI,CAAC;QAC5B,eAAe,EAAE,CAAC;IACpB,CAAC,CAAC,CAAC;IAEH,GAAG,CAAC,EAAE,CAAC,6BAA6B,EAAE,CAAC,IAAI,EAAE,EAAE;QAC7C,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,IAAoC,CAAC,CAAC;QAC3D,eAAe,EAAE,CAAC;IACpB,CAAC,CAAC,CAAC;IAEH,0DAA0D;IAC1D,GAAG,CAAC,IAAI,CAAC,4BAA4B,EAAE,EAAE,CAAC,CAAC;AAC7C,CAAC","sourcesContent":["/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: BSD-3-Clause\n */\n\n/**\n * Timeline runtime install entry point.\n *\n * Injected by the plugin into the host page via `transformIndexHtml` when\n * `timeline: true` is set. Sets up all capture layers and wires them to the\n * transport.\n *\n * Recording starts off; the panel iframe toggles it via the Vite HMR channel\n * (Phase 0/1) or devframe shared state (Phase 2+).\n */\n\nimport {emit, setHotClient} from './transport.js';\nimport {resetClock} from './clock.js';\nimport {installLifecycleLayer} from './lifecycle.js';\nimport {installRenderLayer, setRenderDebugEnabled} from './render.js';\nimport {installMouseLayer, installKeyboardLayer} from './input.js';\nimport type {TimelineLayersState} from '../../../types/timeline.js';\n\n// ---------------------------------------------------------------------------\n// Recording state — written by the panel toggle, read by all capture layers.\n// ---------------------------------------------------------------------------\n\nconst state: TimelineLayersState = {\n recordingState: false,\n litLifecycleEnabled: true,\n litRenderEnabled: true,\n mouseEventEnabled: false,\n keyboardEventEnabled: false,\n};\n\nconst recording = (): boolean => state.recordingState;\nconst lifecycleEnabled = (): boolean => state.litLifecycleEnabled;\nconst renderEnabled = (): boolean => state.litRenderEnabled;\nconst mouseEnabled = (): boolean => state.mouseEventEnabled;\nconst keyboardEnabled = (): boolean => state.keyboardEventEnabled;\n\n// Drive Lit's debug event flag from recording × render-layer-enabled so\n// lit-html only pays the per-render CustomEvent dispatch cost while we're\n// actually capturing the render layer.\nconst syncRenderDebug = (): void => {\n setRenderDebugEnabled(state.recordingState && state.litRenderEnabled);\n};\n\n// ---------------------------------------------------------------------------\n// Capture layer installation\n// ---------------------------------------------------------------------------\n\ninstallLifecycleLayer(emit, recording, lifecycleEnabled);\ninstallRenderLayer(emit, recording, renderEnabled);\ninstallMouseLayer(emit, recording, mouseEnabled);\ninstallKeyboardLayer(emit, recording, keyboardEnabled);\n\n// ---------------------------------------------------------------------------\n// HMR channel wiring (Phase 0/1 transport)\n// ---------------------------------------------------------------------------\n\n// `import.meta.hot` exists in Vite dev builds; the tsconfig lib set doesn't\n// include it, so we access it through the un-typed global shape.\ntype ViteHot = {\n send: (event: string, data: unknown) => void;\n on: (event: string, handler: (data: unknown) => void) => void;\n};\nconst hot = (import.meta as {hot?: ViteHot}).hot;\n\nif (hot !== undefined) {\n setHotClient(hot);\n\n // Panel → app: toggle recording and per-layer flags.\n hot.on('lit:timeline:recording-changed', (data) => {\n const next = (data as {recording: boolean}).recording;\n // Re-zero the timeline clock on the rising edge so event times read as\n // \"ms since recording started\" rather than since page load.\n if (next && !state.recordingState) resetClock();\n state.recordingState = next;\n syncRenderDebug();\n });\n\n hot.on('lit:timeline:layers-changed', (data) => {\n Object.assign(state, data as Partial<TimelineLayersState>);\n syncRenderDebug();\n });\n\n // Announce readiness so the panel can detect the runtime.\n hot.send('lit:timeline:runtime-ready', {});\n}\n"]}
1
+ {"version":3,"file":"install.js","sourceRoot":"","sources":["../../../src/lib/runtime/timeline/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 * Timeline runtime install entry point.\n *\n * Injected by the plugin into the host page via `transformIndexHtml` when\n * `timeline: true` is set. Sets up all capture layers and wires them to the\n * transport.\n *\n * Recording starts off; the panel iframe toggles it via the Vite HMR channel\n * (Phase 0/1) or devframe shared state (Phase 2+).\n */\n\nimport {emit, setHotClient} from './transport.js';\nimport {resetClock} from './clock.js';\nimport {installLifecycleLayer, setUpdateHook} from './lifecycle.js';\nimport {installRenderLayer, setRenderDebugEnabled} from './render.js';\nimport {installMouseLayer, installKeyboardLayer} from './input.js';\nimport {flashUpdate, setFlashEnabled, setFlashRamp} from './flash.js';\nimport {subscribeOverride} from '../overrides.js';\nimport type {TimelineLayersState} from '../../../types/timeline.js';\n\n// ---------------------------------------------------------------------------\n// Recording state — written by the panel toggle, read by all capture layers.\n// ---------------------------------------------------------------------------\n\nconst state: TimelineLayersState = {\n recordingState: false,\n litLifecycleEnabled: true,\n litRenderEnabled: true,\n mouseEventEnabled: false,\n keyboardEventEnabled: false,\n};\n\nconst recording = (): boolean => state.recordingState;\nconst lifecycleEnabled = (): boolean => state.litLifecycleEnabled;\nconst renderEnabled = (): boolean => state.litRenderEnabled;\nconst mouseEnabled = (): boolean => state.mouseEventEnabled;\nconst keyboardEnabled = (): boolean => state.keyboardEventEnabled;\n\n// Drive Lit's debug event flag from recording × render-layer-enabled so\n// lit-html only pays the per-render CustomEvent dispatch cost while we're\n// actually capturing the render layer.\nconst syncRenderDebug = (): void => {\n setRenderDebugEnabled(state.recordingState && state.litRenderEnabled);\n};\n\n// ---------------------------------------------------------------------------\n// Capture layer installation\n// ---------------------------------------------------------------------------\n\ninstallLifecycleLayer(emit, recording, lifecycleEnabled);\ninstallRenderLayer(emit, recording, renderEnabled);\ninstallMouseLayer(emit, recording, mouseEnabled);\ninstallKeyboardLayer(emit, recording, keyboardEnabled);\n\n// Flash-on-update rides the lifecycle wrappers but not the recording gate:\n// it's a page-side visual the panel toggles as a preference, so it follows the\n// settings override (read at boot, pushed live) rather than the layer state.\nsetUpdateHook(flashUpdate);\n\n// ---------------------------------------------------------------------------\n// HMR channel wiring (Phase 0/1 transport)\n// ---------------------------------------------------------------------------\n\n// `import.meta.hot` exists in Vite dev builds; the tsconfig lib set doesn't\n// include it, so we access it through the un-typed global shape.\ntype ViteHot = {\n send: (event: string, data: unknown) => void;\n on: (event: string, handler: (data: unknown) => void) => void;\n};\nconst hot = (import.meta as {hot?: ViteHot}).hot;\n\nsubscribeOverride(hot, (o) => {\n setFlashEnabled(o.flashUpdates ?? false);\n setFlashRamp(o.flashUpdatesRamp ?? false);\n});\n\nif (hot !== undefined) {\n setHotClient(hot);\n\n // Panel → app: toggle recording and per-layer flags.\n hot.on('lit:timeline:recording-changed', (data) => {\n const next = (data as {recording: boolean}).recording;\n // Re-zero the timeline clock on the rising edge so event times read as\n // \"ms since recording started\" rather than since page load.\n if (next && !state.recordingState) resetClock();\n state.recordingState = next;\n syncRenderDebug();\n });\n\n hot.on('lit:timeline:layers-changed', (data) => {\n Object.assign(state, data as Partial<TimelineLayersState>);\n syncRenderDebug();\n });\n\n // Announce readiness so the panel can detect the runtime.\n hot.send('lit:timeline:runtime-ready', {});\n}\n"]}
@@ -7,6 +7,14 @@ import type { TimelineEvent } from '../../../types/timeline.js';
7
7
  type EmitFn = (event: TimelineEvent) => void;
8
8
  type RecordingFn = () => boolean;
9
9
  type LayerEnabledFn = () => boolean;
10
+ /**
11
+ * Called once per completed `performUpdate`, with the element and whether that
12
+ * was its first update. Independent of the recording gate: the flash overlay
13
+ * wants every update while it is on, whether or not the timeline is recording.
14
+ */
15
+ export type UpdateHook = (el: Element, first: boolean) => void;
16
+ /** Install (or clear, with `null`) the per-update hook. One consumer. */
17
+ export declare const setUpdateHook: (hook: UpdateHook | null) => void;
10
18
  /**
11
19
  * Install lifecycle instrumentation for *every* Lit element on the page.
12
20
  *