@oddsquad/vite-plugin-lit 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +70 -0
- package/README.md +16 -5
- package/bin.mjs +16 -12
- package/dist/client/assets/{browser-agent-rpc-BXhoSh1z-CdtPhBL-.js → browser-agent-rpc-BXhoSh1z-CRHFLjFo.js} +2 -2
- package/dist/client/assets/{browser-agent-rpc-BXhoSh1z-CdtPhBL-.js.map → browser-agent-rpc-BXhoSh1z-CRHFLjFo.js.map} +1 -1
- package/dist/client/assets/{index-DVe6M4HV.js → index-Gn4Hk_9s.js} +1840 -758
- package/dist/client/assets/index-Gn4Hk_9s.js.map +1 -0
- package/dist/client/index.html +11 -1
- package/lib/devframe/definition.d.ts +7 -0
- package/lib/devframe/definition.d.ts.map +1 -1
- package/lib/devframe/definition.js +56 -11
- package/lib/devframe/definition.js.map +1 -1
- package/lib/devframe/launch-editor.d.ts +20 -0
- package/lib/devframe/launch-editor.d.ts.map +1 -0
- package/lib/devframe/launch-editor.js +40 -0
- package/lib/devframe/launch-editor.js.map +1 -0
- package/lib/devframe/protocol.d.ts +31 -4
- package/lib/devframe/protocol.d.ts.map +1 -1
- package/lib/devframe/protocol.js +21 -3
- package/lib/devframe/protocol.js.map +1 -1
- package/lib/devframe/rpc-source.d.ts +44 -0
- package/lib/devframe/rpc-source.d.ts.map +1 -0
- package/lib/devframe/rpc-source.js +150 -0
- package/lib/devframe/rpc-source.js.map +1 -0
- package/lib/devframe/source.d.ts +12 -0
- package/lib/devframe/source.d.ts.map +1 -1
- package/lib/devframe/source.js +12 -0
- package/lib/devframe/source.js.map +1 -1
- package/lib/devframe/vite.d.ts +2 -0
- package/lib/devframe/vite.d.ts.map +1 -1
- package/lib/devframe/vite.js +3 -9
- package/lib/devframe/vite.js.map +1 -1
- package/lib/options.d.ts +6 -1
- package/lib/options.d.ts.map +1 -1
- package/lib/options.js +65 -18
- package/lib/options.js.map +1 -1
- package/lib/override-baselines.d.ts +17 -0
- package/lib/override-baselines.d.ts.map +1 -0
- package/lib/override-baselines.js +25 -0
- package/lib/override-baselines.js.map +1 -0
- package/lib/plugin.d.ts.map +1 -1
- package/lib/plugin.js +8 -0
- package/lib/plugin.js.map +1 -1
- package/lib/plugins/open-in-editor.d.ts.map +1 -1
- package/lib/plugins/open-in-editor.js +6 -1
- package/lib/plugins/open-in-editor.js.map +1 -1
- package/lib/runtime/indicator.js.map +1 -1
- package/lib/runtime/inspector/install.js +4 -2
- package/lib/runtime/inspector/install.js.map +1 -1
- package/lib/runtime/inspector/serialize.d.ts.map +1 -1
- package/lib/runtime/inspector/serialize.js +20 -0
- package/lib/runtime/inspector/serialize.js.map +1 -1
- package/lib/runtime/overrides.d.ts +4 -10
- package/lib/runtime/overrides.d.ts.map +1 -1
- package/lib/runtime/overrides.js +5 -3
- package/lib/runtime/overrides.js.map +1 -1
- package/lib/runtime/page-channel.d.ts +52 -0
- package/lib/runtime/page-channel.d.ts.map +1 -0
- package/lib/runtime/page-channel.js +67 -0
- package/lib/runtime/page-channel.js.map +1 -0
- package/lib/runtime/patch.d.ts.map +1 -1
- package/lib/runtime/patch.js +2 -1
- package/lib/runtime/patch.js.map +1 -1
- package/lib/runtime/rpc-transport.d.ts +46 -0
- package/lib/runtime/rpc-transport.d.ts.map +1 -0
- package/lib/runtime/rpc-transport.js +82 -0
- package/lib/runtime/rpc-transport.js.map +1 -0
- package/lib/runtime/source-overlay/overlay-element.d.ts.map +1 -1
- package/lib/runtime/source-overlay/overlay-element.js +13 -3
- package/lib/runtime/source-overlay/overlay-element.js.map +1 -1
- package/lib/runtime/timeline/install.js +15 -4
- package/lib/runtime/timeline/install.js.map +1 -1
- package/lib/runtime/timeline/public-api.d.ts.map +1 -1
- package/lib/runtime/timeline/public-api.js +11 -3
- package/lib/runtime/timeline/public-api.js.map +1 -1
- package/lib/runtime/timeline/transport.d.ts +6 -9
- package/lib/runtime/timeline/transport.d.ts.map +1 -1
- package/lib/runtime/timeline/transport.js.map +1 -1
- package/lib/timeline/filter.d.ts +38 -0
- package/lib/timeline/filter.d.ts.map +1 -0
- package/lib/timeline/filter.js +44 -0
- package/lib/timeline/filter.js.map +1 -0
- package/lib/timeline/tracks.d.ts +113 -0
- package/lib/timeline/tracks.d.ts.map +1 -0
- package/lib/timeline/tracks.js +168 -0
- package/lib/timeline/tracks.js.map +1 -0
- package/package.json +6 -1
- package/types/timeline.d.ts +38 -0
- package/types/timeline.d.ts.map +1 -1
- package/types/timeline.js +2 -0
- package/types/timeline.js.map +1 -1
- package/dist/client/assets/index-DVe6M4HV.js.map +0 -1
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: BSD-3-Clause
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Compiles the regex box. An empty box matches everything. A pattern that
|
|
8
|
+
* does not compile (the user is mid-typing `foo(`) disables the filter rather
|
|
9
|
+
* than hiding every row, and is reported as `invalid` so the input can say so.
|
|
10
|
+
*/
|
|
11
|
+
export const compileRegex = (source) => {
|
|
12
|
+
if (source === '') return {re: null, invalid: false};
|
|
13
|
+
try {
|
|
14
|
+
return {re: new RegExp(source, 'i'), invalid: false};
|
|
15
|
+
} catch {
|
|
16
|
+
return {re: null, invalid: true};
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
/** Text the regex filter searches: element tag, name, subtitle and the
|
|
20
|
+
* changed property keys (the reason is worth searching for by name). */
|
|
21
|
+
export const spanHaystack = (span) =>
|
|
22
|
+
`${span.meta?.tagName ?? ''} ${span.name} ${span.subtitle ?? ''} ${(span.changed ?? []).join(' ')}`;
|
|
23
|
+
/**
|
|
24
|
+
* Applies the element and regex filters. `re` comes from {@link compileRegex}
|
|
25
|
+
* so a caller filtering on every keystroke compiles once, not per span.
|
|
26
|
+
*/
|
|
27
|
+
export const filterSpans = (spans, elementId, re) =>
|
|
28
|
+
spans.filter(
|
|
29
|
+
(span) =>
|
|
30
|
+
(elementId === null || span.meta?.elementId === elementId) &&
|
|
31
|
+
(re === null || re.test(spanHaystack(span)))
|
|
32
|
+
);
|
|
33
|
+
/** Distinct elements (by stable id) seen across the recorded events. */
|
|
34
|
+
export const listElements = (events) => {
|
|
35
|
+
const seen = new Map();
|
|
36
|
+
for (const ev of events) {
|
|
37
|
+
const id = ev.meta?.elementId;
|
|
38
|
+
if (id != null && !seen.has(id)) {
|
|
39
|
+
seen.set(id, ev.meta?.tagName ?? 'unknown');
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return [...seen].map(([id, tag]) => ({id, tag}));
|
|
43
|
+
};
|
|
44
|
+
//# sourceMappingURL=filter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"filter.js","sourceRoot":"","sources":["../../src/lib/timeline/filter.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAcH;;;;GAIG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,CAC1B,MAAc,EACyB,EAAE;IACzC,IAAI,MAAM,KAAK,EAAE;QAAE,OAAO,EAAC,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAC,CAAC;IACrD,IAAI,CAAC;QACH,OAAO,EAAC,EAAE,EAAE,IAAI,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,OAAO,EAAE,KAAK,EAAC,CAAC;IACvD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAC,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAC,CAAC;IACnC,CAAC;AACH,CAAC,CAAC;AAEF;yEACyE;AACzE,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,IAAkB,EAAU,EAAE,CACzD,GAAG,IAAI,CAAC,IAAI,EAAE,OAAO,IAAI,EAAE,IAAI,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,QAAQ,IAAI,EAAE,IAAI,CACjE,IAAI,CAAC,OAAO,IAAI,EAAE,CACnB,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;AAEhB;;;GAGG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,CACzB,KAA8B,EAC9B,SAAwB,EACxB,EAAiB,EACD,EAAE,CAClB,KAAK,CAAC,MAAM,CACV,CAAC,IAAI,EAAE,EAAE,CACP,CAAC,SAAS,KAAK,IAAI,IAAI,IAAI,CAAC,IAAI,EAAE,SAAS,KAAK,SAAS,CAAC;IAC1D,CAAC,EAAE,KAAK,IAAI,IAAI,EAAE,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,CAC/C,CAAC;AAEJ,wEAAwE;AACxE,MAAM,CAAC,MAAM,YAAY,GAAG,CAC1B,MAAgC,EACE,EAAE;IACpC,MAAM,IAAI,GAAG,IAAI,GAAG,EAAkB,CAAC;IACvC,KAAK,MAAM,EAAE,IAAI,MAAM,EAAE,CAAC;QACxB,MAAM,EAAE,GAAG,EAAE,CAAC,IAAI,EAAE,SAAS,CAAC;QAC9B,IAAI,EAAE,IAAI,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC;YAChC,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,CAAC,IAAI,EAAE,OAAO,IAAI,SAAS,CAAC,CAAC;QAC9C,CAAC;IACH,CAAC;IACD,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,EAAC,EAAE,EAAE,GAAG,EAAC,CAAC,CAAC,CAAC;AACnD,CAAC,CAAC","sourcesContent":["/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: BSD-3-Clause\n */\n\n/**\n * The Timeline's element and regex filters, as pure functions.\n *\n * Both presentations (the list and the tracks) answer \"show me only this\n * element\" or \"only things matching /update/\". The filter state therefore\n * lives in `timeline-view` and each presentation applies it here, so the two\n * cannot drift apart on what a match means.\n */\n\nimport type {TimelineEvent} from '../../types/timeline.js';\nimport type {TimelineSpan} from './derive.js';\n\n/**\n * Compiles the regex box. An empty box matches everything. A pattern that\n * does not compile (the user is mid-typing `foo(`) disables the filter rather\n * than hiding every row, and is reported as `invalid` so the input can say so.\n */\nexport const compileRegex = (\n source: string\n): {re: RegExp | null; invalid: boolean} => {\n if (source === '') return {re: null, invalid: false};\n try {\n return {re: new RegExp(source, 'i'), invalid: false};\n } catch {\n return {re: null, invalid: true};\n }\n};\n\n/** Text the regex filter searches: element tag, name, subtitle and the\n * changed property keys (the reason is worth searching for by name). */\nexport const spanHaystack = (span: TimelineSpan): string =>\n `${span.meta?.tagName ?? ''} ${span.name} ${span.subtitle ?? ''} ${(\n span.changed ?? []\n ).join(' ')}`;\n\n/**\n * Applies the element and regex filters. `re` comes from {@link compileRegex}\n * so a caller filtering on every keystroke compiles once, not per span.\n */\nexport const filterSpans = (\n spans: readonly TimelineSpan[],\n elementId: number | null,\n re: RegExp | null\n): TimelineSpan[] =>\n spans.filter(\n (span) =>\n (elementId === null || span.meta?.elementId === elementId) &&\n (re === null || re.test(spanHaystack(span)))\n );\n\n/** Distinct elements (by stable id) seen across the recorded events. */\nexport const listElements = (\n events: readonly TimelineEvent[]\n): Array<{id: number; tag: string}> => {\n const seen = new Map<number, string>();\n for (const ev of events) {\n const id = ev.meta?.elementId;\n if (id != null && !seen.has(id)) {\n seen.set(id, ev.meta?.tagName ?? 'unknown');\n }\n }\n return [...seen].map(([id, tag]) => ({id, tag}));\n};\n"]}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: BSD-3-Clause
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Layout for the Timeline's track view: one horizontal lane per layer on a
|
|
8
|
+
* shared time axis.
|
|
9
|
+
*
|
|
10
|
+
* The list answers "what happened, in what order, to whom". It cannot show
|
|
11
|
+
* concurrency or rhythm — which layers fire together, how a click lines up
|
|
12
|
+
* with the update tick it caused, how long a tick is next to its neighbours.
|
|
13
|
+
* This module turns the same {@link TimelineSpan}s into lanes and rows, and
|
|
14
|
+
* owns the arithmetic between milliseconds and pixels, so the element that
|
|
15
|
+
* draws them (`panel/timeline-tracks.ts`) is only DOM.
|
|
16
|
+
*
|
|
17
|
+
* Pure and dependency-free, like `derive.ts`, so it is unit-tested without a
|
|
18
|
+
* browser.
|
|
19
|
+
*/
|
|
20
|
+
import type { TimelineSpan } from './derive.js';
|
|
21
|
+
/**
|
|
22
|
+
* Spans in one row of a lane, sorted by start and never overlapping, so
|
|
23
|
+
* {@link visibleRange} can binary-search them.
|
|
24
|
+
*/
|
|
25
|
+
export type TrackRow = TimelineSpan[];
|
|
26
|
+
/** One lane: every span of one layer, packed into non-overlapping rows. */
|
|
27
|
+
export interface Track {
|
|
28
|
+
layerId: string;
|
|
29
|
+
rows: TrackRow[];
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Where a span stops occupying its row. A point event occupies only its own
|
|
33
|
+
* instant; a span whose end has not arrived (still running, or its end fell
|
|
34
|
+
* out of the buffer) occupies the rest of the recording, because that is
|
|
35
|
+
* where it is drawn — up to the live edge.
|
|
36
|
+
*/
|
|
37
|
+
export declare const occupiedEnd: (span: TimelineSpan) => number;
|
|
38
|
+
/**
|
|
39
|
+
* Groups spans into one track per layer, in `layers` order, then any layer
|
|
40
|
+
* the spans mention that `layers` does not (a custom layer announced after the
|
|
41
|
+
* last `get-meta`), in first-seen order. A layer with no spans still gets an
|
|
42
|
+
* empty track, so a lane does not appear and vanish as events arrive.
|
|
43
|
+
*
|
|
44
|
+
* Within a track, spans are packed greedily: each goes into the first row
|
|
45
|
+
* whose last span has ended by the time it starts. Lit's lifecycle phases
|
|
46
|
+
* nest, so one update tick lands as `performUpdate` on row 0 and
|
|
47
|
+
* `willUpdate` / `update` / `updated` side by side on row 1 — the flame shape
|
|
48
|
+
* falls out of the packing without modelling it.
|
|
49
|
+
*/
|
|
50
|
+
export declare const buildTracks: (spans: readonly TimelineSpan[], layers: readonly {
|
|
51
|
+
id: string;
|
|
52
|
+
}[]) => Track[];
|
|
53
|
+
/**
|
|
54
|
+
* The recording's time bounds over `spans`: the earliest start, and the
|
|
55
|
+
* latest instant anything is known to have happened (an end, or the start of
|
|
56
|
+
* a span with none). The origin is the earliest start rather than zero
|
|
57
|
+
* because the panel's buffer is capped and rolls its oldest events off; a
|
|
58
|
+
* long recording would otherwise open on an empty stretch.
|
|
59
|
+
*/
|
|
60
|
+
export declare const timeBounds: (spans: readonly TimelineSpan[]) => {
|
|
61
|
+
origin: number;
|
|
62
|
+
extent: number;
|
|
63
|
+
};
|
|
64
|
+
/** Deepest zoom, in multiples of "fit": about a microsecond per pixel on a
|
|
65
|
+
* second-long recording, past which there is nothing left to separate. */
|
|
66
|
+
export declare const MAX_ZOOM = 100000;
|
|
67
|
+
/** Mapping between recording time and pixels for the current zoom and pan. */
|
|
68
|
+
export interface TimeScale {
|
|
69
|
+
pxPerMs: number;
|
|
70
|
+
/** First and last millisecond inside the plot. */
|
|
71
|
+
start: number;
|
|
72
|
+
end: number;
|
|
73
|
+
toX(ms: number): number;
|
|
74
|
+
toMs(x: number): number;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Builds the scale for a plot `width` pixels wide showing a recording that
|
|
78
|
+
* begins at `originMs` and runs for `extentMs`.
|
|
79
|
+
*
|
|
80
|
+
* `zoom` is a multiple of "fit" (1 shows the whole recording); `pan` is how
|
|
81
|
+
* many milliseconds past the origin the left edge sits. Both are clamped, so
|
|
82
|
+
* callers can apply a raw wheel or drag delta and read back where it landed.
|
|
83
|
+
*/
|
|
84
|
+
export declare const timeScale: (originMs: number, extentMs: number, width: number, zoom?: number, pan?: number) => TimeScale;
|
|
85
|
+
export declare const clampZoom: (zoom: number) => number;
|
|
86
|
+
/** Keeps the visible window inside the recording. */
|
|
87
|
+
export declare const clampPan: (pan: number, extentMs: number, zoom: number) => number;
|
|
88
|
+
/** The pan that puts the live edge (the end of the recording) at the right
|
|
89
|
+
* of the plot, for following a recording in progress. */
|
|
90
|
+
export declare const livePan: (extentMs: number, zoom: number) => number;
|
|
91
|
+
/**
|
|
92
|
+
* Zooms by `factor` while keeping the millisecond under pixel `x` where it
|
|
93
|
+
* is, which is what a wheel over a timeline is expected to do.
|
|
94
|
+
*/
|
|
95
|
+
export declare const zoomAt: (originMs: number, extentMs: number, width: number, zoom: number, pan: number, x: number, factor: number) => {
|
|
96
|
+
zoom: number;
|
|
97
|
+
pan: number;
|
|
98
|
+
};
|
|
99
|
+
/**
|
|
100
|
+
* Index range `[from, to)` of the spans in `row` that intersect the window
|
|
101
|
+
* `[start, end]`, found by binary search so a zoomed-in lane renders a
|
|
102
|
+
* handful of marks rather than walking thousands.
|
|
103
|
+
*
|
|
104
|
+
* Only the span just before the first one starting inside the window can
|
|
105
|
+
* reach into it, because a row's spans never overlap.
|
|
106
|
+
*/
|
|
107
|
+
export declare const visibleRange: (row: TrackRow, start: number, end: number) => [number, number];
|
|
108
|
+
/**
|
|
109
|
+
* A round tick interval (1, 2 or 5 times a power of ten, in milliseconds) at
|
|
110
|
+
* least `minMs` long, for axis labels that land on readable numbers.
|
|
111
|
+
*/
|
|
112
|
+
export declare const niceStep: (minMs: number) => number;
|
|
113
|
+
//# sourceMappingURL=tracks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tracks.d.ts","sourceRoot":"","sources":["../../src/lib/timeline/tracks.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,aAAa,CAAC;AAE9C;;;GAGG;AACH,MAAM,MAAM,QAAQ,GAAG,YAAY,EAAE,CAAC;AAEtC,2EAA2E;AAC3E,MAAM,WAAW,KAAK;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,QAAQ,EAAE,CAAC;CAClB;AAED;;;;;GAKG;AACH,eAAO,MAAM,WAAW,SAAU,YAAY,KAAG,MAGhD,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,WAAW,UACf,SAAS,YAAY,EAAE,UACtB,SAAS;IAAC,EAAE,EAAE,MAAM,CAAA;CAAC,EAAE,KAC9B,KAAK,EAeP,CAAC;AAwBF;;;;;;GAMG;AACH,eAAO,MAAM,UAAU,UACd,SAAS,YAAY,EAAE,KAC7B;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CASjC,CAAC;AAEF;2EAC2E;AAC3E,eAAO,MAAM,QAAQ,SAAU,CAAC;AAKhC,8EAA8E;AAC9E,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,kDAAkD;IAClD,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB,IAAI,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CACzB;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,SAAS,aACV,MAAM,YACN,MAAM,SACT,MAAM,kCAGZ,SAcF,CAAC;AAEF,eAAO,MAAM,SAAS,SAAU,MAAM,KAAG,MACuB,CAAC;AAEjE,qDAAqD;AACrD,eAAO,MAAM,QAAQ,QACd,MAAM,YACD,MAAM,QACV,MAAM,KACX,MAIF,CAAC;AAEF;0DAC0D;AAC1D,eAAO,MAAM,OAAO,aAAc,MAAM,QAAQ,MAAM,KAAG,MACrB,CAAC;AAErC;;;GAGG;AACH,eAAO,MAAM,MAAM,aACP,MAAM,YACN,MAAM,SACT,MAAM,QACP,MAAM,OACP,MAAM,KACR,MAAM,UACD,MAAM,KACb;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAO5B,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,YAAY,QAClB,QAAQ,SACN,MAAM,OACR,MAAM,KACV,CAAC,MAAM,EAAE,MAAM,CAgBjB,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,QAAQ,UAAW,MAAM,KAAG,MAOxC,CAAC"}
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: BSD-3-Clause
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Where a span stops occupying its row. A point event occupies only its own
|
|
8
|
+
* instant; a span whose end has not arrived (still running, or its end fell
|
|
9
|
+
* out of the buffer) occupies the rest of the recording, because that is
|
|
10
|
+
* where it is drawn — up to the live edge.
|
|
11
|
+
*/
|
|
12
|
+
export const occupiedEnd = (span) => {
|
|
13
|
+
if (span.end !== undefined) return span.end;
|
|
14
|
+
return span.groupId === undefined ? span.start : Infinity;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Groups spans into one track per layer, in `layers` order, then any layer
|
|
18
|
+
* the spans mention that `layers` does not (a custom layer announced after the
|
|
19
|
+
* last `get-meta`), in first-seen order. A layer with no spans still gets an
|
|
20
|
+
* empty track, so a lane does not appear and vanish as events arrive.
|
|
21
|
+
*
|
|
22
|
+
* Within a track, spans are packed greedily: each goes into the first row
|
|
23
|
+
* whose last span has ended by the time it starts. Lit's lifecycle phases
|
|
24
|
+
* nest, so one update tick lands as `performUpdate` on row 0 and
|
|
25
|
+
* `willUpdate` / `update` / `updated` side by side on row 1 — the flame shape
|
|
26
|
+
* falls out of the packing without modelling it.
|
|
27
|
+
*/
|
|
28
|
+
export const buildTracks = (spans, layers) => {
|
|
29
|
+
const byLayer = new Map();
|
|
30
|
+
for (const layer of layers) byLayer.set(layer.id, []);
|
|
31
|
+
for (const span of spans) {
|
|
32
|
+
let list = byLayer.get(span.layerId);
|
|
33
|
+
if (list === undefined) {
|
|
34
|
+
list = [];
|
|
35
|
+
byLayer.set(span.layerId, list);
|
|
36
|
+
}
|
|
37
|
+
list.push(span);
|
|
38
|
+
}
|
|
39
|
+
return [...byLayer].map(([layerId, list]) => ({
|
|
40
|
+
layerId,
|
|
41
|
+
rows: packRows(list),
|
|
42
|
+
}));
|
|
43
|
+
};
|
|
44
|
+
const packRows = (spans) => {
|
|
45
|
+
// `toSpans` already sorts by start; re-sort only if a caller did not.
|
|
46
|
+
const sorted = spans.every((s, i) => i === 0 || spans[i - 1].start <= s.start)
|
|
47
|
+
? spans
|
|
48
|
+
: [...spans].sort((a, b) => a.start - b.start);
|
|
49
|
+
const rows = [];
|
|
50
|
+
const rowEnds = [];
|
|
51
|
+
for (const span of sorted) {
|
|
52
|
+
let row = rowEnds.findIndex((end) => end <= span.start);
|
|
53
|
+
if (row === -1) {
|
|
54
|
+
row = rows.length;
|
|
55
|
+
rows.push([]);
|
|
56
|
+
rowEnds.push(-Infinity);
|
|
57
|
+
}
|
|
58
|
+
rows[row].push(span);
|
|
59
|
+
rowEnds[row] = occupiedEnd(span);
|
|
60
|
+
}
|
|
61
|
+
return rows;
|
|
62
|
+
};
|
|
63
|
+
/**
|
|
64
|
+
* The recording's time bounds over `spans`: the earliest start, and the
|
|
65
|
+
* latest instant anything is known to have happened (an end, or the start of
|
|
66
|
+
* a span with none). The origin is the earliest start rather than zero
|
|
67
|
+
* because the panel's buffer is capped and rolls its oldest events off; a
|
|
68
|
+
* long recording would otherwise open on an empty stretch.
|
|
69
|
+
*/
|
|
70
|
+
export const timeBounds = (spans) => {
|
|
71
|
+
if (spans.length === 0) return {origin: 0, extent: 0};
|
|
72
|
+
let origin = Infinity;
|
|
73
|
+
let last = -Infinity;
|
|
74
|
+
for (const span of spans) {
|
|
75
|
+
origin = Math.min(origin, span.start);
|
|
76
|
+
last = Math.max(last, span.end ?? span.start);
|
|
77
|
+
}
|
|
78
|
+
return {origin, extent: last - origin};
|
|
79
|
+
};
|
|
80
|
+
/** Deepest zoom, in multiples of "fit": about a microsecond per pixel on a
|
|
81
|
+
* second-long recording, past which there is nothing left to separate. */
|
|
82
|
+
export const MAX_ZOOM = 100_000;
|
|
83
|
+
/** A recording with a single instant in it still needs a nonzero axis. */
|
|
84
|
+
const MIN_EXTENT_MS = 1;
|
|
85
|
+
/**
|
|
86
|
+
* Builds the scale for a plot `width` pixels wide showing a recording that
|
|
87
|
+
* begins at `originMs` and runs for `extentMs`.
|
|
88
|
+
*
|
|
89
|
+
* `zoom` is a multiple of "fit" (1 shows the whole recording); `pan` is how
|
|
90
|
+
* many milliseconds past the origin the left edge sits. Both are clamped, so
|
|
91
|
+
* callers can apply a raw wheel or drag delta and read back where it landed.
|
|
92
|
+
*/
|
|
93
|
+
export const timeScale = (originMs, extentMs, width, zoom = 1, pan = 0) => {
|
|
94
|
+
const extent = Math.max(extentMs, MIN_EXTENT_MS);
|
|
95
|
+
const z = clampZoom(zoom);
|
|
96
|
+
const visibleMs = extent / z;
|
|
97
|
+
const p = clampPan(pan, extent, z);
|
|
98
|
+
const pxPerMs = Math.max(width, 1) / visibleMs;
|
|
99
|
+
const start = originMs + p;
|
|
100
|
+
return {
|
|
101
|
+
pxPerMs,
|
|
102
|
+
start,
|
|
103
|
+
end: start + visibleMs,
|
|
104
|
+
toX: (ms) => (ms - start) * pxPerMs,
|
|
105
|
+
toMs: (x) => start + x / pxPerMs,
|
|
106
|
+
};
|
|
107
|
+
};
|
|
108
|
+
export const clampZoom = (zoom) =>
|
|
109
|
+
Math.min(Math.max(Number.isNaN(zoom) ? 1 : zoom, 1), MAX_ZOOM);
|
|
110
|
+
/** Keeps the visible window inside the recording. */
|
|
111
|
+
export const clampPan = (pan, extentMs, zoom) => {
|
|
112
|
+
const extent = Math.max(extentMs, MIN_EXTENT_MS);
|
|
113
|
+
const max = extent - extent / clampZoom(zoom);
|
|
114
|
+
return Math.min(Math.max(Number.isNaN(pan) ? 0 : pan, 0), max);
|
|
115
|
+
};
|
|
116
|
+
/** The pan that puts the live edge (the end of the recording) at the right
|
|
117
|
+
* of the plot, for following a recording in progress. */
|
|
118
|
+
export const livePan = (extentMs, zoom) => clampPan(Infinity, extentMs, zoom);
|
|
119
|
+
/**
|
|
120
|
+
* Zooms by `factor` while keeping the millisecond under pixel `x` where it
|
|
121
|
+
* is, which is what a wheel over a timeline is expected to do.
|
|
122
|
+
*/
|
|
123
|
+
export const zoomAt = (originMs, extentMs, width, zoom, pan, x, factor) => {
|
|
124
|
+
const before = timeScale(originMs, extentMs, width, zoom, pan);
|
|
125
|
+
const anchor = before.toMs(x);
|
|
126
|
+
const nextZoom = clampZoom(clampZoom(zoom) * factor);
|
|
127
|
+
const after = timeScale(originMs, extentMs, width, nextZoom, 0);
|
|
128
|
+
const nextPan = anchor - originMs - x / after.pxPerMs;
|
|
129
|
+
return {zoom: nextZoom, pan: clampPan(nextPan, extentMs, nextZoom)};
|
|
130
|
+
};
|
|
131
|
+
/**
|
|
132
|
+
* Index range `[from, to)` of the spans in `row` that intersect the window
|
|
133
|
+
* `[start, end]`, found by binary search so a zoomed-in lane renders a
|
|
134
|
+
* handful of marks rather than walking thousands.
|
|
135
|
+
*
|
|
136
|
+
* Only the span just before the first one starting inside the window can
|
|
137
|
+
* reach into it, because a row's spans never overlap.
|
|
138
|
+
*/
|
|
139
|
+
export const visibleRange = (row, start, end) => {
|
|
140
|
+
const firstAtOrAfter = (t, inclusive) => {
|
|
141
|
+
let lo = 0;
|
|
142
|
+
let hi = row.length;
|
|
143
|
+
while (lo < hi) {
|
|
144
|
+
const mid = (lo + hi) >> 1;
|
|
145
|
+
const s = row[mid].start;
|
|
146
|
+
if (inclusive ? s < t : s <= t) lo = mid + 1;
|
|
147
|
+
else hi = mid;
|
|
148
|
+
}
|
|
149
|
+
return lo;
|
|
150
|
+
};
|
|
151
|
+
let from = firstAtOrAfter(start, true);
|
|
152
|
+
if (from > 0 && occupiedEnd(row[from - 1]) >= start) from--;
|
|
153
|
+
const to = firstAtOrAfter(end, false);
|
|
154
|
+
return [from, Math.max(from, to)];
|
|
155
|
+
};
|
|
156
|
+
/**
|
|
157
|
+
* A round tick interval (1, 2 or 5 times a power of ten, in milliseconds) at
|
|
158
|
+
* least `minMs` long, for axis labels that land on readable numbers.
|
|
159
|
+
*/
|
|
160
|
+
export const niceStep = (minMs) => {
|
|
161
|
+
if (!(minMs > 0) || !Number.isFinite(minMs)) return 1;
|
|
162
|
+
const pow = 10 ** Math.floor(Math.log10(minMs));
|
|
163
|
+
for (const m of [1, 2, 5, 10]) {
|
|
164
|
+
if (m * pow >= minMs) return m * pow;
|
|
165
|
+
}
|
|
166
|
+
return 10 * pow;
|
|
167
|
+
};
|
|
168
|
+
//# sourceMappingURL=tracks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tracks.js","sourceRoot":"","sources":["../../src/lib/timeline/tracks.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 * Layout for the Timeline's track view: one horizontal lane per layer on a\n * shared time axis.\n *\n * The list answers \"what happened, in what order, to whom\". It cannot show\n * concurrency or rhythm — which layers fire together, how a click lines up\n * with the update tick it caused, how long a tick is next to its neighbours.\n * This module turns the same {@link TimelineSpan}s into lanes and rows, and\n * owns the arithmetic between milliseconds and pixels, so the element that\n * draws them (`panel/timeline-tracks.ts`) is only DOM.\n *\n * Pure and dependency-free, like `derive.ts`, so it is unit-tested without a\n * browser.\n */\n\nimport type {TimelineSpan} from './derive.js';\n\n/**\n * Spans in one row of a lane, sorted by start and never overlapping, so\n * {@link visibleRange} can binary-search them.\n */\nexport type TrackRow = TimelineSpan[];\n\n/** One lane: every span of one layer, packed into non-overlapping rows. */\nexport interface Track {\n layerId: string;\n rows: TrackRow[];\n}\n\n/**\n * Where a span stops occupying its row. A point event occupies only its own\n * instant; a span whose end has not arrived (still running, or its end fell\n * out of the buffer) occupies the rest of the recording, because that is\n * where it is drawn — up to the live edge.\n */\nexport const occupiedEnd = (span: TimelineSpan): number => {\n if (span.end !== undefined) return span.end;\n return span.groupId === undefined ? span.start : Infinity;\n};\n\n/**\n * Groups spans into one track per layer, in `layers` order, then any layer\n * the spans mention that `layers` does not (a custom layer announced after the\n * last `get-meta`), in first-seen order. A layer with no spans still gets an\n * empty track, so a lane does not appear and vanish as events arrive.\n *\n * Within a track, spans are packed greedily: each goes into the first row\n * whose last span has ended by the time it starts. Lit's lifecycle phases\n * nest, so one update tick lands as `performUpdate` on row 0 and\n * `willUpdate` / `update` / `updated` side by side on row 1 — the flame shape\n * falls out of the packing without modelling it.\n */\nexport const buildTracks = (\n spans: readonly TimelineSpan[],\n layers: readonly {id: string}[]\n): Track[] => {\n const byLayer = new Map<string, TimelineSpan[]>();\n for (const layer of layers) byLayer.set(layer.id, []);\n for (const span of spans) {\n let list = byLayer.get(span.layerId);\n if (list === undefined) {\n list = [];\n byLayer.set(span.layerId, list);\n }\n list.push(span);\n }\n return [...byLayer].map(([layerId, list]) => ({\n layerId,\n rows: packRows(list),\n }));\n};\n\nconst packRows = (spans: TimelineSpan[]): TrackRow[] => {\n // `toSpans` already sorts by start; re-sort only if a caller did not.\n const sorted = spans.every(\n (s, i) => i === 0 || spans[i - 1]!.start <= s.start\n )\n ? spans\n : [...spans].sort((a, b) => a.start - b.start);\n const rows: TrackRow[] = [];\n const rowEnds: number[] = [];\n for (const span of sorted) {\n let row = rowEnds.findIndex((end) => end <= span.start);\n if (row === -1) {\n row = rows.length;\n rows.push([]);\n rowEnds.push(-Infinity);\n }\n rows[row]!.push(span);\n rowEnds[row] = occupiedEnd(span);\n }\n return rows;\n};\n\n/**\n * The recording's time bounds over `spans`: the earliest start, and the\n * latest instant anything is known to have happened (an end, or the start of\n * a span with none). The origin is the earliest start rather than zero\n * because the panel's buffer is capped and rolls its oldest events off; a\n * long recording would otherwise open on an empty stretch.\n */\nexport const timeBounds = (\n spans: readonly TimelineSpan[]\n): {origin: number; extent: number} => {\n if (spans.length === 0) return {origin: 0, extent: 0};\n let origin = Infinity;\n let last = -Infinity;\n for (const span of spans) {\n origin = Math.min(origin, span.start);\n last = Math.max(last, span.end ?? span.start);\n }\n return {origin, extent: last - origin};\n};\n\n/** Deepest zoom, in multiples of \"fit\": about a microsecond per pixel on a\n * second-long recording, past which there is nothing left to separate. */\nexport const MAX_ZOOM = 100_000;\n\n/** A recording with a single instant in it still needs a nonzero axis. */\nconst MIN_EXTENT_MS = 1;\n\n/** Mapping between recording time and pixels for the current zoom and pan. */\nexport interface TimeScale {\n pxPerMs: number;\n /** First and last millisecond inside the plot. */\n start: number;\n end: number;\n toX(ms: number): number;\n toMs(x: number): number;\n}\n\n/**\n * Builds the scale for a plot `width` pixels wide showing a recording that\n * begins at `originMs` and runs for `extentMs`.\n *\n * `zoom` is a multiple of \"fit\" (1 shows the whole recording); `pan` is how\n * many milliseconds past the origin the left edge sits. Both are clamped, so\n * callers can apply a raw wheel or drag delta and read back where it landed.\n */\nexport const timeScale = (\n originMs: number,\n extentMs: number,\n width: number,\n zoom = 1,\n pan = 0\n): TimeScale => {\n const extent = Math.max(extentMs, MIN_EXTENT_MS);\n const z = clampZoom(zoom);\n const visibleMs = extent / z;\n const p = clampPan(pan, extent, z);\n const pxPerMs = Math.max(width, 1) / visibleMs;\n const start = originMs + p;\n return {\n pxPerMs,\n start,\n end: start + visibleMs,\n toX: (ms) => (ms - start) * pxPerMs,\n toMs: (x) => start + x / pxPerMs,\n };\n};\n\nexport const clampZoom = (zoom: number): number =>\n Math.min(Math.max(Number.isNaN(zoom) ? 1 : zoom, 1), MAX_ZOOM);\n\n/** Keeps the visible window inside the recording. */\nexport const clampPan = (\n pan: number,\n extentMs: number,\n zoom: number\n): number => {\n const extent = Math.max(extentMs, MIN_EXTENT_MS);\n const max = extent - extent / clampZoom(zoom);\n return Math.min(Math.max(Number.isNaN(pan) ? 0 : pan, 0), max);\n};\n\n/** The pan that puts the live edge (the end of the recording) at the right\n * of the plot, for following a recording in progress. */\nexport const livePan = (extentMs: number, zoom: number): number =>\n clampPan(Infinity, extentMs, zoom);\n\n/**\n * Zooms by `factor` while keeping the millisecond under pixel `x` where it\n * is, which is what a wheel over a timeline is expected to do.\n */\nexport const zoomAt = (\n originMs: number,\n extentMs: number,\n width: number,\n zoom: number,\n pan: number,\n x: number,\n factor: number\n): {zoom: number; pan: number} => {\n const before = timeScale(originMs, extentMs, width, zoom, pan);\n const anchor = before.toMs(x);\n const nextZoom = clampZoom(clampZoom(zoom) * factor);\n const after = timeScale(originMs, extentMs, width, nextZoom, 0);\n const nextPan = anchor - originMs - x / after.pxPerMs;\n return {zoom: nextZoom, pan: clampPan(nextPan, extentMs, nextZoom)};\n};\n\n/**\n * Index range `[from, to)` of the spans in `row` that intersect the window\n * `[start, end]`, found by binary search so a zoomed-in lane renders a\n * handful of marks rather than walking thousands.\n *\n * Only the span just before the first one starting inside the window can\n * reach into it, because a row's spans never overlap.\n */\nexport const visibleRange = (\n row: TrackRow,\n start: number,\n end: number\n): [number, number] => {\n const firstAtOrAfter = (t: number, inclusive: boolean) => {\n let lo = 0;\n let hi = row.length;\n while (lo < hi) {\n const mid = (lo + hi) >> 1;\n const s = row[mid]!.start;\n if (inclusive ? s < t : s <= t) lo = mid + 1;\n else hi = mid;\n }\n return lo;\n };\n let from = firstAtOrAfter(start, true);\n if (from > 0 && occupiedEnd(row[from - 1]!) >= start) from--;\n const to = firstAtOrAfter(end, false);\n return [from, Math.max(from, to)];\n};\n\n/**\n * A round tick interval (1, 2 or 5 times a power of ten, in milliseconds) at\n * least `minMs` long, for axis labels that land on readable numbers.\n */\nexport const niceStep = (minMs: number): number => {\n if (!(minMs > 0) || !Number.isFinite(minMs)) return 1;\n const pow = 10 ** Math.floor(Math.log10(minMs));\n for (const m of [1, 2, 5, 10]) {\n if (m * pow >= minMs) return m * pow;\n }\n return 10 * pow;\n};\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oddsquad/vite-plugin-lit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Vite plugin providing true HMR for Lit components, plus CSS helpers and a DevTools panel",
|
|
5
5
|
"license": "BSD-3-Clause",
|
|
6
6
|
"author": "Oddsquad (based on @lit-labs/vite-hmr by Google LLC)",
|
|
@@ -28,6 +28,10 @@
|
|
|
28
28
|
"types": "./lib/runtime/css.d.ts",
|
|
29
29
|
"default": "./lib/runtime/css.js"
|
|
30
30
|
},
|
|
31
|
+
"./connect.js": {
|
|
32
|
+
"types": "./lib/runtime/rpc-transport.d.ts",
|
|
33
|
+
"default": "./lib/runtime/rpc-transport.js"
|
|
34
|
+
},
|
|
31
35
|
"./client": {
|
|
32
36
|
"types": "./client.d.ts"
|
|
33
37
|
}
|
|
@@ -81,6 +85,7 @@
|
|
|
81
85
|
"lightningcss": "^1.33.0",
|
|
82
86
|
"lit": "^3.3.3",
|
|
83
87
|
"playwright-core": "^1.63.0",
|
|
88
|
+
"temporal-polyfill": "^1.0.5",
|
|
84
89
|
"typescript": "^7.0.2",
|
|
85
90
|
"vite": "npm:@voidzero-dev/vite-plus-core@0.3.2",
|
|
86
91
|
"vite-plus": "0.3.2"
|
package/types/timeline.d.ts
CHANGED
|
@@ -9,6 +9,12 @@ export interface TimelineLayer {
|
|
|
9
9
|
color: number;
|
|
10
10
|
}
|
|
11
11
|
export interface TimelineEvent<TData = unknown> {
|
|
12
|
+
/**
|
|
13
|
+
* Stable identity, stamped on the Node side (`${epoch}-${seq}`) when the
|
|
14
|
+
* event is received, so it survives the stream, `recent-events` and a
|
|
15
|
+
* snapshot export. Absent on events still in the page runtime.
|
|
16
|
+
*/
|
|
17
|
+
id?: string;
|
|
12
18
|
layerId: string;
|
|
13
19
|
/**
|
|
14
20
|
* Milliseconds since recording started, stamped in the browser page
|
|
@@ -70,6 +76,29 @@ export interface FeatureSettings {
|
|
|
70
76
|
throttleMs: number;
|
|
71
77
|
};
|
|
72
78
|
timeline: boolean;
|
|
79
|
+
/**
|
|
80
|
+
* Which layer supplied each setting, keyed like {@link SettingsOverride}
|
|
81
|
+
* (plus the read-only source-overlay rows). Lets the panel label a value
|
|
82
|
+
* "Zed (env)" and name the baseline a panel override replaced. Optional so
|
|
83
|
+
* older producers (and snapshots) without it still type-check.
|
|
84
|
+
*/
|
|
85
|
+
sources?: SettingSources;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Where a resolved setting came from, in precedence order after a panel
|
|
89
|
+
* override: an explicit `litPlugin({...})` option, a `LIT_PLUGIN_*` env var,
|
|
90
|
+
* or the built-in default.
|
|
91
|
+
*/
|
|
92
|
+
export type SettingSource = 'option' | 'env' | 'default';
|
|
93
|
+
/** Per-setting {@link SettingSource}, as carried on {@link FeatureSettings}. */
|
|
94
|
+
export interface SettingSources {
|
|
95
|
+
hmrReconnect?: SettingSource;
|
|
96
|
+
hmrOnIncompatible?: SettingSource;
|
|
97
|
+
hmrIndicatorVisible?: SettingSource;
|
|
98
|
+
hmrIndicatorCount?: SettingSource;
|
|
99
|
+
sourceOverlayEditor?: SettingSource;
|
|
100
|
+
sourceOverlayKey?: SettingSource;
|
|
101
|
+
sourceOverlayThrottleMs?: SettingSource;
|
|
73
102
|
}
|
|
74
103
|
/**
|
|
75
104
|
* Runtime overrides the panel applies on top of the resolved env config, for
|
|
@@ -110,6 +139,15 @@ export declare const SOURCE_OVERLAY_EDITORS: ReadonlyArray<{
|
|
|
110
139
|
}>;
|
|
111
140
|
/** localStorage key holding the {@link SettingsOverride}. */
|
|
112
141
|
export declare const SETTINGS_OVERRIDE_LS_KEY = "lit-devtools-overrides";
|
|
142
|
+
/**
|
|
143
|
+
* The resolved config value each overridden key was set against, recorded so
|
|
144
|
+
* the Settings tab can notice when `.env` or plugin options moved on. Kept
|
|
145
|
+
* beside the {@link SettingsOverride}, never inside it: the runtime applies and
|
|
146
|
+
* receives the override as-is and has no use for these.
|
|
147
|
+
*/
|
|
148
|
+
export type OverrideBaselines = Partial<Record<'hmrReconnect' | 'hmrOnIncompatible' | 'hmrIndicatorVisible' | 'hmrIndicatorCount' | 'sourceOverlayEditor', unknown>>;
|
|
149
|
+
/** localStorage key holding the {@link OverrideBaselines}. */
|
|
150
|
+
export declare const OVERRIDE_BASELINES_LS_KEY = "lit-devtools-override-baselines";
|
|
113
151
|
/** Vite HMR channel the server uses to push overrides to the app runtime. */
|
|
114
152
|
export declare const SETTINGS_OVERRIDE_CHANNEL = "lit-devtools:settings-override";
|
|
115
153
|
/**
|
package/types/timeline.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"timeline.d.ts","sourceRoot":"","sources":["../src/types/timeline.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,aAAa,CAAC,KAAK,GAAG,OAAO;IAC5C,OAAO,EAAE,MAAM,CAAC;IAChB;;;;OAIG;IACH,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,KAAK,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gFAAgF;IAChF,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC1B,OAAO,CAAC,EAAE,SAAS,GAAG,SAAS,GAAG,OAAO,CAAC;IAC1C,IAAI,CAAC,EAAE;QACL,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,MAAM,CAAC,EAAE;YAAC,IAAI,EAAE,MAAM,CAAC;YAAC,IAAI,EAAE,MAAM,CAAA;SAAC,CAAC;KACvC,CAAC;CACH;AAED,MAAM,WAAW,mBAAmB;IAClC,cAAc,EAAE,OAAO,CAAC;IACxB,mBAAmB,EAAE,OAAO,CAAC;IAC7B,gBAAgB,EAAE,OAAO,CAAC;IAC1B;;;;;OAKG;IACH,uBAAuB,EAAE,OAAO,CAAC;IACjC,iBAAiB,EAAE,OAAO,CAAC;IAC3B,oBAAoB,EAAE,OAAO,CAAC;CAC/B;AAED,eAAO,MAAM,eAAe,EAAE,SAAS,aAAa,EAMnD,CAAC;AAEF,eAAO,MAAM,oBAAoB,EAAE,mBAOlC,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,WAAW,eAAe;IAC9B,GAAG,EAAE;QACH,OAAO,EAAE,OAAO,CAAC;QACjB,SAAS,EAAE,OAAO,CAAC;QACnB,cAAc,EAAE,QAAQ,GAAG,MAAM,CAAC;QAClC,gBAAgB,EAAE,OAAO,CAAC;QAC1B,cAAc,EAAE,OAAO,CAAC;KACzB,CAAC;IACF,aAAa,EAAE;QACb,OAAO,EAAE,OAAO,CAAC;QACjB,oEAAoE;QACpE,GAAG,EAAE,MAAM,CAAC;QACZ,MAAM,EAAE,MAAM,CAAC;QACf,UAAU,EAAE,MAAM,CAAC;KACpB,CAAC;IACF,QAAQ,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"timeline.d.ts","sourceRoot":"","sources":["../src/types/timeline.ts"],"names":[],"mappings":"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"}
|
package/types/timeline.js
CHANGED
|
@@ -31,6 +31,8 @@ export const SOURCE_OVERLAY_EDITORS = [
|
|
|
31
31
|
];
|
|
32
32
|
/** localStorage key holding the {@link SettingsOverride}. */
|
|
33
33
|
export const SETTINGS_OVERRIDE_LS_KEY = 'lit-devtools-overrides';
|
|
34
|
+
/** localStorage key holding the {@link OverrideBaselines}. */
|
|
35
|
+
export const OVERRIDE_BASELINES_LS_KEY = 'lit-devtools-override-baselines';
|
|
34
36
|
/** Vite HMR channel the server uses to push overrides to the app runtime. */
|
|
35
37
|
export const SETTINGS_OVERRIDE_CHANNEL = 'lit-devtools:settings-override';
|
|
36
38
|
/**
|
package/types/timeline.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"timeline.js","sourceRoot":"","sources":["../src/types/timeline.ts"],"names":[],"mappings":"AAAA;;;;GAIG;
|
|
1
|
+
{"version":3,"file":"timeline.js","sourceRoot":"","sources":["../src/types/timeline.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAkDH,MAAM,CAAC,MAAM,eAAe,GAA6B;IACvD,EAAC,EAAE,EAAE,eAAe,EAAE,KAAK,EAAE,eAAe,EAAE,KAAK,EAAE,QAAQ,EAAC;IAC9D,EAAC,EAAE,EAAE,YAAY,EAAE,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,QAAQ,EAAC;IACxD,EAAC,EAAE,EAAE,oBAAoB,EAAE,KAAK,EAAE,sBAAsB,EAAE,KAAK,EAAE,QAAQ,EAAC;IAC1E,EAAC,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAC;IAC9C,EAAC,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,QAAQ,EAAC;CACrD,CAAC;AAEF,MAAM,CAAC,MAAM,oBAAoB,GAAwB;IACvD,cAAc,EAAE,KAAK;IACrB,mBAAmB,EAAE,IAAI;IACzB,gBAAgB,EAAE,IAAI;IACtB,uBAAuB,EAAE,KAAK;IAC9B,iBAAiB,EAAE,KAAK;IACxB,oBAAoB,EAAE,KAAK;CAC5B,CAAC;AAkFF;;;GAGG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAG9B;IACH,EAAC,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,SAAS,EAAC;IACnC,EAAC,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAC;IAClC,EAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAC;IAC5B,EAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,EAAC;IAClC,EAAC,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAC;CACvC,CAAC;AAEF,6DAA6D;AAC7D,MAAM,CAAC,MAAM,wBAAwB,GAAG,wBAAwB,CAAC;AAmBjE,8DAA8D;AAC9D,MAAM,CAAC,MAAM,yBAAyB,GAAG,iCAAiC,CAAC;AAE3E,6EAA6E;AAC7E,MAAM,CAAC,MAAM,yBAAyB,GAAG,gCAAgC,CAAC;AAE1E;;;GAGG;AACH,MAAM,CAAC,MAAM,6BAA6B,GACxC,oCAAoC,CAAC","sourcesContent":["/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: BSD-3-Clause\n */\n\nexport interface TimelineLayer {\n id: string;\n label: string;\n color: number; // 0xRRGGBB\n}\n\nexport interface TimelineEvent<TData = unknown> {\n /**\n * Stable identity, stamped on the Node side (`${epoch}-${seq}`) when the\n * event is received, so it survives the stream, `recent-events` and a\n * snapshot export. Absent on events still in the page runtime.\n */\n id?: string;\n layerId: string;\n /**\n * Milliseconds since recording started, stamped in the browser page\n * (`performance.now()` re-zeroed on each recording start; see\n * `runtime/timeline/clock.ts`). Not comparable to any Node-side clock.\n */\n time: number;\n data: TData;\n title?: string;\n subtitle?: string;\n /** Pairs a start event with its matching end event in the same update group. */\n groupId?: number | string;\n logType?: 'default' | 'warning' | 'error';\n meta?: {\n elementId?: number;\n tagName?: string;\n source?: {file: string; line: number};\n };\n}\n\nexport interface TimelineLayersState {\n recordingState: boolean;\n litLifecycleEnabled: boolean;\n litRenderEnabled: boolean;\n /**\n * Per-part `lit-debug` events (`template updating`, `set part`, `commit\n * *`, …) — one per binding on *every* render, so a ticking clock or\n * animation floods the layer. Off by default; the `lit-render` layer's\n * begin/end render pair already covers the common case.\n */\n litRenderVerboseEnabled: boolean;\n mouseEventEnabled: boolean;\n keyboardEventEnabled: boolean;\n}\n\nexport const TIMELINE_LAYERS: readonly TimelineLayer[] = [\n {id: 'lit-lifecycle', label: 'Lit Lifecycle', color: 0x4d63ff},\n {id: 'lit-render', label: 'Lit Render', color: 0x325cff},\n {id: 'lit-render-verbose', label: 'Lit Render (verbose)', color: 0x99aeff},\n {id: 'mouse', label: 'Mouse', color: 0xa451af},\n {id: 'keyboard', label: 'Keyboard', color: 0x8151af},\n];\n\nexport const DEFAULT_LAYERS_STATE: TimelineLayersState = {\n recordingState: false,\n litLifecycleEnabled: true,\n litRenderEnabled: true,\n litRenderVerboseEnabled: false,\n mouseEventEnabled: false,\n keyboardEventEnabled: false,\n};\n\n/**\n * Snapshot of the plugin's resolved feature settings, surfaced in the panel's\n * Settings tab. The plugin produces this at config time (explicit options >\n * LIT_PLUGIN_* env > defaults) and serves it from the panel server. It's the\n * baseline the panel shows; some HMR settings can then be overridden live (see\n * {@link SettingsOverride}).\n */\nexport interface FeatureSettings {\n hmr: {\n enabled: boolean;\n reconnect: boolean;\n onIncompatible: 'reload' | 'warn';\n indicatorEnabled: boolean;\n indicatorCount: boolean;\n };\n sourceOverlay: {\n enabled: boolean;\n /** Hotkey letter combined with Ctrl+Shift to toggle the overlay. */\n key: string;\n editor: string;\n throttleMs: number;\n };\n timeline: boolean;\n /**\n * Which layer supplied each setting, keyed like {@link SettingsOverride}\n * (plus the read-only source-overlay rows). Lets the panel label a value\n * \"Zed (env)\" and name the baseline a panel override replaced. Optional so\n * older producers (and snapshots) without it still type-check.\n */\n sources?: SettingSources;\n}\n\n/**\n * Where a resolved setting came from, in precedence order after a panel\n * override: an explicit `litPlugin({...})` option, a `LIT_PLUGIN_*` env var,\n * or the built-in default.\n */\nexport type SettingSource = 'option' | 'env' | 'default';\n\n/** Per-setting {@link SettingSource}, as carried on {@link FeatureSettings}. */\nexport interface SettingSources {\n hmrReconnect?: SettingSource;\n hmrOnIncompatible?: SettingSource;\n hmrIndicatorVisible?: SettingSource;\n hmrIndicatorCount?: SettingSource;\n sourceOverlayEditor?: SettingSource;\n sourceOverlayKey?: SettingSource;\n sourceOverlayThrottleMs?: SettingSource;\n}\n\n/**\n * Runtime overrides the panel applies on top of the resolved env config, for\n * settings whose runtime is already injected (so they can change live). A\n * feature disabled at config time has no runtime, so it can't be enabled here\n * — only the behaviour of already-enabled features is overridable.\n *\n * Persisted under {@link SETTINGS_OVERRIDE_LS_KEY} (the panel and app share an\n * origin) so overrides survive reloads, and pushed live over\n * {@link SETTINGS_OVERRIDE_CHANNEL} via Vite HMR for immediate effect.\n */\nexport interface SettingsOverride {\n hmrReconnect?: boolean;\n hmrOnIncompatible?: 'reload' | 'warn';\n hmrIndicatorVisible?: boolean;\n hmrIndicatorCount?: boolean;\n /** Built-in editor key for the source overlay's open-in-editor target. */\n sourceOverlayEditor?: string;\n /**\n * Flash a short outline over every Lit element that completes an update.\n * Pure preference (no config-time baseline), so `undefined` reads as off.\n */\n flashUpdates?: boolean;\n /**\n * Colour the flash by how often the element updated in the last second,\n * calm to hot, instead of one flat colour. Only meaningful with\n * {@link SettingsOverride.flashUpdates}.\n */\n flashUpdatesRamp?: boolean;\n}\n\n/**\n * Built-in editors the source overlay can open files in. Keep in sync with\n * BUILTIN_EDITORS in lib/runtime/source-overlay/editors.ts.\n */\nexport const SOURCE_OVERLAY_EDITORS: ReadonlyArray<{\n value: string;\n label: string;\n}> = [\n {value: 'vscode', label: 'VS Code'},\n {value: 'cursor', label: 'Cursor'},\n {value: 'zed', label: 'Zed'},\n {value: 'idea', label: 'IntelliJ'},\n {value: 'windsurf', label: 'Windsurf'},\n];\n\n/** localStorage key holding the {@link SettingsOverride}. */\nexport const SETTINGS_OVERRIDE_LS_KEY = 'lit-devtools-overrides';\n\n/**\n * The resolved config value each overridden key was set against, recorded so\n * the Settings tab can notice when `.env` or plugin options moved on. Kept\n * beside the {@link SettingsOverride}, never inside it: the runtime applies and\n * receives the override as-is and has no use for these.\n */\nexport type OverrideBaselines = Partial<\n Record<\n | 'hmrReconnect'\n | 'hmrOnIncompatible'\n | 'hmrIndicatorVisible'\n | 'hmrIndicatorCount'\n | 'sourceOverlayEditor',\n unknown\n >\n>;\n\n/** localStorage key holding the {@link OverrideBaselines}. */\nexport const OVERRIDE_BASELINES_LS_KEY = 'lit-devtools-override-baselines';\n\n/** Vite HMR channel the server uses to push overrides to the app runtime. */\nexport const SETTINGS_OVERRIDE_CHANNEL = 'lit-devtools:settings-override';\n\n/**\n * Vite HMR channel the DevTools \"toggle source overlay\" command uses to tell\n * the app runtime to toggle the overlay (the command handler runs server-side).\n */\nexport const SOURCE_OVERLAY_TOGGLE_CHANNEL =\n 'lit-devtools:toggle-source-overlay';\n"]}
|