@phantompixeldev/retrocss 2.7.0 → 2.8.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/retro.js CHANGED
@@ -1,28 +1,4 @@
1
- var RetroCSS = (() => {
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- var __export = (target, all) => {
7
- for (var name in all)
8
- __defProp(target, name, { get: all[name], enumerable: true });
9
- };
10
- var __copyProps = (to, from, except, desc) => {
11
- if (from && typeof from === "object" || typeof from === "function") {
12
- for (let key of __getOwnPropNames(from))
13
- if (!__hasOwnProp.call(to, key) && key !== except)
14
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
- }
16
- return to;
17
- };
18
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
-
20
- // src/js/retro.js
21
- var retro_exports = {};
22
- __export(retro_exports, {
23
- default: () => retro_default
24
- });
25
-
1
+ (() => {
26
2
  // src/js/components/modal.js
27
3
  var FOCUSABLE = [
28
4
  "a[href]",
@@ -130,7 +106,6 @@ var RetroCSS = (() => {
130
106
  }
131
107
  this._trap(e, openModal);
132
108
  });
133
- console.log("Modal component initialized");
134
109
  },
135
110
  show(modalId) {
136
111
  const modal = document.getElementById(modalId);
@@ -155,7 +130,6 @@ var RetroCSS = (() => {
155
130
  this._isolate(modal);
156
131
  const target = modal.querySelector("[autofocus]") || this._focusable(modal)[0] || modal;
157
132
  target.focus();
158
- console.log(`Modal ${modalId} opened`);
159
133
  },
160
134
  hide(modalId) {
161
135
  const modal = document.getElementById(modalId);
@@ -168,35 +142,74 @@ var RetroCSS = (() => {
168
142
  this._lastFocused.focus();
169
143
  }
170
144
  this._lastFocused = null;
171
- console.log(`Modal ${modalId} closed`);
172
145
  }
173
146
  };
174
147
  var modal_default = RetroModal;
175
148
 
176
149
  // src/js/components/toast.js
177
150
  var RetroToast = {
178
- show(message, options = {}) {
179
- let container = document.getElementById("retro-toast-container");
180
- if (!container) {
181
- container = document.createElement("div");
182
- container.id = "retro-toast-container";
183
- document.body.appendChild(container);
151
+ /**
152
+ * The container is a live region. Without this, toasts were shown silently:
153
+ * a screen reader had no way to know anything had appeared, which made the
154
+ * theme toggle and every `data-retro-toast` trigger inaudible.
155
+ */
156
+ container() {
157
+ let el = document.getElementById("retro-toast-container");
158
+ if (!el) {
159
+ el = document.createElement("div");
160
+ el.id = "retro-toast-container";
161
+ document.body.appendChild(el);
184
162
  }
163
+ el.setAttribute("role", "status");
164
+ el.setAttribute("aria-live", "polite");
165
+ el.setAttribute("aria-atomic", "false");
166
+ return el;
167
+ },
168
+ show(message, options = {}) {
169
+ const container = this.container();
185
170
  const toast = document.createElement("div");
186
171
  toast.className = "retro-toast";
187
- if (options.type) {
188
- toast.classList.add(`retro-toast-${options.type}`);
172
+ if (options.type) toast.classList.add(`retro-toast-${options.type}`);
173
+ if (options.type === "danger") {
174
+ toast.setAttribute("role", "alert");
175
+ toast.setAttribute("aria-live", "assertive");
189
176
  }
177
+ const body = document.createElement("div");
178
+ body.className = "retro-toast-body";
190
179
  if (options.html) {
191
180
  toast.classList.add("retro-toast-html");
192
- toast.innerHTML = message;
181
+ body.innerHTML = message;
193
182
  } else {
194
- toast.textContent = message;
183
+ body.textContent = message;
195
184
  }
185
+ toast.appendChild(body);
186
+ const close = document.createElement("button");
187
+ close.type = "button";
188
+ close.className = "retro-toast-close";
189
+ close.setAttribute("aria-label", "Dismiss notification");
190
+ close.textContent = "\xD7";
191
+ close.addEventListener("click", () => dismiss());
192
+ toast.appendChild(close);
196
193
  container.appendChild(toast);
197
- setTimeout(() => {
194
+ const duration = options.duration === void 0 ? 3e3 : options.duration;
195
+ let timer = null;
196
+ let dismissed = false;
197
+ function dismiss() {
198
+ if (dismissed) return;
199
+ dismissed = true;
200
+ clearTimeout(timer);
198
201
  toast.remove();
199
- }, options.duration || 3e3);
202
+ }
203
+ const start = () => {
204
+ if (duration > 0) timer = setTimeout(dismiss, duration);
205
+ };
206
+ const pause = () => clearTimeout(timer);
207
+ toast.addEventListener("mouseenter", pause);
208
+ toast.addEventListener("mouseleave", start);
209
+ toast.addEventListener("focusin", pause);
210
+ toast.addEventListener("focusout", start);
211
+ start();
212
+ return { dismiss, element: toast };
200
213
  }
201
214
  };
202
215
  var toast_default = RetroToast;
@@ -479,7 +492,6 @@ var RetroCSS = (() => {
479
492
  });
480
493
  }
481
494
  });
482
- console.log("File uploads initialized:", root.querySelectorAll(".retro-file-upload").length);
483
495
  }
484
496
  };
485
497
  var file_upload_default = RetroFileUpload;
@@ -593,7 +605,6 @@ var RetroCSS = (() => {
593
605
  startX = null;
594
606
  moveX = null;
595
607
  });
596
- console.log("Carousel initialized:", this.slides.length, "slides");
597
608
  };
598
609
  RetroCarousel.prototype.goTo = function(idx) {
599
610
  if (idx < 0) idx = this.slides.length - 1;
@@ -617,17 +628,29 @@ var RetroCSS = (() => {
617
628
 
618
629
  // src/js/tabs.js
619
630
  var RetroTabs = class {
620
- constructor(selector, options = {}) {
621
- this.tabContainer = document.querySelector(selector);
631
+ constructor(target, options = {}) {
632
+ this.tabContainer = typeof target === "string" ? document.querySelector(target) : target;
622
633
  if (!this.tabContainer) return;
623
634
  this.options = {
624
635
  contentSelector: options.contentSelector || ".retro-tab-content",
625
636
  activeClass: options.activeClass || "active",
626
- defaultTab: options.defaultTab || 0,
627
- ...options
637
+ ...options,
638
+ // findIndex returns -1 when no tab carries .active, and `-1 || 0` is -1
639
+ // because -1 is truthy -- which then indexes this.tabs[-1].
640
+ defaultTab: Math.max(0, options.defaultTab ?? 0)
628
641
  };
629
642
  this.tabs = Array.from(this.tabContainer.querySelectorAll(".retro-nav-item"));
630
- this.contentElements = this.options.contentContainer ? Array.from(document.querySelector(this.options.contentContainer).children) : Array.from(this.tabContainer.nextElementSibling.querySelectorAll(this.options.contentSelector));
643
+ let paneRoot = this.options.contentContainer;
644
+ if (typeof paneRoot === "string") paneRoot = document.querySelector(paneRoot);
645
+ if (!paneRoot) paneRoot = this.tabContainer.nextElementSibling;
646
+ if (!paneRoot) return;
647
+ this.contentElements = Array.from(
648
+ paneRoot.querySelectorAll(this.options.contentSelector)
649
+ );
650
+ if (!this.contentElements.length) {
651
+ this.contentElements = Array.from(paneRoot.children);
652
+ }
653
+ if (!this.tabs.length || !this.contentElements.length) return;
631
654
  this.init();
632
655
  }
633
656
  init() {
@@ -704,11 +727,6 @@ var RetroCSS = (() => {
704
727
  if (i === 0 && tabs[0].classList.contains("active")) {
705
728
  content.appendChild(existingContent);
706
729
  } else {
707
- content.textContent = `Content for ${tab.textContent}`;
708
- content.style.padding = "20px";
709
- content.style.border = "2px solid #000";
710
- content.style.borderTop = "0";
711
- content.style.background = "#fff";
712
730
  }
713
731
  wrapper.appendChild(content);
714
732
  });
@@ -716,7 +734,7 @@ var RetroCSS = (() => {
716
734
  }
717
735
  }
718
736
  new RetroTabs(nav, {
719
- contentContainer: ".retro-tab-pane",
737
+ contentContainer,
720
738
  defaultTab: Array.from(nav.querySelectorAll(".retro-nav-item")).findIndex((tab) => tab.classList.contains("active"))
721
739
  });
722
740
  });
@@ -736,8 +754,6 @@ var RetroCSS = (() => {
736
754
  if (i === 0 && tabs[0].classList.contains("active")) {
737
755
  content.appendChild(existingContent);
738
756
  } else {
739
- content.textContent = `Content for ${tab.textContent}`;
740
- content.style.padding = "20px";
741
757
  content.style.marginTop = "10px";
742
758
  content.style.background = "#f5f5f5";
743
759
  }
@@ -747,7 +763,7 @@ var RetroCSS = (() => {
747
763
  }
748
764
  }
749
765
  new RetroTabs(nav, {
750
- contentContainer: ".retro-tab-pane-underlined",
766
+ contentContainer,
751
767
  defaultTab: Array.from(nav.querySelectorAll(".retro-nav-item")).findIndex((tab) => tab.classList.contains("active"))
752
768
  });
753
769
  });
@@ -767,8 +783,6 @@ var RetroCSS = (() => {
767
783
  if (i === 0 && tabs[0].classList.contains("active") || tab.classList.contains("active")) {
768
784
  content.appendChild(nextEl);
769
785
  } else {
770
- content.textContent = `Content for ${tab.textContent}`;
771
- content.style.padding = "20px";
772
786
  content.style.marginTop = "10px";
773
787
  content.style.background = "#f5f5f5";
774
788
  }
@@ -777,7 +791,7 @@ var RetroCSS = (() => {
777
791
  contentContainer = wrapper;
778
792
  }
779
793
  new RetroTabs(nav, {
780
- contentContainer: ".retro-tab-pane-buttons",
794
+ contentContainer,
781
795
  defaultTab: Array.from(nav.querySelectorAll(".retro-nav-item")).findIndex((tab) => tab.classList.contains("active"))
782
796
  });
783
797
  }
@@ -816,7 +830,6 @@ var RetroCSS = (() => {
816
830
  });
817
831
  });
818
832
  });
819
- console.log("Accordion component initialized");
820
833
  }
821
834
  static init(selector = ".retro-accordion") {
822
835
  new _RetroAccordion(selector);
@@ -879,72 +892,59 @@ var RetroCSS = (() => {
879
892
 
880
893
  // src/js/infinite-scroll.js
881
894
  var RetroInfiniteScroll = {
882
- isLoading: false,
883
- page: 1,
884
- itemsPerPage: 5,
885
- maxPages: 5,
886
- // For demo purposes
887
- init() {
888
- const containers = document.querySelectorAll(".retro-infinite-scroll");
889
- if (!containers.length) return;
895
+ /** How close to the bottom, in px, before more content is requested. */
896
+ threshold: 50,
897
+ init(root = document) {
898
+ const containers = root.querySelectorAll(".retro-infinite-scroll");
890
899
  containers.forEach((container) => {
891
- this.appendItems(container, 1);
900
+ if (container.dataset.retroInfiniteBound === "true") return;
901
+ container.dataset.retroInfiniteBound = "true";
902
+ const state = { page: 1, loading: false, finished: false };
892
903
  container.addEventListener("scroll", () => {
893
- if (this.isNearBottom(container) && !this.isLoading && this.page < this.maxPages) {
894
- this.loadMoreItems(container);
895
- }
904
+ if (state.loading || state.finished) return;
905
+ if (!this.isNearBottom(container)) return;
906
+ this.requestMore(container, state);
896
907
  });
897
908
  });
898
909
  },
899
910
  isNearBottom(container) {
900
- return container.scrollHeight - container.scrollTop - container.clientHeight < 50;
911
+ return container.scrollHeight - container.scrollTop - container.clientHeight < this.threshold;
901
912
  },
902
- loadMoreItems(container) {
913
+ requestMore(container, state) {
903
914
  const loader = container.querySelector(".retro-infinite-loader");
904
- this.isLoading = true;
915
+ state.loading = true;
905
916
  if (loader) loader.style.display = "flex";
906
- setTimeout(() => {
907
- this.page++;
908
- this.appendItems(container, this.page);
909
- this.isLoading = false;
917
+ const settle = () => {
918
+ state.loading = false;
910
919
  if (loader) loader.style.display = "none";
911
- if (this.page >= this.maxPages) {
912
- const endMessage = document.createElement("div");
913
- endMessage.className = "retro-infinite-end";
914
- endMessage.textContent = "End of content";
915
- endMessage.style.textAlign = "center";
916
- endMessage.style.padding = "20px";
917
- endMessage.style.color = "var(--retro-border-medium)";
918
- container.appendChild(endMessage);
919
- }
920
- }, 800);
921
- },
922
- appendItems(container, page) {
923
- const loader = container.querySelector(".retro-infinite-loader");
924
- for (let i = 1; i <= this.itemsPerPage; i++) {
925
- const itemIndex = (page - 1) * this.itemsPerPage + i;
926
- const item = document.createElement("div");
927
- item.className = "retro-card retro-mb-3";
928
- const card = `
929
- <div class="retro-card-header">
930
- Item ${itemIndex}
931
- </div>
932
- <div class="retro-card-content">
933
- <p>This is demo content for infinite scroll. Scroll down to load more items.</p>
934
- <div class="retro-progress" style="margin-top: 10px;">
935
- <div class="retro-progress-bar" style="width: ${Math.floor(
936
- Math.random() * 100
937
- )}%;"></div>
938
- </div>
939
- </div>
940
- `;
941
- item.innerHTML = card;
942
- if (loader) {
943
- container.insertBefore(item, loader);
944
- } else {
945
- container.appendChild(item);
920
+ };
921
+ const detail = {
922
+ page: state.page + 1,
923
+ /** Insert a node above the loader. */
924
+ append(node) {
925
+ if (loader) container.insertBefore(node, loader);
926
+ else container.appendChild(node);
927
+ },
928
+ /** Call when a page has been added. */
929
+ loaded() {
930
+ state.page += 1;
931
+ settle();
932
+ },
933
+ /** Call when there is nothing left. */
934
+ done() {
935
+ state.finished = true;
936
+ settle();
937
+ if (container.querySelector(".retro-infinite-end")) return;
938
+ const end = document.createElement("div");
939
+ end.className = "retro-infinite-end";
940
+ end.textContent = "End of content";
941
+ container.appendChild(end);
946
942
  }
947
- }
943
+ };
944
+ const delivered = container.dispatchEvent(
945
+ new CustomEvent("retro:loadmore", { detail, bubbles: true, cancelable: true })
946
+ );
947
+ if (delivered && state.loading) settle();
948
948
  }
949
949
  };
950
950
  window.RetroInfiniteScroll = RetroInfiniteScroll;
@@ -1134,19 +1134,15 @@ var RetroCSS = (() => {
1134
1134
  };
1135
1135
  window.RetroSidebar = RetroSidebar;
1136
1136
 
1137
- // src/js/datetime.js
1138
- (function() {
1139
- document.querySelectorAll('input[type="date"], input[type="time"]').forEach(function(input) {
1140
- input.addEventListener("change", function() {
1141
- if (window.RetroCSS && RetroCSS.toast) {
1142
- RetroCSS.toast.show("Selected: " + input.value, { type: "info" });
1143
- }
1144
- });
1145
- });
1146
- })();
1147
-
1148
1137
  // src/js/retro.js
1149
- var RetroCSS2 = {
1138
+ function readStoredTheme() {
1139
+ try {
1140
+ return localStorage.getItem("retro-theme") || "light";
1141
+ } catch (e) {
1142
+ return "light";
1143
+ }
1144
+ }
1145
+ var RetroCSS = {
1150
1146
  modal: modal_default,
1151
1147
  toast: toast_default,
1152
1148
  form: form_default,
@@ -1159,11 +1155,13 @@ var RetroCSS = (() => {
1159
1155
  accordion: window.RetroAccordion,
1160
1156
  tabs: window.RetroTabs,
1161
1157
  infiniteScroll: window.RetroInfiniteScroll,
1162
- // Store theme preference
1163
- theme: localStorage.getItem("retro-theme") || "light",
1158
+ // Store theme preference. Read defensively: in a sandboxed iframe, or with
1159
+ // third-party storage blocked, touching localStorage throws SecurityError —
1160
+ // and this runs during module evaluation, so it would take the whole bundle
1161
+ // down before init() ever ran.
1162
+ theme: readStoredTheme(),
1164
1163
  // Initialize all components
1165
1164
  init() {
1166
- console.log("RetroCSS initializing components...");
1167
1165
  modal_default.init();
1168
1166
  dropdown_default.init();
1169
1167
  form_default.init();
@@ -1171,21 +1169,17 @@ var RetroCSS = (() => {
1171
1169
  file_upload_default.init();
1172
1170
  if (window.RetroCarousel && typeof window.RetroCarousel.init === "function") {
1173
1171
  window.RetroCarousel.init();
1174
- console.log("Carousel initialized");
1175
1172
  } else {
1176
1173
  console.warn("RetroCarousel not available");
1177
1174
  }
1178
- if (window.RetroTabsInit && typeof window.RetroTabsInit.init === "function") {
1179
- window.RetroTabsInit.init();
1180
- console.log("Tabs initialized");
1175
+ if (window.RetroTabs && typeof window.RetroTabs.init === "function") {
1176
+ window.RetroTabs.init();
1181
1177
  }
1182
1178
  if (window.RetroAccordion && typeof window.RetroAccordion.init === "function") {
1183
1179
  window.RetroAccordion.init();
1184
- console.log("Accordion initialized");
1185
1180
  }
1186
1181
  if (window.RetroInfiniteScroll && typeof window.RetroInfiniteScroll.init === "function") {
1187
1182
  window.RetroInfiniteScroll.init();
1188
- console.log("Infinite Scroll initialized");
1189
1183
  }
1190
1184
  this.initTooltips();
1191
1185
  this.initToastTriggers();
@@ -1220,7 +1214,6 @@ var RetroCSS = (() => {
1220
1214
  tooltip.classList.remove("show");
1221
1215
  });
1222
1216
  });
1223
- console.log("Tooltips initialized:", tooltipTriggers.length);
1224
1217
  },
1225
1218
  // Initialize toast trigger elements
1226
1219
  initToastTriggers() {
@@ -1236,17 +1229,8 @@ var RetroCSS = (() => {
1236
1229
  duration,
1237
1230
  html
1238
1231
  });
1239
- if (message === "Stacked Toast 1") {
1240
- setTimeout(() => {
1241
- toast_default.show("Stacked Toast 2", { type: "primary" });
1242
- setTimeout(() => {
1243
- toast_default.show("Stacked Toast 3", { type: "success" });
1244
- }, 600);
1245
- }, 600);
1246
- }
1247
1232
  });
1248
1233
  });
1249
- console.log("Toast triggers initialized:", toastTriggers.length);
1250
1234
  },
1251
1235
  // Initialize search bar components
1252
1236
  initSearchBars() {
@@ -1255,55 +1239,35 @@ var RetroCSS = (() => {
1255
1239
  const input = searchBar.querySelector(".retro-search-input");
1256
1240
  const suggestions = searchBar.querySelector(".retro-search-suggestions");
1257
1241
  if (!input) return;
1242
+ const items = suggestions ? Array.from(suggestions.querySelectorAll(".retro-search-suggestion")) : [];
1243
+ const choose = (item) => {
1244
+ input.value = item.textContent.trim();
1245
+ searchBar.classList.remove("active");
1246
+ input.dispatchEvent(new Event("change", { bubbles: true }));
1247
+ input.focus();
1248
+ };
1249
+ items.forEach((item) => item.addEventListener("click", () => choose(item)));
1258
1250
  input.addEventListener("focus", () => {
1259
- if (suggestions) {
1260
- searchBar.classList.add("active");
1261
- }
1262
- });
1263
- document.addEventListener("click", (e) => {
1264
- if (!searchBar.contains(e.target)) {
1265
- searchBar.classList.remove("active");
1266
- }
1251
+ if (suggestions) searchBar.classList.add("active");
1267
1252
  });
1268
- if (suggestions) {
1269
- const suggestionItems = suggestions.querySelectorAll(".retro-search-suggestion");
1270
- suggestionItems.forEach((item) => {
1271
- item.addEventListener("click", () => {
1272
- input.value = item.textContent;
1273
- searchBar.classList.remove("active");
1274
- input.dispatchEvent(new Event("change", { bubbles: true }));
1275
- input.focus();
1276
- });
1277
- });
1278
- }
1279
1253
  input.addEventListener("input", () => {
1280
- if (!suggestions) return;
1281
1254
  const value = input.value.trim().toLowerCase();
1282
- suggestions.innerHTML = "";
1283
- if (value) {
1284
- const demoItems = [
1285
- `${value} - Result 1`,
1286
- `${value} - Result 2`,
1287
- `${value} - Result 3`
1288
- ];
1289
- demoItems.forEach((item) => {
1290
- const suggestion = document.createElement("div");
1291
- suggestion.className = "retro-search-suggestion";
1292
- suggestion.textContent = item;
1293
- suggestion.addEventListener("click", () => {
1294
- input.value = item;
1295
- searchBar.classList.remove("active");
1296
- input.focus();
1297
- });
1298
- suggestions.appendChild(suggestion);
1299
- });
1300
- searchBar.classList.add("active");
1301
- } else {
1302
- searchBar.classList.remove("active");
1303
- }
1255
+ events_default.emit("search", { searchBar, input, value });
1256
+ if (!suggestions) return;
1257
+ let visible = 0;
1258
+ items.forEach((item) => {
1259
+ const match = !value || item.textContent.toLowerCase().includes(value);
1260
+ item.hidden = !match;
1261
+ if (match) visible += 1;
1262
+ });
1263
+ searchBar.classList.toggle("active", visible > 0);
1264
+ });
1265
+ });
1266
+ document.addEventListener("click", (e) => {
1267
+ document.querySelectorAll(".retro-search-bar.active").forEach((bar) => {
1268
+ if (!bar.contains(e.target)) bar.classList.remove("active");
1304
1269
  });
1305
1270
  });
1306
- console.log("Search bars initialized:", searchBars.length);
1307
1271
  },
1308
1272
  // Initialize tag input components
1309
1273
  initTagInputs() {
@@ -1364,7 +1328,6 @@ var RetroCSS = (() => {
1364
1328
  }
1365
1329
  });
1366
1330
  });
1367
- console.log("Tag inputs initialized:", tagInputs.length);
1368
1331
  },
1369
1332
  // Initialize theme toggle button
1370
1333
  initThemeToggle() {
@@ -1379,7 +1342,6 @@ var RetroCSS = (() => {
1379
1342
  });
1380
1343
  });
1381
1344
  });
1382
- console.log("Theme toggles initialized:", themeToggles.length);
1383
1345
  },
1384
1346
  // Apply theme to document
1385
1347
  applyTheme(theme) {
@@ -1420,15 +1382,20 @@ var RetroCSS = (() => {
1420
1382
  });
1421
1383
  });
1422
1384
  });
1423
- console.log("Rating stars initialized:", ratings.length);
1424
1385
  }
1425
1386
  };
1426
- window.RetroCSS = RetroCSS2;
1387
+ window.RetroCSS = RetroCSS;
1388
+ window.RetroModal = modal_default;
1389
+ window.RetroToast = toast_default;
1390
+ window.RetroForm = form_default;
1391
+ window.RetroTable = table_default;
1392
+ window.RetroDropdown = dropdown_default;
1393
+ window.RetroFileUpload = file_upload_default;
1394
+ window.RetroEvents = events_default;
1427
1395
  if (document.readyState === "loading") {
1428
- document.addEventListener("DOMContentLoaded", () => RetroCSS2.init());
1396
+ document.addEventListener("DOMContentLoaded", () => RetroCSS.init());
1429
1397
  } else {
1430
- RetroCSS2.init();
1398
+ RetroCSS.init();
1431
1399
  }
1432
- var retro_default = RetroCSS2;
1433
- return __toCommonJS(retro_exports);
1400
+ var retro_default = RetroCSS;
1434
1401
  })();