@astuteo/breakout-grid 5.1.1 → 5.1.2

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.
@@ -1,6 +1,6 @@
1
1
  (function() {
2
2
  "use strict";
3
- const VERSION = `v${"5.1.1"} lite`;
3
+ const VERSION = `v${"5.1.2"} lite`;
4
4
  const LOREM_CONTENT = `Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium.
5
5
 
6
6
  Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet.`;
@@ -1,6 +1,6 @@
1
1
  (function() {
2
2
  "use strict";
3
- const VERSION = `v${"5.1.1"}`;
3
+ const VERSION = `v${"5.1.2"}`;
4
4
  const LOREM_CONTENT = `Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium.
5
5
 
6
6
  Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet.`;
@@ -12,19 +12,16 @@ Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed
12
12
  { name: "content", label: "Content", className: ".col-content", color: "rgba(168, 85, 247, 0.25)", borderColor: "rgb(168, 85, 247)" }
13
13
  ];
14
14
  const CONFIG_OPTIONS = {
15
- // Base measurements
16
15
  baseGap: { value: "1rem", desc: "Minimum gap between columns. Use rem.", cssVar: "--config-base-gap", liveVar: "--base-gap" },
17
16
  maxGap: { value: "15rem", desc: "Maximum gap cap for ultra-wide. Use rem.", cssVar: "--config-max-gap", liveVar: "--max-gap" },
18
- contentMin: { value: "53rem", desc: "Min width for content column (~848px). Use rem.", cssVar: "--config-content-min", liveVar: "--content-min" },
19
- contentMax: { value: "61rem", desc: "Max width for content column (~976px). Use rem.", cssVar: "--config-content-max", liveVar: "--content-max" },
17
+ contentMin: { value: "50rem", desc: "Min width for content column (~848px). Use rem.", cssVar: "--config-content-min", liveVar: "--content-min" },
18
+ contentMax: { value: "55rem", desc: "Max width for content column (~976px). Use rem.", cssVar: "--config-content-max", liveVar: "--content-max" },
20
19
  contentBase: { value: "75vw", desc: "Preferred width for content (fluid). Use vw.", cssVar: "--config-content-base", liveVar: "--content-base" },
21
- // Track widths
22
20
  popoutWidth: { value: "5rem", desc: "Popout extends beyond content. Use rem.", cssVar: "--config-popout", liveVar: null },
23
21
  featureMin: { value: "0rem", desc: "Minimum feature track width (floor)", cssVar: "--config-feature-min", liveVar: null },
24
22
  featureScale: { value: "12vw", desc: "Fluid feature track scaling", cssVar: "--config-feature-scale", liveVar: null },
25
23
  featureMax: { value: "12rem", desc: "Maximum feature track width (ceiling)", cssVar: "--config-feature-max", liveVar: null },
26
24
  fullLimit: { value: "115rem", desc: "Max width for col-full-limit. Use rem.", cssVar: "--config-full-limit", liveVar: "--full-limit" },
27
- // Default column
28
25
  defaultCol: { value: "content", desc: "Default column when no col-* class", type: "select", options: ["content", "popout", "feature", "full"], cssVar: "--config-default-col" }
29
26
  };
30
27
  const GAP_SCALE_OPTIONS = {
@@ -43,7 +40,6 @@ Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed
43
40
  };
44
41
  function createInitialState() {
45
42
  return {
46
- // UI State
47
43
  isVisible: false,
48
44
  showLabels: true,
49
45
  showClassNames: true,
@@ -65,38 +61,28 @@ Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed
65
61
  editorPos: { x: 20, y: 100 },
66
62
  isDragging: false,
67
63
  dragOffset: { x: 0, y: 0 },
68
- // Column resize drag state
69
64
  resizingColumn: null,
70
65
  resizeStartX: 0,
71
66
  resizeStartValue: 0,
72
- // Panel collapse state
73
67
  controlPanelCollapsed: false,
74
68
  configEditorCollapsed: false,
75
- // Computed column widths in pixels (pre-initialized for reactivity)
76
- columnWidths: {
77
- full: 0,
78
- "full-limit": 0,
79
- feature: 0,
80
- popout: 0,
81
- content: 0,
82
- center: 0
83
- },
84
- // Current breakpoint for gap scale (mobile, lg, xl)
69
+ // Pre-initialized for Alpine reactivity
70
+ columnWidths: { full: 0, "full-limit": 0, feature: 0, popout: 0, content: 0, center: 0 },
85
71
  currentBreakpoint: "mobile",
86
- // Spacing panel state
87
72
  spacingPanelCollapsed: false,
88
73
  spacingPanelPos: { x: 16, y: 16 },
89
74
  isDraggingSpacing: false,
90
75
  dragOffsetSpacing: { x: 0, y: 0 },
91
- // Restore config modal
92
76
  showRestoreModal: false,
93
77
  restoreInput: "",
94
78
  restoreError: null,
95
- // Section copy feedback
96
- sectionCopied: null
79
+ sectionCopied: null,
80
+ showCloseWarningModal: false,
81
+ gridOpacity: 0.8,
82
+ backdropOpacity: 0.85
97
83
  };
98
84
  }
99
- const BUILD_VERSION = "5.1.1";
85
+ const BUILD_VERSION = "5.1.2";
100
86
  function generateCSSExport(c, version = BUILD_VERSION) {
101
87
  var _a, _b, _c, _d, _e;
102
88
  const VERSION2 = version;
@@ -763,7 +749,6 @@ Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed
763
749
  `;
764
750
  }
765
751
  const methods = {
766
- // Initialize
767
752
  init() {
768
753
  const saved = localStorage.getItem("breakoutGridVisualizerVisible");
769
754
  if (saved !== null) {
@@ -818,12 +803,10 @@ Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed
818
803
  this.updateCurrentBreakpoint();
819
804
  console.log("Breakout Grid Visualizer loaded. Press Ctrl/Cmd + G to toggle.");
820
805
  },
821
- // Toggle visibility
822
806
  toggle() {
823
807
  this.isVisible = !this.isVisible;
824
808
  localStorage.setItem("breakoutGridVisualizerVisible", this.isVisible);
825
809
  },
826
- // Update column widths by querying DOM elements
827
810
  updateColumnWidths() {
828
811
  this.$nextTick(() => {
829
812
  this.gridAreas.forEach((area) => {
@@ -834,7 +817,6 @@ Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed
834
817
  });
835
818
  });
836
819
  },
837
- // Detect current breakpoint based on viewport width
838
820
  updateCurrentBreakpoint() {
839
821
  const width = window.innerWidth;
840
822
  if (width >= 1280) {
@@ -845,7 +827,6 @@ Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed
845
827
  this.currentBreakpoint = "mobile";
846
828
  }
847
829
  },
848
- // Update --gap live based on current breakpoint and edit values
849
830
  updateGapLive() {
850
831
  const scaleKey = this.currentBreakpoint === "mobile" ? "default" : this.currentBreakpoint;
851
832
  const base = this.editValues.baseGap || this.configOptions.baseGap.value;
@@ -854,7 +835,6 @@ Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed
854
835
  document.documentElement.style.setProperty("--gap", `clamp(${base}, ${scale}, ${max})`);
855
836
  this.updateColumnWidths();
856
837
  },
857
- // Check if content width exceeds comfortable reading width (55rem)
858
838
  getContentReadabilityWarning() {
859
839
  const contentMax = parseFloat(this.editValues.contentMax || this.configOptions.contentMax.value);
860
840
  if (contentMax > 55) {
@@ -862,7 +842,6 @@ Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed
862
842
  }
863
843
  return null;
864
844
  },
865
- // Check if configured track widths would exceed viewport
866
845
  getTrackOverflowWarning() {
867
846
  const contentMax = parseFloat(this.editValues.contentMax || this.configOptions.contentMax.value) * 16;
868
847
  const featureMax = parseFloat(this.editValues.featureMax || this.configOptions.featureMax.value) * 16;
@@ -875,12 +854,10 @@ Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed
875
854
  }
876
855
  return null;
877
856
  },
878
- // Get computed CSS variable value
879
857
  getCSSVariable(varName) {
880
858
  const value = getComputedStyle(document.documentElement).getPropertyValue(varName).trim();
881
859
  return value || "Not set";
882
860
  },
883
- // Helper to load options from CSS variables
884
861
  loadOptionsFromCSS(options, prefix = "") {
885
862
  Object.keys(options).forEach((key) => {
886
863
  const opt = options[key];
@@ -893,13 +870,11 @@ Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed
893
870
  }
894
871
  });
895
872
  },
896
- // Load current values from CSS variables where available
897
873
  loadCurrentValues() {
898
874
  this.loadOptionsFromCSS(this.configOptions);
899
875
  this.loadOptionsFromCSS(this.gapScaleOptions, "gapScale");
900
876
  this.loadOptionsFromCSS(this.breakoutOptions, "breakout");
901
877
  },
902
- // Generate export config object
903
878
  generateConfigExport() {
904
879
  var _a, _b, _c, _d;
905
880
  const config = {};
@@ -918,7 +893,6 @@ Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed
918
893
  };
919
894
  return config;
920
895
  },
921
- // Format config object with single quotes for values, no quotes for keys
922
896
  formatConfig(obj, indent = 2) {
923
897
  const pad = " ".repeat(indent);
924
898
  const lines = ["{"];
@@ -934,35 +908,14 @@ Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed
934
908
  lines.push("}");
935
909
  return lines.join("\n");
936
910
  },
937
- // Section definitions for partial copying
938
911
  configSections: {
939
- content: {
940
- keys: ["contentMin", "contentBase", "contentMax"],
941
- label: "Content"
942
- },
943
- defaultCol: {
944
- keys: ["defaultCol"],
945
- label: "Default Column"
946
- },
947
- tracks: {
948
- keys: ["popoutWidth", "fullLimit"],
949
- label: "Track Widths"
950
- },
951
- feature: {
952
- keys: ["featureMin", "featureScale", "featureMax"],
953
- label: "Feature"
954
- },
955
- gap: {
956
- keys: ["baseGap", "maxGap"],
957
- nested: { gapScale: ["default", "lg", "xl"] },
958
- label: "Gap"
959
- },
960
- breakout: {
961
- keys: ["breakoutMin", "breakoutScale"],
962
- label: "Breakout"
963
- }
912
+ content: { keys: ["contentMin", "contentBase", "contentMax"], label: "Content" },
913
+ defaultCol: { keys: ["defaultCol"], label: "Default Column" },
914
+ tracks: { keys: ["popoutWidth", "fullLimit"], label: "Track Widths" },
915
+ feature: { keys: ["featureMin", "featureScale", "featureMax"], label: "Feature" },
916
+ gap: { keys: ["baseGap", "maxGap"], nested: { gapScale: ["default", "lg", "xl"] }, label: "Gap" },
917
+ breakout: { keys: ["breakoutMin", "breakoutScale"], label: "Breakout" }
964
918
  },
965
- // Copy a specific section to clipboard
966
919
  copySection(sectionName) {
967
920
  const section = this.configSections[sectionName];
968
921
  if (!section) return;
@@ -990,7 +943,6 @@ Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed
990
943
  setTimeout(() => this.sectionCopied = null, 1500);
991
944
  });
992
945
  },
993
- // Format config as flat key-value pairs (no wrapping braces)
994
946
  formatConfigFlat(obj) {
995
947
  const lines = [];
996
948
  const entries = Object.entries(obj);
@@ -1004,7 +956,6 @@ Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed
1004
956
  });
1005
957
  return lines.join("\n");
1006
958
  },
1007
- // Copy config to clipboard as CSS variables
1008
959
  copyConfig() {
1009
960
  var _a, _b, _c, _d, _e;
1010
961
  const config = this.generateConfigExport();
@@ -1045,7 +996,6 @@ Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed
1045
996
  setTimeout(() => this.copySuccess = false, 2e3);
1046
997
  });
1047
998
  },
1048
- // Generate and download standalone CSS file
1049
999
  downloadCSS() {
1050
1000
  const css = this.generateCSSExport(this.generateConfigExport());
1051
1001
  const blob = new Blob([css], { type: "text/css" });
@@ -1056,7 +1006,6 @@ Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed
1056
1006
  a.click();
1057
1007
  URL.revokeObjectURL(url);
1058
1008
  },
1059
- // Parse CSS value into number and unit (e.g., "4rem" -> { num: 4, unit: "rem" })
1060
1009
  parseValue(val) {
1061
1010
  const match = String(val).match(/^([\d.]+)(.*)$/);
1062
1011
  if (match) {
@@ -1064,29 +1013,23 @@ Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed
1064
1013
  }
1065
1014
  return { num: 0, unit: "rem" };
1066
1015
  },
1067
- // Get the numeric part of a config value
1068
1016
  getNumericValue(key) {
1069
1017
  const val = this.editValues[key] || this.configOptions[key].value;
1070
1018
  return this.parseValue(val).num;
1071
1019
  },
1072
- // Get the unit part of a config value
1073
1020
  getUnit(key) {
1074
1021
  const val = this.editValues[key] || this.configOptions[key].value;
1075
1022
  return this.parseValue(val).unit;
1076
1023
  },
1077
- // Check if a field should have unit selection (rem-based fields only)
1078
1024
  hasUnitSelector(key) {
1079
1025
  const unit = this.getUnit(key);
1080
1026
  return unit === "rem" || unit === "ch" || unit === "px";
1081
1027
  },
1082
- // Available units for selection
1083
1028
  unitOptions: ["rem", "ch", "px"],
1084
- // Update just the unit, keeping the numeric value
1085
1029
  updateUnit(key, newUnit) {
1086
1030
  const num = this.getNumericValue(key);
1087
1031
  this.updateConfigValue(key, num + newUnit);
1088
1032
  },
1089
- // Update just the numeric part, keeping the unit
1090
1033
  updateNumericValue(key, num) {
1091
1034
  if (key === "content" && num < 1) num = 1;
1092
1035
  if (key === "baseGap" && num < 0) num = 0;
@@ -1095,7 +1038,6 @@ Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed
1095
1038
  const unit = this.getUnit(key);
1096
1039
  this.updateConfigValue(key, num + unit);
1097
1040
  },
1098
- // Generic getter for prefixed options (gapScale, breakout)
1099
1041
  getPrefixedNumeric(prefix, options, key) {
1100
1042
  const val = this.editValues[`${prefix}_${key}`] || options[key].value;
1101
1043
  return this.parseValue(val).num;
@@ -1104,7 +1046,6 @@ Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed
1104
1046
  const val = this.editValues[`${prefix}_${key}`] || options[key].value;
1105
1047
  return this.parseValue(val).unit;
1106
1048
  },
1107
- // Gap scale helpers (use generic)
1108
1049
  getGapScaleNumeric(key) {
1109
1050
  return this.getPrefixedNumeric("gapScale", this.gapScaleOptions, key);
1110
1051
  },
@@ -1117,7 +1058,6 @@ Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed
1117
1058
  this.updateGapLive();
1118
1059
  this.saveConfigToStorage();
1119
1060
  },
1120
- // Breakout helpers (use generic)
1121
1061
  getBreakoutNumeric(key) {
1122
1062
  return this.getPrefixedNumeric("breakout", this.breakoutOptions, key);
1123
1063
  },
@@ -1130,19 +1070,16 @@ Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed
1130
1070
  this.updateBreakoutLive();
1131
1071
  this.saveConfigToStorage();
1132
1072
  },
1133
- // Update --breakout-padding live
1134
1073
  updateBreakoutLive() {
1135
1074
  const min = this.editValues.breakout_min || this.breakoutOptions.min.value;
1136
1075
  const scale = this.editValues.breakout_scale || this.breakoutOptions.scale.value;
1137
1076
  const max = this.editValues.popoutWidth || this.configOptions.popoutWidth.value;
1138
1077
  document.documentElement.style.setProperty("--breakout-padding", `clamp(${min}, ${scale}, ${max})`);
1139
1078
  },
1140
- // Save current config to localStorage
1141
1079
  saveConfigToStorage() {
1142
1080
  const config = this.generateConfigExport();
1143
1081
  localStorage.setItem("breakoutGridConfig", JSON.stringify(config));
1144
1082
  },
1145
- // Apply a config object (used by restore and localStorage load)
1146
1083
  applyConfig(config) {
1147
1084
  this.editMode = true;
1148
1085
  Object.keys(this.configOptions).forEach((key) => {
@@ -1188,7 +1125,6 @@ Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed
1188
1125
  }
1189
1126
  this.updateColumnWidths();
1190
1127
  },
1191
- // Reset config to defaults and clear localStorage
1192
1128
  resetConfigToDefaults() {
1193
1129
  if (!confirm("Reset all config values to defaults?")) return;
1194
1130
  localStorage.removeItem("breakoutGridConfig");
@@ -1196,7 +1132,6 @@ Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed
1196
1132
  this.loadCurrentValues();
1197
1133
  this.configCopied = false;
1198
1134
  },
1199
- // Update a config value (and live CSS var if applicable)
1200
1135
  updateConfigValue(key, value) {
1201
1136
  this.editValues[key] = value;
1202
1137
  this.configCopied = false;
@@ -1222,15 +1157,12 @@ Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed
1222
1157
  this.updateGapLive();
1223
1158
  }
1224
1159
  },
1225
- // Select a grid area
1226
1160
  selectArea(areaName) {
1227
1161
  this.selectedArea = this.selectedArea === areaName ? null : areaName;
1228
1162
  },
1229
- // Check if area is selected
1230
1163
  isSelected(areaName) {
1231
1164
  return this.selectedArea === areaName;
1232
1165
  },
1233
- // Restore all CSS variable overrides to original values
1234
1166
  restoreCSSVariables() {
1235
1167
  Object.keys(this.configOptions).forEach((key) => {
1236
1168
  const opt = this.configOptions[key];
@@ -1246,7 +1178,6 @@ Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed
1246
1178
  this.editValues = {};
1247
1179
  this.configCopied = false;
1248
1180
  },
1249
- // Toggle edit mode
1250
1181
  toggleEditMode() {
1251
1182
  this.editMode = !this.editMode;
1252
1183
  if (this.editMode) {
@@ -1255,30 +1186,37 @@ Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed
1255
1186
  this.restoreCSSVariables();
1256
1187
  }
1257
1188
  },
1258
- // Check if any values have been edited and not yet copied
1259
1189
  hasUnsavedEdits() {
1260
1190
  return Object.keys(this.editValues).length > 0 && !this.configCopied;
1261
1191
  },
1262
- // Open floating editor
1263
1192
  openEditor() {
1264
1193
  this.showEditor = true;
1265
1194
  this.editMode = true;
1266
1195
  this.loadCurrentValues();
1267
1196
  localStorage.setItem("breakoutGridEditorOpen", "true");
1268
1197
  },
1269
- // Close floating editor
1270
1198
  closeEditor(force = false) {
1271
1199
  if (!force && this.hasUnsavedEdits()) {
1272
- if (!confirm("You have unsaved config changes. Close without copying?")) {
1273
- return;
1274
- }
1200
+ this.showCloseWarningModal = true;
1201
+ return;
1275
1202
  }
1276
1203
  this.showEditor = false;
1277
1204
  this.editMode = false;
1278
1205
  this.restoreCSSVariables();
1279
1206
  localStorage.setItem("breakoutGridEditorOpen", "false");
1280
1207
  },
1281
- // Generic drag handling for panels
1208
+ closeWarningCopyAndClose() {
1209
+ this.copyConfig();
1210
+ this.showCloseWarningModal = false;
1211
+ this.closeEditor(true);
1212
+ },
1213
+ closeWarningDiscard() {
1214
+ this.showCloseWarningModal = false;
1215
+ this.closeEditor(true);
1216
+ },
1217
+ closeWarningGoBack() {
1218
+ this.showCloseWarningModal = false;
1219
+ },
1282
1220
  _dragConfigs: {
1283
1221
  editor: { pos: "editorPos", dragging: "isDragging", offset: "dragOffset", storage: "breakoutGridEditorPos" },
1284
1222
  spacing: { pos: "spacingPanelPos", dragging: "isDraggingSpacing", offset: "dragOffsetSpacing", storage: "breakoutGridSpacingPos" }
@@ -1299,7 +1237,6 @@ Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed
1299
1237
  if (this[cfg.dragging]) localStorage.setItem(cfg.storage, JSON.stringify(this[cfg.pos]));
1300
1238
  this[cfg.dragging] = false;
1301
1239
  },
1302
- // Editor drag (shorthand)
1303
1240
  startDrag(e) {
1304
1241
  this.startPanelDrag(e, "editor");
1305
1242
  },
@@ -1309,7 +1246,6 @@ Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed
1309
1246
  stopDrag() {
1310
1247
  this.stopPanelDrag("editor");
1311
1248
  },
1312
- // Spacing drag (shorthand)
1313
1249
  startDragSpacing(e) {
1314
1250
  this.startPanelDrag(e, "spacing");
1315
1251
  },
@@ -1319,7 +1255,6 @@ Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed
1319
1255
  stopDragSpacing() {
1320
1256
  this.stopPanelDrag("spacing");
1321
1257
  },
1322
- // Column resize drag handling
1323
1258
  startColumnResize(e, columnType) {
1324
1259
  if (!this.editMode) return;
1325
1260
  e.preventDefault();
@@ -1353,18 +1288,14 @@ Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed
1353
1288
  stopColumnResize() {
1354
1289
  this.resizingColumn = null;
1355
1290
  },
1356
- // Map column names to their config keys for resizing
1357
1291
  getResizeConfig(colName) {
1358
1292
  const map = {
1359
1293
  "full-limit": "fullLimit",
1360
1294
  "feature": "featureScale",
1361
1295
  "popout": "popoutWidth"
1362
- // content has its own integrated handles for min/max/base
1363
- // feature has its own integrated handles for min/scale/max
1364
1296
  };
1365
1297
  return map[colName] || null;
1366
1298
  },
1367
- // Parse a CSS variables string into a config object
1368
1299
  parseConfigString(input) {
1369
1300
  const str = input.trim();
1370
1301
  const config = { gapScale: {}, breakpoints: {} };
@@ -1412,19 +1343,16 @@ Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed
1412
1343
  }
1413
1344
  return config;
1414
1345
  },
1415
- // Open restore modal
1416
1346
  openRestoreModal() {
1417
1347
  this.showRestoreModal = true;
1418
1348
  this.restoreInput = "";
1419
1349
  this.restoreError = null;
1420
1350
  },
1421
- // Close restore modal
1422
1351
  closeRestoreModal() {
1423
1352
  this.showRestoreModal = false;
1424
1353
  this.restoreInput = "";
1425
1354
  this.restoreError = null;
1426
1355
  },
1427
- // Apply a parsed config to the editor
1428
1356
  restoreConfig() {
1429
1357
  this.restoreError = null;
1430
1358
  try {
@@ -1482,7 +1410,7 @@ Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed
1482
1410
  x-transition:leave="transition ease-in duration-150"
1483
1411
  x-transition:leave-start="opacity-100"
1484
1412
  x-transition:leave-end="opacity-0"
1485
- style="position: absolute; inset: 0; background: rgba(255, 255, 255, 0.85); z-index: 1;"></div>
1413
+ :style="{ position: 'absolute', inset: 0, background: 'rgba(255, 255, 255, ' + backdropOpacity + ')', zIndex: 1 }"></div>
1486
1414
 
1487
1415
  <!-- Advanced Span Examples Overlay -->
1488
1416
  <div x-show="showAdvanced"
@@ -1752,7 +1680,7 @@ Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed
1752
1680
  </div>
1753
1681
 
1754
1682
  <!-- Grid Overlay (hidden in Advanced mode) -->
1755
- <div x-show="!showAdvanced" x-init="$watch('isVisible', v => v && setTimeout(() => updateColumnWidths(), 50)); setTimeout(() => updateColumnWidths(), 100)" class="grid-cols-breakout breakout-visualizer-grid" style="height: 100%; position: relative; z-index: 2;">
1683
+ <div x-show="!showAdvanced" x-init="$watch('isVisible', v => v && setTimeout(() => updateColumnWidths(), 50)); setTimeout(() => updateColumnWidths(), 100)" class="grid-cols-breakout breakout-visualizer-grid" :style="{ height: '100%', position: 'relative', zIndex: 2, opacity: gridOpacity }">
1756
1684
  <template x-for="area in gridAreas" :key="area.name">
1757
1685
  <div :class="'col-' + area.name"
1758
1686
  @click="selectArea(area.name)"
@@ -2157,6 +2085,22 @@ Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed
2157
2085
  </div>
2158
2086
  </div>
2159
2087
 
2088
+ <!-- Opacity Sliders -->
2089
+ <div style="padding: 8px 12px; background: white; border-bottom: 1px solid #e5e5e5;">
2090
+ <div style="display: flex; flex-direction: column; gap: 6px;">
2091
+ <div style="display: flex; align-items: center; gap: 12px;">
2092
+ <span style="font-size: 9px; font-weight: 600; color: #6b7280; text-transform: uppercase; letter-spacing: 0.5px; width: 28px; flex-shrink: 0;">Grid</span>
2093
+ <input type="range" x-model="gridOpacity" min="0.1" max="1" step="0.1"
2094
+ style="flex: 1; height: 4px; cursor: pointer; accent-color: #1a1a2e;">
2095
+ </div>
2096
+ <div style="display: flex; align-items: center; gap: 12px;">
2097
+ <span style="font-size: 9px; font-weight: 600; color: #6b7280; text-transform: uppercase; letter-spacing: 0.5px; width: 28px; flex-shrink: 0;">Page</span>
2098
+ <input type="range" x-model="backdropOpacity" min="0" max="1" step="0.05"
2099
+ style="flex: 1; height: 4px; cursor: pointer; accent-color: #1a1a2e;">
2100
+ </div>
2101
+ </div>
2102
+ </div>
2103
+
2160
2104
  <!-- Padding Options -->
2161
2105
  <div style="padding: 8px 12px; background: white; border-bottom: 1px solid #e5e5e5;">
2162
2106
  <div style="font-size: 9px; font-weight: 600; color: #6b7280; text-transform: uppercase; letter-spacing: 0.5px; margin-bottom: 6px;">Padding</div>
@@ -2237,6 +2181,23 @@ Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed
2237
2181
  <span style="font-weight: 600;">⚠️</span> <span x-text="getTrackOverflowWarning()"></span>
2238
2182
  </div>
2239
2183
 
2184
+ <!-- Default Column Section -->
2185
+ <div style="padding: 8px 12px; background: white; border-bottom: 1px solid #e5e5e5;">
2186
+ <div style="display: flex; align-items: center; justify-content: space-between;">
2187
+ <div @click="copySection('defaultCol')" style="cursor: pointer;">
2188
+ <div style="font-size: 9px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.5px;" :style="{ color: sectionCopied === 'defaultCol' ? '#10b981' : '#6b7280' }" x-text="sectionCopied === 'defaultCol' ? '✓ Copied' : 'Default Column'"></div>
2189
+ <div style="font-size: 9px; color: #9ca3af; margin-top: 2px;">For children without col-* class</div>
2190
+ </div>
2191
+ <select @change="editValues.defaultCol = $event.target.value; configCopied = false"
2192
+ :value="editValues.defaultCol || configOptions.defaultCol.value"
2193
+ style="padding: 6px 8px; font-size: 11px; border: 1px solid #e5e5e5; border-radius: 4px; background: #f9fafb; cursor: pointer;">
2194
+ <template x-for="opt in configOptions.defaultCol.options" :key="opt">
2195
+ <option :value="opt" :selected="(editValues.defaultCol || configOptions.defaultCol.value) === opt" x-text="opt"></option>
2196
+ </template>
2197
+ </select>
2198
+ </div>
2199
+ </div>
2200
+
2240
2201
  <!-- Content Section -->
2241
2202
  <div style="padding: 8px 12px; background: white; border-bottom: 1px solid #e5e5e5;">
2242
2203
  <div @click="copySection('content')" style="font-size: 9px; font-weight: 600; color: #6b7280; text-transform: uppercase; letter-spacing: 0.5px; margin-bottom: 6px; cursor: pointer; display: flex; align-items: center; gap: 6px;" :style="{ color: sectionCopied === 'content' ? '#10b981' : '#6b7280' }">
@@ -2282,23 +2243,6 @@ Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed
2282
2243
  </div>
2283
2244
  </div>
2284
2245
 
2285
- <!-- Default Column Section -->
2286
- <div style="padding: 8px 12px; background: white; border-bottom: 1px solid #e5e5e5;">
2287
- <div style="display: flex; align-items: center; justify-content: space-between;">
2288
- <div @click="copySection('defaultCol')" style="cursor: pointer;">
2289
- <div style="font-size: 9px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.5px;" :style="{ color: sectionCopied === 'defaultCol' ? '#10b981' : '#6b7280' }" x-text="sectionCopied === 'defaultCol' ? '✓ Copied' : 'Default Column'"></div>
2290
- <div style="font-size: 9px; color: #9ca3af; margin-top: 2px;">For children without col-* class</div>
2291
- </div>
2292
- <select @change="editValues.defaultCol = $event.target.value; configCopied = false"
2293
- :value="editValues.defaultCol || configOptions.defaultCol.value"
2294
- style="padding: 6px 8px; font-size: 11px; border: 1px solid #e5e5e5; border-radius: 4px; background: #f9fafb; cursor: pointer;">
2295
- <template x-for="opt in configOptions.defaultCol.options" :key="opt">
2296
- <option :value="opt" :selected="(editValues.defaultCol || configOptions.defaultCol.value) === opt" x-text="opt"></option>
2297
- </template>
2298
- </select>
2299
- </div>
2300
- </div>
2301
-
2302
2246
  <!-- Track Widths Section -->
2303
2247
  <div style="padding: 8px 12px; background: white; border-bottom: 1px solid #e5e5e5;">
2304
2248
  <div @click="copySection('tracks')" style="font-size: 9px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.5px; margin-bottom: 6px; cursor: pointer;" :style="{ color: sectionCopied === 'tracks' ? '#10b981' : '#6b7280' }" x-text="sectionCopied === 'tracks' ? '✓ Copied' : 'Track Widths'"></div>
@@ -2490,6 +2434,53 @@ Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed
2490
2434
  </div>
2491
2435
  </div>
2492
2436
 
2437
+ <!-- Close Warning Modal -->
2438
+ <div x-show="showCloseWarningModal"
2439
+ x-transition:enter="transition ease-out duration-200"
2440
+ x-transition:enter-start="opacity-0"
2441
+ x-transition:enter-end="opacity-100"
2442
+ x-transition:leave="transition ease-in duration-150"
2443
+ x-transition:leave-start="opacity-100"
2444
+ x-transition:leave-end="opacity-0"
2445
+ style="position: fixed; inset: 0; background: rgba(0,0,0,0.5); display: flex; align-items: center; justify-content: center; z-index: 10003; pointer-events: auto;">
2446
+ <div @click.stop style="background: white; border-radius: 8px; box-shadow: 0 25px 50px -12px rgba(0,0,0,0.25); width: 420px; max-width: 90vw; font-family: system-ui, -apple-system, sans-serif;">
2447
+ <!-- Modal Header -->
2448
+ <div style="padding: 12px 16px; background: #fef3c7; color: #92400e; border-radius: 8px 8px 0 0; display: flex; align-items: center; gap: 10px;">
2449
+ <svg style="width: 20px; height: 20px; flex-shrink: 0;" fill="currentColor" viewBox="0 0 20 20">
2450
+ <path fill-rule="evenodd" d="M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z" clip-rule="evenodd"/>
2451
+ </svg>
2452
+ <span style="font-weight: 600; font-size: 14px;">Unsaved Configuration</span>
2453
+ </div>
2454
+ <!-- Modal Body -->
2455
+ <div style="padding: 16px;">
2456
+ <p style="font-size: 13px; color: #374151; margin: 0 0 12px 0; line-height: 1.5;">
2457
+ Your grid configuration changes are stored in <strong>browser localStorage</strong> and will only apply while the visualizer is loaded.
2458
+ </p>
2459
+ <div style="background: #f3f4f6; border-radius: 6px; padding: 12px; margin-bottom: 12px;">
2460
+ <p style="font-size: 12px; color: #4b5563; margin: 0 0 8px 0; line-height: 1.5;">
2461
+ <strong>To make changes permanent:</strong>
2462
+ </p>
2463
+ <ol style="font-size: 11px; color: #6b7280; margin: 0; padding-left: 16px; line-height: 1.6;">
2464
+ <li>Copy the config to your clipboard</li>
2465
+ <li>Paste into your project's CSS file</li>
2466
+ <li>Remove the visualizer script from production</li>
2467
+ </ol>
2468
+ </div>
2469
+ <p style="font-size: 11px; color: #9ca3af; margin: 0; line-height: 1.4;">
2470
+ Without copying, your changes will be lost when the visualizer is removed.
2471
+ </p>
2472
+ </div>
2473
+ <!-- Modal Footer -->
2474
+ <div style="padding: 12px 16px; background: #f7f7f7; border-radius: 0 0 8px 8px; display: flex; justify-content: space-between; gap: 8px;">
2475
+ <button @click="closeWarningDiscard()" style="padding: 8px 16px; font-size: 11px; font-weight: 600; border: 1px solid #fca5a5; border-radius: 4px; cursor: pointer; background: #fef2f2; color: #dc2626;">Discard Changes</button>
2476
+ <div style="display: flex; gap: 8px;">
2477
+ <button @click="closeWarningGoBack()" style="padding: 8px 16px; font-size: 11px; font-weight: 600; border: 1px solid #e5e5e5; border-radius: 4px; cursor: pointer; background: white; color: #374151;">Go Back</button>
2478
+ <button @click="closeWarningCopyAndClose()" style="padding: 8px 16px; font-size: 11px; font-weight: 600; border: none; border-radius: 4px; cursor: pointer; background: #1a1a2e; color: white;">Copy & Close</button>
2479
+ </div>
2480
+ </div>
2481
+ </div>
2482
+ </div>
2483
+
2493
2484
  <!-- Grid Diagram -->
2494
2485
  <div x-show="showDiagram"
2495
2486
  style="position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); background: white; border-radius: 0.5rem; box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25); pointer-events: auto; z-index: 10001; padding: 1.5rem; max-width: 90vw;">
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Breakout Grid - Objects Layer (ITCSS)
3
- * Version: 5.1.1
3
+ * Version: 5.1.2
4
4
  *
5
5
  * Documentation: https://github.com/astuteo-llc/breakout-grid
6
6
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@astuteo/breakout-grid",
3
- "version": "5.1.1",
3
+ "version": "5.1.2",
4
4
  "type": "module",
5
5
  "description": "CSS Grid breakout layout system with visual configurator",
6
6
  "main": "dist/_objects.breakout-grid.css",