@tekyzinc/gsd-t 2.73.19 → 2.73.20
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/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to GSD-T are documented here. Updated with each release.
|
|
4
4
|
|
|
5
|
+
## [2.73.20] - 2026-04-09
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
- **Editable fixture data** — segment label, value, and color fields in the Data Props tree are now clickable to edit. Color fields use a color picker. Changes tracked alongside CSS/SVG changes in the review output.
|
|
9
|
+
- **Better SVG tree labels** — circle/arc nodes show stroke color, width, and radius. Path nodes show fill/stroke color. SVG root shows viewBox.
|
|
10
|
+
- **Deeper SVG tree traversal** — SVG subtrees traverse up to depth 8 (was 4), ensuring individual arc segments appear in the element tree.
|
|
11
|
+
|
|
12
|
+
### Removed
|
|
13
|
+
- **`percentages_shown`** from donut chart fixture — redundant with `segments[].value`.
|
|
14
|
+
|
|
5
15
|
## [2.73.19] - 2026-04-09
|
|
6
16
|
|
|
7
17
|
### Added
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tekyzinc/gsd-t",
|
|
3
|
-
"version": "2.73.
|
|
3
|
+
"version": "2.73.20",
|
|
4
4
|
"description": "GSD-T: Contract-Driven Development for Claude Code — 56 slash commands with headless CI/CD mode, graph-powered code analysis, real-time agent dashboard, execution intelligence, task telemetry, doc-ripple enforcement, backlog management, impact analysis, test sync, milestone archival, and PRD generation",
|
|
5
5
|
"author": "Tekyz, Inc.",
|
|
6
6
|
"license": "MIT",
|
|
@@ -898,7 +898,9 @@
|
|
|
898
898
|
let keyCounter = 0;
|
|
899
899
|
|
|
900
900
|
function buildTree(el, depth) {
|
|
901
|
-
|
|
901
|
+
// SVG subtrees get deeper traversal (arcs are nested)
|
|
902
|
+
const isSvgSubtree = el instanceof SVGElement || el.closest("svg");
|
|
903
|
+
if (depth > (isSvgSubtree ? 8 : 4)) return null;
|
|
902
904
|
const tag = el.tagName.toLowerCase();
|
|
903
905
|
const s = getComputedStyle(el);
|
|
904
906
|
const rect = el.getBoundingClientRect();
|
|
@@ -933,11 +935,20 @@
|
|
|
933
935
|
label = "Col " + colIdx;
|
|
934
936
|
if (text && text.length < 15) label += ' "' + text + '"';
|
|
935
937
|
} else if (tag === "svg") {
|
|
936
|
-
|
|
938
|
+
const vb = el.getAttribute("viewBox");
|
|
939
|
+
label = "svg" + (vb ? ` [${vb}]` : "");
|
|
937
940
|
} else if (tag === "circle") {
|
|
938
|
-
|
|
941
|
+
const stroke = el.getAttribute("stroke") || "";
|
|
942
|
+
const fill = el.getAttribute("fill") || "";
|
|
943
|
+
const color = stroke && stroke !== "none" ? stroke : fill && fill !== "none" ? fill : "";
|
|
944
|
+
const r = el.getAttribute("r") || "";
|
|
945
|
+
const sw = el.getAttribute("stroke-width") || "";
|
|
946
|
+
label = "arc" + (color ? " " + color : "") + (sw ? " w:" + sw : "") + (r ? " r:" + r : "");
|
|
939
947
|
} else if (tag === "path") {
|
|
940
|
-
|
|
948
|
+
const stroke = el.getAttribute("stroke") || "";
|
|
949
|
+
const fill = el.getAttribute("fill") || "";
|
|
950
|
+
const color = stroke && stroke !== "none" ? stroke : fill && fill !== "none" ? fill : "";
|
|
951
|
+
label = "path" + (color ? " " + color : "");
|
|
941
952
|
} else if (s.display === "flex" || s.display === "inline-flex") {
|
|
942
953
|
label = "flex " + (s.flexDirection === "column" ? "col" : "row");
|
|
943
954
|
} else if (s.display === "grid") {
|
|
@@ -973,10 +984,16 @@
|
|
|
973
984
|
node.props.fontWeight = s.fontWeight;
|
|
974
985
|
if (tag === "th") node.props.background = s.backgroundColor;
|
|
975
986
|
}
|
|
976
|
-
if (tag === "circle") {
|
|
987
|
+
if (tag === "circle" || tag === "ellipse") {
|
|
977
988
|
node.props.stroke = el.getAttribute("stroke");
|
|
978
989
|
node.props.strokeWidth = el.getAttribute("stroke-width");
|
|
979
990
|
node.props.r = el.getAttribute("r");
|
|
991
|
+
node.props.fill = el.getAttribute("fill");
|
|
992
|
+
node.props.strokeDasharray = el.getAttribute("stroke-dasharray");
|
|
993
|
+
} else if (tag === "path" || tag === "line" || tag === "rect") {
|
|
994
|
+
node.props.stroke = el.getAttribute("stroke");
|
|
995
|
+
node.props.strokeWidth = el.getAttribute("stroke-width");
|
|
996
|
+
node.props.fill = el.getAttribute("fill");
|
|
980
997
|
}
|
|
981
998
|
if (s.display === "flex" || s.display === "inline-flex") {
|
|
982
999
|
node.props.gap = s.gap;
|
|
@@ -1079,7 +1079,7 @@
|
|
|
1079
1079
|
const body = document.createElement("div");
|
|
1080
1080
|
body.style.cssText = "padding-left:8px;";
|
|
1081
1081
|
|
|
1082
|
-
function renderValue(key, val, parent, depth) {
|
|
1082
|
+
function renderValue(key, val, parent, depth, propPath) {
|
|
1083
1083
|
if (Array.isArray(val)) {
|
|
1084
1084
|
const row = document.createElement("div");
|
|
1085
1085
|
row.className = "prop-group-header";
|
|
@@ -1093,6 +1093,7 @@
|
|
|
1093
1093
|
if (expanded) row.querySelector("span").textContent = "▾ " + key;
|
|
1094
1094
|
parent.appendChild(row);
|
|
1095
1095
|
val.forEach((item, i) => {
|
|
1096
|
+
const itemPath = propPath + "." + key + "[" + i + "]";
|
|
1096
1097
|
if (typeof item === "object" && item !== null) {
|
|
1097
1098
|
const itemRow = document.createElement("div");
|
|
1098
1099
|
itemRow.style.paddingLeft = ((depth + 1) * 12) + "px";
|
|
@@ -1100,7 +1101,7 @@
|
|
|
1100
1101
|
itemRow.textContent = `[${i}]`;
|
|
1101
1102
|
items.appendChild(itemRow);
|
|
1102
1103
|
for (const [k, v] of Object.entries(item)) {
|
|
1103
|
-
renderValue(k, v, items, depth + 2);
|
|
1104
|
+
renderValue(k, v, items, depth + 2, itemPath);
|
|
1104
1105
|
}
|
|
1105
1106
|
} else {
|
|
1106
1107
|
const itemRow = document.createElement("div");
|
|
@@ -1124,23 +1125,37 @@
|
|
|
1124
1125
|
if (expanded) row.querySelector("span").textContent = "▾ " + key;
|
|
1125
1126
|
parent.appendChild(row);
|
|
1126
1127
|
for (const [k, v] of Object.entries(val)) {
|
|
1127
|
-
renderValue(k, v, items, depth + 1);
|
|
1128
|
+
renderValue(k, v, items, depth + 1, propPath + "." + key);
|
|
1128
1129
|
}
|
|
1129
1130
|
parent.appendChild(items);
|
|
1130
1131
|
} else {
|
|
1131
1132
|
const row = document.createElement("div");
|
|
1132
1133
|
row.className = "prop-row";
|
|
1133
1134
|
row.style.paddingLeft = (depth * 12) + "px";
|
|
1134
|
-
const
|
|
1135
|
+
const isColor = typeof val === "string" && val.match(/^#[0-9a-fA-F]{3,8}$/);
|
|
1136
|
+
const displayVal = isColor
|
|
1135
1137
|
? `<span class="color-swatch" style="background:${val}"></span>${val}`
|
|
1136
1138
|
: escapeHtml(String(val));
|
|
1137
|
-
|
|
1139
|
+
|
|
1140
|
+
const nameEl = document.createElement("span");
|
|
1141
|
+
nameEl.className = "prop-name";
|
|
1142
|
+
nameEl.textContent = key;
|
|
1143
|
+
row.appendChild(nameEl);
|
|
1144
|
+
|
|
1145
|
+
const valEl = document.createElement("span");
|
|
1146
|
+
valEl.className = "prop-value editable";
|
|
1147
|
+
valEl.setAttribute("data-prop", "fixture:" + propPath + "." + key);
|
|
1148
|
+
valEl.setAttribute("data-original", String(val));
|
|
1149
|
+
valEl.innerHTML = displayVal;
|
|
1150
|
+
|
|
1151
|
+
valEl.addEventListener("click", () => startFixtureEdit(valEl, propPath + "." + key, String(val), isColor));
|
|
1152
|
+
row.appendChild(valEl);
|
|
1138
1153
|
parent.appendChild(row);
|
|
1139
1154
|
}
|
|
1140
1155
|
}
|
|
1141
1156
|
|
|
1142
1157
|
for (const [k, v] of Object.entries(fixture)) {
|
|
1143
|
-
renderValue(k, v, body, 0);
|
|
1158
|
+
renderValue(k, v, body, 0, "");
|
|
1144
1159
|
}
|
|
1145
1160
|
container.appendChild(body);
|
|
1146
1161
|
|
|
@@ -1586,6 +1601,96 @@
|
|
|
1586
1601
|
});
|
|
1587
1602
|
}
|
|
1588
1603
|
|
|
1604
|
+
function startFixtureEdit(valEl, fixturePath, currentVal, isColor) {
|
|
1605
|
+
if (valEl.querySelector("select, input")) return;
|
|
1606
|
+
|
|
1607
|
+
const compId = filteredQueue[selectedIdx]?.id;
|
|
1608
|
+
const compChanges = changes.get(compId) || [];
|
|
1609
|
+
const prop = "fixture:" + fixturePath;
|
|
1610
|
+
const existing = compChanges.find(c => c.property === prop);
|
|
1611
|
+
const displayVal = existing ? existing.newValue : currentVal;
|
|
1612
|
+
|
|
1613
|
+
const inputEl = document.createElement("input");
|
|
1614
|
+
inputEl.className = "prop-edit-input";
|
|
1615
|
+
inputEl.type = isColor ? "color" : "text";
|
|
1616
|
+
inputEl.value = displayVal;
|
|
1617
|
+
|
|
1618
|
+
valEl.innerHTML = "";
|
|
1619
|
+
valEl.appendChild(inputEl);
|
|
1620
|
+
inputEl.focus();
|
|
1621
|
+
if (!isColor) {
|
|
1622
|
+
const numMatch = displayVal.match(/^(-?[\d.]+)/);
|
|
1623
|
+
if (numMatch) {
|
|
1624
|
+
inputEl.setSelectionRange(0, numMatch[1].length);
|
|
1625
|
+
} else {
|
|
1626
|
+
inputEl.select();
|
|
1627
|
+
}
|
|
1628
|
+
}
|
|
1629
|
+
|
|
1630
|
+
let cancelled = false;
|
|
1631
|
+
function commit() {
|
|
1632
|
+
if (cancelled) return;
|
|
1633
|
+
const newVal = inputEl.value.trim();
|
|
1634
|
+
if (newVal && newVal !== currentVal) {
|
|
1635
|
+
// Track as a fixture data change
|
|
1636
|
+
if (compId) {
|
|
1637
|
+
if (!changes.has(compId)) changes.set(compId, []);
|
|
1638
|
+
const list = changes.get(compId);
|
|
1639
|
+
const existingIdx = list.findIndex(c => c.property === prop);
|
|
1640
|
+
const change = {
|
|
1641
|
+
path: "(fixture data)",
|
|
1642
|
+
property: prop,
|
|
1643
|
+
oldValue: currentVal,
|
|
1644
|
+
newValue: newVal,
|
|
1645
|
+
};
|
|
1646
|
+
if (existingIdx >= 0) {
|
|
1647
|
+
list[existingIdx] = change;
|
|
1648
|
+
} else {
|
|
1649
|
+
list.push(change);
|
|
1650
|
+
}
|
|
1651
|
+
renderChanges(compId);
|
|
1652
|
+
renderComponentList();
|
|
1653
|
+
}
|
|
1654
|
+
|
|
1655
|
+
if (isColor) {
|
|
1656
|
+
valEl.innerHTML = `<span class="color-swatch" style="background:${newVal}"></span>${newVal}`;
|
|
1657
|
+
} else {
|
|
1658
|
+
valEl.textContent = newVal;
|
|
1659
|
+
}
|
|
1660
|
+
valEl.classList.add("changed");
|
|
1661
|
+
} else {
|
|
1662
|
+
if (isColor && (existing ? existing.newValue : currentVal).match(/^#/)) {
|
|
1663
|
+
const v = existing ? existing.newValue : currentVal;
|
|
1664
|
+
valEl.innerHTML = `<span class="color-swatch" style="background:${v}"></span>${v}`;
|
|
1665
|
+
} else {
|
|
1666
|
+
valEl.textContent = existing ? existing.newValue : currentVal;
|
|
1667
|
+
}
|
|
1668
|
+
if (existing) valEl.classList.add("changed");
|
|
1669
|
+
}
|
|
1670
|
+
}
|
|
1671
|
+
|
|
1672
|
+
if (isColor) {
|
|
1673
|
+
inputEl.addEventListener("change", () => { commit(); cancelled = true; });
|
|
1674
|
+
inputEl.addEventListener("blur", () => { if (!cancelled) { valEl.innerHTML = `<span class="color-swatch" style="background:${currentVal}"></span>${currentVal}`; } });
|
|
1675
|
+
} else {
|
|
1676
|
+
inputEl.addEventListener("blur", () => { if (!cancelled) commit(); });
|
|
1677
|
+
}
|
|
1678
|
+
inputEl.addEventListener("keydown", (e) => {
|
|
1679
|
+
if (e.key === "Enter") { commit(); cancelled = true; inputEl.blur(); }
|
|
1680
|
+
if (e.key === "Escape") {
|
|
1681
|
+
cancelled = true;
|
|
1682
|
+
if (inputEl.parentElement) inputEl.remove();
|
|
1683
|
+
if (isColor) {
|
|
1684
|
+
const v = existing ? existing.newValue : currentVal;
|
|
1685
|
+
valEl.innerHTML = `<span class="color-swatch" style="background:${v}"></span>${v}`;
|
|
1686
|
+
} else {
|
|
1687
|
+
valEl.textContent = existing ? existing.newValue : currentVal;
|
|
1688
|
+
}
|
|
1689
|
+
if (existing) valEl.classList.add("changed");
|
|
1690
|
+
}
|
|
1691
|
+
});
|
|
1692
|
+
}
|
|
1693
|
+
|
|
1589
1694
|
function renderPropertyValues(styles) {
|
|
1590
1695
|
// Update existing property values in the inspector
|
|
1591
1696
|
inspectorProps.querySelectorAll(".prop-value[data-prop]").forEach(el => {
|