kss-modern 1.3.0 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -6,7 +6,7 @@ A modern, KSS-compatible styleguide generator. Parses KSS comment blocks from CS
6
6
 
7
7
  - KSS-compatible comment parsing from CSS/SCSS files
8
8
  - Live component previews with modifier variants
9
- - Per-section theme dropdown (`Themes:`) to switch previews between the default and themed views
9
+ - Theme dropdowns — a global one in the header (`themes` option) and per-section ones (`Themes:`) — switch previews between the default and themed views
10
10
  - Pug template support via worker thread pool
11
11
  - Color palette and icon gallery documentation
12
12
  - Figma embed integration with light/dark theme sync
@@ -105,6 +105,16 @@ interface StyleguideConfiguration {
105
105
  contentDir: `${string}/`;
106
106
  projectTitle: string;
107
107
  deactivateDarkMode?: boolean;
108
+ /**
109
+ * Themes offered by the header's global **Theme** dropdown. Each entry is a theme class (or class
110
+ * list — `'theme-midnight'`, `'.theme-midnight.compact'`) that is added to the `<html>` of every
111
+ * preview iframe while selected, plus the label shown in the dropdown. A section's own `Themes:`
112
+ * dropdown overrides the global theme for that section.
113
+ */
114
+ themes?: {
115
+ value: string;
116
+ label: string;
117
+ }[];
108
118
  launchInEditor?: boolean | {
109
119
  rootDir: string;
110
120
  };
@@ -105,6 +105,16 @@ interface StyleguideConfiguration {
105
105
  contentDir: `${string}/`;
106
106
  projectTitle: string;
107
107
  deactivateDarkMode?: boolean;
108
+ /**
109
+ * Themes offered by the header's global **Theme** dropdown. Each entry is a theme class (or class
110
+ * list — `'theme-midnight'`, `'.theme-midnight.compact'`) that is added to the `<html>` of every
111
+ * preview iframe while selected, plus the label shown in the dropdown. A section's own `Themes:`
112
+ * dropdown overrides the global theme for that section.
113
+ */
114
+ themes?: {
115
+ value: string;
116
+ label: string;
117
+ }[];
108
118
  launchInEditor?: boolean | {
109
119
  rootDir: string;
110
120
  };
@@ -1435,6 +1435,7 @@ function getHeaderHtml(config) {
1435
1435
  </button>
1436
1436
 
1437
1437
  <div class="flex gap-4">
1438
+ ${config.themes?.length ? renderGlobalThemeSelect(config.themes) : ""}
1438
1439
  ${config.mode === "development" && config.launchInEditor ? `
1439
1440
  <form class="hidden editor-select md:block">
1440
1441
  <fieldset class="flex items-center rounded-3xl border border-styleguide-border">
@@ -1612,19 +1613,19 @@ function renderTab(data, aside = "") {
1612
1613
  </div>
1613
1614
  `;
1614
1615
  }
1615
- function renderThemeSelect(section, themes) {
1616
- const selectId = `theme-select-${sectionSanitizeId(section.id)}`;
1616
+ function renderThemeSelectControl(id, themes, scope) {
1617
+ const wrapperClass = scope === "global" ? "hidden md:inline-flex" : "inline-flex";
1617
1618
  return `
1618
- <div class="inline-flex items-center gap-2 text-sm">
1619
- <label for="${selectId}" class="select-none">Theme</label>
1619
+ <div class="${wrapperClass} items-center gap-2 text-sm">
1620
+ <label for="${id}" class="select-none">Theme</label>
1620
1621
  <span class="relative inline-flex">
1621
1622
  <select
1622
- id="${selectId}"
1623
- class="section-theme-select appearance-none cursor-pointer rounded-md border py-1.5 pl-3 pr-8 text-sm transition duration-200 border-styleguide-border bg-styleguide-bg-highlight hover:text-styleguide-highlight focus:text-styleguide-highlight focus-visible:outline focus-visible:outline-blue-600"
1624
- data-section-theme-select
1623
+ id="${id}"
1624
+ class="appearance-none cursor-pointer rounded-md border py-1.5 pl-3 pr-8 text-sm transition duration-200 border-styleguide-border bg-styleguide-bg-highlight hover:text-styleguide-highlight focus:text-styleguide-highlight focus-visible:outline focus-visible:outline-blue-600"
1625
+ data-${scope}-theme-select
1625
1626
  >
1626
1627
  <option value="">Default</option>
1627
- ${themes.map((theme) => `<option value="${sanitizeSpecialCharacters(themeClassList(theme.value))}">${sanitizeSpecialCharacters(theme.description)}</option>`).join("\n")}
1628
+ ${themes.map((theme) => `<option value="${sanitizeSpecialCharacters(themeClassList(theme.value))}">${sanitizeSpecialCharacters(theme.label)}</option>`).join("\n")}
1628
1629
  </select>
1629
1630
  <svg class="pointer-events-none absolute top-1/2 right-2.5 size-3.5 -translate-y-1/2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor" aria-hidden="true">
1630
1631
  <path fill-rule="evenodd" d="M4.22 6.22a.75.75 0 0 1 1.06 0L8 8.94l2.72-2.72a.75.75 0 1 1 1.06 1.06l-3.25 3.25a.75.75 0 0 1-1.06 0L4.22 7.28a.75.75 0 0 1 0-1.06Z" clip-rule="evenodd"/>
@@ -1633,6 +1634,16 @@ function renderThemeSelect(section, themes) {
1633
1634
  </div>
1634
1635
  `;
1635
1636
  }
1637
+ function renderGlobalThemeSelect(themes) {
1638
+ return renderThemeSelectControl("global-theme-select", themes, "global");
1639
+ }
1640
+ function renderThemeSelect(section, themes) {
1641
+ return renderThemeSelectControl(
1642
+ `theme-select-${sectionSanitizeId(section.id)}`,
1643
+ themes.map((theme) => ({ value: theme.value, label: theme.description })),
1644
+ "section"
1645
+ );
1646
+ }
1636
1647
  function getMainContentHtml(secondLevelSection, config) {
1637
1648
  let output = "";
1638
1649
  function renderSection(section) {
@@ -2384,7 +2395,7 @@ document.addEventListener("DOMContentLoaded", () => {
2384
2395
  //#endregion
2385
2396
  ;
2386
2397
  <\/script>
2387
- <script type="module" src="/styleguide-assets/preview-CWqxR9nN.js"><\/script>
2398
+ <script type="module" src="/styleguide-assets/preview-tkLDBWOv.js"><\/script>
2388
2399
  <link rel="preload" href="/styleguide-assets/fonts/geist-mono-latin-400-normal.woff2" as="font" type="font/woff2" crossorigin="anonymous">
2389
2400
  <link rel="preload" href="/styleguide-assets/fonts/geist-mono-latin-600-normal.woff2" as="font" type="font/woff2" crossorigin="anonymous">
2390
2401
  <link rel="preload" href="/styleguide-assets/fonts/geist-mono-latin-300-normal.woff2" as="font" type="font/woff2" crossorigin="anonymous">
@@ -11,12 +11,19 @@
11
11
  "file": "code-highlight-Fm7cxf-E.js",
12
12
  "name": "code-highlight"
13
13
  },
14
+ "_preview-theme-DS4xqXIm.js": {
15
+ "file": "preview-theme-DS4xqXIm.js",
16
+ "name": "preview-theme",
17
+ "imports": [
18
+ "_section-previews-CnlrC8Gz.js"
19
+ ]
20
+ },
14
21
  "_rolldown-runtime-B1bRi_D7.js": {
15
22
  "file": "rolldown-runtime-B1bRi_D7.js",
16
23
  "name": "rolldown-runtime"
17
24
  },
18
- "_section-previews-V4M5aSu6.js": {
19
- "file": "section-previews-V4M5aSu6.js",
25
+ "_section-previews-CnlrC8Gz.js": {
26
+ "file": "section-previews-CnlrC8Gz.js",
20
27
  "name": "section-previews"
21
28
  },
22
29
  "_shared-hGcWlnRM.js": {
@@ -46,14 +53,14 @@
46
53
  ]
47
54
  },
48
55
  "client/lib/a11y-report.ts": {
49
- "file": "a11y-report-DJQyYaLp.js",
56
+ "file": "a11y-report-BFnWMaWr.js",
50
57
  "name": "a11y-report",
51
58
  "src": "client/lib/a11y-report.ts",
52
59
  "isDynamicEntry": true,
53
60
  "imports": [
54
61
  "_utils-DtB-AzJa.js",
55
62
  "_audit-runner-Ch009v98.js",
56
- "_section-previews-V4M5aSu6.js"
63
+ "_section-previews-CnlrC8Gz.js"
57
64
  ]
58
65
  },
59
66
  "client/lib/clipboard.ts": {
@@ -73,8 +80,17 @@
73
80
  "src": "client/lib/editor-select.ts",
74
81
  "isDynamicEntry": true
75
82
  },
83
+ "client/lib/global-theme-select.ts": {
84
+ "file": "global-theme-select-DM7GN8Dn.js",
85
+ "name": "global-theme-select",
86
+ "src": "client/lib/global-theme-select.ts",
87
+ "isDynamicEntry": true,
88
+ "imports": [
89
+ "_preview-theme-DS4xqXIm.js"
90
+ ]
91
+ },
76
92
  "client/lib/html-validator.ts": {
77
- "file": "html-validator-Cp2OkhS9.js",
93
+ "file": "html-validator-sgeZtEeH.js",
78
94
  "name": "html-validator",
79
95
  "src": "client/lib/html-validator.ts",
80
96
  "isDynamicEntry": true,
@@ -83,7 +99,7 @@
83
99
  "_utils-DtB-AzJa.js",
84
100
  "_shared-hGcWlnRM.js",
85
101
  "_audit-runner-Ch009v98.js",
86
- "_section-previews-V4M5aSu6.js"
102
+ "_section-previews-CnlrC8Gz.js"
87
103
  ]
88
104
  },
89
105
  "client/lib/icons.ts": {
@@ -97,12 +113,13 @@
97
113
  ]
98
114
  },
99
115
  "client/lib/section-theme-select.ts": {
100
- "file": "section-theme-select-ygaSXIuK.js",
116
+ "file": "section-theme-select-BHhiP4pl.js",
101
117
  "name": "section-theme-select",
102
118
  "src": "client/lib/section-theme-select.ts",
103
119
  "isDynamicEntry": true,
104
120
  "imports": [
105
- "_section-previews-V4M5aSu6.js"
121
+ "_section-previews-CnlrC8Gz.js",
122
+ "_preview-theme-DS4xqXIm.js"
106
123
  ]
107
124
  },
108
125
  "client/preview-inline.ts": {
@@ -112,7 +129,7 @@
112
129
  "isEntry": true
113
130
  },
114
131
  "client/preview.ts": {
115
- "file": "preview-CWqxR9nN.js",
132
+ "file": "preview-tkLDBWOv.js",
116
133
  "name": "preview",
117
134
  "src": "client/preview.ts",
118
135
  "isEntry": true,
@@ -128,6 +145,7 @@
128
145
  "client/lib/html-validator.ts",
129
146
  "client/lib/icons.ts",
130
147
  "client/lib/clipboard.ts",
148
+ "client/lib/global-theme-select.ts",
131
149
  "client/lib/section-theme-select.ts",
132
150
  "client/lib/editor-select.ts"
133
151
  ]
@@ -1,6 +1,6 @@
1
1
  import { r as e } from "./utils-DtB-AzJa.js";
2
2
  import { a as t, i as n, n as r, o as i, r as a } from "./audit-runner-Ch009v98.js";
3
- import { n as o, t as s } from "./section-previews-V4M5aSu6.js";
3
+ import { n as o, r as s } from "./section-previews-CnlrC8Gz.js";
4
4
  //#region client/lib/a11y-report.ts
5
5
  var c = {
6
6
  violations: ["violations", "incomplete"],
@@ -10,8 +10,8 @@ function l(t) {
10
10
  return e(t.trim()).replace(/^section-/, "");
11
11
  }
12
12
  function u() {
13
- return Array.from(document.querySelectorAll(s)).flatMap((e) => {
14
- let { base: t, modifiers: n } = o(e);
13
+ return Array.from(document.querySelectorAll(o)).flatMap((e) => {
14
+ let { base: t, modifiers: n } = s(e);
15
15
  if (!t) return [];
16
16
  let r = Number.parseInt(e.dataset.sourceLine ?? "", 10);
17
17
  return [{
@@ -0,0 +1,7 @@
1
+ import { i as e, r as t, t as n } from "./preview-theme-DS4xqXIm.js";
2
+ //#region client/lib/global-theme-select.ts
3
+ function r(r) {
4
+ e(r, n, document), t();
5
+ }
6
+ //#endregion
7
+ export { r as default };
@@ -2,7 +2,7 @@ import { t as e } from "./code-highlight-Fm7cxf-E.js";
2
2
  import { n as t, t as n } from "./utils-DtB-AzJa.js";
3
3
  import { n as r } from "./shared-hGcWlnRM.js";
4
4
  import { a as i, i as a, n as o, o as s, r as c } from "./audit-runner-Ch009v98.js";
5
- import { n as l, t as u } from "./section-previews-V4M5aSu6.js";
5
+ import { n as l, r as u } from "./section-previews-CnlrC8Gz.js";
6
6
  //#region lib/template-utils.ts
7
7
  var d = (e, t) => e ? t() : "";
8
8
  function f(e, t) {
@@ -66,7 +66,7 @@ async function g(g, _, v) {
66
66
  }, 2e3);
67
67
  }
68
68
  };
69
- let S = await i(b), { modifiers: C } = l(b.closest(u)), w = (await Promise.all(C.map(async (e) => {
69
+ let S = await i(b), { modifiers: C } = u(b.closest(l)), w = (await Promise.all(C.map(async (e) => {
70
70
  try {
71
71
  return {
72
72
  iframe: e,
@@ -0,0 +1,50 @@
1
+ import { n as e, t } from "./section-previews-CnlrC8Gz.js";
2
+ //#region client/lib/preview-theme.ts
3
+ var n = "data-theme-class", r = "theme", i = "in2global-theme", a = "in2section-theme:", o = "[data-global-theme-select]", s = "[data-section-theme-select]", c = "a[href^=\"/fullpage-\"]";
4
+ function l(e) {
5
+ return e.split(/\s+/).filter(Boolean);
6
+ }
7
+ function u(e, t) {
8
+ let r = e.getAttribute(n) ?? "";
9
+ if (r === t) return;
10
+ t ? e.setAttribute(n, t) : e.removeAttribute(n);
11
+ let i = e.contentDocument?.documentElement;
12
+ i && (i.classList.remove(...l(r)), i.classList.add(...l(t)));
13
+ }
14
+ function d(e, t) {
15
+ let n = new URL(e.getAttribute("href"), window.location.href);
16
+ t ? n.searchParams.set(r, t) : n.searchParams.delete(r);
17
+ let i = `${n.pathname}${n.search}${n.hash}`;
18
+ i !== e.getAttribute("href") && e.setAttribute("href", i);
19
+ }
20
+ function f(e) {
21
+ let t = e?.querySelector(s), n = document.querySelector(o);
22
+ return t?.value || n?.value || "";
23
+ }
24
+ function p(n = document) {
25
+ n.querySelectorAll(t).forEach((t) => {
26
+ u(t, f(t.closest(e)));
27
+ }), n.querySelectorAll(c).forEach((t) => {
28
+ d(t, f(t.closest(e)));
29
+ });
30
+ }
31
+ function m(e) {
32
+ try {
33
+ return localStorage.getItem(e);
34
+ } catch {
35
+ return null;
36
+ }
37
+ }
38
+ function h(e, t) {
39
+ try {
40
+ t ? localStorage.setItem(e, t) : localStorage.removeItem(e);
41
+ } catch {}
42
+ }
43
+ function g(e, t, n) {
44
+ let r = m(t);
45
+ r && Array.from(e.options).some((e) => e.value === r) && (e.value = r), e.addEventListener("change", () => {
46
+ h(t, e.value), p(n);
47
+ });
48
+ }
49
+ //#endregion
50
+ export { g as i, a as n, p as r, i as t };
@@ -1081,7 +1081,7 @@ q.addEventListener("keydown", Je), Y.forEach((e) => e.addEventListener("keydown"
1081
1081
  let t = e.target, n = new URL(window.location.href), r = new URL(t.href);
1082
1082
  n.pathname === r.pathname && n.search === r.search && await We();
1083
1083
  }), window.kssAudit = async (e) => {
1084
- let { runStyleguideAudit: t } = await import("./a11y-report-DJQyYaLp.js");
1084
+ let { runStyleguideAudit: t } = await import("./a11y-report-BFnWMaWr.js");
1085
1085
  return t(e);
1086
1086
  }, document.querySelectorAll(".styleguide-section").forEach((e) => {
1087
1087
  new ResizeObserver(() => {
@@ -1097,7 +1097,7 @@ Xe.length > 0 && Xe.forEach((e) => {
1097
1097
  });
1098
1098
  var $ = document.querySelectorAll("[data-code-audit-iframe]"), Ze = document.querySelector("#code-audit-dialog"), Qe = document.querySelector(".dialog-backdrop");
1099
1099
  $.length > 0 && Ze && Qe && (async () => {
1100
- let { auditCode: e } = await import("./html-validator-Cp2OkhS9.js"), { show: t, close: n } = s(Ze, Qe);
1100
+ let { auditCode: e } = await import("./html-validator-sgeZtEeH.js"), { show: t, close: n } = s(Ze, Qe);
1101
1101
  $.forEach((r) => r.addEventListener("click", async () => {
1102
1102
  $.forEach((e) => e.setAttribute("aria-expanded", "false")), r.setAttribute("disabled", ""), await e(r, Ze, n), r.removeAttribute("disabled"), r.setAttribute("aria-expanded", "true"), await t(void 0, () => {
1103
1103
  $.forEach((e) => {
@@ -1134,8 +1134,10 @@ window.addEventListener("scroll", () => {
1134
1134
  document.body.classList.remove("is-scrolling");
1135
1135
  }, 250);
1136
1136
  });
1137
- var ot = document.querySelectorAll("[data-section-theme-select]");
1138
- ot.length > 0 && import("./section-theme-select-ygaSXIuK.js").then(({ default: e }) => e(ot)).catch(console.error);
1139
- var st = document.querySelector(".editor-select");
1140
- st && import("./editor-select-DIZFtqe7.js").then(({ default: e }) => e(st)).catch(console.error);
1137
+ var ot = document.querySelector("[data-global-theme-select]");
1138
+ ot && import("./global-theme-select-DM7GN8Dn.js").then(({ default: e }) => e(ot)).catch(console.error);
1139
+ var st = document.querySelectorAll("[data-section-theme-select]");
1140
+ st.length > 0 && import("./section-theme-select-BHhiP4pl.js").then(({ default: e }) => e(st)).catch(console.error);
1141
+ var ct = document.querySelector(".editor-select");
1142
+ ct && import("./editor-select-DIZFtqe7.js").then(({ default: e }) => e(ct)).catch(console.error);
1141
1143
  //#endregion
@@ -1,10 +1,10 @@
1
1
  //#region client/lib/section-previews.ts
2
- var e = ".styleguide-section";
3
- function t(e) {
2
+ var e = ".styleguide-section", t = "iframe.preview-iframe";
3
+ function n(e) {
4
4
  return {
5
5
  base: e?.querySelector("iframe.preview-iframe:not([data-modifier])") ?? null,
6
6
  modifiers: Array.from(e?.querySelectorAll("iframe.preview-iframe[data-modifier]") ?? [])
7
7
  };
8
8
  }
9
9
  //#endregion
10
- export { t as n, e as t };
10
+ export { e as n, n as r, t };
@@ -0,0 +1,12 @@
1
+ import { n as e } from "./section-previews-CnlrC8Gz.js";
2
+ import { i as t, n, r } from "./preview-theme-DS4xqXIm.js";
3
+ //#region client/lib/section-theme-select.ts
4
+ function i(i) {
5
+ for (let r of i) {
6
+ let i = r.closest(e);
7
+ i && t(r, `${n}${i.getAttribute("data-section-reference") ?? i.id}`, i);
8
+ }
9
+ r();
10
+ }
11
+ //#endregion
12
+ export { i as default };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "kss-modern",
3
3
  "type": "module",
4
- "version": "1.3.0",
4
+ "version": "1.4.0",
5
5
  "description": "Modern KSS compatible styleguide generator",
6
6
  "keywords": [
7
7
  "kss",
@@ -1,48 +0,0 @@
1
- import { n as e, t } from "./section-previews-V4M5aSu6.js";
2
- //#region client/lib/section-theme-select.ts
3
- var n = "data-theme-class", r = "theme", i = "in2section-theme:";
4
- function a(e) {
5
- return (e ?? "").split(/\s+/).filter(Boolean);
6
- }
7
- function o(e, t) {
8
- let r = e.getAttribute(n);
9
- t ? e.setAttribute(n, t) : e.removeAttribute(n);
10
- let i = e.contentDocument?.documentElement;
11
- i && (i.classList.remove(...a(r)), i.classList.add(...a(t)));
12
- }
13
- function s(e, t) {
14
- e.querySelectorAll("a[href^=\"/fullpage-\"]").forEach((e) => {
15
- let n = new URL(e.getAttribute("href"), window.location.href);
16
- t ? n.searchParams.set(r, t) : n.searchParams.delete(r), e.setAttribute("href", `${n.pathname}${n.search}${n.hash}`);
17
- });
18
- }
19
- function c(e) {
20
- try {
21
- return localStorage.getItem(e);
22
- } catch {
23
- return null;
24
- }
25
- }
26
- function l(e, t) {
27
- try {
28
- t ? localStorage.setItem(e, t) : localStorage.removeItem(e);
29
- } catch {}
30
- }
31
- function u(e, t) {
32
- return Array.from(e.options).some((e) => e.value === t);
33
- }
34
- function d(n) {
35
- for (let r of n) {
36
- let n = r.closest(t);
37
- if (!n) continue;
38
- let a = `${i}${n.getAttribute("data-section-reference") ?? n.id}`, d = (t) => {
39
- let { base: r, modifiers: i } = e(n);
40
- (r ? [r, ...i] : i).forEach((e) => o(e, t)), s(n, t);
41
- }, f = c(a);
42
- f && u(r, f) && (r.value = f), r.value && d(r.value), r.addEventListener("change", () => {
43
- l(a, r.value), d(r.value);
44
- });
45
- }
46
- }
47
- //#endregion
48
- export { d as default };