@countermeasure-platform/web-components 1.3.3-dev.33.1 → 1.3.4-dev.35.1
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 +31 -0
- package/dist/component-D5sRm1fq.js +389 -0
- package/dist/component-D5sRm1fq.js.map +1 -0
- package/dist/components/index.js +27 -27
- package/dist/icons/index.d.ts +12 -0
- package/dist/icons/index.d.ts.map +1 -1
- package/dist/icons/index.js +12 -0
- package/dist/icons/index.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +127 -126
- package/dist/layout/app-shell.d.ts +50 -3
- package/dist/layout/app-shell.d.ts.map +1 -1
- package/dist/layout/app-shell.js +142 -13
- package/dist/layout/app-shell.js.map +1 -1
- package/dist/layout/core-app-chrome.d.ts +81 -0
- package/dist/layout/core-app-chrome.d.ts.map +1 -0
- package/dist/layout/core-app-chrome.js +349 -0
- package/dist/layout/core-app-chrome.js.map +1 -0
- package/dist/layout/index.d.ts +4 -2
- package/dist/layout/index.d.ts.map +1 -1
- package/dist/layout/index.js +88 -87
- package/dist/layout/index.js.map +1 -1
- package/dist/react/primitives/badge.d.ts +1 -1
- package/dist/react/primitives/button.d.ts +2 -2
- package/dist/react/primitives/copy-button.d.ts +1 -1
- package/dist/react/primitives/stat-card.d.ts +1 -1
- package/dist/react/primitives/toggle.d.ts +1 -1
- package/dist/react/sidebar.d.ts +4 -4
- package/dist/react/sidebar.d.ts.map +1 -1
- package/dist/react/sidebar.js +18 -16
- package/dist/react/sidebar.js.map +1 -1
- package/dist/sidebar/component.d.ts +24 -2
- package/dist/sidebar/component.d.ts.map +1 -1
- package/dist/sidebar/enhance.d.ts +8 -0
- package/dist/sidebar/enhance.d.ts.map +1 -1
- package/dist/sidebar/index.d.ts +3 -0
- package/dist/sidebar/index.d.ts.map +1 -1
- package/dist/sidebar/index.js +81 -28
- package/dist/sidebar/index.js.map +1 -1
- package/dist/sidebar/types.d.ts +126 -4
- package/dist/sidebar/types.d.ts.map +1 -1
- package/dist/styles/layout.css +252 -0
- package/dist/styles/sidebar.css +313 -5
- package/package.json +6 -1
- package/src/icons/icons.test.ts +9 -0
- package/src/icons/index.ts +12 -0
- package/src/index.ts +11 -0
- package/src/layout/app-shell.test.ts +204 -0
- package/src/layout/app-shell.ts +362 -3
- package/src/layout/core-app-chrome.test.ts +507 -0
- package/src/layout/core-app-chrome.ts +662 -0
- package/src/layout/index.ts +36 -2
- package/src/react/sidebar.test.tsx +104 -3
- package/src/react/sidebar.tsx +26 -4
- package/src/sidebar/component.test.ts +395 -1
- package/src/sidebar/component.ts +661 -86
- package/src/sidebar/enhance.ts +118 -0
- package/src/sidebar/index.ts +144 -0
- package/src/sidebar/types.ts +143 -4
- package/src/styles/layout.css +252 -0
- package/src/styles/sidebar.css +313 -5
- package/dist/component-Bxhxf21c.js +0 -167
- package/dist/component-Bxhxf21c.js.map +0 -1
|
@@ -1,167 +0,0 @@
|
|
|
1
|
-
import { getIconSvgInner as e } from "./icons/index.js";
|
|
2
|
-
import { o as t } from "./sanitize-uWpY18N9.js";
|
|
3
|
-
import { t as n } from "./utils-CSEWuKHo.js";
|
|
4
|
-
import { createBrandLockupElement as r } from "./components/brand/index.js";
|
|
5
|
-
//#region src/sidebar/component.ts
|
|
6
|
-
function i(e) {
|
|
7
|
-
return `sidebar--${e.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "") || "app"}`;
|
|
8
|
-
}
|
|
9
|
-
function a(n, r) {
|
|
10
|
-
let i = "http://www.w3.org/2000/svg", a = document.createElementNS(i, "svg");
|
|
11
|
-
a.setAttribute("xmlns", i), a.setAttribute("width", "16"), a.setAttribute("height", "16"), a.setAttribute("viewBox", "0 0 24 24"), a.setAttribute("fill", "none"), a.setAttribute("stroke", "currentColor"), a.setAttribute("stroke-width", "2"), a.setAttribute("stroke-linecap", "round"), a.setAttribute("stroke-linejoin", "round"), a.classList.add("sidebar__item-icon"), a.setAttribute("data-icon", r), a.setAttribute("aria-hidden", "true");
|
|
12
|
-
let o = e(n, r);
|
|
13
|
-
return o && t(a, o), a;
|
|
14
|
-
}
|
|
15
|
-
var o = class {
|
|
16
|
-
container;
|
|
17
|
-
aside;
|
|
18
|
-
config;
|
|
19
|
-
iconSet;
|
|
20
|
-
collapseButton = null;
|
|
21
|
-
constructor(e) {
|
|
22
|
-
this.config = e, this.container = n(e.container), this.iconSet = e.iconSet ?? "lucide", this.aside = document.createElement("aside");
|
|
23
|
-
let t = e.variant ?? "app";
|
|
24
|
-
this.aside.classList.add("sidebar", i(t)), this.aside.setAttribute("data-sidebar", t), this.aside.setAttribute("data-open", String(e.open === !0)), e.collapsed === !0 && this.aside.classList.add("sidebar--collapsed"), this.render(), this.container.appendChild(this.aside);
|
|
25
|
-
}
|
|
26
|
-
render() {
|
|
27
|
-
this.config.collapsible === !0 && this.renderCollapseButton(), this.renderHeader();
|
|
28
|
-
let e = document.createElement("div");
|
|
29
|
-
e.classList.add("sidebar__body");
|
|
30
|
-
for (let t of this.config.sections) e.appendChild(this.buildSection(t));
|
|
31
|
-
this.aside.appendChild(e), this.renderFooter();
|
|
32
|
-
}
|
|
33
|
-
buildSection(e) {
|
|
34
|
-
let t = document.createElement("div");
|
|
35
|
-
t.classList.add("sidebar__section"), t.setAttribute("data-section-id", e.id);
|
|
36
|
-
let n = e.collapsible === !0, r = e.defaultExpanded !== !1;
|
|
37
|
-
if (n && e.label) {
|
|
38
|
-
t.classList.add("sidebar__section--collapsible"), r && t.classList.add("sidebar__section--expanded");
|
|
39
|
-
let n = document.createElement("button");
|
|
40
|
-
n.type = "button", n.classList.add("sidebar__group-header"), n.setAttribute("aria-expanded", String(r)), n.setAttribute("aria-controls", `sidebar-group-${e.id}`), e.icon && n.appendChild(a(this.iconSet, e.icon));
|
|
41
|
-
let i = document.createElement("span");
|
|
42
|
-
i.classList.add("sidebar__group-label"), i.textContent = e.label, n.appendChild(i);
|
|
43
|
-
let o = document.createElementNS("http://www.w3.org/2000/svg", "svg");
|
|
44
|
-
o.setAttribute("class", "sidebar__group-chevron"), o.setAttribute("viewBox", "0 0 24 24"), o.setAttribute("width", "14"), o.setAttribute("height", "14"), o.setAttribute("fill", "none"), o.setAttribute("stroke", "currentColor"), o.setAttribute("stroke-width", "2"), o.setAttribute("stroke-linecap", "round"), o.setAttribute("stroke-linejoin", "round"), o.setAttribute("aria-hidden", "true");
|
|
45
|
-
let s = document.createElementNS("http://www.w3.org/2000/svg", "path");
|
|
46
|
-
s.setAttribute("d", "m6 9 6 6 6-6"), o.appendChild(s), n.appendChild(o), n.addEventListener("click", () => {
|
|
47
|
-
let e = t.classList.toggle("sidebar__section--expanded");
|
|
48
|
-
n.setAttribute("aria-expanded", String(e));
|
|
49
|
-
}), t.appendChild(n);
|
|
50
|
-
} else if (e.label) {
|
|
51
|
-
let n = document.createElement("div");
|
|
52
|
-
n.classList.add("sidebar__section-label"), n.textContent = e.label, t.appendChild(n);
|
|
53
|
-
}
|
|
54
|
-
let i = document.createElement("div");
|
|
55
|
-
i.classList.add("sidebar__items"), i.id = `sidebar-group-${e.id}`;
|
|
56
|
-
for (let t of e.items) {
|
|
57
|
-
let e = document.createElement("a");
|
|
58
|
-
if (e.classList.add("sidebar__item"), e.setAttribute("data-item-id", t.id), e.setAttribute("title", t.label), t.icon) {
|
|
59
|
-
let n = a(this.iconSet, t.icon);
|
|
60
|
-
e.appendChild(n);
|
|
61
|
-
}
|
|
62
|
-
let n = document.createElement("span");
|
|
63
|
-
if (n.classList.add("sidebar__item-label"), n.textContent = t.label, e.appendChild(n), t.badge !== void 0 && t.badge > 0) {
|
|
64
|
-
let n = document.createElement("span"), r = t.badgeTone ?? "primary";
|
|
65
|
-
e.setAttribute("data-badge-visible", "true"), e.setAttribute("data-badge-tone", r), n.classList.add("sidebar__badge", `sidebar__badge--${r}`), n.setAttribute("data-badge", t.id), n.textContent = String(t.badge), e.appendChild(n);
|
|
66
|
-
}
|
|
67
|
-
e.addEventListener("click", () => {
|
|
68
|
-
this.config.onNavigate && this.config.onNavigate(t), t.onClick && t.onClick();
|
|
69
|
-
}), i.appendChild(e);
|
|
70
|
-
}
|
|
71
|
-
return t.appendChild(i), t;
|
|
72
|
-
}
|
|
73
|
-
renderHeader() {
|
|
74
|
-
let e = this.config.brand;
|
|
75
|
-
if (e === void 0) return;
|
|
76
|
-
let t = document.createElement("div");
|
|
77
|
-
t.classList.add("sidebar__header");
|
|
78
|
-
let n = document.createElement("div");
|
|
79
|
-
n.classList.add("sidebar__header-row");
|
|
80
|
-
let i = e.href === void 0 ? e.onClick === void 0 ? document.createElement("span") : document.createElement("button") : document.createElement("a");
|
|
81
|
-
i.classList.add("sidebar__brand"), i instanceof HTMLAnchorElement && (i.href = e.href ?? "#", i.setAttribute("aria-label", e.label ?? "CounterMeasure")), i instanceof HTMLButtonElement && (i.type = "button", i.setAttribute("aria-label", e.label ?? "CounterMeasure")), e.onClick !== void 0 && i.addEventListener("click", e.onClick), i.appendChild(r({
|
|
82
|
-
label: e.label ?? "CounterMeasure",
|
|
83
|
-
markSize: e.markSize ?? 22,
|
|
84
|
-
showWordmark: e.showWordmark ?? !0,
|
|
85
|
-
decorative: e.decorative ?? !1
|
|
86
|
-
})), n.appendChild(i), t.appendChild(n), this.aside.appendChild(t);
|
|
87
|
-
}
|
|
88
|
-
renderCollapseButton() {
|
|
89
|
-
let e = document.createElement("button");
|
|
90
|
-
e.type = "button", e.classList.add("sidebar__collapse-btn", "sidebar__collapse-btn--edge"), e.setAttribute("data-sidebar-toggle", ""), this.config.collapseButtonVisible === !0 && e.setAttribute("data-visible", "true");
|
|
91
|
-
let t = document.createElementNS("http://www.w3.org/2000/svg", "svg");
|
|
92
|
-
t.setAttribute("aria-hidden", "true"), t.setAttribute("viewBox", "0 0 24 24"), t.setAttribute("fill", "none"), t.setAttribute("stroke", "currentColor"), t.setAttribute("stroke-width", "2"), t.setAttribute("stroke-linecap", "round"), t.setAttribute("stroke-linejoin", "round");
|
|
93
|
-
let n = document.createElementNS("http://www.w3.org/2000/svg", "path");
|
|
94
|
-
t.appendChild(n), e.appendChild(t), e.addEventListener("click", () => {
|
|
95
|
-
this.toggleCollapse();
|
|
96
|
-
}), this.collapseButton = e, this.updateCollapseButton(), this.aside.appendChild(e);
|
|
97
|
-
}
|
|
98
|
-
renderFooter() {
|
|
99
|
-
let e = this.config.user !== void 0, t = this.config.footerActions !== void 0 && this.config.footerActions.length > 0;
|
|
100
|
-
if (!e && !t) return;
|
|
101
|
-
let n = document.createElement("div");
|
|
102
|
-
n.classList.add("sidebar__footer");
|
|
103
|
-
let r = document.createElement("div");
|
|
104
|
-
if (r.classList.add("sidebar__footer-bar"), e && this.config.user) {
|
|
105
|
-
let e = document.createElement("span");
|
|
106
|
-
e.classList.add("sidebar__footer-user");
|
|
107
|
-
let t = document.createElement("span");
|
|
108
|
-
t.classList.add("sidebar__footer-name"), t.textContent = this.config.user.name, e.appendChild(t), r.appendChild(e);
|
|
109
|
-
}
|
|
110
|
-
if (t && this.config.footerActions) {
|
|
111
|
-
let e = document.createElement("span");
|
|
112
|
-
e.classList.add("sidebar__footer-icons");
|
|
113
|
-
for (let t of this.config.footerActions) {
|
|
114
|
-
let n = document.createElement("button");
|
|
115
|
-
n.classList.add("sidebar__footer-icon"), t.danger === !0 && n.classList.add("sidebar__footer-icon--danger"), n.setAttribute("aria-label", t.label);
|
|
116
|
-
let r = a(this.iconSet, t.icon);
|
|
117
|
-
if (n.appendChild(r), t.onClick) {
|
|
118
|
-
let e = t.onClick;
|
|
119
|
-
n.addEventListener("click", () => {
|
|
120
|
-
e();
|
|
121
|
-
});
|
|
122
|
-
}
|
|
123
|
-
e.appendChild(n);
|
|
124
|
-
}
|
|
125
|
-
r.appendChild(e);
|
|
126
|
-
}
|
|
127
|
-
n.appendChild(r), this.aside.appendChild(n);
|
|
128
|
-
}
|
|
129
|
-
setActive(e) {
|
|
130
|
-
this.aside.querySelectorAll(".sidebar__item").forEach((e) => {
|
|
131
|
-
e.classList.remove("sidebar__item--active");
|
|
132
|
-
});
|
|
133
|
-
let t = this.aside.querySelector(`[data-item-id="${e}"]`);
|
|
134
|
-
t && t.classList.add("sidebar__item--active");
|
|
135
|
-
}
|
|
136
|
-
updateBadge(e, t) {
|
|
137
|
-
let n = this.aside.querySelector(`[data-badge="${e}"]`);
|
|
138
|
-
n && (n.textContent = t > 0 ? String(t) : "", n.closest(".sidebar__item")?.setAttribute("data-badge-visible", String(t > 0)));
|
|
139
|
-
}
|
|
140
|
-
toggleCollapse() {
|
|
141
|
-
let e = this.aside.classList.toggle("sidebar--collapsed");
|
|
142
|
-
this.updateCollapseButton(), this.config.onCollapse && this.config.onCollapse(e);
|
|
143
|
-
}
|
|
144
|
-
collapse() {
|
|
145
|
-
let e = this.aside.classList.contains("sidebar--collapsed");
|
|
146
|
-
this.aside.classList.add("sidebar--collapsed"), this.updateCollapseButton(), !e && this.config.onCollapse && this.config.onCollapse(!0);
|
|
147
|
-
}
|
|
148
|
-
expand() {
|
|
149
|
-
let e = this.aside.classList.contains("sidebar--collapsed");
|
|
150
|
-
this.aside.classList.remove("sidebar--collapsed"), this.updateCollapseButton(), e && this.config.onCollapse && this.config.onCollapse(!1);
|
|
151
|
-
}
|
|
152
|
-
setOpen(e) {
|
|
153
|
-
this.aside.setAttribute("data-open", String(e));
|
|
154
|
-
}
|
|
155
|
-
destroy() {
|
|
156
|
-
this.aside.remove();
|
|
157
|
-
}
|
|
158
|
-
updateCollapseButton() {
|
|
159
|
-
if (this.collapseButton === null) return;
|
|
160
|
-
let e = this.aside.classList.contains("sidebar--collapsed"), t = e ? "Expand sidebar" : "Collapse sidebar";
|
|
161
|
-
this.collapseButton.setAttribute("aria-label", t), this.collapseButton.setAttribute("aria-expanded", String(!e)), this.collapseButton.setAttribute("title", t), this.collapseButton.setAttribute("data-collapsed", String(e)), this.collapseButton.querySelector("path")?.setAttribute("d", e ? "m9 18 6-6-6-6" : "m15 18-6-6 6-6");
|
|
162
|
-
}
|
|
163
|
-
};
|
|
164
|
-
//#endregion
|
|
165
|
-
export { o as t };
|
|
166
|
-
|
|
167
|
-
//# sourceMappingURL=component-Bxhxf21c.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"component-Bxhxf21c.js","names":[],"sources":["../src/sidebar/component.ts"],"sourcesContent":["/**\n * SidebarComponent - Programmatic sidebar with sections, badges, and footer\n * @countermeasure/web-components/sidebar/component\n *\n * Unlike sidebar/enhance (which enhances server-rendered HTML), this module\n * builds the sidebar DOM from a config object. Use it when the sidebar\n * structure is driven entirely by client-side data.\n *\n * Usage:\n * import { SidebarComponent } from '@countermeasure/web-components/sidebar/component'\n *\n * const sidebar = new SidebarComponent({\n * container: '#sidebar-root',\n * sections: [{ id: 'main', label: 'Nav', items: [...] }],\n * user: { name: 'Alice' },\n * onNavigate: item => console.log(item.id),\n * })\n * sidebar.setActive('dashboard')\n */\n\nimport { createBrandLockupElement } from '../components/brand'\nimport { getIconSvgInner, type IconSet } from '../icons/index'\nimport { resolveContainer } from '../primitives/utils'\nimport { setSafeIconHtml } from '../utils/sanitize'\nimport { type SidebarComponentConfig, type SidebarSection } from './types'\n\nfunction toSidebarVariantClassName(variant: string): string {\n const normalized = variant\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-|-$/g, '')\n return `sidebar--${normalized || 'app'}`\n}\n\n/** Create an SVG element populated with icon content from the registry. */\nfunction createIconSvg(iconSet: IconSet, name: string): SVGElement {\n const svgNs = 'http://www.w3.org/2000/svg'\n const svg = document.createElementNS(svgNs, 'svg')\n svg.setAttribute('xmlns', svgNs)\n svg.setAttribute('width', '16')\n svg.setAttribute('height', '16')\n svg.setAttribute('viewBox', '0 0 24 24')\n svg.setAttribute('fill', 'none')\n svg.setAttribute('stroke', 'currentColor')\n svg.setAttribute('stroke-width', '2')\n svg.setAttribute('stroke-linecap', 'round')\n svg.setAttribute('stroke-linejoin', 'round')\n svg.classList.add('sidebar__item-icon')\n svg.setAttribute('data-icon', name)\n svg.setAttribute('aria-hidden', 'true')\n\n const inner = getIconSvgInner(iconSet, name)\n if (inner) {\n setSafeIconHtml(svg, inner)\n }\n\n return svg\n}\n\nexport class SidebarComponent {\n private readonly container: HTMLElement\n private readonly aside: HTMLElement\n private readonly config: SidebarComponentConfig\n private readonly iconSet: IconSet\n private collapseButton: HTMLButtonElement | null = null\n\n constructor(config: SidebarComponentConfig) {\n this.config = config\n this.container = resolveContainer(config.container)\n this.iconSet = config.iconSet ?? 'lucide'\n\n this.aside = document.createElement('aside')\n const variant = config.variant ?? 'app'\n this.aside.classList.add('sidebar', toSidebarVariantClassName(variant))\n this.aside.setAttribute('data-sidebar', variant)\n this.aside.setAttribute('data-open', String(config.open === true))\n if (config.collapsed === true) {\n this.aside.classList.add('sidebar--collapsed')\n }\n\n this.render()\n this.container.appendChild(this.aside)\n }\n\n private render(): void {\n if (this.config.collapsible === true) {\n this.renderCollapseButton()\n }\n\n this.renderHeader()\n\n const body = document.createElement('div')\n body.classList.add('sidebar__body')\n\n for (const section of this.config.sections) {\n body.appendChild(this.buildSection(section))\n }\n\n this.aside.appendChild(body)\n this.renderFooter()\n }\n\n private buildSection(section: SidebarSection): HTMLElement {\n const sectionEl = document.createElement('div')\n sectionEl.classList.add('sidebar__section')\n sectionEl.setAttribute('data-section-id', section.id)\n\n const collapsible = section.collapsible === true\n const expanded = section.defaultExpanded !== false\n\n if (collapsible && section.label) {\n sectionEl.classList.add('sidebar__section--collapsible')\n if (expanded) sectionEl.classList.add('sidebar__section--expanded')\n\n const header = document.createElement('button')\n header.type = 'button'\n header.classList.add('sidebar__group-header')\n header.setAttribute('aria-expanded', String(expanded))\n header.setAttribute('aria-controls', `sidebar-group-${section.id}`)\n\n if (section.icon) {\n header.appendChild(createIconSvg(this.iconSet, section.icon))\n }\n\n const labelSpan = document.createElement('span')\n labelSpan.classList.add('sidebar__group-label')\n labelSpan.textContent = section.label\n header.appendChild(labelSpan)\n\n const chevron = document.createElementNS('http://www.w3.org/2000/svg', 'svg')\n chevron.setAttribute('class', 'sidebar__group-chevron')\n chevron.setAttribute('viewBox', '0 0 24 24')\n chevron.setAttribute('width', '14')\n chevron.setAttribute('height', '14')\n chevron.setAttribute('fill', 'none')\n chevron.setAttribute('stroke', 'currentColor')\n chevron.setAttribute('stroke-width', '2')\n chevron.setAttribute('stroke-linecap', 'round')\n chevron.setAttribute('stroke-linejoin', 'round')\n chevron.setAttribute('aria-hidden', 'true')\n const chevronPath = document.createElementNS('http://www.w3.org/2000/svg', 'path')\n chevronPath.setAttribute('d', 'm6 9 6 6 6-6')\n chevron.appendChild(chevronPath)\n header.appendChild(chevron)\n\n header.addEventListener('click', () => {\n const nowExpanded = sectionEl.classList.toggle('sidebar__section--expanded')\n header.setAttribute('aria-expanded', String(nowExpanded))\n })\n\n sectionEl.appendChild(header)\n } else if (section.label) {\n const labelEl = document.createElement('div')\n labelEl.classList.add('sidebar__section-label')\n labelEl.textContent = section.label\n sectionEl.appendChild(labelEl)\n }\n\n const itemsWrap = document.createElement('div')\n itemsWrap.classList.add('sidebar__items')\n itemsWrap.id = `sidebar-group-${section.id}`\n\n for (const item of section.items) {\n const link = document.createElement('a')\n link.classList.add('sidebar__item')\n link.setAttribute('data-item-id', item.id)\n link.setAttribute('title', item.label)\n\n if (item.icon) {\n const icon = createIconSvg(this.iconSet, item.icon)\n link.appendChild(icon)\n }\n\n const label = document.createElement('span')\n label.classList.add('sidebar__item-label')\n label.textContent = item.label\n link.appendChild(label)\n\n if (item.badge !== undefined && item.badge > 0) {\n const badge = document.createElement('span')\n const tone = item.badgeTone ?? 'primary'\n link.setAttribute('data-badge-visible', 'true')\n link.setAttribute('data-badge-tone', tone)\n badge.classList.add('sidebar__badge', `sidebar__badge--${tone}`)\n badge.setAttribute('data-badge', item.id)\n badge.textContent = String(item.badge)\n link.appendChild(badge)\n }\n\n link.addEventListener('click', () => {\n if (this.config.onNavigate) {\n this.config.onNavigate(item)\n }\n if (item.onClick) {\n item.onClick()\n }\n })\n\n itemsWrap.appendChild(link)\n }\n\n sectionEl.appendChild(itemsWrap)\n return sectionEl\n }\n\n private renderHeader(): void {\n const brand = this.config.brand\n if (brand === undefined) {\n return\n }\n\n const header = document.createElement('div')\n header.classList.add('sidebar__header')\n\n const row = document.createElement('div')\n row.classList.add('sidebar__header-row')\n\n const brandEl =\n brand.href !== undefined\n ? document.createElement('a')\n : brand.onClick !== undefined\n ? document.createElement('button')\n : document.createElement('span')\n\n brandEl.classList.add('sidebar__brand')\n\n if (brandEl instanceof HTMLAnchorElement) {\n brandEl.href = brand.href ?? '#'\n brandEl.setAttribute('aria-label', brand.label ?? 'CounterMeasure')\n }\n\n if (brandEl instanceof HTMLButtonElement) {\n brandEl.type = 'button'\n brandEl.setAttribute('aria-label', brand.label ?? 'CounterMeasure')\n }\n\n if (brand.onClick !== undefined) {\n brandEl.addEventListener('click', brand.onClick)\n }\n\n brandEl.appendChild(\n createBrandLockupElement({\n label: brand.label ?? 'CounterMeasure',\n markSize: brand.markSize ?? 22,\n showWordmark: brand.showWordmark ?? true,\n decorative: brand.decorative ?? false,\n })\n )\n\n row.appendChild(brandEl)\n header.appendChild(row)\n this.aside.appendChild(header)\n }\n\n private renderCollapseButton(): void {\n const button = document.createElement('button')\n button.type = 'button'\n button.classList.add('sidebar__collapse-btn', 'sidebar__collapse-btn--edge')\n button.setAttribute('data-sidebar-toggle', '')\n\n if (this.config.collapseButtonVisible === true) {\n button.setAttribute('data-visible', 'true')\n }\n\n const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg')\n svg.setAttribute('aria-hidden', 'true')\n svg.setAttribute('viewBox', '0 0 24 24')\n svg.setAttribute('fill', 'none')\n svg.setAttribute('stroke', 'currentColor')\n svg.setAttribute('stroke-width', '2')\n svg.setAttribute('stroke-linecap', 'round')\n svg.setAttribute('stroke-linejoin', 'round')\n\n const path = document.createElementNS('http://www.w3.org/2000/svg', 'path')\n svg.appendChild(path)\n button.appendChild(svg)\n\n button.addEventListener('click', () => {\n this.toggleCollapse()\n })\n\n this.collapseButton = button\n this.updateCollapseButton()\n this.aside.appendChild(button)\n }\n\n private renderFooter(): void {\n const hasUser = this.config.user !== undefined\n const hasActions =\n this.config.footerActions !== undefined && this.config.footerActions.length > 0\n\n if (!hasUser && !hasActions) {\n return\n }\n\n const footer = document.createElement('div')\n footer.classList.add('sidebar__footer')\n\n const footerBar = document.createElement('div')\n footerBar.classList.add('sidebar__footer-bar')\n\n if (hasUser && this.config.user) {\n const userSpan = document.createElement('span')\n userSpan.classList.add('sidebar__footer-user')\n\n const nameSpan = document.createElement('span')\n nameSpan.classList.add('sidebar__footer-name')\n nameSpan.textContent = this.config.user.name\n userSpan.appendChild(nameSpan)\n\n footerBar.appendChild(userSpan)\n }\n\n if (hasActions && this.config.footerActions) {\n const iconsSpan = document.createElement('span')\n iconsSpan.classList.add('sidebar__footer-icons')\n\n for (const action of this.config.footerActions) {\n const button = document.createElement('button')\n button.classList.add('sidebar__footer-icon')\n if (action.danger === true) {\n button.classList.add('sidebar__footer-icon--danger')\n }\n button.setAttribute('aria-label', action.label)\n\n const icon = createIconSvg(this.iconSet, action.icon)\n button.appendChild(icon)\n\n if (action.onClick) {\n const handler = action.onClick\n button.addEventListener('click', () => {\n handler()\n })\n }\n\n iconsSpan.appendChild(button)\n }\n\n footerBar.appendChild(iconsSpan)\n }\n\n footer.appendChild(footerBar)\n this.aside.appendChild(footer)\n }\n\n /** Mark a nav item as active, removing active state from all others. */\n setActive(itemId: string): void {\n this.aside.querySelectorAll<HTMLElement>('.sidebar__item').forEach(el => {\n el.classList.remove('sidebar__item--active')\n })\n\n const target = this.aside.querySelector<HTMLElement>(`[data-item-id=\"${itemId}\"]`)\n if (target) {\n target.classList.add('sidebar__item--active')\n }\n }\n\n /** Update the badge count for a nav item (empty string when count is 0). */\n updateBadge(itemId: string, count: number): void {\n const badge = this.aside.querySelector<HTMLElement>(`[data-badge=\"${itemId}\"]`)\n if (badge) {\n badge.textContent = count > 0 ? String(count) : ''\n const item = badge.closest<HTMLElement>('.sidebar__item')\n item?.setAttribute('data-badge-visible', String(count > 0))\n }\n }\n\n /** Toggle the sidebar between collapsed and expanded states. */\n toggleCollapse(): void {\n const isCollapsed = this.aside.classList.toggle('sidebar--collapsed')\n this.updateCollapseButton()\n if (this.config.onCollapse) {\n this.config.onCollapse(isCollapsed)\n }\n }\n\n /** Collapse the sidebar. */\n collapse(): void {\n const wasCollapsed = this.aside.classList.contains('sidebar--collapsed')\n this.aside.classList.add('sidebar--collapsed')\n this.updateCollapseButton()\n if (!wasCollapsed && this.config.onCollapse) {\n this.config.onCollapse(true)\n }\n }\n\n /** Expand the sidebar. */\n expand(): void {\n const wasCollapsed = this.aside.classList.contains('sidebar--collapsed')\n this.aside.classList.remove('sidebar--collapsed')\n this.updateCollapseButton()\n if (wasCollapsed && this.config.onCollapse) {\n this.config.onCollapse(false)\n }\n }\n\n /** Set the mobile open state reflected by the shared CSS contract. */\n setOpen(open: boolean): void {\n this.aside.setAttribute('data-open', String(open))\n }\n\n /** Remove the sidebar from the DOM. */\n destroy(): void {\n this.aside.remove()\n }\n\n private updateCollapseButton(): void {\n if (this.collapseButton === null) {\n return\n }\n\n const isCollapsed = this.aside.classList.contains('sidebar--collapsed')\n const label = isCollapsed ? 'Expand sidebar' : 'Collapse sidebar'\n this.collapseButton.setAttribute('aria-label', label)\n this.collapseButton.setAttribute('aria-expanded', String(!isCollapsed))\n this.collapseButton.setAttribute('title', label)\n this.collapseButton.setAttribute('data-collapsed', String(isCollapsed))\n this.collapseButton\n .querySelector('path')\n ?.setAttribute('d', isCollapsed ? 'm9 18 6-6-6-6' : 'm15 18-6-6 6-6')\n }\n}\n"],"mappings":"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"}
|