seemore 1.12.5 → 1.12.7

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "seemore",
3
- "version": "1.12.5",
3
+ "version": "1.12.7",
4
4
  "description": "Let AI write the Markdown. Let seemore show it better — zero config documentation framework.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -57,7 +57,23 @@ function waitFor(predicate: () => boolean, timeoutMs: number): Promise<void> {
57
57
  * reloads); the build ships a single hashed stylesheet link. Same-origin sheets are inlined
58
58
  * — a `file://` page cannot fetch them — and a sheet that is genuinely remote stays linked,
59
59
  * the same treaty as remote images.
60
+ *
61
+ * Every `<style>` is taken, not just the framework's: diagram libraries (Mermaid, D2) and
62
+ * Radix inject their own rules at runtime with no marker to select them by, and the export
63
+ * needs those. The two exceptions are the highlight rule (installed per-navigation, and
64
+ * meaningless in a static file) and any sheet a browser extension injected into the page —
65
+ * the latter is not the page's, would not load from a file anyway, and can run to hundreds
66
+ * of kilobytes; it is spotted by the `chrome-extension:`/`moz-extension:` URLs it carries.
67
+ */
68
+ /**
69
+ * A stylesheet a browser extension put on the page, told apart by the extension-only URL
70
+ * scheme it loads its own assets from. Deliberately narrow: it must never match a rule the
71
+ * site or a library authored, since a false positive silently drops real styling.
60
72
  */
73
+ function isExtensionCss(text: string): boolean {
74
+ return /\b(?:chrome-extension|moz-extension):\/\//i.test(text);
75
+ }
76
+
61
77
  async function collectCss(): Promise<{ css: string; remoteLinks: string }> {
62
78
  const seen = new Set<string>();
63
79
  const parts: string[] = [];
@@ -67,7 +83,7 @@ async function collectCss(): Promise<{ css: string; remoteLinks: string }> {
67
83
  // The highlight rule is installed per-navigation and means nothing in a static file.
68
84
  if (style.id === 'seemore-highlight-style') continue;
69
85
  const text = style.textContent ?? '';
70
- if (text.trim() === '' || seen.has(text)) continue;
86
+ if (text.trim() === '' || seen.has(text) || isExtensionCss(text)) continue;
71
87
  seen.add(text);
72
88
  parts.push(text);
73
89
  }
@@ -80,7 +96,9 @@ async function collectCss(): Promise<{ css: string; remoteLinks: string }> {
80
96
  continue;
81
97
  }
82
98
  if (url.origin !== location.origin) {
83
- remote.push(link.outerHTML);
99
+ // An extension's own sheet (`chrome-extension://…`) is not the page's and would not
100
+ // load in the file anyway; only a genuinely remote http(s) sheet stays linked.
101
+ if (url.protocol === 'http:' || url.protocol === 'https:') remote.push(link.outerHTML);
84
102
  continue;
85
103
  }
86
104
  const text = await fetch(url.href)
@@ -384,11 +402,17 @@ const RUNTIME = `(function () {
384
402
  });
385
403
  })();`;
386
404
 
405
+ /** The root attributes that still mean something once the page is a standalone file. */
406
+ const KEPT_ROOT_ATTRIBUTES = new Set(['lang', 'dir', 'class']);
407
+
387
408
  function buildExportHtml(article: Element, css: string, remoteLinks: string, favicons: string): string {
388
- // The root's attributes ride along (lang, dir, whatever a theme added) minus the theme
389
- // class next-themes resolved for *this* screen: THEME_INIT sets that from the reader's
390
- // own OS when the file is opened. An emptied class attribute is dropped entirely.
409
+ // Only the root attributes that mean something in a standalone file ride along: lang,
410
+ // dir, and class minus the theme class next-themes resolved for *this* screen — THEME_INIT
411
+ // sets that from the reader's own OS when the file is opened. The rest of the live root is
412
+ // state for this screen (next-themes' `style="color-scheme: …"`, the sidebar's collapse
413
+ // flag) or was put there by a browser extension. An emptied class attribute is dropped.
391
414
  const attrs = Array.from(document.documentElement.attributes)
415
+ .filter((attr) => KEPT_ROOT_ATTRIBUTES.has(attr.name))
392
416
  .map((attr) => {
393
417
  if (attr.name !== 'class') return { name: attr.name, value: attr.value };
394
418
  const kept = attr.value