@reckona/mreact-devtools 0.0.182 → 0.0.183

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.
@@ -1 +1 @@
1
- {"version":3,"file":"overlay.d.ts","sourceRoot":"","sources":["../src/overlay.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,QAAQ,EAEd,MAAM,YAAY,CAAC;AAEpB,qDAAqD;AACrD,YAAY,EAAE,QAAQ,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAE5E,uEAAuE;AACvE,MAAM,MAAM,kBAAkB,GAAG,OAAO,GAAG,UAAU,GAAG,QAAQ,CAAC;AAEjE,iGAAiG;AACjG,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAC;IAChC,QAAQ,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAC;IAChC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAChC;AAED,qEAAqE;AACrE,MAAM,WAAW,sBAAsB;IACrC,QAAQ,EAAE,QAAQ,CAAC;IACnB,OAAO,IAAI,IAAI,CAAC;IAChB,OAAO,EAAE,WAAW,CAAC;CACtB;AAgBD,sFAAsF;AACtF,wBAAgB,oBAAoB,CAClC,OAAO,GAAE,sBAA2B,GACnC,sBAAsB,CAiIxB"}
1
+ {"version":3,"file":"overlay.d.ts","sourceRoot":"","sources":["../src/overlay.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,QAAQ,EAEd,MAAM,YAAY,CAAC;AAEpB,qDAAqD;AACrD,YAAY,EAAE,QAAQ,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAE5E,uEAAuE;AACvE,MAAM,MAAM,kBAAkB,GAAG,OAAO,GAAG,UAAU,GAAG,QAAQ,CAAC;AAEjE,iGAAiG;AACjG,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAC;IAChC,QAAQ,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAC;IAChC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAChC;AAED,qEAAqE;AACrE,MAAM,WAAW,sBAAsB;IACrC,QAAQ,EAAE,QAAQ,CAAC;IACnB,OAAO,IAAI,IAAI,CAAC;IAChB,OAAO,EAAE,WAAW,CAAC;CACtB;AAgBD,sFAAsF;AACtF,wBAAgB,oBAAoB,CAAC,OAAO,GAAE,sBAA2B,GAAG,sBAAsB,CAuIjG"}
package/dist/overlay.js CHANGED
@@ -14,6 +14,7 @@ export function mountDevtoolsOverlay(options = {}) {
14
14
  const events = devtools.events().slice(-maxEvents);
15
15
  const element = ownerDocument.createElement("section");
16
16
  const tabList = ownerDocument.createElement("nav");
17
+ const summaryList = ownerDocument.createElement("div");
17
18
  const eventList = ownerDocument.createElement("ol");
18
19
  let activeTab = "reactive";
19
20
  let disposed = false;
@@ -51,7 +52,11 @@ export function mountDevtoolsOverlay(options = {}) {
51
52
  overflow: "auto",
52
53
  padding: "0",
53
54
  });
54
- element.append(tabList, eventList);
55
+ Object.assign(summaryList.style, {
56
+ display: "grid",
57
+ gap: "6px",
58
+ });
59
+ element.append(tabList, summaryList, eventList);
55
60
  ownerDocument.body.append(element);
56
61
  const unsubscribe = devtools.subscribe((event) => {
57
62
  events.push(event);
@@ -75,6 +80,7 @@ export function mountDevtoolsOverlay(options = {}) {
75
80
  return;
76
81
  }
77
82
  tabList.replaceChildren(...tabs.map((tab) => renderTab(ownerDocument, tab)));
83
+ summaryList.replaceChildren(...renderSummary(ownerDocument, activeTab, events));
78
84
  const visibleEvents = [...events].filter((event) => eventTab(event) === activeTab).reverse();
79
85
  if (visibleEvents.length === 0) {
80
86
  const empty = ownerDocument.createElement("li");
@@ -124,6 +130,65 @@ export function mountDevtoolsOverlay(options = {}) {
124
130
  return button;
125
131
  }
126
132
  }
133
+ function renderSummary(doc, activeTab, events) {
134
+ if (activeTab !== "query") {
135
+ return [];
136
+ }
137
+ const queries = latestQueryStates(events);
138
+ if (queries.length === 0) {
139
+ return [];
140
+ }
141
+ const section = doc.createElement("section");
142
+ const heading = doc.createElement("div");
143
+ const list = doc.createElement("ol");
144
+ heading.textContent = "Current queries";
145
+ Object.assign(section.style, {
146
+ background: "#121a25",
147
+ border: "1px solid #303846",
148
+ borderRadius: "6px",
149
+ display: "grid",
150
+ gap: "4px",
151
+ padding: "8px",
152
+ });
153
+ Object.assign(heading.style, {
154
+ color: "#ffffff",
155
+ fontWeight: "700",
156
+ });
157
+ Object.assign(list.style, {
158
+ display: "grid",
159
+ gap: "3px",
160
+ listStyle: "none",
161
+ margin: "0",
162
+ padding: "0",
163
+ });
164
+ list.replaceChildren(...queries.map((query) => renderQuerySummary(doc, query)));
165
+ section.append(heading, list);
166
+ return [section];
167
+ }
168
+ function latestQueryStates(events) {
169
+ const byHash = new Map();
170
+ for (const event of events) {
171
+ if (event.type !== "query:update" || typeof event.queryHash !== "string") {
172
+ continue;
173
+ }
174
+ byHash.set(event.queryHash, {
175
+ hash: event.queryHash,
176
+ isFetching: event.isFetching === true,
177
+ stale: event.stale === true,
178
+ status: typeof event.status === "string" ? event.status : "unknown",
179
+ });
180
+ }
181
+ return Array.from(byHash.values()).sort((left, right) => left.hash.localeCompare(right.hash));
182
+ }
183
+ function renderQuerySummary(doc, query) {
184
+ const item = doc.createElement("li");
185
+ item.textContent = `${query.hash} | ${query.status}${query.isFetching ? " | fetching" : ""}${query.stale ? " | stale" : ""}`;
186
+ Object.assign(item.style, {
187
+ color: "#c8d7ec",
188
+ overflowWrap: "anywhere",
189
+ });
190
+ return item;
191
+ }
127
192
  function renderEvent(doc, event) {
128
193
  const item = doc.createElement("li");
129
194
  const title = doc.createElement("div");
@@ -1 +1 @@
1
- {"version":3,"file":"overlay.js","sourceRoot":"","sources":["../src/overlay.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,cAAc,EACd,oBAAoB,EACpB,eAAe,GAGhB,MAAM,YAAY,CAAC;AA2BpB,MAAM,IAAI,GAA6B;IACrC,EAAE,KAAK,EAAE,UAAU,EAAE,GAAG,EAAE,UAAU,EAAE;IACtC,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE;IAChC,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,EAAE,QAAQ,EAAE;CACnC,CAAC;AAEF,MAAM,gBAAgB,GAAG,GAAG,CAAC;AAC7B,MAAM,qBAAqB,GAAG,KAAK,CAAC;AAEpC,sFAAsF;AACtF,MAAM,UAAU,oBAAoB,CAClC,UAAkC,EAAE;IAEpC,MAAM,aAAa,GAAG,OAAO,CAAC,QAAQ,IAAI,kBAAkB,EAAE,CAAC;IAC/D,MAAM,SAAS,GAAG,kBAAkB,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IACxD,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,oBAAoB,EAAE,IAAI,eAAe,CAAC,cAAc,EAAE,CAAC,CAAC;IACjG,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,CAAC;IACnD,MAAM,OAAO,GAAG,aAAa,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC;IACvD,MAAM,OAAO,GAAG,aAAa,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;IACnD,MAAM,SAAS,GAAG,aAAa,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;IACpD,IAAI,SAAS,GAAuB,UAAU,CAAC;IAC/C,IAAI,QAAQ,GAAG,KAAK,CAAC;IACrB,IAAI,eAAe,GAAG,KAAK,CAAC;IAE5B,OAAO,CAAC,OAAO,CAAC,qBAAqB,GAAG,EAAE,CAAC;IAC3C,OAAO,CAAC,YAAY,CAAC,YAAY,EAAE,iBAAiB,CAAC,CAAC;IACtD,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE;QAC3B,UAAU,EAAE,SAAS;QACrB,MAAM,EAAE,mBAAmB;QAC3B,YAAY,EAAE,KAAK;QACnB,MAAM,EAAE,MAAM;QACd,SAAS,EAAE,+BAA+B;QAC1C,KAAK,EAAE,SAAS;QAChB,OAAO,EAAE,MAAM;QACf,IAAI,EAAE,oEAAoE;QAC1E,GAAG,EAAE,KAAK;QACV,SAAS,EAAE,gCAAgC;QAC3C,QAAQ,EAAE,QAAQ;QAClB,OAAO,EAAE,MAAM;QACf,QAAQ,EAAE,OAAO;QACjB,KAAK,EAAE,MAAM;QACb,KAAK,EAAE,gCAAgC;QACvC,MAAM,EAAE,YAAY;KACrB,CAAC,CAAC;IACH,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE;QAC3B,OAAO,EAAE,MAAM;QACf,GAAG,EAAE,KAAK;QACV,mBAAmB,EAAE,2BAA2B;KACjD,CAAC,CAAC;IACH,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,EAAE;QAC7B,OAAO,EAAE,MAAM;QACf,GAAG,EAAE,KAAK;QACV,SAAS,EAAE,MAAM;QACjB,MAAM,EAAE,GAAG;QACX,QAAQ,EAAE,MAAM;QAChB,OAAO,EAAE,GAAG;KACb,CAAC,CAAC;IAEH,OAAO,CAAC,MAAM,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;IACnC,aAAa,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAEnC,MAAM,WAAW,GAAG,QAAQ,CAAC,SAAS,CAAC,CAAC,KAAK,EAAE,EAAE;QAC/C,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACnB,IAAI,MAAM,CAAC,MAAM,GAAG,SAAS,EAAE,CAAC;YAC9B,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,MAAM,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;QAC9C,CAAC;QACD,cAAc,EAAE,CAAC;IACnB,CAAC,CAAC,CAAC;IAEH,MAAM,EAAE,CAAC;IAET,OAAO;QACL,QAAQ;QACR,OAAO;YACL,QAAQ,GAAG,IAAI,CAAC;YAChB,WAAW,EAAE,CAAC;YACd,OAAO,CAAC,MAAM,EAAE,CAAC;QACnB,CAAC;QACD,OAAO;KACR,CAAC;IAEF,SAAS,MAAM;QACb,IAAI,QAAQ,EAAE,CAAC;YACb,OAAO;QACT,CAAC;QAED,OAAO,CAAC,eAAe,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,SAAS,CAAC,aAAa,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC;QAC7E,MAAM,aAAa,GAAG,CAAC,GAAG,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK,SAAS,CAAC,CAAC,OAAO,EAAE,CAAC;QAE7F,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC/B,MAAM,KAAK,GAAG,aAAa,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;YAChD,KAAK,CAAC,WAAW,GAAG,WAAW,CAAC;YAChC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,EAAE;gBACzB,KAAK,EAAE,SAAS;gBAChB,OAAO,EAAE,UAAU;aACpB,CAAC,CAAC;YACH,SAAS,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;YACjC,OAAO;QACT,CAAC;QAED,SAAS,CAAC,eAAe,CAAC,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,WAAW,CAAC,aAAa,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;IAChG,CAAC;IAED,SAAS,cAAc;QACrB,IAAI,eAAe,IAAI,QAAQ,EAAE,CAAC;YAChC,OAAO;QACT,CAAC;QAED,eAAe,GAAG,IAAI,CAAC;QACvB,cAAc,CAAC,GAAG,EAAE;YAClB,eAAe,GAAG,KAAK,CAAC;YACxB,MAAM,EAAE,CAAC;QACX,CAAC,CAAC,CAAC;IACL,CAAC;IAED,SAAS,SAAS,CAAC,GAAa,EAAE,UAAyB;QACzD,MAAM,MAAM,GAAG,GAAG,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;QAC3C,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK,UAAU,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC;QAClF,MAAM,CAAC,IAAI,GAAG,QAAQ,CAAC;QACvB,MAAM,CAAC,WAAW,GAAG,GAAG,UAAU,CAAC,KAAK,IAAI,KAAK,EAAE,CAAC;QACpD,MAAM,CAAC,YAAY,CAAC,cAAc,EAAE,MAAM,CAAC,UAAU,CAAC,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC;QAC1E,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE;YAC1B,UAAU,EAAE,UAAU,CAAC,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS;YAChE,MAAM,EAAE,mBAAmB;YAC3B,YAAY,EAAE,KAAK;YACnB,KAAK,EAAE,UAAU,CAAC,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS;YAC3D,MAAM,EAAE,SAAS;YACjB,IAAI,EAAE,SAAS;YACf,SAAS,EAAE,MAAM;YACjB,QAAQ,EAAE,QAAQ;YAClB,OAAO,EAAE,SAAS;YAClB,YAAY,EAAE,UAAU;YACxB,UAAU,EAAE,QAAQ;SACrB,CAAC,CAAC;QACH,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE;YACpC,SAAS,GAAG,UAAU,CAAC,GAAG,CAAC;YAC3B,MAAM,EAAE,CAAC;QACX,CAAC,CAAC,CAAC;QAEH,OAAO,MAAM,CAAC;IAChB,CAAC;AACH,CAAC;AAED,SAAS,WAAW,CAAC,GAAa,EAAE,KAAoB;IACtD,MAAM,IAAI,GAAG,GAAG,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;IACrC,MAAM,KAAK,GAAG,GAAG,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;IACvC,MAAM,IAAI,GAAG,GAAG,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;IACtC,MAAM,OAAO,GAAG,GAAG,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;IAEzC,KAAK,CAAC,WAAW,GAAG,KAAK,CAAC,IAAI,CAAC;IAC/B,IAAI,CAAC,WAAW,GAAG,CAAC,KAAK,CAAC,OAAO,EAAE,eAAe,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACjG,OAAO,CAAC,WAAW,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC;IAE1C,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE;QACxB,UAAU,EAAE,SAAS;QACrB,MAAM,EAAE,mBAAmB;QAC3B,YAAY,EAAE,KAAK;QACnB,OAAO,EAAE,MAAM;QACf,GAAG,EAAE,KAAK;QACV,OAAO,EAAE,KAAK;KACf,CAAC,CAAC;IACH,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,EAAE;QACzB,KAAK,EAAE,SAAS;QAChB,UAAU,EAAE,KAAK;QACjB,YAAY,EAAE,UAAU;KACzB,CAAC,CAAC;IACH,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE;QACxB,KAAK,EAAE,SAAS;QAChB,YAAY,EAAE,UAAU;KACzB,CAAC,CAAC;IACH,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE;QAC3B,KAAK,EAAE,SAAS;QAChB,MAAM,EAAE,GAAG;QACX,QAAQ,EAAE,MAAM;QAChB,UAAU,EAAE,UAAU;KACvB,CAAC,CAAC;IAEH,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;IAElC,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,YAAY,CAAC,KAAoB;IACxC,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,UAAU,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,OAAO,EAAE,GAAG,KAAK,CAAC;IAExF,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACtC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,UAAkB,CAAC;IACvB,IAAI,CAAC;QACH,UAAU,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;IACvC,CAAC;IAAC,MAAM,CAAC;QACP,UAAU,GAAG,kBAAkB,CAAC;IAClC,CAAC;IAED,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC;QAC7B,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO,UAAU,CAAC,MAAM,GAAG,qBAAqB;QAC9C,CAAC,CAAC,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,EAAE,qBAAqB,CAAC,KAAK;QACpD,CAAC,CAAC,UAAU,CAAC;AACjB,CAAC;AAED,SAAS,QAAQ,CAAC,KAAoB;IACpC,MAAM,MAAM,GAAG,GAAG,KAAK,CAAC,OAAO,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAE9D,IAAI,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC;QAC3F,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,IAAI,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;QAC5D,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,OAAO,UAAU,CAAC;AACpB,CAAC;AAED,SAAS,eAAe,CAAC,SAA6B;IACpD,OAAO,OAAO,SAAS,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,SAAS,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;AAChF,CAAC;AAED,SAAS,kBAAkB,CAAC,KAAyB;IACnD,OAAO,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,GAAG,CAAC;QAC/D,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC;QACnB,CAAC,CAAC,gBAAgB,CAAC;AACvB,CAAC;AAED,SAAS,kBAAkB;IACzB,IAAI,OAAO,QAAQ,KAAK,WAAW,EAAE,CAAC;QACpC,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAC;IACvE,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC","sourcesContent":["import {\n createDevtools,\n getInstalledDevtools,\n installDevtools,\n type Devtools,\n type DevtoolsEvent,\n} from \"./index.js\";\n\n/** Re-exports devtools types used by the overlay. */\nexport type { Devtools, DevtoolsEvent, DevtoolsListener } from \"./index.js\";\n\n/** Names the event category tabs displayed by the devtools overlay. */\nexport type DevtoolsOverlayTab = \"query\" | \"reactive\" | \"router\";\n\n/** Configures document ownership, event source, and event retention for the devtools overlay. */\nexport interface DevtoolsOverlayOptions {\n devtools?: Devtools | undefined;\n document?: Document | undefined;\n maxEvents?: number | undefined;\n}\n\n/** Represents a mounted devtools overlay and its disposal handle. */\nexport interface MountedDevtoolsOverlay {\n devtools: Devtools;\n dispose(): void;\n element: HTMLElement;\n}\n\ninterface TabDefinition {\n label: string;\n tab: DevtoolsOverlayTab;\n}\n\nconst tabs: readonly TabDefinition[] = [\n { label: \"Reactive\", tab: \"reactive\" },\n { label: \"Query\", tab: \"query\" },\n { label: \"Router\", tab: \"router\" },\n];\n\nconst defaultMaxEvents = 200;\nconst maxEventDetailsLength = 4_000;\n\n/** Mounts a browser devtools overlay that groups recent mreact events by category. */\nexport function mountDevtoolsOverlay(\n options: DevtoolsOverlayOptions = {},\n): MountedDevtoolsOverlay {\n const ownerDocument = options.document ?? documentFromGlobal();\n const maxEvents = normalizeMaxEvents(options.maxEvents);\n const devtools = options.devtools ?? getInstalledDevtools() ?? installDevtools(createDevtools());\n const events = devtools.events().slice(-maxEvents);\n const element = ownerDocument.createElement(\"section\");\n const tabList = ownerDocument.createElement(\"nav\");\n const eventList = ownerDocument.createElement(\"ol\");\n let activeTab: DevtoolsOverlayTab = \"reactive\";\n let disposed = false;\n let renderScheduled = false;\n\n element.dataset.mreactDevtoolsOverlay = \"\";\n element.setAttribute(\"aria-label\", \"mreact devtools\");\n Object.assign(element.style, {\n background: \"#10151f\",\n border: \"1px solid #3b4350\",\n borderRadius: \"8px\",\n bottom: \"16px\",\n boxShadow: \"0 18px 50px rgb(0 0 0 / 0.35)\",\n color: \"#eef2f8\",\n display: \"grid\",\n font: \"12px/1.45 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace\",\n gap: \"8px\",\n maxHeight: \"min(420px, calc(100vh - 32px))\",\n overflow: \"hidden\",\n padding: \"10px\",\n position: \"fixed\",\n right: \"16px\",\n width: \"min(520px, calc(100vw - 32px))\",\n zIndex: \"2147483647\",\n });\n Object.assign(tabList.style, {\n display: \"grid\",\n gap: \"6px\",\n gridTemplateColumns: \"repeat(3, minmax(0, 1fr))\",\n });\n Object.assign(eventList.style, {\n display: \"grid\",\n gap: \"6px\",\n listStyle: \"none\",\n margin: \"0\",\n overflow: \"auto\",\n padding: \"0\",\n });\n\n element.append(tabList, eventList);\n ownerDocument.body.append(element);\n\n const unsubscribe = devtools.subscribe((event) => {\n events.push(event);\n if (events.length > maxEvents) {\n events.splice(0, events.length - maxEvents);\n }\n scheduleRender();\n });\n\n render();\n\n return {\n devtools,\n dispose() {\n disposed = true;\n unsubscribe();\n element.remove();\n },\n element,\n };\n\n function render(): void {\n if (disposed) {\n return;\n }\n\n tabList.replaceChildren(...tabs.map((tab) => renderTab(ownerDocument, tab)));\n const visibleEvents = [...events].filter((event) => eventTab(event) === activeTab).reverse();\n\n if (visibleEvents.length === 0) {\n const empty = ownerDocument.createElement(\"li\");\n empty.textContent = \"No events\";\n Object.assign(empty.style, {\n color: \"#9aa8bc\",\n padding: \"12px 4px\",\n });\n eventList.replaceChildren(empty);\n return;\n }\n\n eventList.replaceChildren(...visibleEvents.map((event) => renderEvent(ownerDocument, event)));\n }\n\n function scheduleRender(): void {\n if (renderScheduled || disposed) {\n return;\n }\n\n renderScheduled = true;\n queueMicrotask(() => {\n renderScheduled = false;\n render();\n });\n }\n\n function renderTab(doc: Document, definition: TabDefinition): HTMLButtonElement {\n const button = doc.createElement(\"button\");\n const count = events.filter((event) => eventTab(event) === definition.tab).length;\n button.type = \"button\";\n button.textContent = `${definition.label} ${count}`;\n button.setAttribute(\"aria-pressed\", String(definition.tab === activeTab));\n Object.assign(button.style, {\n background: definition.tab === activeTab ? \"#d8e7ff\" : \"#1b2330\",\n border: \"1px solid #3b4350\",\n borderRadius: \"6px\",\n color: definition.tab === activeTab ? \"#111827\" : \"#d8e7ff\",\n cursor: \"pointer\",\n font: \"inherit\",\n minHeight: \"32px\",\n overflow: \"hidden\",\n padding: \"6px 8px\",\n textOverflow: \"ellipsis\",\n whiteSpace: \"nowrap\",\n });\n button.addEventListener(\"click\", () => {\n activeTab = definition.tab;\n render();\n });\n\n return button;\n }\n}\n\nfunction renderEvent(doc: Document, event: DevtoolsEvent): HTMLLIElement {\n const item = doc.createElement(\"li\");\n const title = doc.createElement(\"div\");\n const meta = doc.createElement(\"div\");\n const details = doc.createElement(\"pre\");\n\n title.textContent = event.type;\n meta.textContent = [event.package, formatTimestamp(event.timestamp)].filter(Boolean).join(\" | \");\n details.textContent = eventDetails(event);\n\n Object.assign(item.style, {\n background: \"#161d28\",\n border: \"1px solid #303846\",\n borderRadius: \"6px\",\n display: \"grid\",\n gap: \"3px\",\n padding: \"8px\",\n });\n Object.assign(title.style, {\n color: \"#ffffff\",\n fontWeight: \"700\",\n overflowWrap: \"anywhere\",\n });\n Object.assign(meta.style, {\n color: \"#9aa8bc\",\n overflowWrap: \"anywhere\",\n });\n Object.assign(details.style, {\n color: \"#c8d7ec\",\n margin: \"0\",\n overflow: \"auto\",\n whiteSpace: \"pre-wrap\",\n });\n\n item.append(title, meta, details);\n\n return item;\n}\n\nfunction eventDetails(event: DevtoolsEvent): string {\n const { package: _packageName, timestamp: _timestamp, type: _type, ...details } = event;\n\n if (Object.keys(details).length === 0) {\n return \"{}\";\n }\n\n let serialized: string;\n try {\n serialized = JSON.stringify(details);\n } catch {\n serialized = \"[unserializable]\";\n }\n\n if (serialized === undefined) {\n return \"{}\";\n }\n\n return serialized.length > maxEventDetailsLength\n ? `${serialized.slice(0, maxEventDetailsLength)}...`\n : serialized;\n}\n\nfunction eventTab(event: DevtoolsEvent): DevtoolsOverlayTab {\n const search = `${event.package} ${event.type}`.toLowerCase();\n\n if (search.includes(\"router\") || search.includes(\"route\") || search.includes(\"navigation\")) {\n return \"router\";\n }\n\n if (search.includes(\"query\") || search.includes(\"mutation\")) {\n return \"query\";\n }\n\n return \"reactive\";\n}\n\nfunction formatTimestamp(timestamp: number | undefined): string {\n return typeof timestamp === \"number\" ? new Date(timestamp).toISOString() : \"\";\n}\n\nfunction normalizeMaxEvents(value: number | undefined): number {\n return Number.isFinite(value) && value !== undefined && value > 0\n ? Math.floor(value)\n : defaultMaxEvents;\n}\n\nfunction documentFromGlobal(): Document {\n if (typeof document === \"undefined\") {\n throw new Error(\"mountDevtoolsOverlay requires a browser document.\");\n }\n\n return document;\n}\n"]}
1
+ {"version":3,"file":"overlay.js","sourceRoot":"","sources":["../src/overlay.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,cAAc,EACd,oBAAoB,EACpB,eAAe,GAGhB,MAAM,YAAY,CAAC;AA2BpB,MAAM,IAAI,GAA6B;IACrC,EAAE,KAAK,EAAE,UAAU,EAAE,GAAG,EAAE,UAAU,EAAE;IACtC,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE;IAChC,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,EAAE,QAAQ,EAAE;CACnC,CAAC;AAEF,MAAM,gBAAgB,GAAG,GAAG,CAAC;AAC7B,MAAM,qBAAqB,GAAG,KAAK,CAAC;AAEpC,sFAAsF;AACtF,MAAM,UAAU,oBAAoB,CAAC,UAAkC,EAAE;IACvE,MAAM,aAAa,GAAG,OAAO,CAAC,QAAQ,IAAI,kBAAkB,EAAE,CAAC;IAC/D,MAAM,SAAS,GAAG,kBAAkB,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IACxD,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,oBAAoB,EAAE,IAAI,eAAe,CAAC,cAAc,EAAE,CAAC,CAAC;IACjG,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,CAAC;IACnD,MAAM,OAAO,GAAG,aAAa,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC;IACvD,MAAM,OAAO,GAAG,aAAa,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;IACnD,MAAM,WAAW,GAAG,aAAa,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;IACvD,MAAM,SAAS,GAAG,aAAa,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;IACpD,IAAI,SAAS,GAAuB,UAAU,CAAC;IAC/C,IAAI,QAAQ,GAAG,KAAK,CAAC;IACrB,IAAI,eAAe,GAAG,KAAK,CAAC;IAE5B,OAAO,CAAC,OAAO,CAAC,qBAAqB,GAAG,EAAE,CAAC;IAC3C,OAAO,CAAC,YAAY,CAAC,YAAY,EAAE,iBAAiB,CAAC,CAAC;IACtD,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE;QAC3B,UAAU,EAAE,SAAS;QACrB,MAAM,EAAE,mBAAmB;QAC3B,YAAY,EAAE,KAAK;QACnB,MAAM,EAAE,MAAM;QACd,SAAS,EAAE,+BAA+B;QAC1C,KAAK,EAAE,SAAS;QAChB,OAAO,EAAE,MAAM;QACf,IAAI,EAAE,oEAAoE;QAC1E,GAAG,EAAE,KAAK;QACV,SAAS,EAAE,gCAAgC;QAC3C,QAAQ,EAAE,QAAQ;QAClB,OAAO,EAAE,MAAM;QACf,QAAQ,EAAE,OAAO;QACjB,KAAK,EAAE,MAAM;QACb,KAAK,EAAE,gCAAgC;QACvC,MAAM,EAAE,YAAY;KACrB,CAAC,CAAC;IACH,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE;QAC3B,OAAO,EAAE,MAAM;QACf,GAAG,EAAE,KAAK;QACV,mBAAmB,EAAE,2BAA2B;KACjD,CAAC,CAAC;IACH,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,EAAE;QAC7B,OAAO,EAAE,MAAM;QACf,GAAG,EAAE,KAAK;QACV,SAAS,EAAE,MAAM;QACjB,MAAM,EAAE,GAAG;QACX,QAAQ,EAAE,MAAM;QAChB,OAAO,EAAE,GAAG;KACb,CAAC,CAAC;IACH,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,KAAK,EAAE;QAC/B,OAAO,EAAE,MAAM;QACf,GAAG,EAAE,KAAK;KACX,CAAC,CAAC;IAEH,OAAO,CAAC,MAAM,CAAC,OAAO,EAAE,WAAW,EAAE,SAAS,CAAC,CAAC;IAChD,aAAa,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAEnC,MAAM,WAAW,GAAG,QAAQ,CAAC,SAAS,CAAC,CAAC,KAAK,EAAE,EAAE;QAC/C,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACnB,IAAI,MAAM,CAAC,MAAM,GAAG,SAAS,EAAE,CAAC;YAC9B,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,MAAM,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;QAC9C,CAAC;QACD,cAAc,EAAE,CAAC;IACnB,CAAC,CAAC,CAAC;IAEH,MAAM,EAAE,CAAC;IAET,OAAO;QACL,QAAQ;QACR,OAAO;YACL,QAAQ,GAAG,IAAI,CAAC;YAChB,WAAW,EAAE,CAAC;YACd,OAAO,CAAC,MAAM,EAAE,CAAC;QACnB,CAAC;QACD,OAAO;KACR,CAAC;IAEF,SAAS,MAAM;QACb,IAAI,QAAQ,EAAE,CAAC;YACb,OAAO;QACT,CAAC;QAED,OAAO,CAAC,eAAe,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,SAAS,CAAC,aAAa,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC;QAC7E,WAAW,CAAC,eAAe,CAAC,GAAG,aAAa,CAAC,aAAa,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC;QAChF,MAAM,aAAa,GAAG,CAAC,GAAG,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK,SAAS,CAAC,CAAC,OAAO,EAAE,CAAC;QAE7F,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC/B,MAAM,KAAK,GAAG,aAAa,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;YAChD,KAAK,CAAC,WAAW,GAAG,WAAW,CAAC;YAChC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,EAAE;gBACzB,KAAK,EAAE,SAAS;gBAChB,OAAO,EAAE,UAAU;aACpB,CAAC,CAAC;YACH,SAAS,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;YACjC,OAAO;QACT,CAAC;QAED,SAAS,CAAC,eAAe,CAAC,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,WAAW,CAAC,aAAa,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;IAChG,CAAC;IAED,SAAS,cAAc;QACrB,IAAI,eAAe,IAAI,QAAQ,EAAE,CAAC;YAChC,OAAO;QACT,CAAC;QAED,eAAe,GAAG,IAAI,CAAC;QACvB,cAAc,CAAC,GAAG,EAAE;YAClB,eAAe,GAAG,KAAK,CAAC;YACxB,MAAM,EAAE,CAAC;QACX,CAAC,CAAC,CAAC;IACL,CAAC;IAED,SAAS,SAAS,CAAC,GAAa,EAAE,UAAyB;QACzD,MAAM,MAAM,GAAG,GAAG,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;QAC3C,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK,UAAU,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC;QAClF,MAAM,CAAC,IAAI,GAAG,QAAQ,CAAC;QACvB,MAAM,CAAC,WAAW,GAAG,GAAG,UAAU,CAAC,KAAK,IAAI,KAAK,EAAE,CAAC;QACpD,MAAM,CAAC,YAAY,CAAC,cAAc,EAAE,MAAM,CAAC,UAAU,CAAC,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC;QAC1E,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE;YAC1B,UAAU,EAAE,UAAU,CAAC,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS;YAChE,MAAM,EAAE,mBAAmB;YAC3B,YAAY,EAAE,KAAK;YACnB,KAAK,EAAE,UAAU,CAAC,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS;YAC3D,MAAM,EAAE,SAAS;YACjB,IAAI,EAAE,SAAS;YACf,SAAS,EAAE,MAAM;YACjB,QAAQ,EAAE,QAAQ;YAClB,OAAO,EAAE,SAAS;YAClB,YAAY,EAAE,UAAU;YACxB,UAAU,EAAE,QAAQ;SACrB,CAAC,CAAC;QACH,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE;YACpC,SAAS,GAAG,UAAU,CAAC,GAAG,CAAC;YAC3B,MAAM,EAAE,CAAC;QACX,CAAC,CAAC,CAAC;QAEH,OAAO,MAAM,CAAC;IAChB,CAAC;AACH,CAAC;AAED,SAAS,aAAa,CACpB,GAAa,EACb,SAA6B,EAC7B,MAAgC;IAEhC,IAAI,SAAS,KAAK,OAAO,EAAE,CAAC;QAC1B,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,MAAM,OAAO,GAAG,iBAAiB,CAAC,MAAM,CAAC,CAAC;IAE1C,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,MAAM,OAAO,GAAG,GAAG,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC;IAC7C,MAAM,OAAO,GAAG,GAAG,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;IACzC,MAAM,IAAI,GAAG,GAAG,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;IAErC,OAAO,CAAC,WAAW,GAAG,iBAAiB,CAAC;IACxC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE;QAC3B,UAAU,EAAE,SAAS;QACrB,MAAM,EAAE,mBAAmB;QAC3B,YAAY,EAAE,KAAK;QACnB,OAAO,EAAE,MAAM;QACf,GAAG,EAAE,KAAK;QACV,OAAO,EAAE,KAAK;KACf,CAAC,CAAC;IACH,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE;QAC3B,KAAK,EAAE,SAAS;QAChB,UAAU,EAAE,KAAK;KAClB,CAAC,CAAC;IACH,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE;QACxB,OAAO,EAAE,MAAM;QACf,GAAG,EAAE,KAAK;QACV,SAAS,EAAE,MAAM;QACjB,MAAM,EAAE,GAAG;QACX,OAAO,EAAE,GAAG;KACb,CAAC,CAAC;IAEH,IAAI,CAAC,eAAe,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,kBAAkB,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;IAChF,OAAO,CAAC,MAAM,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IAE9B,OAAO,CAAC,OAAO,CAAC,CAAC;AACnB,CAAC;AASD,SAAS,iBAAiB,CAAC,MAAgC;IACzD,MAAM,MAAM,GAAG,IAAI,GAAG,EAAwB,CAAC;IAE/C,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,IAAI,KAAK,CAAC,IAAI,KAAK,cAAc,IAAI,OAAO,KAAK,CAAC,SAAS,KAAK,QAAQ,EAAE,CAAC;YACzE,SAAS;QACX,CAAC;QAED,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,EAAE;YAC1B,IAAI,EAAE,KAAK,CAAC,SAAS;YACrB,UAAU,EAAE,KAAK,CAAC,UAAU,KAAK,IAAI;YACrC,KAAK,EAAE,KAAK,CAAC,KAAK,KAAK,IAAI;YAC3B,MAAM,EAAE,OAAO,KAAK,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS;SACpE,CAAC,CAAC;IACL,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;AAChG,CAAC;AAED,SAAS,kBAAkB,CAAC,GAAa,EAAE,KAAmB;IAC5D,MAAM,IAAI,GAAG,GAAG,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;IACrC,IAAI,CAAC,WAAW,GAAG,GAAG,KAAK,CAAC,IAAI,MAAM,KAAK,CAAC,MAAM,GAAG,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;IAC7H,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE;QACxB,KAAK,EAAE,SAAS;QAChB,YAAY,EAAE,UAAU;KACzB,CAAC,CAAC;IAEH,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,WAAW,CAAC,GAAa,EAAE,KAAoB;IACtD,MAAM,IAAI,GAAG,GAAG,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;IACrC,MAAM,KAAK,GAAG,GAAG,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;IACvC,MAAM,IAAI,GAAG,GAAG,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;IACtC,MAAM,OAAO,GAAG,GAAG,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;IAEzC,KAAK,CAAC,WAAW,GAAG,KAAK,CAAC,IAAI,CAAC;IAC/B,IAAI,CAAC,WAAW,GAAG,CAAC,KAAK,CAAC,OAAO,EAAE,eAAe,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACjG,OAAO,CAAC,WAAW,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC;IAE1C,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE;QACxB,UAAU,EAAE,SAAS;QACrB,MAAM,EAAE,mBAAmB;QAC3B,YAAY,EAAE,KAAK;QACnB,OAAO,EAAE,MAAM;QACf,GAAG,EAAE,KAAK;QACV,OAAO,EAAE,KAAK;KACf,CAAC,CAAC;IACH,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,EAAE;QACzB,KAAK,EAAE,SAAS;QAChB,UAAU,EAAE,KAAK;QACjB,YAAY,EAAE,UAAU;KACzB,CAAC,CAAC;IACH,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE;QACxB,KAAK,EAAE,SAAS;QAChB,YAAY,EAAE,UAAU;KACzB,CAAC,CAAC;IACH,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE;QAC3B,KAAK,EAAE,SAAS;QAChB,MAAM,EAAE,GAAG;QACX,QAAQ,EAAE,MAAM;QAChB,UAAU,EAAE,UAAU;KACvB,CAAC,CAAC;IAEH,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;IAElC,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,YAAY,CAAC,KAAoB;IACxC,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,UAAU,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,OAAO,EAAE,GAAG,KAAK,CAAC;IAExF,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACtC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,UAAkB,CAAC;IACvB,IAAI,CAAC;QACH,UAAU,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;IACvC,CAAC;IAAC,MAAM,CAAC;QACP,UAAU,GAAG,kBAAkB,CAAC;IAClC,CAAC;IAED,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC;QAC7B,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO,UAAU,CAAC,MAAM,GAAG,qBAAqB;QAC9C,CAAC,CAAC,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,EAAE,qBAAqB,CAAC,KAAK;QACpD,CAAC,CAAC,UAAU,CAAC;AACjB,CAAC;AAED,SAAS,QAAQ,CAAC,KAAoB;IACpC,MAAM,MAAM,GAAG,GAAG,KAAK,CAAC,OAAO,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAE9D,IAAI,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC;QAC3F,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,IAAI,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;QAC5D,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,OAAO,UAAU,CAAC;AACpB,CAAC;AAED,SAAS,eAAe,CAAC,SAA6B;IACpD,OAAO,OAAO,SAAS,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,SAAS,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;AAChF,CAAC;AAED,SAAS,kBAAkB,CAAC,KAAyB;IACnD,OAAO,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,GAAG,CAAC;QAC/D,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC;QACnB,CAAC,CAAC,gBAAgB,CAAC;AACvB,CAAC;AAED,SAAS,kBAAkB;IACzB,IAAI,OAAO,QAAQ,KAAK,WAAW,EAAE,CAAC;QACpC,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAC;IACvE,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC","sourcesContent":["import {\n createDevtools,\n getInstalledDevtools,\n installDevtools,\n type Devtools,\n type DevtoolsEvent,\n} from \"./index.js\";\n\n/** Re-exports devtools types used by the overlay. */\nexport type { Devtools, DevtoolsEvent, DevtoolsListener } from \"./index.js\";\n\n/** Names the event category tabs displayed by the devtools overlay. */\nexport type DevtoolsOverlayTab = \"query\" | \"reactive\" | \"router\";\n\n/** Configures document ownership, event source, and event retention for the devtools overlay. */\nexport interface DevtoolsOverlayOptions {\n devtools?: Devtools | undefined;\n document?: Document | undefined;\n maxEvents?: number | undefined;\n}\n\n/** Represents a mounted devtools overlay and its disposal handle. */\nexport interface MountedDevtoolsOverlay {\n devtools: Devtools;\n dispose(): void;\n element: HTMLElement;\n}\n\ninterface TabDefinition {\n label: string;\n tab: DevtoolsOverlayTab;\n}\n\nconst tabs: readonly TabDefinition[] = [\n { label: \"Reactive\", tab: \"reactive\" },\n { label: \"Query\", tab: \"query\" },\n { label: \"Router\", tab: \"router\" },\n];\n\nconst defaultMaxEvents = 200;\nconst maxEventDetailsLength = 4_000;\n\n/** Mounts a browser devtools overlay that groups recent mreact events by category. */\nexport function mountDevtoolsOverlay(options: DevtoolsOverlayOptions = {}): MountedDevtoolsOverlay {\n const ownerDocument = options.document ?? documentFromGlobal();\n const maxEvents = normalizeMaxEvents(options.maxEvents);\n const devtools = options.devtools ?? getInstalledDevtools() ?? installDevtools(createDevtools());\n const events = devtools.events().slice(-maxEvents);\n const element = ownerDocument.createElement(\"section\");\n const tabList = ownerDocument.createElement(\"nav\");\n const summaryList = ownerDocument.createElement(\"div\");\n const eventList = ownerDocument.createElement(\"ol\");\n let activeTab: DevtoolsOverlayTab = \"reactive\";\n let disposed = false;\n let renderScheduled = false;\n\n element.dataset.mreactDevtoolsOverlay = \"\";\n element.setAttribute(\"aria-label\", \"mreact devtools\");\n Object.assign(element.style, {\n background: \"#10151f\",\n border: \"1px solid #3b4350\",\n borderRadius: \"8px\",\n bottom: \"16px\",\n boxShadow: \"0 18px 50px rgb(0 0 0 / 0.35)\",\n color: \"#eef2f8\",\n display: \"grid\",\n font: \"12px/1.45 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace\",\n gap: \"8px\",\n maxHeight: \"min(420px, calc(100vh - 32px))\",\n overflow: \"hidden\",\n padding: \"10px\",\n position: \"fixed\",\n right: \"16px\",\n width: \"min(520px, calc(100vw - 32px))\",\n zIndex: \"2147483647\",\n });\n Object.assign(tabList.style, {\n display: \"grid\",\n gap: \"6px\",\n gridTemplateColumns: \"repeat(3, minmax(0, 1fr))\",\n });\n Object.assign(eventList.style, {\n display: \"grid\",\n gap: \"6px\",\n listStyle: \"none\",\n margin: \"0\",\n overflow: \"auto\",\n padding: \"0\",\n });\n Object.assign(summaryList.style, {\n display: \"grid\",\n gap: \"6px\",\n });\n\n element.append(tabList, summaryList, eventList);\n ownerDocument.body.append(element);\n\n const unsubscribe = devtools.subscribe((event) => {\n events.push(event);\n if (events.length > maxEvents) {\n events.splice(0, events.length - maxEvents);\n }\n scheduleRender();\n });\n\n render();\n\n return {\n devtools,\n dispose() {\n disposed = true;\n unsubscribe();\n element.remove();\n },\n element,\n };\n\n function render(): void {\n if (disposed) {\n return;\n }\n\n tabList.replaceChildren(...tabs.map((tab) => renderTab(ownerDocument, tab)));\n summaryList.replaceChildren(...renderSummary(ownerDocument, activeTab, events));\n const visibleEvents = [...events].filter((event) => eventTab(event) === activeTab).reverse();\n\n if (visibleEvents.length === 0) {\n const empty = ownerDocument.createElement(\"li\");\n empty.textContent = \"No events\";\n Object.assign(empty.style, {\n color: \"#9aa8bc\",\n padding: \"12px 4px\",\n });\n eventList.replaceChildren(empty);\n return;\n }\n\n eventList.replaceChildren(...visibleEvents.map((event) => renderEvent(ownerDocument, event)));\n }\n\n function scheduleRender(): void {\n if (renderScheduled || disposed) {\n return;\n }\n\n renderScheduled = true;\n queueMicrotask(() => {\n renderScheduled = false;\n render();\n });\n }\n\n function renderTab(doc: Document, definition: TabDefinition): HTMLButtonElement {\n const button = doc.createElement(\"button\");\n const count = events.filter((event) => eventTab(event) === definition.tab).length;\n button.type = \"button\";\n button.textContent = `${definition.label} ${count}`;\n button.setAttribute(\"aria-pressed\", String(definition.tab === activeTab));\n Object.assign(button.style, {\n background: definition.tab === activeTab ? \"#d8e7ff\" : \"#1b2330\",\n border: \"1px solid #3b4350\",\n borderRadius: \"6px\",\n color: definition.tab === activeTab ? \"#111827\" : \"#d8e7ff\",\n cursor: \"pointer\",\n font: \"inherit\",\n minHeight: \"32px\",\n overflow: \"hidden\",\n padding: \"6px 8px\",\n textOverflow: \"ellipsis\",\n whiteSpace: \"nowrap\",\n });\n button.addEventListener(\"click\", () => {\n activeTab = definition.tab;\n render();\n });\n\n return button;\n }\n}\n\nfunction renderSummary(\n doc: Document,\n activeTab: DevtoolsOverlayTab,\n events: readonly DevtoolsEvent[],\n): Node[] {\n if (activeTab !== \"query\") {\n return [];\n }\n\n const queries = latestQueryStates(events);\n\n if (queries.length === 0) {\n return [];\n }\n\n const section = doc.createElement(\"section\");\n const heading = doc.createElement(\"div\");\n const list = doc.createElement(\"ol\");\n\n heading.textContent = \"Current queries\";\n Object.assign(section.style, {\n background: \"#121a25\",\n border: \"1px solid #303846\",\n borderRadius: \"6px\",\n display: \"grid\",\n gap: \"4px\",\n padding: \"8px\",\n });\n Object.assign(heading.style, {\n color: \"#ffffff\",\n fontWeight: \"700\",\n });\n Object.assign(list.style, {\n display: \"grid\",\n gap: \"3px\",\n listStyle: \"none\",\n margin: \"0\",\n padding: \"0\",\n });\n\n list.replaceChildren(...queries.map((query) => renderQuerySummary(doc, query)));\n section.append(heading, list);\n\n return [section];\n}\n\ninterface QuerySummary {\n hash: string;\n isFetching: boolean;\n stale: boolean;\n status: string;\n}\n\nfunction latestQueryStates(events: readonly DevtoolsEvent[]): QuerySummary[] {\n const byHash = new Map<string, QuerySummary>();\n\n for (const event of events) {\n if (event.type !== \"query:update\" || typeof event.queryHash !== \"string\") {\n continue;\n }\n\n byHash.set(event.queryHash, {\n hash: event.queryHash,\n isFetching: event.isFetching === true,\n stale: event.stale === true,\n status: typeof event.status === \"string\" ? event.status : \"unknown\",\n });\n }\n\n return Array.from(byHash.values()).sort((left, right) => left.hash.localeCompare(right.hash));\n}\n\nfunction renderQuerySummary(doc: Document, query: QuerySummary): HTMLLIElement {\n const item = doc.createElement(\"li\");\n item.textContent = `${query.hash} | ${query.status}${query.isFetching ? \" | fetching\" : \"\"}${query.stale ? \" | stale\" : \"\"}`;\n Object.assign(item.style, {\n color: \"#c8d7ec\",\n overflowWrap: \"anywhere\",\n });\n\n return item;\n}\n\nfunction renderEvent(doc: Document, event: DevtoolsEvent): HTMLLIElement {\n const item = doc.createElement(\"li\");\n const title = doc.createElement(\"div\");\n const meta = doc.createElement(\"div\");\n const details = doc.createElement(\"pre\");\n\n title.textContent = event.type;\n meta.textContent = [event.package, formatTimestamp(event.timestamp)].filter(Boolean).join(\" | \");\n details.textContent = eventDetails(event);\n\n Object.assign(item.style, {\n background: \"#161d28\",\n border: \"1px solid #303846\",\n borderRadius: \"6px\",\n display: \"grid\",\n gap: \"3px\",\n padding: \"8px\",\n });\n Object.assign(title.style, {\n color: \"#ffffff\",\n fontWeight: \"700\",\n overflowWrap: \"anywhere\",\n });\n Object.assign(meta.style, {\n color: \"#9aa8bc\",\n overflowWrap: \"anywhere\",\n });\n Object.assign(details.style, {\n color: \"#c8d7ec\",\n margin: \"0\",\n overflow: \"auto\",\n whiteSpace: \"pre-wrap\",\n });\n\n item.append(title, meta, details);\n\n return item;\n}\n\nfunction eventDetails(event: DevtoolsEvent): string {\n const { package: _packageName, timestamp: _timestamp, type: _type, ...details } = event;\n\n if (Object.keys(details).length === 0) {\n return \"{}\";\n }\n\n let serialized: string;\n try {\n serialized = JSON.stringify(details);\n } catch {\n serialized = \"[unserializable]\";\n }\n\n if (serialized === undefined) {\n return \"{}\";\n }\n\n return serialized.length > maxEventDetailsLength\n ? `${serialized.slice(0, maxEventDetailsLength)}...`\n : serialized;\n}\n\nfunction eventTab(event: DevtoolsEvent): DevtoolsOverlayTab {\n const search = `${event.package} ${event.type}`.toLowerCase();\n\n if (search.includes(\"router\") || search.includes(\"route\") || search.includes(\"navigation\")) {\n return \"router\";\n }\n\n if (search.includes(\"query\") || search.includes(\"mutation\")) {\n return \"query\";\n }\n\n return \"reactive\";\n}\n\nfunction formatTimestamp(timestamp: number | undefined): string {\n return typeof timestamp === \"number\" ? new Date(timestamp).toISOString() : \"\";\n}\n\nfunction normalizeMaxEvents(value: number | undefined): number {\n return Number.isFinite(value) && value !== undefined && value > 0\n ? Math.floor(value)\n : defaultMaxEvents;\n}\n\nfunction documentFromGlobal(): Document {\n if (typeof document === \"undefined\") {\n throw new Error(\"mountDevtoolsOverlay requires a browser document.\");\n }\n\n return document;\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reckona/mreact-devtools",
3
- "version": "0.0.182",
3
+ "version": "0.0.183",
4
4
  "description": "Runtime event bridge for mreact developer tooling.",
5
5
  "keywords": [
6
6
  "debugging",
package/src/overlay.ts CHANGED
@@ -41,15 +41,14 @@ const defaultMaxEvents = 200;
41
41
  const maxEventDetailsLength = 4_000;
42
42
 
43
43
  /** Mounts a browser devtools overlay that groups recent mreact events by category. */
44
- export function mountDevtoolsOverlay(
45
- options: DevtoolsOverlayOptions = {},
46
- ): MountedDevtoolsOverlay {
44
+ export function mountDevtoolsOverlay(options: DevtoolsOverlayOptions = {}): MountedDevtoolsOverlay {
47
45
  const ownerDocument = options.document ?? documentFromGlobal();
48
46
  const maxEvents = normalizeMaxEvents(options.maxEvents);
49
47
  const devtools = options.devtools ?? getInstalledDevtools() ?? installDevtools(createDevtools());
50
48
  const events = devtools.events().slice(-maxEvents);
51
49
  const element = ownerDocument.createElement("section");
52
50
  const tabList = ownerDocument.createElement("nav");
51
+ const summaryList = ownerDocument.createElement("div");
53
52
  const eventList = ownerDocument.createElement("ol");
54
53
  let activeTab: DevtoolsOverlayTab = "reactive";
55
54
  let disposed = false;
@@ -88,8 +87,12 @@ export function mountDevtoolsOverlay(
88
87
  overflow: "auto",
89
88
  padding: "0",
90
89
  });
90
+ Object.assign(summaryList.style, {
91
+ display: "grid",
92
+ gap: "6px",
93
+ });
91
94
 
92
- element.append(tabList, eventList);
95
+ element.append(tabList, summaryList, eventList);
93
96
  ownerDocument.body.append(element);
94
97
 
95
98
  const unsubscribe = devtools.subscribe((event) => {
@@ -118,6 +121,7 @@ export function mountDevtoolsOverlay(
118
121
  }
119
122
 
120
123
  tabList.replaceChildren(...tabs.map((tab) => renderTab(ownerDocument, tab)));
124
+ summaryList.replaceChildren(...renderSummary(ownerDocument, activeTab, events));
121
125
  const visibleEvents = [...events].filter((event) => eventTab(event) === activeTab).reverse();
122
126
 
123
127
  if (visibleEvents.length === 0) {
@@ -174,6 +178,89 @@ export function mountDevtoolsOverlay(
174
178
  }
175
179
  }
176
180
 
181
+ function renderSummary(
182
+ doc: Document,
183
+ activeTab: DevtoolsOverlayTab,
184
+ events: readonly DevtoolsEvent[],
185
+ ): Node[] {
186
+ if (activeTab !== "query") {
187
+ return [];
188
+ }
189
+
190
+ const queries = latestQueryStates(events);
191
+
192
+ if (queries.length === 0) {
193
+ return [];
194
+ }
195
+
196
+ const section = doc.createElement("section");
197
+ const heading = doc.createElement("div");
198
+ const list = doc.createElement("ol");
199
+
200
+ heading.textContent = "Current queries";
201
+ Object.assign(section.style, {
202
+ background: "#121a25",
203
+ border: "1px solid #303846",
204
+ borderRadius: "6px",
205
+ display: "grid",
206
+ gap: "4px",
207
+ padding: "8px",
208
+ });
209
+ Object.assign(heading.style, {
210
+ color: "#ffffff",
211
+ fontWeight: "700",
212
+ });
213
+ Object.assign(list.style, {
214
+ display: "grid",
215
+ gap: "3px",
216
+ listStyle: "none",
217
+ margin: "0",
218
+ padding: "0",
219
+ });
220
+
221
+ list.replaceChildren(...queries.map((query) => renderQuerySummary(doc, query)));
222
+ section.append(heading, list);
223
+
224
+ return [section];
225
+ }
226
+
227
+ interface QuerySummary {
228
+ hash: string;
229
+ isFetching: boolean;
230
+ stale: boolean;
231
+ status: string;
232
+ }
233
+
234
+ function latestQueryStates(events: readonly DevtoolsEvent[]): QuerySummary[] {
235
+ const byHash = new Map<string, QuerySummary>();
236
+
237
+ for (const event of events) {
238
+ if (event.type !== "query:update" || typeof event.queryHash !== "string") {
239
+ continue;
240
+ }
241
+
242
+ byHash.set(event.queryHash, {
243
+ hash: event.queryHash,
244
+ isFetching: event.isFetching === true,
245
+ stale: event.stale === true,
246
+ status: typeof event.status === "string" ? event.status : "unknown",
247
+ });
248
+ }
249
+
250
+ return Array.from(byHash.values()).sort((left, right) => left.hash.localeCompare(right.hash));
251
+ }
252
+
253
+ function renderQuerySummary(doc: Document, query: QuerySummary): HTMLLIElement {
254
+ const item = doc.createElement("li");
255
+ item.textContent = `${query.hash} | ${query.status}${query.isFetching ? " | fetching" : ""}${query.stale ? " | stale" : ""}`;
256
+ Object.assign(item.style, {
257
+ color: "#c8d7ec",
258
+ overflowWrap: "anywhere",
259
+ });
260
+
261
+ return item;
262
+ }
263
+
177
264
  function renderEvent(doc: Document, event: DevtoolsEvent): HTMLLIElement {
178
265
  const item = doc.createElement("li");
179
266
  const title = doc.createElement("div");