@tekyzinc/gsd-t 2.73.20 → 2.73.22

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,18 @@
2
2
 
3
3
  All notable changes to GSD-T are documented here. Updated with each release.
4
4
 
5
+ ## [2.73.22] - 2026-04-09
6
+
7
+ ### Added
8
+ - **Stack-level border-radius** — setting `borderRadius` on a flex/grid bar column container auto-sets `overflow: hidden` (so rounded corners clip child segments) and propagates to all sibling columns. One change rounds all stacked bars.
9
+
10
+ ## [2.73.21] - 2026-04-09
11
+
12
+ ### Fixed
13
+ - **Undo All / Cmd+Z now reverts display** — undo properly sends `gsdt-set-svg-attr` for SVG changes and skips fixture changes. Undo All individually reverts each change before resetting CSS, so the preview updates correctly.
14
+ - **Can re-enter original value** — changing a property back to its original value now removes the tracked change and reverts the style (previously rejected as "no change").
15
+ - **Gap propagation for bar charts** — setting `gap` on a flex/grid container propagates to all sibling containers with the same display type (e.g., all bar columns). Shows "→ N all columns" feedback.
16
+
5
17
  ## [2.73.20] - 2026-04-09
6
18
 
7
19
  ### Added
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tekyzinc/gsd-t",
3
- "version": "2.73.20",
3
+ "version": "2.73.22",
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",
@@ -790,10 +790,35 @@
790
790
  }
791
791
  }
792
792
  } else if (tag === "div" && parent) {
793
- // For bar segments: propagate to sibling divs in the same flex container
793
+ const elStyle = getComputedStyle(lockedEl);
794
794
  const parentStyle = getComputedStyle(parent);
795
- if ((parentStyle.display === "flex" || parentStyle.display === "inline-flex") &&
795
+ const layoutProps = new Set(["gap", "row-gap", "column-gap"]);
796
+
797
+ // Props that propagate across sibling containers (all bar columns)
798
+ const containerProps = new Set(["gap", "row-gap", "column-gap", "border-radius", "overflow"]);
799
+
800
+ if (containerProps.has(cssName)) {
801
+ const elDisplay = elStyle.display;
802
+ if (elDisplay === "flex" || elDisplay === "inline-flex" || elDisplay === "grid") {
803
+ // Auto-set overflow:hidden when border-radius is applied to a container
804
+ if (cssName === "border-radius" && msg.value && msg.value !== "0px" && msg.value !== "0") {
805
+ lockedEl.style.setProperty("overflow", "hidden", "important");
806
+ }
807
+ for (const sib of parent.children) {
808
+ if (sib === lockedEl || sib.tagName !== "DIV") continue;
809
+ const sibStyle = getComputedStyle(sib);
810
+ if (sibStyle.display === elDisplay) {
811
+ sib.style.setProperty(cssName, msg.value, "important");
812
+ if (cssName === "border-radius" && msg.value && msg.value !== "0px" && msg.value !== "0") {
813
+ sib.style.setProperty("overflow", "hidden", "important");
814
+ }
815
+ propagatedCount++;
816
+ }
817
+ }
818
+ }
819
+ } else if ((parentStyle.display === "flex" || parentStyle.display === "inline-flex") &&
796
820
  parent.classList.contains("overflow-hidden")) {
821
+ // For bar segments: propagate to sibling divs in the same flex container
797
822
  for (const sib of parent.children) {
798
823
  if (sib === lockedEl || sib.tagName !== "DIV") continue;
799
824
  sib.style.setProperty(cssName, msg.value, "important");
@@ -809,6 +834,7 @@
809
834
  const tag = lockedEl.tagName.toLowerCase();
810
835
  const columnProps = new Set(["text-align", "width", "min-width", "max-width"]);
811
836
  const rowProps = new Set(["height", "min-height", "max-height"]);
837
+ const containerPropsLabel = new Set(["gap", "row-gap", "column-gap", "border-radius", "overflow"]);
812
838
  if ((tag === "td" || tag === "th") && columnProps.has(cssName)) {
813
839
  const row = lockedEl.closest("tr");
814
840
  const colIdx = row ? Array.from(row.children).indexOf(lockedEl) + 1 : 0;
@@ -817,6 +843,8 @@
817
843
  propagateScope = "all rows";
818
844
  } else if (tag === "tr") {
819
845
  propagateScope = "all rows";
846
+ } else if (containerPropsLabel.has(cssName)) {
847
+ propagateScope = "all columns";
820
848
  } else {
821
849
  propagateScope = "similar";
822
850
  }
@@ -1879,17 +1879,35 @@
1879
1879
  function commit() {
1880
1880
  if (cancelled) return;
1881
1881
  const newVal = inputEl.value.trim();
1882
- if (newVal && newVal !== currentVal) {
1883
- // Apply the style change to the iframe
1884
- previewIframe.contentWindow.postMessage({
1885
- type: "gsdt-set-style",
1886
- property: prop,
1887
- value: newVal,
1888
- propagate: true,
1889
- }, "*");
1882
+ if (!newVal) {
1883
+ valEl.textContent = existing ? existing.newValue : currentVal;
1884
+ if (existing) valEl.classList.add("changed");
1885
+ return;
1886
+ }
1890
1887
 
1888
+ // Apply the style change to the iframe (always, even if reverting to original)
1889
+ previewIframe.contentWindow.postMessage({
1890
+ type: "gsdt-set-style",
1891
+ property: prop,
1892
+ value: newVal,
1893
+ propagate: true,
1894
+ }, "*");
1895
+
1896
+ const compId = filteredQueue[selectedIdx]?.id;
1897
+ if (newVal === currentVal) {
1898
+ // Reverting to original — remove tracked change
1899
+ if (compId && existing) {
1900
+ const list = changes.get(compId);
1901
+ const idx = list.findIndex(c => c.path === currentElementPath && c.property === prop);
1902
+ if (idx >= 0) list.splice(idx, 1);
1903
+ if (list.length === 0) changes.delete(compId);
1904
+ renderChanges(compId);
1905
+ renderComponentList();
1906
+ }
1907
+ valEl.textContent = currentVal;
1908
+ valEl.classList.remove("changed");
1909
+ } else {
1891
1910
  // Track the change
1892
- const compId = filteredQueue[selectedIdx]?.id;
1893
1911
  if (compId) {
1894
1912
  if (!changes.has(compId)) changes.set(compId, []);
1895
1913
  const list = changes.get(compId);
@@ -1908,12 +1926,8 @@
1908
1926
  renderChanges(compId);
1909
1927
  renderComponentList();
1910
1928
  }
1911
-
1912
1929
  valEl.textContent = newVal;
1913
1930
  valEl.classList.add("changed");
1914
- } else {
1915
- valEl.textContent = existing ? existing.newValue : currentVal;
1916
- if (existing) valEl.classList.add("changed");
1917
1931
  }
1918
1932
  }
1919
1933
 
@@ -1941,14 +1955,22 @@
1941
1955
  if (!list || index < 0 || index >= list.length) return;
1942
1956
  const change = list[index];
1943
1957
 
1944
- // Revert in iframe
1958
+ // Revert in iframe based on property type
1945
1959
  if (previewIframe.contentWindow) {
1946
- previewIframe.contentWindow.postMessage({
1947
- type: "gsdt-set-style",
1948
- property: change.property,
1949
- value: change.oldValue,
1950
- propagate: true,
1951
- }, "*");
1960
+ if (change.property.startsWith("svg:")) {
1961
+ previewIframe.contentWindow.postMessage({
1962
+ type: "gsdt-set-svg-attr",
1963
+ attribute: change.property.slice(4),
1964
+ value: change.oldValue,
1965
+ }, "*");
1966
+ } else if (!change.property.startsWith("fixture:")) {
1967
+ previewIframe.contentWindow.postMessage({
1968
+ type: "gsdt-set-style",
1969
+ property: change.property,
1970
+ value: change.oldValue,
1971
+ propagate: true,
1972
+ }, "*");
1973
+ }
1952
1974
  }
1953
1975
 
1954
1976
  // Remove from change list
@@ -2189,14 +2211,32 @@
2189
2211
  undoAllChanges.addEventListener("click", () => {
2190
2212
  const compId = filteredQueue[selectedIdx]?.id;
2191
2213
  if (compId) {
2214
+ // Revert each change individually (SVG attrs need setAttribute, not cssText reset)
2215
+ const list = changes.get(compId) || [];
2216
+ if (previewIframe.contentWindow) {
2217
+ for (const change of list) {
2218
+ if (change.property.startsWith("svg:")) {
2219
+ previewIframe.contentWindow.postMessage({
2220
+ type: "gsdt-set-svg-attr",
2221
+ attribute: change.property.slice(4),
2222
+ value: change.oldValue,
2223
+ }, "*");
2224
+ } else if (!change.property.startsWith("fixture:")) {
2225
+ previewIframe.contentWindow.postMessage({
2226
+ type: "gsdt-set-style",
2227
+ property: change.property,
2228
+ value: change.oldValue,
2229
+ propagate: true,
2230
+ }, "*");
2231
+ }
2232
+ }
2233
+ // Also reset inline CSS overrides
2234
+ previewIframe.contentWindow.postMessage({ type: "gsdt-reset-styles" }, "*");
2235
+ }
2192
2236
  changes.delete(compId);
2193
2237
  renderChanges(compId);
2194
2238
  renderComponentList();
2195
2239
  refreshPropHighlights(compId);
2196
- // Reset iframe styles
2197
- if (previewIframe.contentWindow) {
2198
- previewIframe.contentWindow.postMessage({ type: "gsdt-reset-styles" }, "*");
2199
- }
2200
2240
  }
2201
2241
  });
2202
2242