web-remarq 0.1.10 → 0.2.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/dist/index.js CHANGED
@@ -712,6 +712,62 @@ var CSS = `
712
712
  .remarq-toast-fade {
713
713
  opacity: 0;
714
714
  }
715
+
716
+ .remarq-spacing {
717
+ position: fixed;
718
+ top: 0;
719
+ left: 0;
720
+ pointer-events: none;
721
+ z-index: 2147483646;
722
+ }
723
+
724
+ .remarq-spacing-margin {
725
+ position: fixed;
726
+ background: rgba(249, 115, 22, 0.2);
727
+ pointer-events: none;
728
+ }
729
+
730
+ .remarq-spacing-padding {
731
+ position: fixed;
732
+ background: rgba(34, 197, 94, 0.2);
733
+ pointer-events: none;
734
+ }
735
+
736
+ .remarq-spacing-content {
737
+ position: fixed;
738
+ background: rgba(59, 130, 246, 0.15);
739
+ border: 1px dashed rgba(59, 130, 246, 0.5);
740
+ pointer-events: none;
741
+ }
742
+
743
+ .remarq-spacing-gap {
744
+ position: fixed;
745
+ background: rgba(168, 85, 247, 0.25);
746
+ border: 1px dashed rgba(168, 85, 247, 0.5);
747
+ pointer-events: none;
748
+ display: flex;
749
+ align-items: center;
750
+ justify-content: center;
751
+ }
752
+
753
+ .remarq-spacing-label {
754
+ position: fixed;
755
+ font-size: 11px;
756
+ font-weight: 700;
757
+ pointer-events: none;
758
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
759
+ line-height: 1;
760
+ padding: 1px 3px;
761
+ border-radius: 2px;
762
+ }
763
+
764
+ .remarq-spacing-label-margin { color: #fff; background: rgba(249, 115, 22, 0.85); }
765
+ .remarq-spacing-label-padding { color: #fff; background: rgba(34, 197, 94, 0.85); }
766
+ .remarq-spacing-label-content { color: #fff; background: rgba(59, 130, 246, 0.85); font-size: 10px; }
767
+ .remarq-spacing-label-gap { color: #fff; background: rgba(168, 85, 247, 0.85); font-size: 10px; }
768
+
769
+ .remarq-toolbar-btn:disabled { opacity: 0.3; cursor: default; }
770
+ .remarq-toolbar-btn:disabled:hover { background: transparent; }
715
771
  `;
716
772
  function injectStyles() {
717
773
  if (document.querySelector(`style[${STYLES_ID}]`)) return;
@@ -783,6 +839,7 @@ var ThemeManager = class {
783
839
  // src/ui/toolbar.ts
784
840
  var ICONS = {
785
841
  inspect: '<svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5"><circle cx="7" cy="7" r="4"/><line x1="10" y1="10" x2="14" y2="14"/></svg>',
842
+ spacing: '<svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M2 2h12M2 14h12M2 2v12M14 2v12"/><path d="M5 5h6v6H5z" stroke-dasharray="2 1"/></svg>',
786
843
  copy: '<svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5"><rect x="5" y="5" width="8" height="9" rx="1"/><path d="M3 11V3a1 1 0 0 1 1-1h6"/></svg>',
787
844
  export: '<svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M8 2v8M4 6l4-4 4 4M2 12h12"/></svg>',
788
845
  import: '<svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M8 10V2M4 6l4 4 4-4M2 12h12"/></svg>',
@@ -804,6 +861,8 @@ var Toolbar = class {
804
861
  this.badgeEl.className = "remarq-badge";
805
862
  this.badgeEl.style.display = "none";
806
863
  this.inspectBtn.appendChild(this.badgeEl);
864
+ this.spacingBtn = this.createButton("spacing", ICONS.spacing, () => callbacks.onSpacingToggle());
865
+ this.spacingBtn.disabled = true;
807
866
  const copyBtn = this.createButton("copy", ICONS.copy, () => callbacks.onCopy());
808
867
  const exportBtn = this.createButton("export", ICONS.export, (e) => this.toggleExportMenu(e));
809
868
  this.fileInput = document.createElement("input");
@@ -818,8 +877,9 @@ var Toolbar = class {
818
877
  const clearBtn = this.createButton("clear", ICONS.clear, () => callbacks.onClear());
819
878
  const themeBtn = this.createButton("theme", ICONS.theme, () => callbacks.onThemeToggle());
820
879
  const minimizeBtn = this.createButton("minimize", ICONS.minimize, () => this.toggleMinimize());
821
- this.buttons = [this.inspectBtn, copyBtn, exportBtn, importBtn, clearBtn, themeBtn];
880
+ this.buttons = [this.inspectBtn, this.spacingBtn, copyBtn, exportBtn, importBtn, clearBtn, themeBtn];
822
881
  this.toolbarEl.appendChild(this.inspectBtn);
882
+ this.toolbarEl.appendChild(this.spacingBtn);
823
883
  this.toolbarEl.appendChild(copyBtn);
824
884
  this.toolbarEl.appendChild(exportBtn);
825
885
  this.toolbarEl.appendChild(importBtn);
@@ -832,6 +892,15 @@ var Toolbar = class {
832
892
  setInspectActive(active) {
833
893
  this.inspectBtn.classList.toggle("remarq-active", active);
834
894
  }
895
+ setSpacingActive(active) {
896
+ this.spacingBtn.classList.toggle("remarq-active", active);
897
+ }
898
+ setSpacingEnabled(enabled) {
899
+ this.spacingBtn.disabled = !enabled;
900
+ if (!enabled) {
901
+ this.spacingBtn.classList.remove("remarq-active");
902
+ }
903
+ }
835
904
  setBadgeCount(count) {
836
905
  this.badgeEl.textContent = String(count);
837
906
  this.badgeEl.style.display = count > 0 ? "flex" : "none";
@@ -927,6 +996,9 @@ var Overlay = class {
927
996
  this.tooltipEl.style.left = `${x + 12}px`;
928
997
  this.tooltipEl.style.top = `${y - 28}px`;
929
998
  }
999
+ hideHighlight() {
1000
+ this.overlayEl.style.display = "none";
1001
+ }
930
1002
  hide() {
931
1003
  this.overlayEl.style.display = "none";
932
1004
  this.tooltipEl.style.display = "none";
@@ -974,6 +1046,229 @@ function getDirectText(el) {
974
1046
  return text.slice(0, 30);
975
1047
  }
976
1048
 
1049
+ // src/ui/spacing-overlay.ts
1050
+ function parsePx(value) {
1051
+ return parseFloat(value) || 0;
1052
+ }
1053
+ var SpacingOverlay = class {
1054
+ constructor(parent) {
1055
+ this.parent = parent;
1056
+ this.labels = [];
1057
+ this.gapEls = [];
1058
+ this.lastTarget = null;
1059
+ this.containerEl = document.createElement("div");
1060
+ this.containerEl.className = "remarq-spacing";
1061
+ this.containerEl.style.display = "none";
1062
+ this.marginEl = document.createElement("div");
1063
+ this.marginEl.className = "remarq-spacing-margin";
1064
+ this.paddingEl = document.createElement("div");
1065
+ this.paddingEl.className = "remarq-spacing-padding";
1066
+ this.contentEl = document.createElement("div");
1067
+ this.contentEl.className = "remarq-spacing-content";
1068
+ this.containerEl.appendChild(this.marginEl);
1069
+ this.containerEl.appendChild(this.paddingEl);
1070
+ this.containerEl.appendChild(this.contentEl);
1071
+ parent.appendChild(this.containerEl);
1072
+ }
1073
+ show(target) {
1074
+ if (target === this.lastTarget) return;
1075
+ this.lastTarget = target;
1076
+ try {
1077
+ const rect = target.getBoundingClientRect();
1078
+ const cs = window.getComputedStyle(target);
1079
+ const margin = this.readSides(cs, "margin");
1080
+ const padding = this.readSides(cs, "padding");
1081
+ const border = this.readBorderSides(cs);
1082
+ const marginBox = {
1083
+ top: rect.top - margin.top,
1084
+ left: rect.left - margin.left,
1085
+ width: rect.width + margin.left + margin.right,
1086
+ height: rect.height + margin.top + margin.bottom
1087
+ };
1088
+ const paddingBox = {
1089
+ top: rect.top,
1090
+ left: rect.left,
1091
+ width: rect.width,
1092
+ height: rect.height
1093
+ };
1094
+ const contentBox = {
1095
+ top: rect.top + border.top + padding.top,
1096
+ left: rect.left + border.left + padding.left,
1097
+ width: rect.width - border.left - border.right - padding.left - padding.right,
1098
+ height: rect.height - border.top - border.bottom - padding.top - padding.bottom
1099
+ };
1100
+ this.positionEl(this.marginEl, marginBox);
1101
+ this.positionEl(this.paddingEl, paddingBox);
1102
+ this.positionEl(this.contentEl, contentBox);
1103
+ this.clearLabels();
1104
+ this.clearGaps();
1105
+ this.addSideLabels(margin, marginBox, paddingBox, "margin");
1106
+ this.addSideLabels(padding, paddingBox, contentBox, "padding");
1107
+ if (contentBox.width > 40 && contentBox.height > 14) {
1108
+ this.addLabel(
1109
+ `${Math.round(contentBox.width)} \xD7 ${Math.round(contentBox.height)}`,
1110
+ contentBox.top + contentBox.height / 2 - 6,
1111
+ contentBox.left + contentBox.width / 2,
1112
+ "content"
1113
+ );
1114
+ }
1115
+ this.showGaps(target);
1116
+ this.containerEl.style.display = "block";
1117
+ } catch (e) {
1118
+ this.hide();
1119
+ }
1120
+ }
1121
+ hide() {
1122
+ this.containerEl.style.display = "none";
1123
+ this.lastTarget = null;
1124
+ this.clearLabels();
1125
+ this.clearGaps();
1126
+ }
1127
+ destroy() {
1128
+ this.clearLabels();
1129
+ this.clearGaps();
1130
+ this.containerEl.remove();
1131
+ }
1132
+ readSides(cs, prop) {
1133
+ return {
1134
+ top: parsePx(cs[`${prop}Top`]),
1135
+ right: parsePx(cs[`${prop}Right`]),
1136
+ bottom: parsePx(cs[`${prop}Bottom`]),
1137
+ left: parsePx(cs[`${prop}Left`])
1138
+ };
1139
+ }
1140
+ readBorderSides(cs) {
1141
+ return {
1142
+ top: parsePx(cs.borderTopWidth),
1143
+ right: parsePx(cs.borderRightWidth),
1144
+ bottom: parsePx(cs.borderBottomWidth),
1145
+ left: parsePx(cs.borderLeftWidth)
1146
+ };
1147
+ }
1148
+ positionEl(el, box) {
1149
+ el.style.top = `${box.top}px`;
1150
+ el.style.left = `${box.left}px`;
1151
+ el.style.width = `${Math.max(0, box.width)}px`;
1152
+ el.style.height = `${Math.max(0, box.height)}px`;
1153
+ }
1154
+ addSideLabels(sides, outerBox, innerBox, type) {
1155
+ if (sides.top > 0) {
1156
+ const y = outerBox.top + (innerBox.top - outerBox.top) / 2 - 6;
1157
+ const x = outerBox.left + outerBox.width / 2;
1158
+ this.addLabel(String(Math.round(sides.top)), y, x, type);
1159
+ }
1160
+ if (sides.bottom > 0) {
1161
+ const innerBottom = innerBox.top + innerBox.height;
1162
+ const outerBottom = outerBox.top + outerBox.height;
1163
+ const y = innerBottom + (outerBottom - innerBottom) / 2 - 6;
1164
+ const x = outerBox.left + outerBox.width / 2;
1165
+ this.addLabel(String(Math.round(sides.bottom)), y, x, type);
1166
+ }
1167
+ if (sides.left > 0) {
1168
+ const y = outerBox.top + outerBox.height / 2 - 6;
1169
+ const x = outerBox.left + (innerBox.left - outerBox.left) / 2;
1170
+ this.addLabel(String(Math.round(sides.left)), y, x, type);
1171
+ }
1172
+ if (sides.right > 0) {
1173
+ const innerRight = innerBox.left + innerBox.width;
1174
+ const outerRight = outerBox.left + outerBox.width;
1175
+ const y = outerBox.top + outerBox.height / 2 - 6;
1176
+ const x = innerRight + (outerRight - innerRight) / 2;
1177
+ this.addLabel(String(Math.round(sides.right)), y, x, type);
1178
+ }
1179
+ }
1180
+ addLabel(text, top, left, type) {
1181
+ const label = document.createElement("div");
1182
+ label.className = `remarq-spacing-label remarq-spacing-label-${type}`;
1183
+ label.textContent = text;
1184
+ label.style.top = `${top}px`;
1185
+ label.style.left = `${left}px`;
1186
+ label.style.transform = "translateX(-50%)";
1187
+ this.containerEl.appendChild(label);
1188
+ this.labels.push(label);
1189
+ }
1190
+ clearLabels() {
1191
+ for (const label of this.labels) label.remove();
1192
+ this.labels = [];
1193
+ }
1194
+ showGaps(target) {
1195
+ const targetCs = window.getComputedStyle(target);
1196
+ if (targetCs.display.includes("flex")) {
1197
+ this.showContainerGaps(target, targetCs);
1198
+ return;
1199
+ }
1200
+ const parent = target.parentElement;
1201
+ if (!parent) return;
1202
+ const parentCs = window.getComputedStyle(parent);
1203
+ if (!parentCs.display.includes("flex")) return;
1204
+ const rowGap = parsePx(parentCs.rowGap);
1205
+ const columnGap = parsePx(parentCs.columnGap);
1206
+ const direction = parentCs.flexDirection;
1207
+ const isRow = direction === "row" || direction === "row-reverse";
1208
+ const gap = isRow ? columnGap : rowGap;
1209
+ if (gap <= 0) return;
1210
+ const children = Array.from(parent.children);
1211
+ const targetIndex = children.indexOf(target);
1212
+ if (targetIndex === -1) return;
1213
+ if (targetIndex > 0) {
1214
+ this.renderGap(children[targetIndex - 1], target, gap, isRow);
1215
+ }
1216
+ if (targetIndex < children.length - 1) {
1217
+ this.renderGap(target, children[targetIndex + 1], gap, isRow);
1218
+ }
1219
+ }
1220
+ showContainerGaps(container, cs) {
1221
+ const rowGap = parsePx(cs.rowGap);
1222
+ const columnGap = parsePx(cs.columnGap);
1223
+ const direction = cs.flexDirection;
1224
+ const isRow = direction === "row" || direction === "row-reverse";
1225
+ const gap = isRow ? columnGap : rowGap;
1226
+ if (gap <= 0) return;
1227
+ const children = Array.from(container.children);
1228
+ for (let i = 0; i < children.length - 1; i++) {
1229
+ this.renderGap(children[i], children[i + 1], gap, isRow);
1230
+ }
1231
+ }
1232
+ renderGap(before, after, gap, isRow) {
1233
+ const rectBefore = before.getBoundingClientRect();
1234
+ const rectAfter = after.getBoundingClientRect();
1235
+ const gapEl = document.createElement("div");
1236
+ gapEl.className = "remarq-spacing-gap";
1237
+ if (isRow) {
1238
+ const left = Math.min(rectBefore.right, rectAfter.right);
1239
+ const right = Math.max(rectBefore.left, rectAfter.left);
1240
+ const top = Math.min(rectBefore.top, rectAfter.top);
1241
+ const height = Math.max(rectBefore.height, rectAfter.height);
1242
+ gapEl.style.top = `${top}px`;
1243
+ gapEl.style.left = `${left}px`;
1244
+ gapEl.style.width = `${Math.abs(right - left)}px`;
1245
+ gapEl.style.height = `${height}px`;
1246
+ } else {
1247
+ const top = Math.min(rectBefore.bottom, rectAfter.bottom);
1248
+ const bottom = Math.max(rectBefore.top, rectAfter.top);
1249
+ const left = Math.min(rectBefore.left, rectAfter.left);
1250
+ const width = Math.max(rectBefore.width, rectAfter.width);
1251
+ gapEl.style.top = `${top}px`;
1252
+ gapEl.style.left = `${left}px`;
1253
+ gapEl.style.width = `${width}px`;
1254
+ gapEl.style.height = `${Math.abs(bottom - top)}px`;
1255
+ }
1256
+ if (gap >= 10) {
1257
+ const label = document.createElement("span");
1258
+ label.className = "remarq-spacing-label-gap";
1259
+ label.textContent = `gap: ${Math.round(gap)}`;
1260
+ label.style.cssText = "font-size:10px;font-weight:700;pointer-events:none;";
1261
+ gapEl.appendChild(label);
1262
+ }
1263
+ this.containerEl.appendChild(gapEl);
1264
+ this.gapEls.push(gapEl);
1265
+ }
1266
+ clearGaps() {
1267
+ for (const el of this.gapEls) el.remove();
1268
+ this.gapEls = [];
1269
+ }
1270
+ };
1271
+
977
1272
  // src/ui/popup.ts
978
1273
  var POPUP_WIDTH = 300;
979
1274
  var POPUP_MARGIN = 8;
@@ -1360,6 +1655,8 @@ var markers;
1360
1655
  var detachedPanel;
1361
1656
  var routeObserver;
1362
1657
  var inspecting = false;
1658
+ var spacingMode = false;
1659
+ var spacingOverlay;
1363
1660
  var mutationObserver = null;
1364
1661
  var unsubRoute = null;
1365
1662
  var refreshScheduled = false;
@@ -1453,7 +1750,6 @@ function handleInspectClick(e) {
1453
1750
  if (!target || target.closest("[data-remarq-theme]")) return;
1454
1751
  e.preventDefault();
1455
1752
  e.stopPropagation();
1456
- overlay.hide();
1457
1753
  setInspecting(false);
1458
1754
  const rect = target.getBoundingClientRect();
1459
1755
  popup.show(
@@ -1493,19 +1789,40 @@ function handleInspectHover(e) {
1493
1789
  if (!inspecting) return;
1494
1790
  const target = e.target;
1495
1791
  if (!target || target.closest("[data-remarq-theme]")) return;
1496
- overlay.show(target);
1792
+ if (spacingMode) {
1793
+ overlay.show(target);
1794
+ overlay.hideHighlight();
1795
+ spacingOverlay.show(target);
1796
+ } else {
1797
+ overlay.show(target);
1798
+ }
1497
1799
  overlay.updateTooltipPosition(e.clientX, e.clientY);
1498
1800
  }
1499
1801
  function handleInspectKeydown(e) {
1802
+ var _a, _b;
1803
+ const tag = (_a = e.target) == null ? void 0 : _a.tagName;
1804
+ if (tag === "INPUT" || tag === "TEXTAREA" || ((_b = e.target) == null ? void 0 : _b.isContentEditable)) return;
1500
1805
  if (e.key === "Escape" && inspecting) {
1501
1806
  setInspecting(false);
1502
1807
  overlay.hide();
1808
+ spacingOverlay.hide();
1809
+ }
1810
+ if (e.key === "s" && inspecting) {
1811
+ spacingMode = !spacingMode;
1812
+ toolbar.setSpacingActive(spacingMode);
1813
+ if (!spacingMode) spacingOverlay.hide();
1503
1814
  }
1504
1815
  }
1505
1816
  function setInspecting(value) {
1506
1817
  inspecting = value;
1507
1818
  toolbar.setInspectActive(value);
1508
- if (!value) overlay.hide();
1819
+ toolbar.setSpacingEnabled(value);
1820
+ if (!value) {
1821
+ overlay.hide();
1822
+ spacingOverlay == null ? void 0 : spacingOverlay.hide();
1823
+ spacingMode = false;
1824
+ toolbar.setSpacingActive(false);
1825
+ }
1509
1826
  }
1510
1827
  function handleMarkerClick(annotationId) {
1511
1828
  var _a;
@@ -1637,6 +1954,7 @@ var WebRemarq = {
1637
1954
  storage = new AnnotationStorage();
1638
1955
  themeManager = new ThemeManager(document.body, options.theme);
1639
1956
  overlay = new Overlay(themeManager.container);
1957
+ spacingOverlay = new SpacingOverlay(themeManager.container);
1640
1958
  popup = new Popup(themeManager.container);
1641
1959
  markers = new MarkerManager(themeManager.container, handleMarkerClick);
1642
1960
  detachedPanel = new DetachedPanel(themeManager.container, (id) => {
@@ -1646,6 +1964,12 @@ var WebRemarq = {
1646
1964
  });
1647
1965
  toolbar = new Toolbar(themeManager.container, {
1648
1966
  onInspect: () => setInspecting(!inspecting),
1967
+ onSpacingToggle: () => {
1968
+ if (!inspecting) return;
1969
+ spacingMode = !spacingMode;
1970
+ toolbar.setSpacingActive(spacingMode);
1971
+ if (!spacingMode) spacingOverlay.hide();
1972
+ },
1649
1973
  onCopy: copyToClipboard,
1650
1974
  onExportMd: exportMarkdown,
1651
1975
  onExportJson: exportJSON,
@@ -1695,11 +2019,13 @@ var WebRemarq = {
1695
2019
  detachedPanel == null ? void 0 : detachedPanel.destroy();
1696
2020
  popup == null ? void 0 : popup.destroy();
1697
2021
  overlay == null ? void 0 : overlay.destroy();
2022
+ spacingOverlay == null ? void 0 : spacingOverlay.destroy();
1698
2023
  toolbar == null ? void 0 : toolbar.destroy();
1699
2024
  themeManager == null ? void 0 : themeManager.destroy();
1700
2025
  removeStyles();
1701
2026
  elementCache.clear();
1702
2027
  inspecting = false;
2028
+ spacingMode = false;
1703
2029
  initialized = false;
1704
2030
  } catch (err) {
1705
2031
  console.error("[web-remarq] Destroy failed:", err);