@oddsquad/vite-plugin-lit 0.2.3 → 0.4.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 (240) hide show
  1. package/CHANGELOG.md +112 -0
  2. package/LICENSE +28 -0
  3. package/README.md +157 -0
  4. package/bin.mjs +154 -0
  5. package/client.d.ts +61 -0
  6. package/dist/client/assets/browser-agent-rpc-BXhoSh1z-CdtPhBL-.js +69 -0
  7. package/dist/client/assets/browser-agent-rpc-BXhoSh1z-CdtPhBL-.js.map +1 -0
  8. package/dist/client/assets/flow-DK8vmxvN.js +745 -0
  9. package/dist/client/assets/flow-DK8vmxvN.js.map +1 -0
  10. package/dist/client/assets/index-DVe6M4HV.js +10614 -0
  11. package/dist/client/assets/index-DVe6M4HV.js.map +1 -0
  12. package/{panel → dist/client}/index.html +1 -0
  13. package/index.d.ts.map +1 -1
  14. package/index.js +2 -2
  15. package/index.js.map +1 -1
  16. package/lib/color-scheme.d.ts.map +1 -1
  17. package/lib/color-scheme.js +17 -21
  18. package/lib/color-scheme.js.map +1 -1
  19. package/lib/devframe/definition.d.ts +45 -0
  20. package/lib/devframe/definition.d.ts.map +1 -0
  21. package/lib/devframe/definition.js +547 -0
  22. package/lib/devframe/definition.js.map +1 -0
  23. package/lib/devframe/icon.d.ts +8 -0
  24. package/lib/devframe/icon.d.ts.map +1 -0
  25. package/lib/devframe/icon.js +21 -0
  26. package/lib/devframe/icon.js.map +1 -0
  27. package/lib/devframe/paths.d.ts +12 -0
  28. package/lib/devframe/paths.d.ts.map +1 -0
  29. package/lib/devframe/paths.js +38 -0
  30. package/lib/devframe/paths.js.map +1 -0
  31. package/lib/devframe/protocol.d.ts +218 -0
  32. package/lib/devframe/protocol.d.ts.map +1 -0
  33. package/lib/devframe/protocol.js +77 -0
  34. package/lib/devframe/protocol.js.map +1 -0
  35. package/lib/devframe/source.d.ts +49 -0
  36. package/lib/devframe/source.d.ts.map +1 -0
  37. package/lib/devframe/source.js +23 -0
  38. package/lib/devframe/source.js.map +1 -0
  39. package/lib/devframe/vite.d.ts +116 -0
  40. package/lib/devframe/vite.d.ts.map +1 -0
  41. package/lib/devframe/vite.js +292 -0
  42. package/lib/devframe/vite.js.map +1 -0
  43. package/lib/http.d.ts +29 -0
  44. package/lib/http.d.ts.map +1 -0
  45. package/lib/http.js +35 -0
  46. package/lib/http.js.map +1 -0
  47. package/lib/icons.d.ts +2 -0
  48. package/lib/icons.d.ts.map +1 -1
  49. package/lib/icons.js +10 -4
  50. package/lib/icons.js.map +1 -1
  51. package/lib/options.d.ts +131 -0
  52. package/lib/options.d.ts.map +1 -0
  53. package/lib/options.js +128 -0
  54. package/lib/options.js.map +1 -0
  55. package/lib/plugin.d.ts +6 -137
  56. package/lib/plugin.d.ts.map +1 -1
  57. package/lib/plugin.js +280 -677
  58. package/lib/plugin.js.map +1 -1
  59. package/lib/plugins/css-literals.d.ts +15 -0
  60. package/lib/plugins/css-literals.d.ts.map +1 -0
  61. package/lib/plugins/css-literals.js +154 -0
  62. package/lib/plugins/css-literals.js.map +1 -0
  63. package/lib/plugins/css-queries.d.ts +20 -0
  64. package/lib/plugins/css-queries.d.ts.map +1 -0
  65. package/lib/plugins/css-queries.js +139 -0
  66. package/lib/plugins/css-queries.js.map +1 -0
  67. package/lib/plugins/open-in-editor.d.ts +16 -0
  68. package/lib/plugins/open-in-editor.d.ts.map +1 -0
  69. package/lib/plugins/open-in-editor.js +91 -0
  70. package/lib/plugins/open-in-editor.js.map +1 -0
  71. package/lib/plugins/shared.d.ts +13 -0
  72. package/lib/plugins/shared.d.ts.map +1 -0
  73. package/lib/plugins/shared.js +23 -0
  74. package/lib/plugins/shared.js.map +1 -0
  75. package/lib/plugins/timeline-virtual.d.ts +19 -0
  76. package/lib/plugins/timeline-virtual.d.ts.map +1 -0
  77. package/lib/plugins/timeline-virtual.js +53 -0
  78. package/lib/plugins/timeline-virtual.js.map +1 -0
  79. package/lib/runtime/css.d.ts +2 -2
  80. package/lib/runtime/css.d.ts.map +1 -1
  81. package/lib/runtime/css.js +41 -34
  82. package/lib/runtime/css.js.map +1 -1
  83. package/lib/runtime/edge-panel.d.ts.map +1 -1
  84. package/lib/runtime/edge-panel.js +82 -91
  85. package/lib/runtime/edge-panel.js.map +1 -1
  86. package/lib/runtime/fonts.d.ts.map +1 -1
  87. package/lib/runtime/fonts.js +1 -1
  88. package/lib/runtime/fonts.js.map +1 -1
  89. package/lib/runtime/indicator.d.ts.map +1 -1
  90. package/lib/runtime/indicator.js +71 -74
  91. package/lib/runtime/indicator.js.map +1 -1
  92. package/lib/runtime/inspector/collect.d.ts.map +1 -1
  93. package/lib/runtime/inspector/collect.js +83 -90
  94. package/lib/runtime/inspector/collect.js.map +1 -1
  95. package/lib/runtime/inspector/highlight.d.ts +16 -0
  96. package/lib/runtime/inspector/highlight.d.ts.map +1 -0
  97. package/lib/runtime/inspector/highlight.js +66 -0
  98. package/lib/runtime/inspector/highlight.js.map +1 -0
  99. package/lib/runtime/inspector/install.d.ts.map +1 -1
  100. package/lib/runtime/inspector/install.js +230 -205
  101. package/lib/runtime/inspector/install.js.map +1 -1
  102. package/lib/runtime/inspector/serialize.d.ts.map +1 -1
  103. package/lib/runtime/inspector/serialize.js +86 -107
  104. package/lib/runtime/inspector/serialize.js.map +1 -1
  105. package/lib/runtime/intern.d.ts.map +1 -1
  106. package/lib/runtime/intern.js +31 -29
  107. package/lib/runtime/intern.js.map +1 -1
  108. package/lib/runtime/overrides.d.ts.map +1 -1
  109. package/lib/runtime/overrides.js +14 -13
  110. package/lib/runtime/overrides.js.map +1 -1
  111. package/lib/runtime/patch.d.ts +8 -0
  112. package/lib/runtime/patch.d.ts.map +1 -1
  113. package/lib/runtime/patch.js +321 -282
  114. package/lib/runtime/patch.js.map +1 -1
  115. package/lib/runtime/source-meta.d.ts.map +1 -1
  116. package/lib/runtime/source-meta.js +1 -1
  117. package/lib/runtime/source-meta.js.map +1 -1
  118. package/lib/runtime/source-overlay/editors.d.ts.map +1 -1
  119. package/lib/runtime/source-overlay/editors.js +27 -27
  120. package/lib/runtime/source-overlay/editors.js.map +1 -1
  121. package/lib/runtime/source-overlay/mask-path.d.ts.map +1 -1
  122. package/lib/runtime/source-overlay/mask-path.js +15 -15
  123. package/lib/runtime/source-overlay/mask-path.js.map +1 -1
  124. package/lib/runtime/source-overlay/overlay-element.d.ts.map +1 -1
  125. package/lib/runtime/source-overlay/overlay-element.js +359 -355
  126. package/lib/runtime/source-overlay/overlay-element.js.map +1 -1
  127. package/lib/runtime/source-overlay/source-host.d.ts.map +1 -1
  128. package/lib/runtime/source-overlay/source-host.js +64 -71
  129. package/lib/runtime/source-overlay/source-host.js.map +1 -1
  130. package/lib/runtime/source-overlay/template.d.ts.map +1 -1
  131. package/lib/runtime/source-overlay/template.js +3 -3
  132. package/lib/runtime/source-overlay/template.js.map +1 -1
  133. package/lib/runtime/source-overlay.d.ts.map +1 -1
  134. package/lib/runtime/source-overlay.js +5 -2
  135. package/lib/runtime/source-overlay.js.map +1 -1
  136. package/lib/runtime/timeline/clock.d.ts.map +1 -1
  137. package/lib/runtime/timeline/clock.js +2 -2
  138. package/lib/runtime/timeline/clock.js.map +1 -1
  139. package/lib/runtime/timeline/flash.d.ts +39 -0
  140. package/lib/runtime/timeline/flash.d.ts.map +1 -0
  141. package/lib/runtime/timeline/flash.js +169 -0
  142. package/lib/runtime/timeline/flash.js.map +1 -0
  143. package/lib/runtime/timeline/identity.d.ts.map +1 -1
  144. package/lib/runtime/timeline/identity.js +27 -27
  145. package/lib/runtime/timeline/identity.js.map +1 -1
  146. package/lib/runtime/timeline/input.d.ts.map +1 -1
  147. package/lib/runtime/timeline/input.js +54 -67
  148. package/lib/runtime/timeline/input.js.map +1 -1
  149. package/lib/runtime/timeline/install.d.ts.map +1 -1
  150. package/lib/runtime/timeline/install.js +47 -33
  151. package/lib/runtime/timeline/install.js.map +1 -1
  152. package/lib/runtime/timeline/lifecycle.d.ts +8 -0
  153. package/lib/runtime/timeline/lifecycle.d.ts.map +1 -1
  154. package/lib/runtime/timeline/lifecycle.js +149 -133
  155. package/lib/runtime/timeline/lifecycle.js.map +1 -1
  156. package/lib/runtime/timeline/public-api.d.ts +2 -2
  157. package/lib/runtime/timeline/public-api.d.ts.map +1 -1
  158. package/lib/runtime/timeline/public-api.js +11 -11
  159. package/lib/runtime/timeline/public-api.js.map +1 -1
  160. package/lib/runtime/timeline/render.d.ts +15 -6
  161. package/lib/runtime/timeline/render.d.ts.map +1 -1
  162. package/lib/runtime/timeline/render.js +212 -78
  163. package/lib/runtime/timeline/render.js.map +1 -1
  164. package/lib/runtime/timeline/transport.d.ts.map +1 -1
  165. package/lib/runtime/timeline/transport.js +39 -43
  166. package/lib/runtime/timeline/transport.js.map +1 -1
  167. package/lib/segmented-tabs.d.ts +3 -1
  168. package/lib/segmented-tabs.d.ts.map +1 -1
  169. package/lib/segmented-tabs.js +136 -107
  170. package/lib/segmented-tabs.js.map +1 -1
  171. package/lib/snapshot.d.ts +28 -0
  172. package/lib/snapshot.d.ts.map +1 -0
  173. package/lib/snapshot.js +57 -0
  174. package/lib/snapshot.js.map +1 -0
  175. package/lib/source-meta.d.ts.map +1 -1
  176. package/lib/source-meta.js +176 -162
  177. package/lib/source-meta.js.map +1 -1
  178. package/lib/timeline/derive.d.ts +152 -0
  179. package/lib/timeline/derive.d.ts.map +1 -0
  180. package/lib/timeline/derive.js +242 -0
  181. package/lib/timeline/derive.js.map +1 -0
  182. package/lib/tokens.d.ts.map +1 -1
  183. package/lib/tokens.js +17 -18
  184. package/lib/tokens.js.map +1 -1
  185. package/lib/transform.d.ts.map +1 -1
  186. package/lib/transform.js +62 -57
  187. package/lib/transform.js.map +1 -1
  188. package/lib/types.d.ts.map +1 -1
  189. package/lib/types.js +1 -1
  190. package/lib/types.js.map +1 -1
  191. package/lib/wrap-table.d.ts.map +1 -1
  192. package/lib/wrap-table.js +19 -17
  193. package/lib/wrap-table.js.map +1 -1
  194. package/package.json +80 -13
  195. package/types/hmr-incompatibility.d.ts +59 -0
  196. package/types/hmr-incompatibility.d.ts.map +1 -0
  197. package/types/hmr-incompatibility.js +30 -0
  198. package/types/hmr-incompatibility.js.map +1 -0
  199. package/types/in-page.d.ts +49 -0
  200. package/types/in-page.d.ts.map +1 -0
  201. package/types/in-page.js +33 -0
  202. package/types/in-page.js.map +1 -0
  203. package/types/inspector.d.ts.map +1 -1
  204. package/types/inspector.js.map +1 -1
  205. package/types/snapshot.d.ts +44 -0
  206. package/types/snapshot.d.ts.map +1 -0
  207. package/types/snapshot.js +7 -0
  208. package/types/snapshot.js.map +1 -0
  209. package/types/timeline.d.ts +23 -1
  210. package/types/timeline.d.ts.map +1 -1
  211. package/types/timeline.js +2 -0
  212. package/types/timeline.js.map +1 -1
  213. package/lib/timeline-plugin.d.ts +0 -72
  214. package/lib/timeline-plugin.d.ts.map +0 -1
  215. package/lib/timeline-plugin.js +0 -376
  216. package/lib/timeline-plugin.js.map +0 -1
  217. package/panel/components-view.d.ts +0 -60
  218. package/panel/components-view.d.ts.map +0 -1
  219. package/panel/components-view.js +0 -587
  220. package/panel/components-view.js.map +0 -1
  221. package/panel/devtools-settings.d.ts +0 -41
  222. package/panel/devtools-settings.d.ts.map +0 -1
  223. package/panel/devtools-settings.js +0 -463
  224. package/panel/devtools-settings.js.map +0 -1
  225. package/panel/lit-devtools-panel.d.ts +0 -37
  226. package/panel/lit-devtools-panel.d.ts.map +0 -1
  227. package/panel/lit-devtools-panel.js +0 -185
  228. package/panel/lit-devtools-panel.js.map +0 -1
  229. package/panel/timeline-event-list.d.ts +0 -43
  230. package/panel/timeline-event-list.d.ts.map +0 -1
  231. package/panel/timeline-event-list.js +0 -416
  232. package/panel/timeline-event-list.js.map +0 -1
  233. package/panel/timeline-layers.d.ts +0 -25
  234. package/panel/timeline-layers.d.ts.map +0 -1
  235. package/panel/timeline-layers.js +0 -96
  236. package/panel/timeline-layers.js.map +0 -1
  237. package/panel/timeline-view.d.ts +0 -38
  238. package/panel/timeline-view.d.ts.map +0 -1
  239. package/panel/timeline-view.js +0 -234
  240. package/panel/timeline-view.js.map +0 -1
@@ -0,0 +1,242 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Google LLC
4
+ * SPDX-License-Identifier: BSD-3-Clause
5
+ */
6
+ /** Layer whose events describe Lit update ticks. */
7
+ const LIFECYCLE_LAYER_ID = 'lit-lifecycle';
8
+ /** Layers whose events are developer input, for {@link attributeInput}. */
9
+ const INPUT_LAYER_IDS = ['mouse', 'keyboard'];
10
+ /** The phase that brackets an entire update tick. */
11
+ const ROOT_PHASE = 'performUpdate';
12
+ const START_SUFFIX = ':start';
13
+ const END_SUFFIX = ':end';
14
+ /** Reads `data.changed` defensively — `data` is `unknown` on the wire. */
15
+ const changedOf = (event) => {
16
+ const data = event.data;
17
+ if (data === null || typeof data !== 'object') return undefined;
18
+ const changed = data.changed;
19
+ if (!Array.isArray(changed)) return undefined;
20
+ const keys = changed.filter((key) => typeof key === 'string');
21
+ return keys.length > 0 ? keys : undefined;
22
+ };
23
+ const pointSpan = (event, index) => ({
24
+ layerId: event.layerId,
25
+ key: `${event.layerId}:point:${index}`,
26
+ name: event.title ?? event.layerId,
27
+ start: event.time,
28
+ changed: changedOf(event),
29
+ subtitle: event.subtitle,
30
+ logType: event.logType,
31
+ meta: event.meta,
32
+ events: [event],
33
+ });
34
+ /**
35
+ * Collapses `:start` / `:end` event pairs into spans, passing anything else
36
+ * through as a point span.
37
+ *
38
+ * Pairing is keyed on **layer + groupId + phase name**, never on `groupId`
39
+ * alone: a whole update tick shares one groupId (`runtime/timeline/
40
+ * lifecycle.ts` builds it as `${elementId}:${tick}`), so matching on the id
41
+ * would marry `willUpdate:start` to `performUpdate:end`. Each phase occurs at
42
+ * most once per tick, which makes the triple unique.
43
+ *
44
+ * Unmatched halves survive rather than disappear — the buffer is a bounded
45
+ * ring, so its oldest end and its newest start routinely have no partner, and
46
+ * an update that is still running has a genuinely open span.
47
+ */
48
+ export const toSpans = (events) => {
49
+ const spans = [];
50
+ const open = new Map();
51
+ events.forEach((event, index) => {
52
+ const title = event.title ?? event.layerId;
53
+ const isStart = title.endsWith(START_SUFFIX);
54
+ const isEnd = !isStart && title.endsWith(END_SUFFIX);
55
+ if (event.groupId === undefined || (!isStart && !isEnd)) {
56
+ spans.push(pointSpan(event, index));
57
+ return;
58
+ }
59
+ const name = title.slice(
60
+ 0,
61
+ -(isStart ? START_SUFFIX.length : END_SUFFIX.length)
62
+ );
63
+ const key = `${event.layerId}:${event.groupId}:${name}`;
64
+ if (isStart) {
65
+ const span = {
66
+ layerId: event.layerId,
67
+ key,
68
+ name,
69
+ groupId: event.groupId,
70
+ start: event.time,
71
+ changed: changedOf(event),
72
+ subtitle: event.subtitle,
73
+ logType: event.logType,
74
+ meta: event.meta,
75
+ events: [event],
76
+ };
77
+ open.set(key, span);
78
+ // Pushed on its start, so the list is already in start order and an
79
+ // open span keeps its place instead of appearing when it finally ends.
80
+ spans.push(span);
81
+ return;
82
+ }
83
+ const span = open.get(key);
84
+ if (span === undefined) {
85
+ spans.push(pointSpan(event, index));
86
+ return;
87
+ }
88
+ open.delete(key);
89
+ span.events.push(event);
90
+ // A negative delta means the buffer straddles a clock reset (the runtime
91
+ // re-zeroes on the rising edge of recording). Report no duration rather
92
+ // than a negative one; the span stays open, which is what it honestly is.
93
+ if (event.time >= span.start) {
94
+ span.end = event.time;
95
+ span.duration = event.time - span.start;
96
+ }
97
+ span.changed ??= changedOf(event);
98
+ });
99
+ return spans.sort((a, b) => a.start - b.start);
100
+ };
101
+ /**
102
+ * Groups lifecycle spans into update ticks.
103
+ *
104
+ * `duration` is taken from the `performUpdate` span alone, never from a sum of
105
+ * the phases: `willUpdate` / `update` / `updated` all run *inside*
106
+ * `performUpdate`, so summing counts the same milliseconds several times over.
107
+ *
108
+ * `changed` is the union across the tick's phases because only the phases that
109
+ * receive a `PropertyValues` argument carry it — `performUpdate` takes none,
110
+ * so the bracketing span is always silent about the reason.
111
+ */
112
+ export const toUpdateCycles = (spans) => {
113
+ const byGroup = new Map();
114
+ for (const span of spans) {
115
+ const elementId = span.meta?.elementId;
116
+ if (
117
+ span.layerId !== LIFECYCLE_LAYER_ID ||
118
+ span.groupId === undefined ||
119
+ elementId === undefined
120
+ ) {
121
+ // Point lifecycle events (connect/disconnect) have no groupId and are
122
+ // not update ticks; other layers are not this function's business.
123
+ continue;
124
+ }
125
+ const key = String(span.groupId);
126
+ let cycle = byGroup.get(key);
127
+ if (cycle === undefined) {
128
+ cycle = {
129
+ key,
130
+ elementId,
131
+ tagName: span.meta?.tagName ?? 'unknown',
132
+ source: span.meta?.source,
133
+ start: span.start,
134
+ changed: [],
135
+ phases: [],
136
+ };
137
+ byGroup.set(key, cycle);
138
+ }
139
+ cycle.phases.push(span);
140
+ if (span.start < cycle.start) cycle.start = span.start;
141
+ if (span.name === ROOT_PHASE) cycle.duration = span.duration;
142
+ for (const changedKey of span.changed ?? []) {
143
+ if (!cycle.changed.includes(changedKey)) cycle.changed.push(changedKey);
144
+ }
145
+ }
146
+ return [...byGroup.values()].sort((a, b) => a.start - b.start);
147
+ };
148
+ /**
149
+ * Totals update cycles per component tag.
150
+ *
151
+ * Grouped by tag rather than by instance because the question this answers is
152
+ * "which *component* re-renders too much" — a list of 200 rows each updating
153
+ * twice is one component's problem, not 200. The instance ids are kept so the
154
+ * caller can still drill in.
155
+ */
156
+ export const rollup = (cycles) => {
157
+ const byTag = new Map();
158
+ for (const cycle of cycles) {
159
+ let record = byTag.get(cycle.tagName);
160
+ if (record === undefined) {
161
+ record = {
162
+ entry: {
163
+ tagName: cycle.tagName,
164
+ elementIds: [],
165
+ updates: 0,
166
+ totalMs: 0,
167
+ maxMs: 0,
168
+ reasons: [],
169
+ source: cycle.source,
170
+ },
171
+ reasons: new Map(),
172
+ };
173
+ byTag.set(cycle.tagName, record);
174
+ }
175
+ const {entry, reasons} = record;
176
+ entry.updates++;
177
+ if (!entry.elementIds.includes(cycle.elementId)) {
178
+ entry.elementIds.push(cycle.elementId);
179
+ }
180
+ entry.source ??= cycle.source;
181
+ // An open or clock-straddling cycle contributes a count but no time —
182
+ // better than inventing one, and the count is what flags a hot component.
183
+ if (cycle.duration !== undefined) {
184
+ entry.totalMs += cycle.duration;
185
+ if (cycle.duration > entry.maxMs) entry.maxMs = cycle.duration;
186
+ }
187
+ for (const key of cycle.changed) {
188
+ reasons.set(key, (reasons.get(key) ?? 0) + 1);
189
+ }
190
+ }
191
+ const entries = [];
192
+ for (const {entry, reasons} of byTag.values()) {
193
+ entry.reasons = [...reasons]
194
+ .map(([key, count]) => ({key, count}))
195
+ .sort((a, b) => b.count - a.count || a.key.localeCompare(b.key));
196
+ entries.push(entry);
197
+ }
198
+ // Slowest first, then most frequent: a component with no measured durations
199
+ // still sorts above a quiet one.
200
+ return entries.sort((a, b) => b.totalMs - a.totalMs || b.updates - a.updates);
201
+ };
202
+ /**
203
+ * Attributes each update cycle to the input event that preceded it, within
204
+ * `windowMs`.
205
+ *
206
+ * This is what the mouse and keyboard layers are for. On their own they
207
+ * duplicate what the browser's own event log already shows; joined to the
208
+ * updates they precede they answer the question the raw layers only imply —
209
+ * an update with a cause is an interaction, and an update without one is a
210
+ * timer, a signal, or a stray `requestUpdate()`.
211
+ *
212
+ * Returns a new array; cycles with no cause are returned as-is.
213
+ */
214
+ export const attributeInput = (cycles, events, windowMs = 200) => {
215
+ const inputs = events
216
+ .filter((event) => INPUT_LAYER_IDS.includes(event.layerId))
217
+ .sort((a, b) => a.time - b.time);
218
+ if (inputs.length === 0) return [...cycles];
219
+ // Both sides are sorted by time, so one forward pass suffices.
220
+ let cursor = 0;
221
+ return cycles.map((cycle) => {
222
+ while (
223
+ cursor + 1 < inputs.length &&
224
+ inputs[cursor + 1].time <= cycle.start
225
+ ) {
226
+ cursor++;
227
+ }
228
+ const candidate = inputs[cursor];
229
+ const delta = cycle.start - candidate.time;
230
+ if (delta < 0 || delta > windowMs) return cycle;
231
+ return {
232
+ ...cycle,
233
+ cause: {
234
+ layerId: candidate.layerId,
235
+ type: candidate.title ?? candidate.layerId,
236
+ detail: candidate.subtitle,
237
+ time: candidate.time,
238
+ },
239
+ };
240
+ });
241
+ };
242
+ //# sourceMappingURL=derive.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"derive.js","sourceRoot":"","sources":["../../src/lib/timeline/derive.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 * Derivation over recorded timeline events.\n *\n * The capture layers emit one event per phase boundary, which is the right\n * wire format and the wrong thing to read: a single update tick of one\n * component is five to ten rows whose durations the reader has to subtract by\n * hand. Everything needed to do better is already on the events — `groupId`\n * pairs a start with its end, `data.changed` names the reactive properties\n * that caused the update — so this module turns a flat event list into the\n * three shapes the panel and agents actually ask for:\n *\n * - {@link TimelineSpan} — a start/end pair collapsed into one entry with a\n * duration (\"`update` took 1.8ms\").\n * - {@link UpdateCycle} — one component's whole update tick, with the changed\n * property keys that triggered it (\"`<hmr-counter>` updated because\n * `count` changed\").\n * - {@link ComponentRollup} — per-component totals over a recording (\"this\n * component updated 340 times for 120ms\").\n *\n * Pure and dependency-free by design: it imports only the shared event types,\n * so the panel derives client-side over its 5000-event buffer and\n * `devframe/definition.ts` — which must stay framework-neutral — can derive\n * server-side over the ring buffer for the agent-facing summary.\n */\n\nimport type {TimelineEvent} from '../../types/timeline.js';\n\n/** Layer whose events describe Lit update ticks. */\nconst LIFECYCLE_LAYER_ID = 'lit-lifecycle';\n\n/** Layers whose events are developer input, for {@link attributeInput}. */\nconst INPUT_LAYER_IDS: readonly string[] = ['mouse', 'keyboard'];\n\n/** The phase that brackets an entire update tick. */\nconst ROOT_PHASE = 'performUpdate';\n\nconst START_SUFFIX = ':start';\nconst END_SUFFIX = ':end';\n\n/**\n * A start/end pair collapsed into one entry, or a point event that never had\n * an end to begin with.\n */\nexport interface TimelineSpan {\n layerId: string;\n /**\n * Stable across re-derivation of the same events, which a Lit `repeat()`\n * key and a selection comparison both need — the span objects themselves\n * are rebuilt whenever the event buffer changes.\n */\n key: string;\n /** The event title with its `:start` / `:end` suffix removed. */\n name: string;\n /** Pairing id as emitted; `undefined` for point events. */\n groupId?: number | string;\n start: number;\n /** Absent while the span is still open, or if its end was never recorded. */\n end?: number;\n /** `end - start`. Absent for open spans and for point events. */\n duration?: number;\n /** Reactive property keys that caused this update, where the phase has them. */\n changed?: string[];\n subtitle?: string;\n logType?: TimelineEvent['logType'];\n meta?: TimelineEvent['meta'];\n /** The events this span was built from, for the detail pane. */\n events: TimelineEvent[];\n}\n\n/** One component's complete update tick. */\nexport interface UpdateCycle {\n /** The `${elementId}:${tick}` groupId the phases share. */\n key: string;\n elementId: number;\n tagName: string;\n source?: {file: string; line: number};\n start: number;\n /** The `performUpdate` span's duration — see {@link toUpdateCycles}. */\n duration?: number;\n /** Union of the changed reactive property keys across the tick's phases. */\n changed: string[];\n phases: TimelineSpan[];\n /** The input event this update followed, if any. See {@link attributeInput}. */\n cause?: {layerId: string; type: string; detail?: string; time: number};\n}\n\n/** Per-component totals over a set of update cycles. */\nexport interface ComponentRollup {\n tagName: string;\n /** Every instance of this component that updated, in first-seen order. */\n elementIds: number[];\n updates: number;\n /** Summed `performUpdate` durations; excludes cycles with no measured end. */\n totalMs: number;\n maxMs: number;\n /** Changed-key frequency across the cycles, most frequent first. */\n reasons: Array<{key: string; count: number}>;\n source?: {file: string; line: number};\n}\n\n/** Reads `data.changed` defensively — `data` is `unknown` on the wire. */\nconst changedOf = (event: TimelineEvent): string[] | undefined => {\n const data = event.data;\n if (data === null || typeof data !== 'object') return undefined;\n const changed = (data as {changed?: unknown}).changed;\n if (!Array.isArray(changed)) return undefined;\n const keys = changed.filter((key): key is string => typeof key === 'string');\n return keys.length > 0 ? keys : undefined;\n};\n\nconst pointSpan = (event: TimelineEvent, index: number): TimelineSpan => ({\n layerId: event.layerId,\n key: `${event.layerId}:point:${index}`,\n name: event.title ?? event.layerId,\n start: event.time,\n changed: changedOf(event),\n subtitle: event.subtitle,\n logType: event.logType,\n meta: event.meta,\n events: [event],\n});\n\n/**\n * Collapses `:start` / `:end` event pairs into spans, passing anything else\n * through as a point span.\n *\n * Pairing is keyed on **layer + groupId + phase name**, never on `groupId`\n * alone: a whole update tick shares one groupId (`runtime/timeline/\n * lifecycle.ts` builds it as `${elementId}:${tick}`), so matching on the id\n * would marry `willUpdate:start` to `performUpdate:end`. Each phase occurs at\n * most once per tick, which makes the triple unique.\n *\n * Unmatched halves survive rather than disappear — the buffer is a bounded\n * ring, so its oldest end and its newest start routinely have no partner, and\n * an update that is still running has a genuinely open span.\n */\nexport const toSpans = (events: readonly TimelineEvent[]): TimelineSpan[] => {\n const spans: TimelineSpan[] = [];\n const open = new Map<string, TimelineSpan>();\n\n events.forEach((event, index) => {\n const title = event.title ?? event.layerId;\n const isStart = title.endsWith(START_SUFFIX);\n const isEnd = !isStart && title.endsWith(END_SUFFIX);\n\n if (event.groupId === undefined || (!isStart && !isEnd)) {\n spans.push(pointSpan(event, index));\n return;\n }\n\n const name = title.slice(\n 0,\n -(isStart ? START_SUFFIX.length : END_SUFFIX.length)\n );\n const key = `${event.layerId}:${event.groupId}:${name}`;\n\n if (isStart) {\n const span: TimelineSpan = {\n layerId: event.layerId,\n key,\n name,\n groupId: event.groupId,\n start: event.time,\n changed: changedOf(event),\n subtitle: event.subtitle,\n logType: event.logType,\n meta: event.meta,\n events: [event],\n };\n open.set(key, span);\n // Pushed on its start, so the list is already in start order and an\n // open span keeps its place instead of appearing when it finally ends.\n spans.push(span);\n return;\n }\n\n const span = open.get(key);\n if (span === undefined) {\n spans.push(pointSpan(event, index));\n return;\n }\n open.delete(key);\n span.events.push(event);\n // A negative delta means the buffer straddles a clock reset (the runtime\n // re-zeroes on the rising edge of recording). Report no duration rather\n // than a negative one; the span stays open, which is what it honestly is.\n if (event.time >= span.start) {\n span.end = event.time;\n span.duration = event.time - span.start;\n }\n span.changed ??= changedOf(event);\n });\n\n return spans.sort((a, b) => a.start - b.start);\n};\n\n/**\n * Groups lifecycle spans into update ticks.\n *\n * `duration` is taken from the `performUpdate` span alone, never from a sum of\n * the phases: `willUpdate` / `update` / `updated` all run *inside*\n * `performUpdate`, so summing counts the same milliseconds several times over.\n *\n * `changed` is the union across the tick's phases because only the phases that\n * receive a `PropertyValues` argument carry it — `performUpdate` takes none,\n * so the bracketing span is always silent about the reason.\n */\nexport const toUpdateCycles = (\n spans: readonly TimelineSpan[]\n): UpdateCycle[] => {\n const byGroup = new Map<string, UpdateCycle>();\n\n for (const span of spans) {\n const elementId = span.meta?.elementId;\n if (\n span.layerId !== LIFECYCLE_LAYER_ID ||\n span.groupId === undefined ||\n elementId === undefined\n ) {\n // Point lifecycle events (connect/disconnect) have no groupId and are\n // not update ticks; other layers are not this function's business.\n continue;\n }\n\n const key = String(span.groupId);\n let cycle = byGroup.get(key);\n if (cycle === undefined) {\n cycle = {\n key,\n elementId,\n tagName: span.meta?.tagName ?? 'unknown',\n source: span.meta?.source,\n start: span.start,\n changed: [],\n phases: [],\n };\n byGroup.set(key, cycle);\n }\n\n cycle.phases.push(span);\n if (span.start < cycle.start) cycle.start = span.start;\n if (span.name === ROOT_PHASE) cycle.duration = span.duration;\n for (const changedKey of span.changed ?? []) {\n if (!cycle.changed.includes(changedKey)) cycle.changed.push(changedKey);\n }\n }\n\n return [...byGroup.values()].sort((a, b) => a.start - b.start);\n};\n\n/**\n * Totals update cycles per component tag.\n *\n * Grouped by tag rather than by instance because the question this answers is\n * \"which *component* re-renders too much\" — a list of 200 rows each updating\n * twice is one component's problem, not 200. The instance ids are kept so the\n * caller can still drill in.\n */\nexport const rollup = (cycles: readonly UpdateCycle[]): ComponentRollup[] => {\n const byTag = new Map<\n string,\n {entry: ComponentRollup; reasons: Map<string, number>}\n >();\n\n for (const cycle of cycles) {\n let record = byTag.get(cycle.tagName);\n if (record === undefined) {\n record = {\n entry: {\n tagName: cycle.tagName,\n elementIds: [],\n updates: 0,\n totalMs: 0,\n maxMs: 0,\n reasons: [],\n source: cycle.source,\n },\n reasons: new Map(),\n };\n byTag.set(cycle.tagName, record);\n }\n\n const {entry, reasons} = record;\n entry.updates++;\n if (!entry.elementIds.includes(cycle.elementId)) {\n entry.elementIds.push(cycle.elementId);\n }\n entry.source ??= cycle.source;\n // An open or clock-straddling cycle contributes a count but no time —\n // better than inventing one, and the count is what flags a hot component.\n if (cycle.duration !== undefined) {\n entry.totalMs += cycle.duration;\n if (cycle.duration > entry.maxMs) entry.maxMs = cycle.duration;\n }\n for (const key of cycle.changed) {\n reasons.set(key, (reasons.get(key) ?? 0) + 1);\n }\n }\n\n const entries: ComponentRollup[] = [];\n for (const {entry, reasons} of byTag.values()) {\n entry.reasons = [...reasons]\n .map(([key, count]) => ({key, count}))\n .sort((a, b) => b.count - a.count || a.key.localeCompare(b.key));\n entries.push(entry);\n }\n\n // Slowest first, then most frequent: a component with no measured durations\n // still sorts above a quiet one.\n return entries.sort((a, b) => b.totalMs - a.totalMs || b.updates - a.updates);\n};\n\n/**\n * Attributes each update cycle to the input event that preceded it, within\n * `windowMs`.\n *\n * This is what the mouse and keyboard layers are for. On their own they\n * duplicate what the browser's own event log already shows; joined to the\n * updates they precede they answer the question the raw layers only imply —\n * an update with a cause is an interaction, and an update without one is a\n * timer, a signal, or a stray `requestUpdate()`.\n *\n * Returns a new array; cycles with no cause are returned as-is.\n */\nexport const attributeInput = (\n cycles: readonly UpdateCycle[],\n events: readonly TimelineEvent[],\n windowMs = 200\n): UpdateCycle[] => {\n const inputs = events\n .filter((event) => INPUT_LAYER_IDS.includes(event.layerId))\n .sort((a, b) => a.time - b.time);\n if (inputs.length === 0) return [...cycles];\n\n // Both sides are sorted by time, so one forward pass suffices.\n let cursor = 0;\n return cycles.map((cycle) => {\n while (\n cursor + 1 < inputs.length &&\n inputs[cursor + 1]!.time <= cycle.start\n ) {\n cursor++;\n }\n const candidate = inputs[cursor]!;\n const delta = cycle.start - candidate.time;\n if (delta < 0 || delta > windowMs) return cycle;\n return {\n ...cycle,\n cause: {\n layerId: candidate.layerId,\n type: candidate.title ?? candidate.layerId,\n detail: candidate.subtitle,\n time: candidate.time,\n },\n };\n });\n};\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["../../../packages/labs/vite-plugin-lit/src/lib/tokens.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AA2MH;;;;GAIG;AACH,eAAO,MAAM,QAAQ,stKAAqC,CAAC;AAE3D;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,MAAM,yBAIlB,CAAC;AAIF;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC;;;;;;OAMG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,cAAc,GAAI,mBAE5B,mBAAwB,KAAG,MAwB7B,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,YAAY,GAAI,UAAU,mBAAmB,KAAG,IAO5D,CAAC"}
1
+ {"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["../src/lib/tokens.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AA2MH;;;;GAIG;AACH,eAAO,MAAM,QAAQ,stKAAqC,CAAC;AAE3D;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,MAAM,yBAIlB,CAAC;AAIF;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC;;;;;;OAMG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,cAAc,sBAExB,mBAAmB,KAAQ,MAwB7B,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,YAAY,aAAc,mBAAmB,KAAG,IAO5D,CAAC"}
package/lib/tokens.js CHANGED
@@ -3,7 +3,7 @@
3
3
  * Copyright 2026 Google LLC
4
4
  * SPDX-License-Identifier: BSD-3-Clause
5
5
  */
6
- import { css, unsafeCSS } from 'lit';
6
+ import {css, unsafeCSS} from 'lit';
7
7
  /**
8
8
  * Design token CSS custom properties for the Lit DevTools.
9
9
  *
@@ -217,7 +217,7 @@ export const tokenCSS = `${baseTokenCSS}\n${darkThemeCSS}`;
217
217
  * by {@link injectTokens}. The panel iframe calls `injectTokens()` from
218
218
  * \`lit-devtools-panel.ts\` so all components inherit the same dark/light theme.
219
219
  */
220
- export const tokens = css `
220
+ export const tokens = css`
221
221
  :host {
222
222
  ${unsafeCSS(baseTokenCSS)}
223
223
  }
@@ -231,14 +231,14 @@ let _injected = false;
231
231
  * the owning document's UA surfaces (canvas, form controls, scrollbars)
232
232
  * follow the devtools theme.
233
233
  */
234
- export const tokenStyleText = ({ colorScheme = false, } = {}) => {
235
- const dark = colorScheme
236
- ? `${darkThemeCSS}\n ${darkSchemeCSS}`
237
- : darkThemeCSS;
238
- const light = colorScheme
239
- ? `${lightThemeCSS}\n ${lightSchemeCSS}`
240
- : lightThemeCSS;
241
- return `
234
+ export const tokenStyleText = ({colorScheme = false} = {}) => {
235
+ const dark = colorScheme
236
+ ? `${darkThemeCSS}\n ${darkSchemeCSS}`
237
+ : darkThemeCSS;
238
+ const light = colorScheme
239
+ ? `${lightThemeCSS}\n ${lightSchemeCSS}`
240
+ : lightThemeCSS;
241
+ return `
242
242
  :root {
243
243
  ${baseTokenCSS}
244
244
  ${dark}
@@ -269,12 +269,11 @@ export const tokenStyleText = ({ colorScheme = false, } = {}) => {
269
269
  * {@link InjectTokensOptions.colorScheme} for its own document.
270
270
  */
271
271
  export const injectTokens = (options) => {
272
- if (_injected)
273
- return;
274
- _injected = true;
275
- const style = document.createElement('style');
276
- style.setAttribute('data-lit-devtools-tokens', '');
277
- style.textContent = tokenStyleText(options);
278
- document.head.prepend(style);
272
+ if (_injected) return;
273
+ _injected = true;
274
+ const style = document.createElement('style');
275
+ style.setAttribute('data-lit-devtools-tokens', '');
276
+ style.textContent = tokenStyleText(options);
277
+ document.head.prepend(style);
279
278
  };
280
- //# sourceMappingURL=tokens.js.map
279
+ //# sourceMappingURL=tokens.js.map
package/lib/tokens.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"tokens.js","sourceRoot":"","sources":["../../../packages/labs/vite-plugin-lit/src/lib/tokens.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAC,GAAG,EAAE,SAAS,EAAC,MAAM,KAAK,CAAC;AAEnC;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,MAAM,YAAY,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqFpB,CAAC;AAEF,MAAM,YAAY,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAwCpB,CAAC;AAEF,MAAM,aAAa,GAAG,qBAAqB,CAAC;AAE5C,MAAM,aAAa,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAwCrB,CAAC;AAEF,MAAM,cAAc,GAAG,sBAAsB,CAAC;AAE9C;;;;GAIG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG,GAAG,YAAY,KAAK,YAAY,EAAE,CAAC;AAE3D;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG,GAAG,CAAA;;MAEnB,SAAS,CAAC,YAAY,CAAC;;CAE5B,CAAC;AAEF,IAAI,SAAS,GAAG,KAAK,CAAC;AAgBtB;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,EAC7B,WAAW,GAAG,KAAK,MACI,EAAE,EAAU,EAAE;IACrC,MAAM,IAAI,GAAG,WAAW;QACtB,CAAC,CAAC,GAAG,YAAY,OAAO,aAAa,EAAE;QACvC,CAAC,CAAC,YAAY,CAAC;IACjB,MAAM,KAAK,GAAG,WAAW;QACvB,CAAC,CAAC,GAAG,aAAa,OAAO,cAAc,EAAE;QACzC,CAAC,CAAC,aAAa,CAAC;IAClB,OAAO;;QAED,YAAY;QACZ,IAAI;;;;UAIF,KAAK;;;;QAIP,KAAK;;;QAGL,IAAI;;GAET,CAAC;AACJ,CAAC,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,OAA6B,EAAQ,EAAE;IAClE,IAAI,SAAS;QAAE,OAAO;IACtB,SAAS,GAAG,IAAI,CAAC;IACjB,MAAM,KAAK,GAAG,QAAQ,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;IAC9C,KAAK,CAAC,YAAY,CAAC,0BAA0B,EAAE,EAAE,CAAC,CAAC;IACnD,KAAK,CAAC,WAAW,GAAG,cAAc,CAAC,OAAO,CAAC,CAAC;IAC5C,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAC/B,CAAC,CAAC","sourcesContent":["/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: BSD-3-Clause\n */\n\nimport {css, unsafeCSS} from 'lit';\n\n/**\n * Design token CSS custom properties for the Lit DevTools.\n *\n * Two entry points:\n * - **`tokens`** — Lit `css` template that defines the theme-agnostic base\n * tokens on `:host`. Semantic color aliases (`--lit-devtools-bg`, `--lit-devtools-surface`, `--lit-devtools-text`,\n * etc.) are inherited from `:root`, where {@link injectTokens} installs them.\n * Use as `static styles = [tokens, css`…`]`.\n * - **`injectTokens()`** — injects `:root { … }` into the page `<head>` once.\n * This makes semantic aliases available to every devtools surface, both\n * runtime elements (indicator, source-overlay) that build their shadow DOM\n * via `innerHTML` and Lit panel components that inherit from `:root`.\n * The injected stylesheet reacts to `prefers-color-scheme` and to\n * `.color-scheme-light` / `.color-scheme-dark` classes on `:root`.\n *\n * Sourced from the lit-design skill (`tokens/colors.css`). Defaults to the\n * dark DevTools theme; the light lit.dev website palette is applied when the\n * OS/browser requests a light color scheme or when `:root` has the matching\n * theme class.\n *\n * Fonts are system stacks (no webfonts). For the branded Manrope + Roboto Mono\n * see the lit-design skill's `fonts/` directory.\n */\n\nconst baseTokenCSS = `\n /* ---- Brand · the Lit flame ---- */\n --lit-devtools-lit-blue: #324fff;\n --lit-devtools-lit-blue-bright: #4d63ff;\n --lit-devtools-lit-indigo: #2a2c9d;\n --lit-devtools-lit-dark-blue: #283198;\n --lit-devtools-lit-cyan: #00ffff;\n --lit-devtools-lit-dark-cyan: #00e8ff;\n\n /* ---- Neutral ink scale (0 = near-black, 13 = white) ---- */\n --lit-devtools-ink-0: hsl(0 0% 1%);\n --lit-devtools-ink-1: hsl(0 0% 5%);\n --lit-devtools-ink-2: hsl(0 0% 7%);\n --lit-devtools-ink-3: hsl(0 0% 11%);\n --lit-devtools-ink-4: hsl(0 0% 13%);\n --lit-devtools-ink-5: hsl(0 0% 16%);\n --lit-devtools-ink-6: hsl(0 0% 21%);\n --lit-devtools-ink-7: hsl(0 0% 28%);\n --lit-devtools-ink-8: hsl(0 0% 38%);\n --lit-devtools-ink-9: hsl(0 0% 57%);\n --lit-devtools-ink-10: hsl(0 0% 63%);\n --lit-devtools-ink-11: hsl(0 0% 78%);\n --lit-devtools-ink-12: hsl(0 0% 89%);\n --lit-devtools-ink-13: hsl(0 0% 100%);\n\n /* ---- Typography ---- */\n --lit-devtools-font-sans: system-ui, -apple-system, 'Segoe UI', sans-serif;\n --lit-devtools-font-mono: ui-monospace, 'SF Mono', Menlo, Consolas, monospace;\n\n --lit-devtools-weight-regular: 400;\n --lit-devtools-weight-medium: 500;\n --lit-devtools-weight-semibold: 600;\n --lit-devtools-weight-bold: 700;\n --lit-devtools-weight-extrabold: 800;\n\n --lit-devtools-text-2xs: 11px;\n --lit-devtools-text-xs: 12px;\n --lit-devtools-text-sm: 13px;\n --lit-devtools-text-md: 14px;\n --lit-devtools-text-base:16px;\n\n --lit-devtools-leading-tight: 1.15;\n --lit-devtools-leading-snug: 1.3;\n --lit-devtools-leading-normal: 1.5;\n\n --lit-devtools-tracking-tight: -0.02em;\n --lit-devtools-tracking-snug: -0.01em;\n --lit-devtools-tracking-normal: 0;\n --lit-devtools-tracking-wide: 0.02em;\n --lit-devtools-tracking-caps: 0.06em;\n\n /* ---- Spacing (4px base) ---- */\n --lit-devtools-space-0: 0;\n --lit-devtools-space-1: 2px;\n --lit-devtools-space-2: 4px;\n --lit-devtools-space-3: 6px;\n --lit-devtools-space-4: 8px;\n --lit-devtools-space-5: 12px;\n --lit-devtools-space-6: 16px;\n --lit-devtools-space-7: 20px;\n --lit-devtools-space-8: 24px;\n --lit-devtools-space-9: 32px;\n\n /* ---- Radius ---- */\n --lit-devtools-radius-xs: 3px;\n --lit-devtools-radius-sm: 5px;\n --lit-devtools-radius-md: 8px;\n --lit-devtools-radius-lg: 12px;\n --lit-devtools-radius-xl: 16px;\n --lit-devtools-radius-pill: 999px;\n\n /* ---- Elevation ---- */\n --lit-devtools-shadow-xs: 0 1px 2px hsl(0 0% 0% / 0.30);\n --lit-devtools-shadow-sm: 0 1px 5px hsl(0 0% 0% / 0.35);\n --lit-devtools-shadow-md: 0 4px 14px hsl(0 0% 0% / 0.40);\n --lit-devtools-shadow-lg: 0 12px 32px hsl(0 0% 0% / 0.50);\n --lit-devtools-shadow-xl: 0 24px 64px hsl(0 0% 0% / 0.55);\n --lit-devtools-shadow-window: 0 24px 80px hsl(0 0% 0% / 0.6),\n 0 0 0 1px hsl(0 0% 100% / 0.06);\n --lit-devtools-ring: 0 0 0 2px var(--lit-devtools-accent-ring);\n\n /* ---- Motion ---- */\n --lit-devtools-ease-standard: cubic-bezier(0.2, 0, 0, 1);\n --lit-devtools-dur-fast: 140ms;\n --lit-devtools-dur-normal: 220ms;\n`;\n\nconst darkThemeCSS = `\n /* ---- DARK · DevTools theme ---- */\n --lit-devtools-accent: var(--lit-devtools-lit-blue-bright);\n --lit-devtools-accent-hover: #6478ff;\n --lit-devtools-accent-pressed: #3d54f0;\n --lit-devtools-accent-soft: hsla(232 100% 65% / 0.16);\n --lit-devtools-accent-ring: hsla(232 100% 65% / 0.45);\n --lit-devtools-on-accent: #ffffff;\n --lit-devtools-accent-cyan: var(--lit-devtools-lit-dark-cyan);\n\n --lit-devtools-bg: var(--lit-devtools-ink-0);\n --lit-devtools-surface: var(--lit-devtools-ink-2);\n --lit-devtools-surface-low: var(--lit-devtools-ink-1);\n --lit-devtools-surface-container: var(--lit-devtools-ink-4);\n --lit-devtools-surface-container-high: var(--lit-devtools-ink-5);\n --lit-devtools-surface-elevated: var(--lit-devtools-ink-6);\n --lit-devtools-surface-hover: hsl(0 0% 100% / 0.04);\n --lit-devtools-surface-active: hsl(0 0% 100% / 0.07);\n\n --lit-devtools-text: var(--lit-devtools-ink-12);\n --lit-devtools-text-strong: var(--lit-devtools-ink-13);\n --lit-devtools-text-secondary: var(--lit-devtools-ink-10);\n --lit-devtools-text-muted: var(--lit-devtools-ink-8);\n --lit-devtools-text-link: var(--lit-devtools-lit-blue-bright);\n\n --lit-devtools-border: var(--lit-devtools-ink-6);\n --lit-devtools-border-strong: var(--lit-devtools-ink-7);\n --lit-devtools-border-subtle: hsl(0 0% 100% / 0.06);\n\n --lit-devtools-success: hsl(158 74% 53%);\n --lit-devtools-success-soft: hsl(158 74% 53% / 0.15);\n --lit-devtools-warning: #f4bf4f;\n --lit-devtools-warning-soft: hsl(43 88% 63% / 0.15);\n --lit-devtools-error: #ff6b6b;\n --lit-devtools-error-soft: hsl(0 100% 71% / 0.15);\n --lit-devtools-info: var(--lit-devtools-lit-dark-cyan);\n --lit-devtools-info-soft: hsl(187 100% 47% / 0.15);\n\n --lit-devtools-selection-bg: var(--lit-devtools-accent);\n --lit-devtools-on-selection: #ffffff;\n`;\n\nconst darkSchemeCSS = `color-scheme: dark;`;\n\nconst lightThemeCSS = `\n /* ---- LIGHT · lit.dev website theme ---- */\n --lit-devtools-accent: var(--lit-devtools-lit-blue);\n --lit-devtools-accent-hover: #1f3bff;\n --lit-devtools-accent-pressed: #2a2c9d;\n --lit-devtools-accent-soft: hsla(232 100% 60% / 0.12);\n --lit-devtools-accent-ring: hsla(232 100% 60% / 0.40);\n --lit-devtools-on-accent: #ffffff;\n --lit-devtools-accent-cyan: var(--lit-devtools-lit-dark-cyan);\n\n --lit-devtools-bg: #f4f4f4;\n --lit-devtools-surface: #ffffff;\n --lit-devtools-surface-low: #f3f3f3;\n --lit-devtools-surface-container: #ffffff;\n --lit-devtools-surface-container-high: #e8e8e8;\n --lit-devtools-surface-elevated: #ffffff;\n --lit-devtools-surface-hover: hsl(0 0% 0% / 0.04);\n --lit-devtools-surface-active: hsl(0 0% 0% / 0.07);\n\n --lit-devtools-text: #242424;\n --lit-devtools-text-strong: #000000;\n --lit-devtools-text-secondary: #6e6e6e;\n --lit-devtools-text-muted: #949494;\n --lit-devtools-text-link: #005dc7;\n\n --lit-devtools-border: #e2e2e2;\n --lit-devtools-border-strong: #c6c6c6;\n --lit-devtools-border-subtle: hsl(0 0% 0% / 0.07);\n\n --lit-devtools-success: #00865b;\n --lit-devtools-success-soft: hsl(158 100% 26% / 0.10);\n --lit-devtools-warning: #b26a00;\n --lit-devtools-warning-soft: hsl(40 100% 35% / 0.10);\n --lit-devtools-error: #ba1a1a;\n --lit-devtools-error-soft: hsl(0 75% 42% / 0.10);\n --lit-devtools-info: #005dc7;\n --lit-devtools-info-soft: hsl(210 100% 39% / 0.10);\n\n --lit-devtools-selection-bg: var(--lit-devtools-accent);\n --lit-devtools-on-selection: #ffffff;\n`;\n\nconst lightSchemeCSS = `color-scheme: light;`;\n\n/**\n * Default dark theme tokens as a flat string, primarily for use by\n * {@link injectTokens}. Prefer importing `tokens` for Lit components so the\n * semantic aliases are inherited from `:root`.\n */\nexport const tokenCSS = `${baseTokenCSS}\\n${darkThemeCSS}`;\n\n/**\n * Lit `css` template for use in panel component shadow roots.\n *\n * ```ts\n * import {tokens} from '../lib/tokens.js';\n * // ...\n * static override styles = [tokens, css`…`];\n * ```\n *\n * This installs the theme-agnostic base tokens on `:host`. Semantic aliases\n * (`--lit-devtools-bg`, `--lit-devtools-text`, etc.) are inherited from `:root`, where they are installed\n * by {@link injectTokens}. The panel iframe calls `injectTokens()` from\n * \\`lit-devtools-panel.ts\\` so all components inherit the same dark/light theme.\n */\nexport const tokens = css`\n :host {\n ${unsafeCSS(baseTokenCSS)}\n }\n`;\n\nlet _injected = false;\n\n/**\n * Options for {@link injectTokens} / {@link tokenStyleText}.\n */\nexport interface InjectTokensOptions {\n /**\n * Also declare `color-scheme` on `:root`. Only safe when the devtools OWN\n * the target document (the panel iframe / standalone panel page). Never set\n * this when injecting into the host page: `color-scheme` on the embedder's\n * `:root` makes the UA repaint the canvas dark for apps that don't declare\n * an opaque background. Defaults to `false`.\n */\n colorScheme?: boolean;\n}\n\n/**\n * Builds the token stylesheet text injected by {@link injectTokens}.\n *\n * By default the sheet defines custom properties only — inert for the host\n * page. With `colorScheme: true` it additionally declares `color-scheme` so\n * the owning document's UA surfaces (canvas, form controls, scrollbars)\n * follow the devtools theme.\n */\nexport const tokenStyleText = ({\n colorScheme = false,\n}: InjectTokensOptions = {}): string => {\n const dark = colorScheme\n ? `${darkThemeCSS}\\n ${darkSchemeCSS}`\n : darkThemeCSS;\n const light = colorScheme\n ? `${lightThemeCSS}\\n ${lightSchemeCSS}`\n : lightThemeCSS;\n return `\n :root {\n ${baseTokenCSS}\n ${dark}\n }\n @media (prefers-color-scheme: light) {\n :root {\n ${light}\n }\n }\n :root.color-scheme-light {\n ${light}\n }\n :root.color-scheme-dark {\n ${dark}\n }\n `;\n};\n\n/**\n * Injects `:root { … }` into the page `<head>` once.\n *\n * CSS custom properties defined on `:root` cascade through shadow DOM\n * boundaries, so this makes every `var(--lit-devtools-accent)` etc. resolve inside both\n * runtime elements (indicator, source-overlay) and Lit panel components.\n *\n * The injected stylesheet reacts to `prefers-color-scheme` and to\n * `.color-scheme-light` / `.color-scheme-dark` classes on the document root.\n * It never sets `color-scheme` on the host page; the panel opts in via\n * {@link InjectTokensOptions.colorScheme} for its own document.\n */\nexport const injectTokens = (options?: InjectTokensOptions): void => {\n if (_injected) return;\n _injected = true;\n const style = document.createElement('style');\n style.setAttribute('data-lit-devtools-tokens', '');\n style.textContent = tokenStyleText(options);\n document.head.prepend(style);\n};\n"]}
1
+ {"version":3,"file":"tokens.js","sourceRoot":"","sources":["../src/lib/tokens.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAC,GAAG,EAAE,SAAS,EAAC,MAAM,KAAK,CAAC;AAEnC;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,MAAM,YAAY,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqFpB,CAAC;AAEF,MAAM,YAAY,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAwCpB,CAAC;AAEF,MAAM,aAAa,GAAG,qBAAqB,CAAC;AAE5C,MAAM,aAAa,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAwCrB,CAAC;AAEF,MAAM,cAAc,GAAG,sBAAsB,CAAC;AAE9C;;;;GAIG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG,GAAG,YAAY,KAAK,YAAY,EAAE,CAAC;AAE3D;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG,GAAG,CAAA;;MAEnB,SAAS,CAAC,YAAY,CAAC;;CAE5B,CAAC;AAEF,IAAI,SAAS,GAAG,KAAK,CAAC;AAgBtB;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,EAC7B,WAAW,GAAG,KAAK,GACpB,GAAwB,EAAE,EAAU,EAAE;IACrC,MAAM,IAAI,GAAG,WAAW;QACtB,CAAC,CAAC,GAAG,YAAY,OAAO,aAAa,EAAE;QACvC,CAAC,CAAC,YAAY,CAAC;IACjB,MAAM,KAAK,GAAG,WAAW;QACvB,CAAC,CAAC,GAAG,aAAa,OAAO,cAAc,EAAE;QACzC,CAAC,CAAC,aAAa,CAAC;IAClB,OAAO;;QAED,YAAY;QACZ,IAAI;;;;UAIF,KAAK;;;;QAIP,KAAK;;;QAGL,IAAI;;GAET,CAAC;AACJ,CAAC,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,OAA6B,EAAQ,EAAE;IAClE,IAAI,SAAS;QAAE,OAAO;IACtB,SAAS,GAAG,IAAI,CAAC;IACjB,MAAM,KAAK,GAAG,QAAQ,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;IAC9C,KAAK,CAAC,YAAY,CAAC,0BAA0B,EAAE,EAAE,CAAC,CAAC;IACnD,KAAK,CAAC,WAAW,GAAG,cAAc,CAAC,OAAO,CAAC,CAAC;IAC5C,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAC/B,CAAC,CAAC","sourcesContent":["/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: BSD-3-Clause\n */\n\nimport {css, unsafeCSS} from 'lit';\n\n/**\n * Design token CSS custom properties for the Lit DevTools.\n *\n * Two entry points:\n * - **`tokens`** — Lit `css` template that defines the theme-agnostic base\n * tokens on `:host`. Semantic color aliases (`--lit-devtools-bg`, `--lit-devtools-surface`, `--lit-devtools-text`,\n * etc.) are inherited from `:root`, where {@link injectTokens} installs them.\n * Use as `static styles = [tokens, css`…`]`.\n * - **`injectTokens()`** — injects `:root { … }` into the page `<head>` once.\n * This makes semantic aliases available to every devtools surface, both\n * runtime elements (indicator, source-overlay) that build their shadow DOM\n * via `innerHTML` and Lit panel components that inherit from `:root`.\n * The injected stylesheet reacts to `prefers-color-scheme` and to\n * `.color-scheme-light` / `.color-scheme-dark` classes on `:root`.\n *\n * Sourced from the lit-design skill (`tokens/colors.css`). Defaults to the\n * dark DevTools theme; the light lit.dev website palette is applied when the\n * OS/browser requests a light color scheme or when `:root` has the matching\n * theme class.\n *\n * Fonts are system stacks (no webfonts). For the branded Manrope + Roboto Mono\n * see the lit-design skill's `fonts/` directory.\n */\n\nconst baseTokenCSS = `\n /* ---- Brand · the Lit flame ---- */\n --lit-devtools-lit-blue: #324fff;\n --lit-devtools-lit-blue-bright: #4d63ff;\n --lit-devtools-lit-indigo: #2a2c9d;\n --lit-devtools-lit-dark-blue: #283198;\n --lit-devtools-lit-cyan: #00ffff;\n --lit-devtools-lit-dark-cyan: #00e8ff;\n\n /* ---- Neutral ink scale (0 = near-black, 13 = white) ---- */\n --lit-devtools-ink-0: hsl(0 0% 1%);\n --lit-devtools-ink-1: hsl(0 0% 5%);\n --lit-devtools-ink-2: hsl(0 0% 7%);\n --lit-devtools-ink-3: hsl(0 0% 11%);\n --lit-devtools-ink-4: hsl(0 0% 13%);\n --lit-devtools-ink-5: hsl(0 0% 16%);\n --lit-devtools-ink-6: hsl(0 0% 21%);\n --lit-devtools-ink-7: hsl(0 0% 28%);\n --lit-devtools-ink-8: hsl(0 0% 38%);\n --lit-devtools-ink-9: hsl(0 0% 57%);\n --lit-devtools-ink-10: hsl(0 0% 63%);\n --lit-devtools-ink-11: hsl(0 0% 78%);\n --lit-devtools-ink-12: hsl(0 0% 89%);\n --lit-devtools-ink-13: hsl(0 0% 100%);\n\n /* ---- Typography ---- */\n --lit-devtools-font-sans: system-ui, -apple-system, 'Segoe UI', sans-serif;\n --lit-devtools-font-mono: ui-monospace, 'SF Mono', Menlo, Consolas, monospace;\n\n --lit-devtools-weight-regular: 400;\n --lit-devtools-weight-medium: 500;\n --lit-devtools-weight-semibold: 600;\n --lit-devtools-weight-bold: 700;\n --lit-devtools-weight-extrabold: 800;\n\n --lit-devtools-text-2xs: 11px;\n --lit-devtools-text-xs: 12px;\n --lit-devtools-text-sm: 13px;\n --lit-devtools-text-md: 14px;\n --lit-devtools-text-base:16px;\n\n --lit-devtools-leading-tight: 1.15;\n --lit-devtools-leading-snug: 1.3;\n --lit-devtools-leading-normal: 1.5;\n\n --lit-devtools-tracking-tight: -0.02em;\n --lit-devtools-tracking-snug: -0.01em;\n --lit-devtools-tracking-normal: 0;\n --lit-devtools-tracking-wide: 0.02em;\n --lit-devtools-tracking-caps: 0.06em;\n\n /* ---- Spacing (4px base) ---- */\n --lit-devtools-space-0: 0;\n --lit-devtools-space-1: 2px;\n --lit-devtools-space-2: 4px;\n --lit-devtools-space-3: 6px;\n --lit-devtools-space-4: 8px;\n --lit-devtools-space-5: 12px;\n --lit-devtools-space-6: 16px;\n --lit-devtools-space-7: 20px;\n --lit-devtools-space-8: 24px;\n --lit-devtools-space-9: 32px;\n\n /* ---- Radius ---- */\n --lit-devtools-radius-xs: 3px;\n --lit-devtools-radius-sm: 5px;\n --lit-devtools-radius-md: 8px;\n --lit-devtools-radius-lg: 12px;\n --lit-devtools-radius-xl: 16px;\n --lit-devtools-radius-pill: 999px;\n\n /* ---- Elevation ---- */\n --lit-devtools-shadow-xs: 0 1px 2px hsl(0 0% 0% / 0.30);\n --lit-devtools-shadow-sm: 0 1px 5px hsl(0 0% 0% / 0.35);\n --lit-devtools-shadow-md: 0 4px 14px hsl(0 0% 0% / 0.40);\n --lit-devtools-shadow-lg: 0 12px 32px hsl(0 0% 0% / 0.50);\n --lit-devtools-shadow-xl: 0 24px 64px hsl(0 0% 0% / 0.55);\n --lit-devtools-shadow-window: 0 24px 80px hsl(0 0% 0% / 0.6),\n 0 0 0 1px hsl(0 0% 100% / 0.06);\n --lit-devtools-ring: 0 0 0 2px var(--lit-devtools-accent-ring);\n\n /* ---- Motion ---- */\n --lit-devtools-ease-standard: cubic-bezier(0.2, 0, 0, 1);\n --lit-devtools-dur-fast: 140ms;\n --lit-devtools-dur-normal: 220ms;\n`;\n\nconst darkThemeCSS = `\n /* ---- DARK · DevTools theme ---- */\n --lit-devtools-accent: var(--lit-devtools-lit-blue-bright);\n --lit-devtools-accent-hover: #6478ff;\n --lit-devtools-accent-pressed: #3d54f0;\n --lit-devtools-accent-soft: hsla(232 100% 65% / 0.16);\n --lit-devtools-accent-ring: hsla(232 100% 65% / 0.45);\n --lit-devtools-on-accent: #ffffff;\n --lit-devtools-accent-cyan: var(--lit-devtools-lit-dark-cyan);\n\n --lit-devtools-bg: var(--lit-devtools-ink-0);\n --lit-devtools-surface: var(--lit-devtools-ink-2);\n --lit-devtools-surface-low: var(--lit-devtools-ink-1);\n --lit-devtools-surface-container: var(--lit-devtools-ink-4);\n --lit-devtools-surface-container-high: var(--lit-devtools-ink-5);\n --lit-devtools-surface-elevated: var(--lit-devtools-ink-6);\n --lit-devtools-surface-hover: hsl(0 0% 100% / 0.04);\n --lit-devtools-surface-active: hsl(0 0% 100% / 0.07);\n\n --lit-devtools-text: var(--lit-devtools-ink-12);\n --lit-devtools-text-strong: var(--lit-devtools-ink-13);\n --lit-devtools-text-secondary: var(--lit-devtools-ink-10);\n --lit-devtools-text-muted: var(--lit-devtools-ink-8);\n --lit-devtools-text-link: var(--lit-devtools-lit-blue-bright);\n\n --lit-devtools-border: var(--lit-devtools-ink-6);\n --lit-devtools-border-strong: var(--lit-devtools-ink-7);\n --lit-devtools-border-subtle: hsl(0 0% 100% / 0.06);\n\n --lit-devtools-success: hsl(158 74% 53%);\n --lit-devtools-success-soft: hsl(158 74% 53% / 0.15);\n --lit-devtools-warning: #f4bf4f;\n --lit-devtools-warning-soft: hsl(43 88% 63% / 0.15);\n --lit-devtools-error: #ff6b6b;\n --lit-devtools-error-soft: hsl(0 100% 71% / 0.15);\n --lit-devtools-info: var(--lit-devtools-lit-dark-cyan);\n --lit-devtools-info-soft: hsl(187 100% 47% / 0.15);\n\n --lit-devtools-selection-bg: var(--lit-devtools-accent);\n --lit-devtools-on-selection: #ffffff;\n`;\n\nconst darkSchemeCSS = `color-scheme: dark;`;\n\nconst lightThemeCSS = `\n /* ---- LIGHT · lit.dev website theme ---- */\n --lit-devtools-accent: var(--lit-devtools-lit-blue);\n --lit-devtools-accent-hover: #1f3bff;\n --lit-devtools-accent-pressed: #2a2c9d;\n --lit-devtools-accent-soft: hsla(232 100% 60% / 0.12);\n --lit-devtools-accent-ring: hsla(232 100% 60% / 0.40);\n --lit-devtools-on-accent: #ffffff;\n --lit-devtools-accent-cyan: var(--lit-devtools-lit-dark-cyan);\n\n --lit-devtools-bg: #f4f4f4;\n --lit-devtools-surface: #ffffff;\n --lit-devtools-surface-low: #f3f3f3;\n --lit-devtools-surface-container: #ffffff;\n --lit-devtools-surface-container-high: #e8e8e8;\n --lit-devtools-surface-elevated: #ffffff;\n --lit-devtools-surface-hover: hsl(0 0% 0% / 0.04);\n --lit-devtools-surface-active: hsl(0 0% 0% / 0.07);\n\n --lit-devtools-text: #242424;\n --lit-devtools-text-strong: #000000;\n --lit-devtools-text-secondary: #6e6e6e;\n --lit-devtools-text-muted: #949494;\n --lit-devtools-text-link: #005dc7;\n\n --lit-devtools-border: #e2e2e2;\n --lit-devtools-border-strong: #c6c6c6;\n --lit-devtools-border-subtle: hsl(0 0% 0% / 0.07);\n\n --lit-devtools-success: #00865b;\n --lit-devtools-success-soft: hsl(158 100% 26% / 0.10);\n --lit-devtools-warning: #b26a00;\n --lit-devtools-warning-soft: hsl(40 100% 35% / 0.10);\n --lit-devtools-error: #ba1a1a;\n --lit-devtools-error-soft: hsl(0 75% 42% / 0.10);\n --lit-devtools-info: #005dc7;\n --lit-devtools-info-soft: hsl(210 100% 39% / 0.10);\n\n --lit-devtools-selection-bg: var(--lit-devtools-accent);\n --lit-devtools-on-selection: #ffffff;\n`;\n\nconst lightSchemeCSS = `color-scheme: light;`;\n\n/**\n * Default dark theme tokens as a flat string, primarily for use by\n * {@link injectTokens}. Prefer importing `tokens` for Lit components so the\n * semantic aliases are inherited from `:root`.\n */\nexport const tokenCSS = `${baseTokenCSS}\\n${darkThemeCSS}`;\n\n/**\n * Lit `css` template for use in panel component shadow roots.\n *\n * ```ts\n * import {tokens} from '../lib/tokens.js';\n * // ...\n * static override styles = [tokens, css`…`];\n * ```\n *\n * This installs the theme-agnostic base tokens on `:host`. Semantic aliases\n * (`--lit-devtools-bg`, `--lit-devtools-text`, etc.) are inherited from `:root`, where they are installed\n * by {@link injectTokens}. The panel iframe calls `injectTokens()` from\n * \\`lit-devtools-panel.ts\\` so all components inherit the same dark/light theme.\n */\nexport const tokens = css`\n :host {\n ${unsafeCSS(baseTokenCSS)}\n }\n`;\n\nlet _injected = false;\n\n/**\n * Options for {@link injectTokens} / {@link tokenStyleText}.\n */\nexport interface InjectTokensOptions {\n /**\n * Also declare `color-scheme` on `:root`. Only safe when the devtools OWN\n * the target document (the panel iframe / standalone panel page). Never set\n * this when injecting into the host page: `color-scheme` on the embedder's\n * `:root` makes the UA repaint the canvas dark for apps that don't declare\n * an opaque background. Defaults to `false`.\n */\n colorScheme?: boolean;\n}\n\n/**\n * Builds the token stylesheet text injected by {@link injectTokens}.\n *\n * By default the sheet defines custom properties only — inert for the host\n * page. With `colorScheme: true` it additionally declares `color-scheme` so\n * the owning document's UA surfaces (canvas, form controls, scrollbars)\n * follow the devtools theme.\n */\nexport const tokenStyleText = ({\n colorScheme = false,\n}: InjectTokensOptions = {}): string => {\n const dark = colorScheme\n ? `${darkThemeCSS}\\n ${darkSchemeCSS}`\n : darkThemeCSS;\n const light = colorScheme\n ? `${lightThemeCSS}\\n ${lightSchemeCSS}`\n : lightThemeCSS;\n return `\n :root {\n ${baseTokenCSS}\n ${dark}\n }\n @media (prefers-color-scheme: light) {\n :root {\n ${light}\n }\n }\n :root.color-scheme-light {\n ${light}\n }\n :root.color-scheme-dark {\n ${dark}\n }\n `;\n};\n\n/**\n * Injects `:root { … }` into the page `<head>` once.\n *\n * CSS custom properties defined on `:root` cascade through shadow DOM\n * boundaries, so this makes every `var(--lit-devtools-accent)` etc. resolve inside both\n * runtime elements (indicator, source-overlay) and Lit panel components.\n *\n * The injected stylesheet reacts to `prefers-color-scheme` and to\n * `.color-scheme-light` / `.color-scheme-dark` classes on the document root.\n * It never sets `color-scheme` on the host page; the panel opts in via\n * {@link InjectTokensOptions.colorScheme} for its own document.\n */\nexport const injectTokens = (options?: InjectTokensOptions): void => {\n if (_injected) return;\n _injected = true;\n const style = document.createElement('style');\n style.setAttribute('data-lit-devtools-tokens', '');\n style.textContent = tokenStyleText(options);\n document.head.prepend(style);\n};\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"transform.d.ts","sourceRoot":"","sources":["../../../packages/labs/vite-plugin-lit/src/lib/transform.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,WAAW,MAAM,cAAc,CAAC;AAGvC;;;;;GAKG;AACH,eAAO,MAAM,cAAc,kBAAkB,CAAC;AAE9C,2DAA2D;AAC3D,eAAO,MAAM,UAAU,yBAA6B,CAAC;AASrD;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,GAC5B,MAAM,MAAM,EACZ,oBAAoB,OAAO,KAC1B,OAIwD,CAAC;AAE5D,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,UAAU,CAAC,WAAW,CAAC,aAAa,CAAC,CAAC,CAAC;CAC7C;AAED;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,kBAAkB,GAC7B,MAAM,MAAM,KACX,OAAO,CAAC,wBAAwB,GAAG,IAAI,CAqDzC,CAAC"}
1
+ {"version":3,"file":"transform.d.ts","sourceRoot":"","sources":["../src/lib/transform.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,WAAW,MAAM,cAAc,CAAC;AAGvC;;;;;GAKG;AACH,eAAO,MAAM,cAAc,kBAAkB,CAAC;AAE9C,2DAA2D;AAC3D,eAAO,MAAM,UAAU,yBAA6B,CAAC;AASrD;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,SACtB,MAAM,sBACQ,OAAO,KAC1B,OAIwD,CAAC;AAE5D,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,UAAU,CAAC,WAAW,CAAC,aAAa,CAAC,CAAC,CAAC;CAC7C;AAED;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,kBAAkB,SACvB,MAAM,KACX,OAAO,CAAC,wBAAwB,GAAG,IAAI,CAwDzC,CAAC"}
package/lib/transform.js CHANGED
@@ -3,9 +3,9 @@
3
3
  * Copyright 2026 Google LLC
4
4
  * SPDX-License-Identifier: BSD-3-Clause
5
5
  */
6
- import { init, parse } from 'es-module-lexer';
6
+ import {init, parse} from 'es-module-lexer';
7
7
  import MagicString from 'magic-string';
8
- import { WRAP_TABLE } from './wrap-table.js';
8
+ import {WRAP_TABLE} from './wrap-table.js';
9
9
  /**
10
10
  * Prefix for this plugin's virtual module ids. Rewritten specifiers carry
11
11
  * the `\0` convention directly in the transformed source; Vite's
@@ -17,16 +17,20 @@ export const VIRTUAL_PREFIX = '\0lit-plugin:';
17
17
  export const INSTALL_ID = `${VIRTUAL_PREFIX}install`;
18
18
  const LIT_FAMILY_PACKAGES = ['lit', 'lit-html', 'lit-element'];
19
19
  const LIT_FAMILY_SCOPES = ['@lit/', '@lit-labs/'];
20
- const isLitFamilySpecifier = (spec) => LIT_FAMILY_PACKAGES.some((p) => spec === p || spec.startsWith(`${p}/`)) ||
21
- LIT_FAMILY_SCOPES.some((s) => spec.startsWith(s));
20
+ const isLitFamilySpecifier = (spec) =>
21
+ LIT_FAMILY_PACKAGES.some((p) => spec === p || spec.startsWith(`${p}/`)) ||
22
+ LIT_FAMILY_SCOPES.some((s) => spec.startsWith(s));
22
23
  /**
23
24
  * A module needs the define interceptor + self-accept if it registers
24
25
  * custom elements: a textual `customElements.define(` call, or — only when
25
26
  * a lit-family import is present — a `customElement(` decorator call (the
26
27
  * decorator runtime call stays textually present after TS transpilation).
27
28
  */
28
- export const isComponentModule = (code, hasLitFamilyImport) => /(?<![.\w$])(?:(?:window|globalThis|self)\.)?customElements\.define\s*\(/.test(code) ||
29
- (hasLitFamilyImport && /\bcustomElement\s*\(/.test(code));
29
+ export const isComponentModule = (code, hasLitFamilyImport) =>
30
+ /(?<![.\w$])(?:(?:window|globalThis|self)\.)?customElements\.define\s*\(/.test(
31
+ code
32
+ ) ||
33
+ (hasLitFamilyImport && /\bcustomElement\s*\(/.test(code));
30
34
  /**
31
35
  * The whole dev transform, as a pure function of the module source:
32
36
  *
@@ -41,59 +45,60 @@ export const isComponentModule = (code, hasLitFamilyImport) => /(?<![.\w$])(?:(?
41
45
  * Returns `null` when the module needs no changes.
42
46
  */
43
47
  export const transformLitModule = async (code) => {
44
- // Cheap pre-filter before parsing.
45
- if (!code.includes('lit') && !code.includes('customElements')) {
46
- return null;
48
+ // Cheap pre-filter before parsing.
49
+ if (!code.includes('lit') && !code.includes('customElements')) {
50
+ return null;
51
+ }
52
+ // Idempotency: never re-instrument our own output.
53
+ if (code.includes(VIRTUAL_PREFIX)) {
54
+ return null;
55
+ }
56
+ await init();
57
+ let imports;
58
+ try {
59
+ [imports] = parse(code);
60
+ } catch {
61
+ // Not parseable as a module; leave it to Vite to error.
62
+ return null;
63
+ }
64
+ const ms = new MagicString(code);
65
+ let changed = false;
66
+ let hasLitFamilyImport = false;
67
+ for (const imp of imports) {
68
+ // `import.meta` reports a null specifier; a dynamic import reports
69
+ // undefined when its argument is not statically analyzable, and a glob
70
+ // (template literal) specifier is a pattern rather than a real id.
71
+ const spec = imp.specifier;
72
+ if (spec == null || (imp.type === 'dynamic' && imp.glob)) {
73
+ continue;
47
74
  }
48
- // Idempotency: never re-instrument our own output.
49
- if (code.includes(VIRTUAL_PREFIX)) {
50
- return null;
75
+ if (isLitFamilySpecifier(spec)) {
76
+ hasLitFamilyImport = true;
51
77
  }
52
- await init;
53
- let imports;
54
- try {
55
- [imports] = parse(code);
78
+ if (!WRAP_TABLE.has(spec)) {
79
+ continue;
56
80
  }
57
- catch {
58
- // Not parseable as a module; leave it to Vite to error.
59
- return null;
81
+ if (imp.type === 'dynamic') {
82
+ // Dynamic import: [start, end) includes the quotes (or backticks) —
83
+ // narrow them to plain quotes around the rewritten specifier.
84
+ ms.overwrite(imp.start, imp.end, `'${VIRTUAL_PREFIX}${spec}'`);
85
+ } else {
86
+ // Static import / export-from: [start, end) is the bare specifier text.
87
+ ms.overwrite(imp.start, imp.end, `${VIRTUAL_PREFIX}${spec}`);
60
88
  }
61
- const ms = new MagicString(code);
62
- let changed = false;
63
- let hasLitFamilyImport = false;
64
- for (const imp of imports) {
65
- const spec = imp.n;
66
- if (spec === undefined) {
67
- continue;
68
- }
69
- if (isLitFamilySpecifier(spec)) {
70
- hasLitFamilyImport = true;
71
- }
72
- if (!WRAP_TABLE.has(spec)) {
73
- continue;
74
- }
75
- if (imp.d > -1) {
76
- // Dynamic import: [s, e) includes the quotes (or backticks) — narrow
77
- // them to plain quotes around the rewritten specifier.
78
- ms.overwrite(imp.s, imp.e, `'${VIRTUAL_PREFIX}${spec}'`);
79
- }
80
- else {
81
- // Static import / export-from: [s, e) is the bare specifier text.
82
- ms.overwrite(imp.s, imp.e, `${VIRTUAL_PREFIX}${spec}`);
83
- }
84
- changed = true;
85
- }
86
- if (isComponentModule(code, hasLitFamilyImport)) {
87
- ms.prepend(`import '${INSTALL_ID}';\n`);
88
- ms.append(`\nimport.meta.hot?.accept();\n`);
89
- changed = true;
90
- }
91
- if (!changed) {
92
- return null;
93
- }
94
- return {
95
- code: ms.toString(),
96
- map: ms.generateMap({ hires: 'boundary' }),
97
- };
89
+ changed = true;
90
+ }
91
+ if (isComponentModule(code, hasLitFamilyImport)) {
92
+ ms.prepend(`import '${INSTALL_ID}';\n`);
93
+ ms.append(`\nimport.meta.hot?.accept();\n`);
94
+ changed = true;
95
+ }
96
+ if (!changed) {
97
+ return null;
98
+ }
99
+ return {
100
+ code: ms.toString(),
101
+ map: ms.generateMap({hires: 'boundary'}),
102
+ };
98
103
  };
99
- //# sourceMappingURL=transform.js.map
104
+ //# sourceMappingURL=transform.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"transform.js","sourceRoot":"","sources":["../../../packages/labs/vite-plugin-lit/src/lib/transform.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: BSD-3-Clause\n */\n\nimport {init, parse} from 'es-module-lexer';\nimport MagicString from 'magic-string';\nimport {WRAP_TABLE} from './wrap-table.js';\n\n/**\n * Prefix for this plugin's virtual module ids. Rewritten specifiers carry\n * the `\\0` convention directly in the transformed source; Vite's\n * import-analysis resolves them through our `resolveId` and encodes the\n * `\\0` for the browser, so it never reaches the network.\n */\nexport const VIRTUAL_PREFIX = '\\0lit-plugin:';\n\n/** Virtual module that installs the define interceptor. */\nexport const INSTALL_ID = `${VIRTUAL_PREFIX}install`;\n\nconst LIT_FAMILY_PACKAGES = ['lit', 'lit-html', 'lit-element'];\nconst LIT_FAMILY_SCOPES = ['@lit/', '@lit-labs/'];\n\nconst isLitFamilySpecifier = (spec: string): boolean =>\n LIT_FAMILY_PACKAGES.some((p) => spec === p || spec.startsWith(`${p}/`)) ||\n LIT_FAMILY_SCOPES.some((s) => spec.startsWith(s));\n\n/**\n * A module needs the define interceptor + self-accept if it registers\n * custom elements: a textual `customElements.define(` call, or — only when\n * a lit-family import is present — a `customElement(` decorator call (the\n * decorator runtime call stays textually present after TS transpilation).\n */\nexport const isComponentModule = (\n code: string,\n hasLitFamilyImport: boolean\n): boolean =>\n /(?<![.\\w$])(?:(?:window|globalThis|self)\\.)?customElements\\.define\\s*\\(/.test(\n code\n ) ||\n (hasLitFamilyImport && /\\bcustomElement\\s*\\(/.test(code));\n\nexport interface LitPluginTransformResult {\n code: string;\n map: ReturnType<MagicString['generateMap']>;\n}\n\n/**\n * The whole dev transform, as a pure function of the module source:\n *\n * - Pass 1 (all user modules — shared template-partial modules must intern\n * too): rewrite import/export-from/dynamic-import specifiers found in the\n * wrap table to their `\\0lit-plugin:` wrapper module.\n * - Pass 2 (component modules): prepend the interceptor install import\n * (static imports hoist, so the interceptor is installed before this\n * module's defines) and append a self-accept (re-execution alone triggers\n * the define interceptor — no hotUpdate hook needed).\n *\n * Returns `null` when the module needs no changes.\n */\nexport const transformLitModule = async (\n code: string\n): Promise<LitPluginTransformResult | null> => {\n // Cheap pre-filter before parsing.\n if (!code.includes('lit') && !code.includes('customElements')) {\n return null;\n }\n // Idempotency: never re-instrument our own output.\n if (code.includes(VIRTUAL_PREFIX)) {\n return null;\n }\n await init;\n let imports;\n try {\n [imports] = parse(code);\n } catch {\n // Not parseable as a module; leave it to Vite to error.\n return null;\n }\n const ms = new MagicString(code);\n let changed = false;\n let hasLitFamilyImport = false;\n for (const imp of imports) {\n const spec = imp.n;\n if (spec === undefined) {\n continue;\n }\n if (isLitFamilySpecifier(spec)) {\n hasLitFamilyImport = true;\n }\n if (!WRAP_TABLE.has(spec)) {\n continue;\n }\n if (imp.d > -1) {\n // Dynamic import: [s, e) includes the quotes (or backticks) — narrow\n // them to plain quotes around the rewritten specifier.\n ms.overwrite(imp.s, imp.e, `'${VIRTUAL_PREFIX}${spec}'`);\n } else {\n // Static import / export-from: [s, e) is the bare specifier text.\n ms.overwrite(imp.s, imp.e, `${VIRTUAL_PREFIX}${spec}`);\n }\n changed = true;\n }\n if (isComponentModule(code, hasLitFamilyImport)) {\n ms.prepend(`import '${INSTALL_ID}';\\n`);\n ms.append(`\\nimport.meta.hot?.accept();\\n`);\n changed = true;\n }\n if (!changed) {\n return null;\n }\n return {\n code: ms.toString(),\n map: ms.generateMap({hires: 'boundary'}),\n };\n};\n"]}
1
+ {"version":3,"file":"transform.js","sourceRoot":"","sources":["../src/lib/transform.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: BSD-3-Clause\n */\n\nimport {init, parse} from 'es-module-lexer';\nimport MagicString from 'magic-string';\nimport {WRAP_TABLE} from './wrap-table.js';\n\n/**\n * Prefix for this plugin's virtual module ids. Rewritten specifiers carry\n * the `\\0` convention directly in the transformed source; Vite's\n * import-analysis resolves them through our `resolveId` and encodes the\n * `\\0` for the browser, so it never reaches the network.\n */\nexport const VIRTUAL_PREFIX = '\\0lit-plugin:';\n\n/** Virtual module that installs the define interceptor. */\nexport const INSTALL_ID = `${VIRTUAL_PREFIX}install`;\n\nconst LIT_FAMILY_PACKAGES = ['lit', 'lit-html', 'lit-element'];\nconst LIT_FAMILY_SCOPES = ['@lit/', '@lit-labs/'];\n\nconst isLitFamilySpecifier = (spec: string): boolean =>\n LIT_FAMILY_PACKAGES.some((p) => spec === p || spec.startsWith(`${p}/`)) ||\n LIT_FAMILY_SCOPES.some((s) => spec.startsWith(s));\n\n/**\n * A module needs the define interceptor + self-accept if it registers\n * custom elements: a textual `customElements.define(` call, or — only when\n * a lit-family import is present — a `customElement(` decorator call (the\n * decorator runtime call stays textually present after TS transpilation).\n */\nexport const isComponentModule = (\n code: string,\n hasLitFamilyImport: boolean\n): boolean =>\n /(?<![.\\w$])(?:(?:window|globalThis|self)\\.)?customElements\\.define\\s*\\(/.test(\n code\n ) ||\n (hasLitFamilyImport && /\\bcustomElement\\s*\\(/.test(code));\n\nexport interface LitPluginTransformResult {\n code: string;\n map: ReturnType<MagicString['generateMap']>;\n}\n\n/**\n * The whole dev transform, as a pure function of the module source:\n *\n * - Pass 1 (all user modules — shared template-partial modules must intern\n * too): rewrite import/export-from/dynamic-import specifiers found in the\n * wrap table to their `\\0lit-plugin:` wrapper module.\n * - Pass 2 (component modules): prepend the interceptor install import\n * (static imports hoist, so the interceptor is installed before this\n * module's defines) and append a self-accept (re-execution alone triggers\n * the define interceptor — no hotUpdate hook needed).\n *\n * Returns `null` when the module needs no changes.\n */\nexport const transformLitModule = async (\n code: string\n): Promise<LitPluginTransformResult | null> => {\n // Cheap pre-filter before parsing.\n if (!code.includes('lit') && !code.includes('customElements')) {\n return null;\n }\n // Idempotency: never re-instrument our own output.\n if (code.includes(VIRTUAL_PREFIX)) {\n return null;\n }\n await init();\n let imports;\n try {\n [imports] = parse(code);\n } catch {\n // Not parseable as a module; leave it to Vite to error.\n return null;\n }\n const ms = new MagicString(code);\n let changed = false;\n let hasLitFamilyImport = false;\n for (const imp of imports) {\n // `import.meta` reports a null specifier; a dynamic import reports\n // undefined when its argument is not statically analyzable, and a glob\n // (template literal) specifier is a pattern rather than a real id.\n const spec = imp.specifier;\n if (spec == null || (imp.type === 'dynamic' && imp.glob)) {\n continue;\n }\n if (isLitFamilySpecifier(spec)) {\n hasLitFamilyImport = true;\n }\n if (!WRAP_TABLE.has(spec)) {\n continue;\n }\n if (imp.type === 'dynamic') {\n // Dynamic import: [start, end) includes the quotes (or backticks) —\n // narrow them to plain quotes around the rewritten specifier.\n ms.overwrite(imp.start, imp.end, `'${VIRTUAL_PREFIX}${spec}'`);\n } else {\n // Static import / export-from: [start, end) is the bare specifier text.\n ms.overwrite(imp.start, imp.end, `${VIRTUAL_PREFIX}${spec}`);\n }\n changed = true;\n }\n if (isComponentModule(code, hasLitFamilyImport)) {\n ms.prepend(`import '${INSTALL_ID}';\\n`);\n ms.append(`\\nimport.meta.hot?.accept();\\n`);\n changed = true;\n }\n if (!changed) {\n return null;\n }\n return {\n code: ms.toString(),\n map: ms.generateMap({hires: 'boundary'}),\n };\n};\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../packages/labs/vite-plugin-lit/src/lib/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE;QACN,QAAQ,EAAE,MAAM,CAAC;QACjB,UAAU,EAAE,MAAM,CAAC;KACpB,CAAC;CACH;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;CAC7C;AAED,MAAM,WAAW,oBAAoB;IACnC;;OAEG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;IAEb,2EAA2E;IAC3E,MAAM,CAAC,EAAE,YAAY,GAAG,MAAM,CAAC;IAE/B,8DAA8D;IAC9D,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB,8CAA8C;IAC9C,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB,iDAAiD;IACjD,OAAO,CAAC,EAAE,CAAC,EAAE,EAAE,OAAO,KAAK,OAAO,CAAC;IAEnC,uDAAuD;IACvD,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,WAAW,KAAK,IAAI,CAAC;CACxC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/lib/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE;QACN,QAAQ,EAAE,MAAM,CAAC;QACjB,UAAU,EAAE,MAAM,CAAC;KACpB,CAAC;CACH;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;CAC7C;AAED,MAAM,WAAW,oBAAoB;IACnC;;OAEG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;IAEb,2EAA2E;IAC3E,MAAM,CAAC,EAAE,YAAY,GAAG,MAAM,CAAC;IAE/B,8DAA8D;IAC9D,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB,8CAA8C;IAC9C,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB,iDAAiD;IACjD,OAAO,CAAC,EAAE,CAAC,EAAE,EAAE,OAAO,KAAK,OAAO,CAAC;IAEnC,uDAAuD;IACvD,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,WAAW,KAAK,IAAI,CAAC;CACxC"}
package/lib/types.js CHANGED
@@ -4,4 +4,4 @@
4
4
  * SPDX-License-Identifier: BSD-3-Clause
5
5
  */
6
6
  export {};
7
- //# sourceMappingURL=types.js.map
7
+ //# sourceMappingURL=types.js.map
package/lib/types.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../packages/labs/vite-plugin-lit/src/lib/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG","sourcesContent":["/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: BSD-3-Clause\n */\n\nexport interface ElementInfo {\n tagName: string;\n componentName?: string;\n source: {\n filePath: string;\n lineNumber: number;\n };\n}\n\nexport interface EditorConfig {\n name: string;\n url: (path: string, line: number) => string;\n}\n\nexport interface SourceOverlayOptions {\n /**\n * Hotkey letter with Ctrl+Shift (default `s` -> Ctrl+Shift+S).\n */\n key?: string;\n\n /** Built-in editor key or custom `{ name, url }`. Defaults to `vscode`. */\n editor?: EditorConfig | string;\n\n /** Optional workspace root prefix for absolute file paths. */\n workspaceRoot?: string;\n\n /** Mouse move throttle in ms (default 50). */\n throttleMs?: number;\n\n /** Filter elements to skip during inspection. */\n exclude?: (el: Element) => boolean;\n\n /** Callback fired when the user clicks a component. */\n onSelect?: (info: ElementInfo) => void;\n}\n"]}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/lib/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG","sourcesContent":["/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: BSD-3-Clause\n */\n\nexport interface ElementInfo {\n tagName: string;\n componentName?: string;\n source: {\n filePath: string;\n lineNumber: number;\n };\n}\n\nexport interface EditorConfig {\n name: string;\n url: (path: string, line: number) => string;\n}\n\nexport interface SourceOverlayOptions {\n /**\n * Hotkey letter with Ctrl+Shift (default `s` -> Ctrl+Shift+S).\n */\n key?: string;\n\n /** Built-in editor key or custom `{ name, url }`. Defaults to `vscode`. */\n editor?: EditorConfig | string;\n\n /** Optional workspace root prefix for absolute file paths. */\n workspaceRoot?: string;\n\n /** Mouse move throttle in ms (default 50). */\n throttleMs?: number;\n\n /** Filter elements to skip during inspection. */\n exclude?: (el: Element) => boolean;\n\n /** Callback fired when the user clicks a component. */\n onSelect?: (info: ElementInfo) => void;\n}\n"]}