@treelocator/runtime 0.5.2 → 0.6.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 (163) hide show
  1. package/.eslintignore +1 -0
  2. package/dist/_generated_styles.d.ts +1 -1
  3. package/dist/_generated_styles.js +20 -0
  4. package/dist/_generated_tree_icon.d.ts +1 -1
  5. package/dist/adapters/HtmlElementTreeNode.d.ts +2 -2
  6. package/dist/adapters/HtmlElementTreeNode.js +4 -6
  7. package/dist/adapters/createTreeNode.js +17 -44
  8. package/dist/adapters/detectFramework.d.ts +8 -0
  9. package/dist/adapters/detectFramework.js +25 -0
  10. package/dist/adapters/detectFramework.test.d.ts +1 -0
  11. package/dist/adapters/detectFramework.test.js +60 -0
  12. package/dist/adapters/jsx/jsxAdapter.js +54 -89
  13. package/dist/adapters/jsx/jsxAdapter.test.d.ts +1 -0
  14. package/dist/adapters/jsx/jsxAdapter.test.js +273 -0
  15. package/dist/adapters/nextjs/parseNextjsDataAttributes.js +1 -1
  16. package/dist/adapters/nextjs/parseNextjsDataAttributes.test.d.ts +1 -0
  17. package/dist/adapters/nextjs/parseNextjsDataAttributes.test.js +158 -0
  18. package/dist/adapters/react/findFiberByHtmlElement.d.ts +1 -1
  19. package/dist/adapters/react/findFiberByHtmlElement.js +1 -1
  20. package/dist/adapters/react/getAllParentsElementsAndRootComponent.js +4 -0
  21. package/dist/adapters/resolveAdapter.d.ts +1 -1
  22. package/dist/adapters/resolveAdapter.js +4 -8
  23. package/dist/adapters/svelte/svelteAdapter.test.d.ts +1 -0
  24. package/dist/adapters/svelte/svelteAdapter.test.js +280 -0
  25. package/dist/adapters/vue/vueAdapter.test.d.ts +1 -0
  26. package/dist/adapters/vue/vueAdapter.test.js +222 -0
  27. package/dist/browserApi.d.ts +148 -0
  28. package/dist/browserApi.js +146 -5
  29. package/dist/browserApi.test.d.ts +1 -0
  30. package/dist/browserApi.test.js +287 -0
  31. package/dist/components/RecordingPillButton.d.ts +11 -0
  32. package/dist/components/RecordingPillButton.js +202 -0
  33. package/dist/components/RecordingResults.d.ts +2 -0
  34. package/dist/components/RecordingResults.js +213 -78
  35. package/dist/components/Runtime.js +161 -554
  36. package/dist/components/SettingsPanel.d.ts +5 -0
  37. package/dist/components/SettingsPanel.js +312 -0
  38. package/dist/consoleCapture.d.ts +9 -0
  39. package/dist/consoleCapture.js +95 -0
  40. package/dist/functions/cssRuleInspector.d.ts +83 -0
  41. package/dist/functions/cssRuleInspector.js +608 -0
  42. package/dist/functions/cssRuleInspector.test.d.ts +1 -0
  43. package/dist/functions/cssRuleInspector.test.js +439 -0
  44. package/dist/functions/deduplicateLabels.test.d.ts +1 -0
  45. package/dist/functions/deduplicateLabels.test.js +178 -0
  46. package/dist/functions/enrichAncestrySourceMaps.js +0 -1
  47. package/dist/functions/extractComputedStyles.d.ts +51 -0
  48. package/dist/functions/extractComputedStyles.js +447 -0
  49. package/dist/functions/extractComputedStyles.test.d.ts +1 -0
  50. package/dist/functions/extractComputedStyles.test.js +549 -0
  51. package/dist/functions/formatAncestryChain.d.ts +8 -0
  52. package/dist/functions/formatAncestryChain.js +21 -1
  53. package/dist/functions/formatAncestryChain.test.js +18 -0
  54. package/dist/functions/getUsableName.test.d.ts +1 -0
  55. package/dist/functions/getUsableName.test.js +219 -0
  56. package/dist/functions/isCombinationModifiersPressed.test.d.ts +1 -0
  57. package/dist/functions/isCombinationModifiersPressed.test.js +192 -0
  58. package/dist/functions/mergeRects.test.js +210 -1
  59. package/dist/functions/namedSnapshots.d.ts +52 -0
  60. package/dist/functions/namedSnapshots.js +161 -0
  61. package/dist/functions/namedSnapshots.test.d.ts +1 -0
  62. package/dist/functions/namedSnapshots.test.js +85 -0
  63. package/dist/functions/normalizeFilePath.test.d.ts +1 -0
  64. package/dist/functions/normalizeFilePath.test.js +66 -0
  65. package/dist/functions/parseDataId.test.d.ts +1 -0
  66. package/dist/functions/parseDataId.test.js +101 -0
  67. package/dist/hooks/getStorage.d.ts +3 -0
  68. package/dist/hooks/getStorage.js +17 -0
  69. package/dist/hooks/useEventListeners.d.ts +15 -0
  70. package/dist/hooks/useEventListeners.js +56 -0
  71. package/dist/hooks/useLocatorStorage.d.ts +18 -0
  72. package/dist/hooks/useLocatorStorage.js +41 -0
  73. package/dist/hooks/useLocatorStorage.test.d.ts +1 -0
  74. package/dist/hooks/useLocatorStorage.test.js +124 -0
  75. package/dist/hooks/useRecordingState.d.ts +43 -0
  76. package/dist/hooks/useRecordingState.js +387 -0
  77. package/dist/hooks/useSettings.d.ts +13 -0
  78. package/dist/hooks/useSettings.js +66 -0
  79. package/dist/index.d.ts +5 -2
  80. package/dist/index.js +4 -2
  81. package/dist/initRuntime.d.ts +3 -1
  82. package/dist/initRuntime.js +4 -1
  83. package/dist/mcpBridge.d.ts +61 -0
  84. package/dist/mcpBridge.js +534 -0
  85. package/dist/mcpBridge.test.d.ts +1 -0
  86. package/dist/mcpBridge.test.js +248 -0
  87. package/dist/output.css +20 -0
  88. package/dist/visualDiff/diff.d.ts +9 -0
  89. package/dist/visualDiff/diff.js +209 -0
  90. package/dist/visualDiff/diff.test.d.ts +1 -0
  91. package/dist/visualDiff/diff.test.js +253 -0
  92. package/dist/visualDiff/settle.d.ts +3 -0
  93. package/dist/visualDiff/settle.js +50 -0
  94. package/dist/visualDiff/settle.test.d.ts +1 -0
  95. package/dist/visualDiff/settle.test.js +65 -0
  96. package/dist/visualDiff/snapshot.d.ts +4 -0
  97. package/dist/visualDiff/snapshot.js +84 -0
  98. package/dist/visualDiff/snapshot.test.d.ts +1 -0
  99. package/dist/visualDiff/snapshot.test.js +245 -0
  100. package/dist/visualDiff/types.d.ts +37 -0
  101. package/dist/visualDiff/types.js +1 -0
  102. package/package.json +2 -2
  103. package/scripts/wrapCSS.js +1 -1
  104. package/scripts/wrapImage.js +1 -1
  105. package/src/_generated_styles.ts +21 -1
  106. package/src/_generated_tree_icon.ts +1 -1
  107. package/src/adapters/HtmlElementTreeNode.ts +10 -7
  108. package/src/adapters/createTreeNode.ts +12 -51
  109. package/src/adapters/detectFramework.test.ts +73 -0
  110. package/src/adapters/detectFramework.ts +28 -0
  111. package/src/adapters/jsx/jsxAdapter.test.ts +240 -0
  112. package/src/adapters/jsx/jsxAdapter.ts +53 -106
  113. package/src/adapters/nextjs/parseNextjsDataAttributes.test.ts +212 -0
  114. package/src/adapters/nextjs/parseNextjsDataAttributes.ts +1 -1
  115. package/src/adapters/react/findDebugSource.ts +5 -6
  116. package/src/adapters/react/findFiberByHtmlElement.ts +3 -3
  117. package/src/adapters/react/getAllParentsElementsAndRootComponent.ts +3 -0
  118. package/src/adapters/react/reactAdapter.ts +1 -2
  119. package/src/adapters/resolveAdapter.ts +4 -14
  120. package/src/adapters/svelte/svelteAdapter.test.ts +334 -0
  121. package/src/adapters/vue/vueAdapter.test.ts +259 -0
  122. package/src/browserApi.test.ts +329 -0
  123. package/src/browserApi.ts +351 -4
  124. package/src/components/RecordingPillButton.tsx +301 -0
  125. package/src/components/RecordingResults.tsx +114 -13
  126. package/src/components/Runtime.tsx +176 -621
  127. package/src/components/SettingsPanel.tsx +339 -0
  128. package/src/consoleCapture.ts +113 -0
  129. package/src/functions/cssRuleInspector.test.ts +517 -0
  130. package/src/functions/cssRuleInspector.ts +708 -0
  131. package/src/functions/deduplicateLabels.test.ts +115 -0
  132. package/src/functions/enrichAncestrySourceMaps.ts +6 -3
  133. package/src/functions/extractComputedStyles.test.ts +681 -0
  134. package/src/functions/extractComputedStyles.ts +768 -0
  135. package/src/functions/formatAncestryChain.test.ts +23 -1
  136. package/src/functions/formatAncestryChain.ts +22 -1
  137. package/src/functions/getUsableName.test.ts +242 -0
  138. package/src/functions/isCombinationModifiersPressed.test.ts +156 -0
  139. package/src/functions/mergeRects.test.ts +111 -1
  140. package/src/functions/namedSnapshots.test.ts +106 -0
  141. package/src/functions/namedSnapshots.ts +232 -0
  142. package/src/functions/normalizeFilePath.test.ts +80 -0
  143. package/src/functions/parseDataId.test.ts +125 -0
  144. package/src/hooks/getStorage.ts +26 -0
  145. package/src/hooks/useEventListeners.ts +97 -0
  146. package/src/hooks/useLocatorStorage.test.ts +127 -0
  147. package/src/hooks/useLocatorStorage.ts +60 -0
  148. package/src/hooks/useRecordingState.ts +516 -0
  149. package/src/hooks/useSettings.ts +83 -0
  150. package/src/index.ts +10 -5
  151. package/src/initRuntime.ts +5 -0
  152. package/src/mcpBridge.test.ts +260 -0
  153. package/src/mcpBridge.ts +677 -0
  154. package/src/visualDiff/diff.test.ts +167 -0
  155. package/src/visualDiff/diff.ts +242 -0
  156. package/src/visualDiff/settle.test.ts +77 -0
  157. package/src/visualDiff/settle.ts +62 -0
  158. package/src/visualDiff/snapshot.test.ts +200 -0
  159. package/src/visualDiff/snapshot.ts +119 -0
  160. package/src/visualDiff/types.ts +40 -0
  161. package/tsconfig.json +3 -1
  162. package/vitest.config.ts +18 -0
  163. package/jest.config.ts +0 -195
@@ -0,0 +1,5 @@
1
+ type SettingsPanelProps = {
2
+ onDismiss: () => void;
3
+ };
4
+ export declare function SettingsPanel(props: SettingsPanelProps): import("solid-js").JSX.Element;
5
+ export {};
@@ -0,0 +1,312 @@
1
+ import { template as _$template } from "solid-js/web";
2
+ import { delegateEvents as _$delegateEvents } from "solid-js/web";
3
+ import { style as _$style } from "solid-js/web";
4
+ import { createComponent as _$createComponent } from "solid-js/web";
5
+ import { addEventListener as _$addEventListener } from "solid-js/web";
6
+ import { insert as _$insert } from "solid-js/web";
7
+ import { setAttribute as _$setAttribute } from "solid-js/web";
8
+ import { effect as _$effect } from "solid-js/web";
9
+ import { setStyleProperty as _$setStyleProperty } from "solid-js/web";
10
+ var _tmpl$ = /*#__PURE__*/_$template(`<div role=switch style=border-radius:9px;flex-shrink:0><div style=border-radius:50%>`),
11
+ _tmpl$2 = /*#__PURE__*/_$template(`<div style=align-items:center;flex-shrink:0><input type=number style=border-radius:4px;font-family:inherit;font-size:11px;text-align:right><span style=font-size:11px;min-width:18px>`),
12
+ _tmpl$3 = /*#__PURE__*/_$template(`<div data-treelocator-settings-panel style="z-index:2147483646;max-height:400px;overflow-y:auto;backdrop-filter:blur(12px);border-radius:12px;box-shadow:0 8px 32px rgba(0, 0, 0, 0.4);font-family:system-ui, -apple-system, sans-serif;font-size:12px;pointer-events:auto"><div style="align-items:center;justify-content:space-between;border-bottom:1px solid rgba(255, 255, 255, 0.08)"><div><div style=font-weight:600;font-size:13px>Settings</div><div style=margin-top:2px>Persisted to localStorage</div></div><div style=align-items:center><div style=border-radius:4px;font-size:11px;font-weight:600>Reset</div><div style=border-radius:4px;font-size:16px;line-height:1>&times;</div></div></div><div><div>Features</div></div><div style="border-top:1px solid rgba(255, 255, 255, 0.08)"><div>Thresholds</div><div style=font-size:11px;margin-top:8px>Defaults: sample <!>Hz, max <!>ms, jump <!>px, lag <!>ms`),
13
+ _tmpl$4 = /*#__PURE__*/_$template(`<div><div><div></div><div>`);
14
+ import { For } from "solid-js";
15
+ import { DEFAULT_SETTINGS, resetSettings, setSetting, settings } from "../hooks/useSettings";
16
+ const TOGGLES = [{
17
+ key: "anomalyTracking",
18
+ label: "Anomaly tracking",
19
+ hint: "Detect jitter, jumps, stutter, stuck frames"
20
+ }, {
21
+ key: "visualDiff",
22
+ label: "Visual diff",
23
+ hint: "Snapshot before/after element tree"
24
+ }, {
25
+ key: "computedStyles",
26
+ label: "Computed styles",
27
+ hint: "Include styles in alt+click clipboard output"
28
+ }, {
29
+ key: "computedStylesIncludeDefaults",
30
+ label: "Include default styles",
31
+ hint: "Show browser-default values like display:block and font-weight:bold"
32
+ }];
33
+ const NUMBERS = [{
34
+ key: "sampleRate",
35
+ label: "Sample rate",
36
+ hint: "Max frames per second to capture",
37
+ unit: "Hz",
38
+ min: 1,
39
+ max: 60,
40
+ step: 1
41
+ }, {
42
+ key: "maxDurationMs",
43
+ label: "Max duration",
44
+ hint: "Auto-stop recording after this long",
45
+ unit: "ms",
46
+ min: 1000,
47
+ max: 120000,
48
+ step: 1000
49
+ }, {
50
+ key: "jumpMinAbsolute",
51
+ label: "Jump threshold",
52
+ hint: "Minimum px delta to flag a jump",
53
+ unit: "px",
54
+ min: 1,
55
+ max: 1000,
56
+ step: 1
57
+ }, {
58
+ key: "lagMinDelay",
59
+ label: "Lag threshold",
60
+ hint: "Minimum rAF delay to flag lag",
61
+ unit: "ms",
62
+ min: 1,
63
+ max: 1000,
64
+ step: 1
65
+ }];
66
+ const rowStyle = {
67
+ display: "flex",
68
+ "align-items": "center",
69
+ "justify-content": "space-between",
70
+ gap: "12px",
71
+ padding: "8px 0",
72
+ "border-bottom": "1px solid rgba(255, 255, 255, 0.05)"
73
+ };
74
+ const labelStyle = {
75
+ "min-width": "0",
76
+ flex: "1 1 auto"
77
+ };
78
+ const labelTitle = {
79
+ "font-weight": "600",
80
+ color: "#fff"
81
+ };
82
+ const labelHint = {
83
+ color: "#9ca3af",
84
+ "font-size": "11px",
85
+ "margin-top": "2px",
86
+ "line-height": "1.3"
87
+ };
88
+ const sectionTitleStyle = {
89
+ "margin-bottom": "4px",
90
+ color: "#9ca3af",
91
+ "font-size": "11px",
92
+ "text-transform": "uppercase",
93
+ "letter-spacing": "0.5px"
94
+ };
95
+ function Toggle(props) {
96
+ return (() => {
97
+ var _el$ = _tmpl$(),
98
+ _el$2 = _el$.firstChild;
99
+ _el$.$$click = () => props.onChange(!props.checked);
100
+ _$setStyleProperty(_el$, "cursor", "pointer");
101
+ _$setStyleProperty(_el$, "width", "32px");
102
+ _$setStyleProperty(_el$, "height", "18px");
103
+ _$setStyleProperty(_el$, "position", "relative");
104
+ _$setStyleProperty(_el$, "transition", "background 0.15s");
105
+ _$setStyleProperty(_el$2, "position", "absolute");
106
+ _$setStyleProperty(_el$2, "top", "2px");
107
+ _$setStyleProperty(_el$2, "width", "14px");
108
+ _$setStyleProperty(_el$2, "height", "14px");
109
+ _$setStyleProperty(_el$2, "background", "#fff");
110
+ _$setStyleProperty(_el$2, "transition", "left 0.15s");
111
+ _$effect(_p$ => {
112
+ var _v$ = props.checked,
113
+ _v$2 = props.checked ? "rgba(59, 130, 246, 0.6)" : "rgba(255, 255, 255, 0.12)",
114
+ _v$3 = props.checked ? "16px" : "2px";
115
+ _v$ !== _p$.e && _$setAttribute(_el$, "aria-checked", _p$.e = _v$);
116
+ _v$2 !== _p$.t && _$setStyleProperty(_el$, "background", _p$.t = _v$2);
117
+ _v$3 !== _p$.a && _$setStyleProperty(_el$2, "left", _p$.a = _v$3);
118
+ return _p$;
119
+ }, {
120
+ e: undefined,
121
+ t: undefined,
122
+ a: undefined
123
+ });
124
+ return _el$;
125
+ })();
126
+ }
127
+ function NumberInput(props) {
128
+ return (() => {
129
+ var _el$3 = _tmpl$2(),
130
+ _el$4 = _el$3.firstChild,
131
+ _el$5 = _el$4.nextSibling;
132
+ _$setStyleProperty(_el$3, "display", "flex");
133
+ _$setStyleProperty(_el$3, "gap", "4px");
134
+ _el$4.$$input = e => {
135
+ const n = Number(e.currentTarget.value);
136
+ if (!Number.isFinite(n)) return;
137
+ const clamped = Math.min(props.max, Math.max(props.min, n));
138
+ props.onChange(clamped);
139
+ };
140
+ _$setStyleProperty(_el$4, "width", "72px");
141
+ _$setStyleProperty(_el$4, "padding", "4px 6px");
142
+ _$setStyleProperty(_el$4, "background", "rgba(255, 255, 255, 0.08)");
143
+ _$setStyleProperty(_el$4, "border", "1px solid rgba(255, 255, 255, 0.1)");
144
+ _$setStyleProperty(_el$4, "color", "#fff");
145
+ _$setStyleProperty(_el$4, "outline", "none");
146
+ _$setStyleProperty(_el$5, "color", "#9ca3af");
147
+ _$insert(_el$5, () => props.unit);
148
+ _$effect(_p$ => {
149
+ var _v$4 = props.min,
150
+ _v$5 = props.max,
151
+ _v$6 = props.step;
152
+ _v$4 !== _p$.e && _$setAttribute(_el$4, "min", _p$.e = _v$4);
153
+ _v$5 !== _p$.t && _$setAttribute(_el$4, "max", _p$.t = _v$5);
154
+ _v$6 !== _p$.a && _$setAttribute(_el$4, "step", _p$.a = _v$6);
155
+ return _p$;
156
+ }, {
157
+ e: undefined,
158
+ t: undefined,
159
+ a: undefined
160
+ });
161
+ _$effect(() => _el$4.value = props.value);
162
+ return _el$3;
163
+ })();
164
+ }
165
+ export function SettingsPanel(props) {
166
+ const current = () => settings();
167
+ return (() => {
168
+ var _el$6 = _tmpl$3(),
169
+ _el$7 = _el$6.firstChild,
170
+ _el$8 = _el$7.firstChild,
171
+ _el$9 = _el$8.firstChild,
172
+ _el$0 = _el$9.nextSibling,
173
+ _el$1 = _el$8.nextSibling,
174
+ _el$10 = _el$1.firstChild,
175
+ _el$11 = _el$10.nextSibling,
176
+ _el$12 = _el$7.nextSibling,
177
+ _el$13 = _el$12.firstChild,
178
+ _el$14 = _el$12.nextSibling,
179
+ _el$15 = _el$14.firstChild,
180
+ _el$16 = _el$15.nextSibling,
181
+ _el$17 = _el$16.firstChild,
182
+ _el$23 = _el$17.nextSibling,
183
+ _el$18 = _el$23.nextSibling,
184
+ _el$24 = _el$18.nextSibling,
185
+ _el$20 = _el$24.nextSibling,
186
+ _el$25 = _el$20.nextSibling,
187
+ _el$21 = _el$25.nextSibling,
188
+ _el$26 = _el$21.nextSibling,
189
+ _el$22 = _el$26.nextSibling;
190
+ _$setStyleProperty(_el$6, "position", "fixed");
191
+ _$setStyleProperty(_el$6, "bottom", "180px");
192
+ _$setStyleProperty(_el$6, "right", "20px");
193
+ _$setStyleProperty(_el$6, "width", "340px");
194
+ _$setStyleProperty(_el$6, "background", "rgba(15, 15, 15, 0.92)");
195
+ _$setStyleProperty(_el$6, "border", "1px solid rgba(255, 255, 255, 0.1)");
196
+ _$setStyleProperty(_el$6, "color", "#e5e5e5");
197
+ _$setStyleProperty(_el$7, "display", "flex");
198
+ _$setStyleProperty(_el$7, "padding", "12px 14px 8px");
199
+ _$setStyleProperty(_el$9, "color", "#fff");
200
+ _$setStyleProperty(_el$0, "color", "#9ca3af");
201
+ _$setStyleProperty(_el$1, "display", "flex");
202
+ _$setStyleProperty(_el$1, "gap", "4px");
203
+ _$addEventListener(_el$10, "click", resetSettings, true);
204
+ _$setStyleProperty(_el$10, "cursor", "pointer");
205
+ _$setStyleProperty(_el$10, "padding", "4px 10px");
206
+ _$setStyleProperty(_el$10, "background", "rgba(255, 255, 255, 0.08)");
207
+ _$setStyleProperty(_el$10, "color", "#9ca3af");
208
+ _$addEventListener(_el$11, "click", props.onDismiss, true);
209
+ _$setStyleProperty(_el$11, "cursor", "pointer");
210
+ _$setStyleProperty(_el$11, "padding", "4px 8px");
211
+ _$setStyleProperty(_el$11, "color", "#9ca3af");
212
+ _$setStyleProperty(_el$12, "padding", "8px 14px");
213
+ _$insert(_el$12, _$createComponent(For, {
214
+ each: TOGGLES,
215
+ children: item => (() => {
216
+ var _el$27 = _tmpl$4(),
217
+ _el$28 = _el$27.firstChild,
218
+ _el$29 = _el$28.firstChild,
219
+ _el$30 = _el$29.nextSibling;
220
+ _$insert(_el$29, () => item.label);
221
+ _$insert(_el$30, () => item.hint);
222
+ _$insert(_el$27, _$createComponent(Toggle, {
223
+ get checked() {
224
+ return current()[item.key];
225
+ },
226
+ onChange: v => setSetting(item.key, v)
227
+ }), null);
228
+ _$effect(_p$ => {
229
+ var _v$9 = rowStyle,
230
+ _v$0 = labelStyle,
231
+ _v$1 = labelTitle,
232
+ _v$10 = labelHint;
233
+ _p$.e = _$style(_el$27, _v$9, _p$.e);
234
+ _p$.t = _$style(_el$28, _v$0, _p$.t);
235
+ _p$.a = _$style(_el$29, _v$1, _p$.a);
236
+ _p$.o = _$style(_el$30, _v$10, _p$.o);
237
+ return _p$;
238
+ }, {
239
+ e: undefined,
240
+ t: undefined,
241
+ a: undefined,
242
+ o: undefined
243
+ });
244
+ return _el$27;
245
+ })()
246
+ }), null);
247
+ _$setStyleProperty(_el$14, "padding", "8px 14px 12px");
248
+ _$insert(_el$14, _$createComponent(For, {
249
+ each: NUMBERS,
250
+ children: item => (() => {
251
+ var _el$31 = _tmpl$4(),
252
+ _el$32 = _el$31.firstChild,
253
+ _el$33 = _el$32.firstChild,
254
+ _el$34 = _el$33.nextSibling;
255
+ _$insert(_el$33, () => item.label);
256
+ _$insert(_el$34, () => item.hint);
257
+ _$insert(_el$31, _$createComponent(NumberInput, {
258
+ get value() {
259
+ return current()[item.key];
260
+ },
261
+ get min() {
262
+ return item.min;
263
+ },
264
+ get max() {
265
+ return item.max;
266
+ },
267
+ get step() {
268
+ return item.step;
269
+ },
270
+ get unit() {
271
+ return item.unit;
272
+ },
273
+ onChange: v => setSetting(item.key, v)
274
+ }), null);
275
+ _$effect(_p$ => {
276
+ var _v$11 = rowStyle,
277
+ _v$12 = labelStyle,
278
+ _v$13 = labelTitle,
279
+ _v$14 = labelHint;
280
+ _p$.e = _$style(_el$31, _v$11, _p$.e);
281
+ _p$.t = _$style(_el$32, _v$12, _p$.t);
282
+ _p$.a = _$style(_el$33, _v$13, _p$.a);
283
+ _p$.o = _$style(_el$34, _v$14, _p$.o);
284
+ return _p$;
285
+ }, {
286
+ e: undefined,
287
+ t: undefined,
288
+ a: undefined,
289
+ o: undefined
290
+ });
291
+ return _el$31;
292
+ })()
293
+ }), _el$16);
294
+ _$setStyleProperty(_el$16, "color", "#6b7280");
295
+ _$insert(_el$16, () => DEFAULT_SETTINGS.sampleRate, _el$23);
296
+ _$insert(_el$16, () => DEFAULT_SETTINGS.maxDurationMs, _el$24);
297
+ _$insert(_el$16, () => DEFAULT_SETTINGS.jumpMinAbsolute, _el$25);
298
+ _$insert(_el$16, () => DEFAULT_SETTINGS.lagMinDelay, _el$26);
299
+ _$effect(_p$ => {
300
+ var _v$7 = sectionTitleStyle,
301
+ _v$8 = sectionTitleStyle;
302
+ _p$.e = _$style(_el$13, _v$7, _p$.e);
303
+ _p$.t = _$style(_el$15, _v$8, _p$.t);
304
+ return _p$;
305
+ }, {
306
+ e: undefined,
307
+ t: undefined
308
+ });
309
+ return _el$6;
310
+ })();
311
+ }
312
+ _$delegateEvents(["click", "input"]);
@@ -0,0 +1,9 @@
1
+ export type ConsoleLevel = "log" | "info" | "warn" | "error" | "debug";
2
+ export interface ConsoleEntry {
3
+ level: ConsoleLevel;
4
+ timestamp: number;
5
+ message: string;
6
+ }
7
+ export declare function installConsoleCapture(): void;
8
+ export declare function getConsoleEntries(last?: number): ConsoleEntry[];
9
+ export declare function clearConsoleEntries(): void;
@@ -0,0 +1,95 @@
1
+ const MAX_ENTRIES = 500;
2
+ const LEVELS = ["log", "info", "warn", "error", "debug"];
3
+ const CAPTURE_FLAG = "__treelocator_console_captured__";
4
+ const entries = [];
5
+ function formatArg(value, seen) {
6
+ if (value === null) return "null";
7
+ if (value === undefined) return "undefined";
8
+ const t = typeof value;
9
+ if (t === "string") return value;
10
+ if (t === "number" || t === "boolean" || t === "bigint") return String(value);
11
+ if (t === "function") {
12
+ const name = value.name || "anonymous";
13
+ return `[Function: ${name}]`;
14
+ }
15
+ if (value instanceof Error) {
16
+ return `${value.name}: ${value.message}`;
17
+ }
18
+ if (typeof Element !== "undefined" && value instanceof Element) {
19
+ const el = value;
20
+ const id = el.id ? `#${el.id}` : "";
21
+ const cls = el.className && typeof el.className === "string" ? `.${el.className.trim().split(/\s+/).join(".")}` : "";
22
+ return `<${el.tagName.toLowerCase()}${id}${cls}>`;
23
+ }
24
+ if (t === "object") {
25
+ if (seen.has(value)) return "[Circular]";
26
+ seen.add(value);
27
+ try {
28
+ const localSeen = new WeakSet();
29
+ return JSON.stringify(value, (_key, v) => {
30
+ if (v === null || v === undefined) return v;
31
+ if (typeof v === "bigint") return v.toString();
32
+ if (typeof v === "function") return `[Function: ${v.name || "anonymous"}]`;
33
+ if (typeof v === "object") {
34
+ if (localSeen.has(v)) return "[Circular]";
35
+ localSeen.add(v);
36
+ }
37
+ return v;
38
+ });
39
+ } catch {
40
+ try {
41
+ return String(value);
42
+ } catch {
43
+ return "[Unserializable]";
44
+ }
45
+ }
46
+ }
47
+ return String(value);
48
+ }
49
+ function formatArgs(args) {
50
+ const seen = new WeakSet();
51
+ return args.map(arg => formatArg(arg, seen)).join(" ");
52
+ }
53
+ function pushEntry(level, args) {
54
+ entries.push({
55
+ level,
56
+ timestamp: Date.now(),
57
+ message: formatArgs(args)
58
+ });
59
+ if (entries.length > MAX_ENTRIES) {
60
+ entries.splice(0, entries.length - MAX_ENTRIES);
61
+ }
62
+ }
63
+ export function installConsoleCapture() {
64
+ if (typeof console === "undefined") return;
65
+ const target = console;
66
+ if (target[CAPTURE_FLAG]) return;
67
+ target[CAPTURE_FLAG] = true;
68
+ for (const level of LEVELS) {
69
+ const original = target[level];
70
+ if (typeof original !== "function") continue;
71
+ const wrapped = function (...args) {
72
+ try {
73
+ pushEntry(level, args);
74
+ } catch {
75
+ // Swallow — capture must never break logging.
76
+ }
77
+ return original.apply(this, args);
78
+ };
79
+ try {
80
+ target[level] = wrapped;
81
+ } catch {
82
+ // Some environments freeze console — ignore.
83
+ }
84
+ }
85
+ }
86
+ export function getConsoleEntries(last) {
87
+ if (typeof last !== "number" || !Number.isFinite(last) || last <= 0) {
88
+ return entries.slice();
89
+ }
90
+ const n = Math.min(Math.floor(last), entries.length);
91
+ return entries.slice(entries.length - n);
92
+ }
93
+ export function clearConsoleEntries() {
94
+ entries.length = 0;
95
+ }
@@ -0,0 +1,83 @@
1
+ /**
2
+ * CSS Rule Inspector
3
+ *
4
+ * Walks all loaded stylesheets, finds every rule that matches an element,
5
+ * calculates specificity, and determines which rule "wins" for each property.
6
+ * Designed to produce AI-friendly output for debugging CSS issues.
7
+ */
8
+ export type SpecificityTuple = [number, number, number];
9
+ export interface CSSRuleInfo {
10
+ selector: string;
11
+ property: string;
12
+ value: string;
13
+ specificity: SpecificityTuple;
14
+ important: boolean;
15
+ source: string;
16
+ /** Monotonic index in source order — higher = later in cascade. */
17
+ sourceIndex: number;
18
+ }
19
+ export interface CSSPropertyResult {
20
+ property: string;
21
+ value: string;
22
+ rules: {
23
+ selector: string;
24
+ value: string;
25
+ specificity: SpecificityTuple;
26
+ important: boolean;
27
+ source: string;
28
+ winning: boolean;
29
+ }[];
30
+ }
31
+ export interface CSSInspectionResult {
32
+ element: string;
33
+ properties: CSSPropertyResult[];
34
+ unreachableSheets: string[];
35
+ }
36
+ /**
37
+ * Calculate CSS specificity for a selector string.
38
+ *
39
+ * Returns [ids, classes, elements] where:
40
+ * - ids: count of #id selectors
41
+ * - classes: count of .class, [attr], :pseudo-class (except :not, :is, :where, :has)
42
+ * - elements: count of element, ::pseudo-element
43
+ *
44
+ * This is a lightweight parser that handles the vast majority of real-world
45
+ * selectors without pulling in a full CSS parser.
46
+ */
47
+ export declare function calculateSpecificity(selector: string): SpecificityTuple;
48
+ /**
49
+ * Compare two specificity tuples.
50
+ * Returns positive if a > b, negative if a < b, 0 if equal.
51
+ */
52
+ export declare function compareSpecificity(a: SpecificityTuple, b: SpecificityTuple): number;
53
+ /**
54
+ * Format specificity tuple as a human-readable string.
55
+ */
56
+ export declare function formatSpecificity(s: SpecificityTuple): string;
57
+ /**
58
+ * Describe an element for display: tagName.class1.class2#id
59
+ */
60
+ export declare function describeElement(element: Element): string;
61
+ /**
62
+ * Inspect an element and return all CSS rules grouped by property,
63
+ * showing which rule wins for each property.
64
+ */
65
+ export declare function inspectCSSRules(element: Element): CSSInspectionResult;
66
+ /**
67
+ * Format CSS inspection result as a human-readable string for AI consumption.
68
+ *
69
+ * Example output:
70
+ *
71
+ * CSS Rules for button.primary#submit
72
+ * ════════════════════════════════════
73
+ *
74
+ * color: #333
75
+ * ✓ .button.primary (0,2,0) — components.css
76
+ * ✗ .button (0,1,0) — base.css
77
+ * ✗ button (0,0,1) — reset.css
78
+ *
79
+ * font-size: 14px
80
+ * ✓ element.style (inline) — inline
81
+ * ✗ .button (0,1,0) — base.css
82
+ */
83
+ export declare function formatCSSInspection(result: CSSInspectionResult): string;