diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json
index f738221..5b4e222 100644
--- a/.claude-plugin/plugin.json
+++ b/.claude-plugin/plugin.json
@@ -1,7 +1,7 @@
{
"name": "diagram-design",
"description": "Create branded architecture, IT current-state, flowchart, sequence, state machine, ER/data model, timeline, swimlane, quadrant, radar/spider, loop/flywheel, nested, tree, org chart, layer stack, Venn, pyramid/funnel, bar, line, Gantt and scatter charts, high-level, process, medallion, data flow, DP integration, or DP security matrix diagrams as standalone HTML/SVG/PNG. Redraw .drawio/.drawio.png/.drawio.svg or Mermaid .mmd sources at a chosen size/detail; onboard brand tokens from a website; add semantic patterns, callouts, accessible motion, or sketchy/hand-drawn styling.",
- "version": "2.4.2",
+ "version": "2.4.3",
"author": {
"name": "Cathryn Lavery",
"url": "https://github.com/cathrynlavery"
diff --git a/.codex-plugin/plugin.json b/.codex-plugin/plugin.json
index 69cf5cf..67b3edf 100644
--- a/.codex-plugin/plugin.json
+++ b/.codex-plugin/plugin.json
@@ -1,7 +1,7 @@
{
"name": "diagram-design",
"description": "Create branded architecture, IT current-state, flowchart, sequence, state machine, ER/data model, timeline, swimlane, quadrant, radar/spider, loop/flywheel, nested, tree, org chart, layer stack, Venn, pyramid/funnel, bar, line, Gantt and scatter charts, high-level, process, medallion, data flow, DP integration, or DP security matrix diagrams as standalone HTML/SVG/PNG. Redraw .drawio/.drawio.png/.drawio.svg or Mermaid .mmd sources at a chosen size/detail; onboard brand tokens from a website; add semantic patterns, callouts, accessible motion, or sketchy/hand-drawn styling.",
- "version": "2.4.2",
+ "version": "2.4.3",
"author": {
"name": "Cathryn Lavery",
"url": "https://github.com/cathrynlavery"
diff --git a/skills/diagram-design/assets/index.html b/skills/diagram-design/assets/index.html
index b368eff..69f3341 100644
--- a/skills/diagram-design/assets/index.html
+++ b/skills/diagram-design/assets/index.html
@@ -194,7 +194,7 @@
-
+
@@ -311,7 +311,7 @@
@@ -334,30 +334,73 @@
const openRaw = document.getElementById("open-raw");
function update() {
- const activeType = document.querySelector("#type-tabs .tab.active");
+ const activeType = [...document.querySelectorAll("#type-tabs .tab")].find(
+ (tab) => tab.dataset.type === state.type,
+ );
const single = activeType && activeType.hasAttribute("data-single");
const variantTabs = document.querySelectorAll("#variant-tabs .tab");
if (single) state.variant = "";
variantTabs.forEach((tab) => {
tab.disabled = single && tab.dataset.variant !== "";
- tab.classList.toggle("active", tab.dataset.variant === state.variant);
});
+ for (const [containerId, key] of [
+ ["type-tabs", "type"],
+ ["variant-tabs", "variant"],
+ ]) {
+ document.querySelectorAll(`#${containerId} .tab`).forEach((tab) => {
+ const active = tab.dataset[key] === state[key];
+ tab.classList.toggle("active", active);
+ tab.setAttribute("aria-checked", String(active));
+ tab.tabIndex = active ? 0 : -1;
+ });
+ }
const src = `example-${state.type}${state.variant}.html`;
iframe.src = src;
openRaw.href = src;
+ const selectedTabs = document.querySelectorAll('[role="radio"][aria-checked="true"]');
+ iframe.setAttribute(
+ "aria-labelledby",
+ [...selectedTabs].map((tab) => tab.id).join(" "),
+ );
}
function bindTabs(containerId, key) {
const container = document.getElementById(containerId);
+ const tabs = [...container.querySelectorAll(".tab")];
+ tabs.forEach((tab, index) => {
+ tab.id = `${containerId}-${index}`;
+ tab.setAttribute("role", "radio");
+ tab.setAttribute("aria-controls", "preview");
+ });
+
+ function activate(tab, focus = false) {
+ state[key] = tab.dataset[key];
+ update();
+ if (focus) tab.focus();
+ }
+
container.addEventListener("click", (e) => {
const btn = e.target.closest(".tab");
if (!btn) return;
- container
- .querySelectorAll(".tab")
- .forEach((t) => t.classList.remove("active"));
- btn.classList.add("active");
- state[key] = btn.dataset[key];
- update();
+ activate(btn);
+ });
+ container.addEventListener("keydown", (e) => {
+ const current = e.target.closest('[role="radio"]');
+ if (!current || !container.contains(current)) return;
+ const enabledTabs = tabs.filter((tab) => !tab.disabled);
+ const index = enabledTabs.indexOf(current);
+ let next;
+ if (e.key === "ArrowRight" || e.key === "ArrowDown") {
+ next = enabledTabs[(index + 1) % enabledTabs.length];
+ }
+ if (e.key === "ArrowLeft" || e.key === "ArrowUp") {
+ next = enabledTabs[(index - 1 + enabledTabs.length) % enabledTabs.length];
+ }
+ if (e.key === "Home") next = enabledTabs[0];
+ if (e.key === "End") next = enabledTabs.at(-1);
+ if (!next) return;
+ e.preventDefault();
+ activate(next, true);
});
}