fokus-styles 2.0.0 → 2.3.0

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.
Files changed (131) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/README.md +4 -3
  3. package/dist/css/components.css +510 -2
  4. package/dist/css/components.css.map +1 -1
  5. package/dist/css/components.min.css +1 -1
  6. package/dist/css/components.min.css.map +1 -1
  7. package/dist/css/fokus-components.css +4050 -0
  8. package/dist/css/fokus-components.css.map +1 -0
  9. package/dist/css/fokus-components.min.css +2 -0
  10. package/dist/css/fokus-components.min.css.map +1 -0
  11. package/dist/css/fokus-core.css +1563 -0
  12. package/dist/css/fokus-core.css.map +1 -0
  13. package/dist/css/fokus-core.min.css +2 -0
  14. package/dist/css/fokus-core.min.css.map +1 -0
  15. package/dist/css/fokus-dark.css +304 -0
  16. package/dist/css/fokus-dark.css.map +1 -0
  17. package/dist/css/fokus-dark.min.css +2 -0
  18. package/dist/css/fokus-dark.min.css.map +1 -0
  19. package/dist/css/fokus-utilities.css +4176 -0
  20. package/dist/css/fokus-utilities.css.map +1 -0
  21. package/dist/css/fokus-utilities.min.css +2 -0
  22. package/dist/css/fokus-utilities.min.css.map +1 -0
  23. package/dist/css/fokus.css +1339 -53
  24. package/dist/css/fokus.css.map +1 -1
  25. package/dist/css/fokus.min.css +1 -1
  26. package/dist/css/fokus.min.css.map +1 -1
  27. package/dist/css/forms.css +115 -2
  28. package/dist/css/forms.css.map +1 -1
  29. package/dist/css/forms.min.css +1 -1
  30. package/dist/css/forms.min.css.map +1 -1
  31. package/dist/css/helpers.css +376 -2
  32. package/dist/css/helpers.css.map +1 -1
  33. package/dist/css/helpers.min.css +1 -1
  34. package/dist/css/helpers.min.css.map +1 -1
  35. package/dist/css/layout.css +560 -2
  36. package/dist/css/layout.css.map +1 -1
  37. package/dist/css/layout.min.css +1 -1
  38. package/dist/css/layout.min.css.map +1 -1
  39. package/dist/js/fokus.js +347 -12
  40. package/dist/js/fokus.js.map +4 -4
  41. package/dist/js/fokus.min.js +17 -17
  42. package/dist/js/fokus.min.js.map +4 -4
  43. package/docs/components/accordion.md +3 -0
  44. package/docs/components/avatar.md +13 -0
  45. package/docs/components/button-group.md +13 -0
  46. package/docs/components/close-button.md +13 -0
  47. package/docs/components/code.md +13 -0
  48. package/docs/components/icon-link.md +13 -0
  49. package/docs/components/list-group.md +13 -0
  50. package/docs/components/modal.md +3 -0
  51. package/docs/components/navbar.md +3 -0
  52. package/docs/components/pagination.md +3 -0
  53. package/docs/components/placeholder.md +13 -0
  54. package/docs/components/ratio.md +13 -0
  55. package/docs/components/scrollspy.md +13 -0
  56. package/docs/components/skeleton.md +3 -0
  57. package/docs/components/table.md +3 -0
  58. package/docs/guides/javascript-api.md +9 -0
  59. package/docs/guides/utility-api.md +9 -0
  60. package/docs/reference/size-baseline.json +13 -13
  61. package/mockup/assets/example-theme.css +3 -1
  62. package/mockup/assets/example-theme.js +2 -0
  63. package/mockup/assets/showcase-contracts.js +2 -2
  64. package/mockup/assets/showcase.css +4 -2
  65. package/mockup/assets/showcase.js +2 -0
  66. package/mockup/examples/js-foundation.html +25 -0
  67. package/mockup/examples/tables-navbar.html +12 -8
  68. package/mockup/examples/theming.html +2 -1
  69. package/mockup/foundations.html +2 -2
  70. package/package.json +14 -1
  71. package/packages/fokus-cli/bin/fokus.mjs +18 -1
  72. package/packages/fokus-cli/lib/build.mjs +12 -2
  73. package/packages/fokus-components/scss/components/_accordion.scss +19 -0
  74. package/packages/fokus-components/scss/components/_avatar.scss +22 -0
  75. package/packages/fokus-components/scss/components/_button-group.scss +14 -0
  76. package/packages/fokus-components/scss/components/_close-button.scss +22 -0
  77. package/packages/fokus-components/scss/components/_code.scss +19 -0
  78. package/packages/fokus-components/scss/components/_icon-link.scss +8 -0
  79. package/packages/fokus-components/scss/components/_index.scss +10 -0
  80. package/packages/fokus-components/scss/components/_list-group.scss +26 -0
  81. package/packages/fokus-components/scss/components/_modal.scss +36 -0
  82. package/packages/fokus-components/scss/components/_navbar.scss +48 -0
  83. package/packages/fokus-components/scss/components/_offcanvas.scss +19 -0
  84. package/packages/fokus-components/scss/components/_pagination.scss +10 -0
  85. package/packages/fokus-components/scss/components/_placeholder.scss +13 -0
  86. package/packages/fokus-components/scss/components/_progress.scss +8 -0
  87. package/packages/fokus-components/scss/components/_ratio.scss +10 -0
  88. package/packages/fokus-components/scss/components/_scrollspy.scss +5 -0
  89. package/packages/fokus-components/scss/components/_skeleton.scss +19 -0
  90. package/packages/fokus-components/scss/components/_spinner.scss +9 -53
  91. package/packages/fokus-components/scss/components/_tables.scss +20 -0
  92. package/packages/fokus-components/scss/forms/_forms.scss +29 -0
  93. package/packages/fokus-core/scss/base/_accessibility.scss +45 -0
  94. package/packages/fokus-core/scss/base/_index.scss +1 -0
  95. package/packages/fokus-core/scss/layout/_grid.scss +18 -0
  96. package/packages/fokus-core/scss/settings/_config.scss +43 -0
  97. package/packages/fokus-core/scss/settings/_index.scss +1 -0
  98. package/packages/fokus-core/scss/themes/_dark.scss +38 -2
  99. package/packages/fokus-core/scss/tokens/_root.scss +14 -0
  100. package/packages/fokus-core/scss/tools/_mixins.scss +8 -0
  101. package/packages/fokus-js/js/accordion.js +7 -1
  102. package/packages/fokus-js/js/core/focus.js +20 -0
  103. package/packages/fokus-js/js/core/overlay.d.ts +2 -0
  104. package/packages/fokus-js/js/core/overlay.js +10 -0
  105. package/packages/fokus-js/js/core/register.js +4 -2
  106. package/packages/fokus-js/js/focus-trap.d.ts +3 -0
  107. package/packages/fokus-js/js/focus-trap.js +1 -0
  108. package/packages/fokus-js/js/fokus.d.ts +7 -0
  109. package/packages/fokus-js/js/fokus.js +7 -0
  110. package/packages/fokus-js/js/form-validation.d.ts +7 -0
  111. package/packages/fokus-js/js/form-validation.js +20 -0
  112. package/packages/fokus-js/js/modal.js +16 -2
  113. package/packages/fokus-js/js/navbar.d.ts +10 -0
  114. package/packages/fokus-js/js/navbar.js +27 -0
  115. package/packages/fokus-js/js/offcanvas.d.ts +4 -0
  116. package/packages/fokus-js/js/offcanvas.js +16 -2
  117. package/packages/fokus-js/js/pagination.d.ts +7 -0
  118. package/packages/fokus-js/js/pagination.js +38 -0
  119. package/packages/fokus-js/js/scrollspy.d.ts +7 -0
  120. package/packages/fokus-js/js/scrollspy.js +26 -0
  121. package/packages/fokus-js/js/spinner.d.ts +9 -0
  122. package/packages/fokus-js/js/spinner.js +18 -0
  123. package/packages/fokus-js/js/theme.d.ts +9 -0
  124. package/packages/fokus-js/js/theme.js +19 -0
  125. package/packages/fokus-js/js/toast.js +4 -0
  126. package/packages/fokus-utilities/scss/utilities/_api.scss +48 -0
  127. package/packages/fokus-utilities/scss/utilities/_index.scss +2 -0
  128. package/packages/fokus-utilities/scss/utilities/_states.scss +19 -0
  129. package/packages/fokus-utilities/scss/utilities/_visibility.scss +24 -0
  130. package/scss/entries/core-entry.scss +5 -0
  131. package/scss/entries/dark-entry.scss +3 -0
package/dist/js/fokus.js CHANGED
@@ -31,21 +31,30 @@ var FokusStyles = (() => {
31
31
  Dropdown: () => Dropdown,
32
32
  FileDrop: () => FileDrop,
33
33
  FileUploadAdvanced: () => FileUploadAdvanced,
34
+ FormValidation: () => FormValidation,
34
35
  Modal: () => Modal,
36
+ Navbar: () => Navbar,
35
37
  NestedMenu: () => NestedMenu,
36
38
  NotificationCenter: () => NotificationCenter,
37
39
  Offcanvas: () => Offcanvas,
40
+ Pagination: () => Pagination,
38
41
  Popover: () => Popover,
39
42
  RangeSlider: () => RangeSlider,
43
+ Scrollspy: () => Scrollspy,
40
44
  Select: () => Select,
45
+ Spinner: () => Spinner,
41
46
  Stepper: () => Stepper,
42
47
  Tabs: () => Tabs,
43
48
  Tag: () => Tag,
49
+ Theme: () => Theme,
44
50
  Toast: () => Toast,
45
51
  Tooltip: () => Tooltip,
46
52
  TreeView: () => TreeView,
47
53
  confirm: () => confirm,
48
- core: () => core_exports
54
+ core: () => core_exports,
55
+ createFocusTrap: () => createFocusTrap,
56
+ getFocusableElements: () => getFocusableElements,
57
+ onEscapeKey: () => onEscapeKey
49
58
  });
50
59
 
51
60
  // packages/fokus-js/js/core/index.js
@@ -63,7 +72,9 @@ var FokusStyles = (() => {
63
72
  onClickOutside: () => onClickOutside,
64
73
  onEscapeKey: () => onEscapeKey,
65
74
  onTransitionEnd: () => onTransitionEnd,
75
+ registerOverlay: () => registerOverlay,
66
76
  unlockScroll: () => unlockScroll,
77
+ unregisterOverlay: () => unregisterOverlay,
67
78
  watchPosition: () => watchPosition
68
79
  });
69
80
 
@@ -160,6 +171,14 @@ var FokusStyles = (() => {
160
171
  var paddingCompensated = false;
161
172
  var previousOverflow = "";
162
173
  var previousPaddingRight = "";
174
+ var activeOverlays = [];
175
+ function registerOverlay(instance) {
176
+ if (!activeOverlays.includes(instance)) activeOverlays.push(instance);
177
+ }
178
+ function unregisterOverlay(instance) {
179
+ const index = activeOverlays.lastIndexOf(instance);
180
+ if (index >= 0) activeOverlays.splice(index, 1);
181
+ }
163
182
  function lockScroll() {
164
183
  lockCount += 1;
165
184
  if (lockCount > 1) return;
@@ -197,6 +216,23 @@ var FokusStyles = (() => {
197
216
  return Array.from(container.querySelectorAll(FOCUSABLE_SELECTOR)).filter((el) => el.offsetParent !== null);
198
217
  }
199
218
  function createFocusTrap(container) {
219
+ const inertSiblings = [];
220
+ const setSiblingsInert = (value) => {
221
+ if (!container.parentElement) return;
222
+ [...container.parentElement.children].filter((el) => el !== container).forEach((el) => {
223
+ if (value) {
224
+ inertSiblings.push({ el, value: el.inert, ariaHidden: el.getAttribute("aria-hidden") });
225
+ el.inert = true;
226
+ el.setAttribute("aria-hidden", "true");
227
+ } else {
228
+ const previous = inertSiblings.find((item) => item.el === el);
229
+ if (previous) {
230
+ el.inert = previous.value;
231
+ previous.ariaHidden === null ? el.removeAttribute("aria-hidden") : el.setAttribute("aria-hidden", previous.ariaHidden);
232
+ }
233
+ }
234
+ });
235
+ };
200
236
  function handleKeydown(event) {
201
237
  if (event.key !== "Tab") return;
202
238
  const focusable = getFocusableElements(container);
@@ -217,11 +253,14 @@ var FokusStyles = (() => {
217
253
  container.addEventListener("keydown", handleKeydown);
218
254
  return {
219
255
  activate() {
256
+ setSiblingsInert(true);
220
257
  const focusable = getFocusableElements(container);
221
258
  if (focusable.length > 0) focusable[0].focus();
222
259
  },
223
260
  deactivate() {
224
261
  container.removeEventListener("keydown", handleKeydown);
262
+ setSiblingsInert(false);
263
+ inertSiblings.length = 0;
225
264
  }
226
265
  };
227
266
  }
@@ -315,23 +354,25 @@ var FokusStyles = (() => {
315
354
 
316
355
  // packages/fokus-js/js/core/register.js
317
356
  function createInstanceRegistry() {
318
- const instances25 = /* @__PURE__ */ new WeakMap();
357
+ const instances31 = /* @__PURE__ */ new WeakMap();
319
358
  return {
320
359
  get(el) {
321
- return instances25.get(el);
360
+ return instances31.get(el);
322
361
  },
323
362
  set(el, instance) {
324
- instances25.set(el, instance);
363
+ instances31.set(el, instance);
325
364
  },
326
365
  delete(el) {
327
- instances25.delete(el);
366
+ instances31.delete(el);
328
367
  }
329
368
  };
330
369
  }
331
- function autoInit(name, Ctor) {
370
+ function autoInit(name, Ctor, options = {}) {
371
+ var _a;
332
372
  if (typeof document === "undefined") return;
373
+ const selector = (_a = options.selector) != null ? _a : `[data-fs="${name}"]`;
333
374
  const init = () => {
334
- document.querySelectorAll(`[data-fs="${name}"]`).forEach((el) => {
375
+ document.querySelectorAll(selector).forEach((el) => {
335
376
  if (!Ctor.getInstance(el)) new Ctor(el);
336
377
  });
337
378
  };
@@ -744,7 +785,7 @@ var FokusStyles = (() => {
744
785
 
745
786
  // packages/fokus-js/js/modal.js
746
787
  var instances4 = createInstanceRegistry();
747
- var Modal = class {
788
+ var Modal = class _Modal {
748
789
  constructor(triggerEl, options = {}) {
749
790
  var _a, _b;
750
791
  const targetSelector = triggerEl.getAttribute("data-fs-target");
@@ -779,6 +820,20 @@ var FokusStyles = (() => {
779
820
  static getInstance(el) {
780
821
  return instances4.get(el);
781
822
  }
823
+ static getOrCreateInstance(el, options = {}) {
824
+ var _a;
825
+ return (_a = this.getInstance(el)) != null ? _a : new _Modal(el, options);
826
+ }
827
+ static show(el, options = {}) {
828
+ return this.getOrCreateInstance(el, options).show();
829
+ }
830
+ static hide(el) {
831
+ var _a;
832
+ return (_a = this.getInstance(el)) == null ? void 0 : _a.hide();
833
+ }
834
+ static toggle(el, options = {}) {
835
+ return this.getOrCreateInstance(el, options).toggle();
836
+ }
782
837
  _handleTriggerClick(event) {
783
838
  event.preventDefault();
784
839
  this.show();
@@ -790,7 +845,9 @@ var FokusStyles = (() => {
790
845
  }
791
846
  show() {
792
847
  if (this.isOpen) return;
848
+ this.triggerEl.dispatchEvent(new CustomEvent("fs:show", { bubbles: true }));
793
849
  this.isOpen = true;
850
+ registerOverlay(this);
794
851
  this.modalEl.classList.add("is-open");
795
852
  this.modalEl.setAttribute("aria-hidden", "false");
796
853
  lockScroll();
@@ -799,12 +856,15 @@ var FokusStyles = (() => {
799
856
  if (!this.staticBackdrop) {
800
857
  this._outsideClickCleanup = onClickOutside(this.dialogEl, () => this.hide());
801
858
  }
859
+ this.triggerEl.dispatchEvent(new CustomEvent("fs:shown", { bubbles: true }));
802
860
  this.triggerEl.dispatchEvent(new CustomEvent("fs:modal:shown", { bubbles: true }));
803
861
  }
804
862
  hide() {
805
863
  var _a, _b;
806
864
  if (!this.isOpen) return;
865
+ this.triggerEl.dispatchEvent(new CustomEvent("fs:hide", { bubbles: true }));
807
866
  this.isOpen = false;
867
+ unregisterOverlay(this);
808
868
  this.modalEl.classList.remove("is-open");
809
869
  this.modalEl.setAttribute("aria-hidden", "true");
810
870
  unlockScroll();
@@ -813,6 +873,7 @@ var FokusStyles = (() => {
813
873
  (_b = this._outsideClickCleanup) == null ? void 0 : _b.call(this);
814
874
  this._outsideClickCleanup = null;
815
875
  this.triggerEl.focus();
876
+ this.triggerEl.dispatchEvent(new CustomEvent("fs:hidden", { bubbles: true }));
816
877
  this.triggerEl.dispatchEvent(new CustomEvent("fs:modal:hidden", { bubbles: true }));
817
878
  }
818
879
  toggle() {
@@ -830,7 +891,7 @@ var FokusStyles = (() => {
830
891
  instances4.delete(this.triggerEl);
831
892
  }
832
893
  };
833
- autoInit("modal", Modal);
894
+ autoInit("modal", Modal, { selector: '[data-fs="modal"], [data-fs-toggle="modal"]' });
834
895
 
835
896
  // packages/fokus-js/js/confirm.js
836
897
  var idCounter3 = 0;
@@ -1007,7 +1068,7 @@ var FokusStyles = (() => {
1007
1068
 
1008
1069
  // packages/fokus-js/js/offcanvas.js
1009
1070
  var instances7 = createInstanceRegistry();
1010
- var Offcanvas = class {
1071
+ var Offcanvas = class _Offcanvas {
1011
1072
  constructor(triggerEl, options = {}) {
1012
1073
  var _a, _b;
1013
1074
  const targetSelector = triggerEl.getAttribute("data-fs-target");
@@ -1043,6 +1104,20 @@ var FokusStyles = (() => {
1043
1104
  static getInstance(el) {
1044
1105
  return instances7.get(el);
1045
1106
  }
1107
+ static getOrCreateInstance(el, options = {}) {
1108
+ var _a;
1109
+ return (_a = this.getInstance(el)) != null ? _a : new _Offcanvas(el, options);
1110
+ }
1111
+ static show(el, options = {}) {
1112
+ return this.getOrCreateInstance(el, options).show();
1113
+ }
1114
+ static hide(el) {
1115
+ var _a;
1116
+ return (_a = this.getInstance(el)) == null ? void 0 : _a.hide();
1117
+ }
1118
+ static toggle(el, options = {}) {
1119
+ return this.getOrCreateInstance(el, options).toggle();
1120
+ }
1046
1121
  _handleTriggerClick(event) {
1047
1122
  event.preventDefault();
1048
1123
  this.show();
@@ -1054,7 +1129,9 @@ var FokusStyles = (() => {
1054
1129
  }
1055
1130
  show() {
1056
1131
  if (this.isOpen) return;
1132
+ this.triggerEl.dispatchEvent(new CustomEvent("fs:show", { bubbles: true }));
1057
1133
  this.isOpen = true;
1134
+ registerOverlay(this);
1058
1135
  if (this.hasBackdrop) {
1059
1136
  this._backdropEl = document.createElement("div");
1060
1137
  this._backdropEl.className = "fs-offcanvas-backdrop";
@@ -1077,12 +1154,15 @@ var FokusStyles = (() => {
1077
1154
  this.hide();
1078
1155
  });
1079
1156
  }
1157
+ this.triggerEl.dispatchEvent(new CustomEvent("fs:shown", { bubbles: true }));
1080
1158
  this.triggerEl.dispatchEvent(new CustomEvent("fs:offcanvas:shown", { bubbles: true }));
1081
1159
  }
1082
1160
  hide() {
1083
1161
  var _a, _b, _c;
1084
1162
  if (!this.isOpen) return;
1163
+ this.triggerEl.dispatchEvent(new CustomEvent("fs:hide", { bubbles: true }));
1085
1164
  this.isOpen = false;
1165
+ unregisterOverlay(this);
1086
1166
  this.offcanvasEl.classList.remove("is-open");
1087
1167
  this.offcanvasEl.setAttribute("aria-hidden", "true");
1088
1168
  unlockScroll();
@@ -1093,6 +1173,7 @@ var FokusStyles = (() => {
1093
1173
  (_c = this._outsideClickCleanup) == null ? void 0 : _c.call(this);
1094
1174
  this._outsideClickCleanup = null;
1095
1175
  this.triggerEl.focus();
1176
+ this.triggerEl.dispatchEvent(new CustomEvent("fs:hidden", { bubbles: true }));
1096
1177
  this.triggerEl.dispatchEvent(new CustomEvent("fs:offcanvas:hidden", { bubbles: true }));
1097
1178
  }
1098
1179
  toggle() {
@@ -1110,7 +1191,7 @@ var FokusStyles = (() => {
1110
1191
  instances7.delete(this.triggerEl);
1111
1192
  }
1112
1193
  };
1113
- autoInit("offcanvas", Offcanvas);
1194
+ autoInit("offcanvas", Offcanvas, { selector: '[data-fs="offcanvas"], [data-fs-toggle="offcanvas"]' });
1114
1195
 
1115
1196
  // packages/fokus-js/js/select.js
1116
1197
  var instances8 = createInstanceRegistry();
@@ -1217,7 +1298,8 @@ var FokusStyles = (() => {
1217
1298
  var Accordion = class {
1218
1299
  constructor(accordionEl) {
1219
1300
  this.accordionEl = accordionEl;
1220
- this.exclusive = accordionEl.getAttribute("data-multiple") !== "true";
1301
+ this.exclusive = accordionEl.getAttribute("data-multiple") !== "true" && accordionEl.getAttribute("data-fs-always-open") !== "true";
1302
+ this.alwaysOpen = accordionEl.getAttribute("data-fs-always-open") === "true";
1221
1303
  this.items = [];
1222
1304
  const buttons = Array.from(accordionEl.querySelectorAll(".fs-accordion-button"));
1223
1305
  buttons.forEach((button) => {
@@ -1246,6 +1328,7 @@ var FokusStyles = (() => {
1246
1328
  _toggle(entry) {
1247
1329
  const isOpen = entry.button.getAttribute("aria-expanded") === "true";
1248
1330
  if (isOpen) {
1331
+ if (this.alwaysOpen) return;
1249
1332
  this._close(entry);
1250
1333
  return;
1251
1334
  }
@@ -1255,16 +1338,20 @@ var FokusStyles = (() => {
1255
1338
  this._open(entry);
1256
1339
  }
1257
1340
  _open(entry) {
1341
+ entry.button.dispatchEvent(new CustomEvent("fs:show", { bubbles: true }));
1258
1342
  entry.button.setAttribute("aria-expanded", "true");
1259
1343
  entry.panel.hidden = false;
1260
1344
  expand(entry.panel).then(() => {
1345
+ entry.button.dispatchEvent(new CustomEvent("fs:shown", { bubbles: true }));
1261
1346
  entry.button.dispatchEvent(new CustomEvent("fs:accordion:shown", { bubbles: true }));
1262
1347
  });
1263
1348
  }
1264
1349
  _close(entry) {
1350
+ entry.button.dispatchEvent(new CustomEvent("fs:hide", { bubbles: true }));
1265
1351
  entry.button.setAttribute("aria-expanded", "false");
1266
1352
  collapse(entry.panel).then(() => {
1267
1353
  entry.panel.hidden = true;
1354
+ entry.button.dispatchEvent(new CustomEvent("fs:hidden", { bubbles: true }));
1268
1355
  entry.button.dispatchEvent(new CustomEvent("fs:accordion:hidden", { bubbles: true }));
1269
1356
  });
1270
1357
  }
@@ -1436,8 +1523,10 @@ var FokusStyles = (() => {
1436
1523
  }
1437
1524
  show() {
1438
1525
  if (this.isOpen) return;
1526
+ this.toastEl.dispatchEvent(new CustomEvent("fs:show", { bubbles: true }));
1439
1527
  this.isOpen = true;
1440
1528
  expand(this.toastEl).then(() => {
1529
+ this.toastEl.dispatchEvent(new CustomEvent("fs:shown", { bubbles: true }));
1441
1530
  this.toastEl.dispatchEvent(new CustomEvent("fs:toast:shown", { bubbles: true }));
1442
1531
  });
1443
1532
  if (this.autohide) {
@@ -1446,10 +1535,12 @@ var FokusStyles = (() => {
1446
1535
  }
1447
1536
  hide() {
1448
1537
  if (!this.isOpen) return;
1538
+ this.toastEl.dispatchEvent(new CustomEvent("fs:hide", { bubbles: true }));
1449
1539
  this.isOpen = false;
1450
1540
  clearTimeout(this._hideTimer);
1451
1541
  this._hideTimer = null;
1452
1542
  collapse(this.toastEl).then(() => {
1543
+ this.toastEl.dispatchEvent(new CustomEvent("fs:hidden", { bubbles: true }));
1453
1544
  this.toastEl.dispatchEvent(new CustomEvent("fs:toast:hidden", { bubbles: true }));
1454
1545
  });
1455
1546
  }
@@ -3823,6 +3914,250 @@ var FokusStyles = (() => {
3823
3914
  }
3824
3915
  };
3825
3916
  autoInit("file-upload-advanced", FileUploadAdvanced);
3917
+
3918
+ // packages/fokus-js/js/theme.js
3919
+ var instances25 = createInstanceRegistry();
3920
+ var Theme = class _Theme {
3921
+ constructor(root = document.documentElement) {
3922
+ this.root = root;
3923
+ instances25.set(root, this);
3924
+ }
3925
+ static getInstance(root = document.documentElement) {
3926
+ return instances25.get(root);
3927
+ }
3928
+ static getOrCreateInstance(root = document.documentElement) {
3929
+ var _a;
3930
+ return (_a = this.getInstance(root)) != null ? _a : new _Theme(root);
3931
+ }
3932
+ static set(mode, root = document.documentElement) {
3933
+ return this.getOrCreateInstance(root).set(mode);
3934
+ }
3935
+ get() {
3936
+ var _a, _b;
3937
+ return (_b = (_a = this.root.getAttribute("data-fs-theme")) != null ? _a : this.root.getAttribute("data-theme")) != null ? _b : "light";
3938
+ }
3939
+ set(mode) {
3940
+ if (!["light", "dark", "auto"].includes(mode)) throw new TypeError("FokusStyles.Theme: modo inv\xE1lido.");
3941
+ this.root.setAttribute("data-fs-theme", mode);
3942
+ this.root.setAttribute("data-theme", mode === "dark" ? "dark" : "light");
3943
+ this.root.dispatchEvent(new CustomEvent("fs:theme:change", { bubbles: true, detail: { mode } }));
3944
+ return this;
3945
+ }
3946
+ dispose() {
3947
+ instances25.delete(this.root);
3948
+ }
3949
+ };
3950
+
3951
+ // packages/fokus-js/js/navbar.js
3952
+ var instances26 = createInstanceRegistry();
3953
+ var Navbar = class _Navbar {
3954
+ constructor(navbarEl) {
3955
+ var _a;
3956
+ this.navbarEl = navbarEl;
3957
+ this.toggleEl = navbarEl.querySelector('[data-fs-toggle="navbar"]');
3958
+ const target = (_a = this.toggleEl) == null ? void 0 : _a.getAttribute("data-fs-target");
3959
+ this.menuEl = target ? document.querySelector(target) : navbarEl.querySelector(".fs-navbar-collapse");
3960
+ if (!this.toggleEl || !this.menuEl) return;
3961
+ this._toggle = () => this.toggle();
3962
+ this._escape = (event) => {
3963
+ if (event.key === "Escape" && this.isOpen()) this.hide();
3964
+ };
3965
+ this.toggleEl.addEventListener("click", this._toggle);
3966
+ this.menuEl.addEventListener("keydown", this._escape);
3967
+ instances26.set(navbarEl, this);
3968
+ }
3969
+ static getInstance(el) {
3970
+ return instances26.get(el);
3971
+ }
3972
+ static getOrCreateInstance(el) {
3973
+ var _a;
3974
+ return (_a = this.getInstance(el)) != null ? _a : new _Navbar(el);
3975
+ }
3976
+ isOpen() {
3977
+ var _a;
3978
+ return (_a = this.menuEl) == null ? void 0 : _a.classList.contains("is-open");
3979
+ }
3980
+ show() {
3981
+ this.menuEl.classList.add("is-open");
3982
+ this.menuEl.hidden = false;
3983
+ this.toggleEl.setAttribute("aria-expanded", "true");
3984
+ this.navbarEl.dispatchEvent(new CustomEvent("fs:shown", { bubbles: true }));
3985
+ }
3986
+ hide() {
3987
+ this.menuEl.classList.remove("is-open");
3988
+ this.menuEl.hidden = true;
3989
+ this.toggleEl.setAttribute("aria-expanded", "false");
3990
+ this.toggleEl.focus();
3991
+ this.navbarEl.dispatchEvent(new CustomEvent("fs:hidden", { bubbles: true }));
3992
+ }
3993
+ toggle() {
3994
+ this.isOpen() ? this.hide() : this.show();
3995
+ }
3996
+ dispose() {
3997
+ var _a, _b;
3998
+ (_a = this.toggleEl) == null ? void 0 : _a.removeEventListener("click", this._toggle);
3999
+ (_b = this.menuEl) == null ? void 0 : _b.removeEventListener("keydown", this._escape);
4000
+ instances26.delete(this.navbarEl);
4001
+ }
4002
+ };
4003
+ autoInit("navbar", Navbar);
4004
+
4005
+ // packages/fokus-js/js/scrollspy.js
4006
+ var instances27 = createInstanceRegistry();
4007
+ var Scrollspy = class _Scrollspy {
4008
+ constructor(navEl) {
4009
+ this.navEl = navEl;
4010
+ this.links = [...navEl.querySelectorAll('a[href^="#"]')];
4011
+ this.sections = this.links.map((link) => document.querySelector(link.getAttribute("href"))).filter(Boolean);
4012
+ this.observer = typeof IntersectionObserver === "undefined" ? null : new IntersectionObserver((entries) => entries.forEach((entry) => entry.isIntersecting && this.activate(entry.target)), { rootMargin: "-20% 0px -65%" });
4013
+ this.sections.forEach((section) => {
4014
+ var _a;
4015
+ return (_a = this.observer) == null ? void 0 : _a.observe(section);
4016
+ });
4017
+ this._onScroll = () => {
4018
+ if (this.observer) return;
4019
+ const current = this.sections.filter((section) => section.getBoundingClientRect().top <= window.innerHeight * 0.35).at(-1);
4020
+ if (current) this.activate(current);
4021
+ };
4022
+ if (!this.observer) window.addEventListener("scroll", this._onScroll, { passive: true });
4023
+ instances27.set(navEl, this);
4024
+ }
4025
+ static getInstance(el) {
4026
+ return instances27.get(el);
4027
+ }
4028
+ static getOrCreateInstance(el) {
4029
+ var _a;
4030
+ return (_a = this.getInstance(el)) != null ? _a : new _Scrollspy(el);
4031
+ }
4032
+ activate(section) {
4033
+ this.links.forEach((link) => link.classList.toggle("is-active", link.getAttribute("href") === `#${section.id}`));
4034
+ this.navEl.dispatchEvent(new CustomEvent("fs:scrollspy:activate", { bubbles: true, detail: { section } }));
4035
+ }
4036
+ dispose() {
4037
+ var _a;
4038
+ (_a = this.observer) == null ? void 0 : _a.disconnect();
4039
+ window.removeEventListener("scroll", this._onScroll);
4040
+ instances27.delete(this.navEl);
4041
+ }
4042
+ };
4043
+ autoInit("scrollspy", Scrollspy);
4044
+
4045
+ // packages/fokus-js/js/form-validation.js
4046
+ var instances28 = createInstanceRegistry();
4047
+ var FormValidation = class _FormValidation {
4048
+ constructor(form) {
4049
+ this.form = form;
4050
+ this._submit = (event) => this.validate(event);
4051
+ form.addEventListener("submit", this._submit);
4052
+ instances28.set(form, this);
4053
+ }
4054
+ static getInstance(el) {
4055
+ return instances28.get(el);
4056
+ }
4057
+ static getOrCreateInstance(el) {
4058
+ var _a;
4059
+ return (_a = this.getInstance(el)) != null ? _a : new _FormValidation(el);
4060
+ }
4061
+ validate(event) {
4062
+ const valid = this.form.checkValidity();
4063
+ this.form.classList.add("fs-was-validated");
4064
+ this.form.querySelectorAll('[required], [aria-required="true"]').forEach((field) => field.setAttribute("aria-invalid", String(!field.checkValidity())));
4065
+ if (!valid) {
4066
+ event.preventDefault();
4067
+ event.stopPropagation();
4068
+ }
4069
+ this.form.dispatchEvent(new CustomEvent("fs:form:validated", { bubbles: true, detail: { valid } }));
4070
+ return valid;
4071
+ }
4072
+ dispose() {
4073
+ this.form.removeEventListener("submit", this._submit);
4074
+ instances28.delete(this.form);
4075
+ }
4076
+ };
4077
+ autoInit("form-validation", FormValidation);
4078
+
4079
+ // packages/fokus-js/js/spinner.js
4080
+ var instances29 = createInstanceRegistry();
4081
+ var Spinner = class _Spinner {
4082
+ constructor(element) {
4083
+ this.element = element;
4084
+ this._setLoading(element.hasAttribute("data-fs-loading") && element.getAttribute("data-fs-loading") !== "false");
4085
+ instances29.set(element, this);
4086
+ }
4087
+ static getInstance(el) {
4088
+ return instances29.get(el);
4089
+ }
4090
+ static getOrCreateInstance(el) {
4091
+ var _a;
4092
+ return (_a = this.getInstance(el)) != null ? _a : new _Spinner(el);
4093
+ }
4094
+ _setLoading(value) {
4095
+ this.loading = value;
4096
+ this.element.toggleAttribute("aria-busy", value);
4097
+ this.element.toggleAttribute("data-fs-loading", value);
4098
+ }
4099
+ start() {
4100
+ this._setLoading(true);
4101
+ this.element.dispatchEvent(new CustomEvent("fs:loading:start", { bubbles: true }));
4102
+ }
4103
+ stop() {
4104
+ this._setLoading(false);
4105
+ this.element.dispatchEvent(new CustomEvent("fs:loading:stop", { bubbles: true }));
4106
+ }
4107
+ toggle() {
4108
+ this.loading ? this.stop() : this.start();
4109
+ }
4110
+ dispose() {
4111
+ instances29.delete(this.element);
4112
+ }
4113
+ };
4114
+ autoInit("spinner", Spinner);
4115
+
4116
+ // packages/fokus-js/js/pagination.js
4117
+ var instances30 = createInstanceRegistry();
4118
+ var Pagination = class _Pagination {
4119
+ constructor(element) {
4120
+ this.element = element;
4121
+ this.current = Number(element.getAttribute("data-fs-page")) || 1;
4122
+ this.total = Number(element.getAttribute("data-fs-pages")) || element.querySelectorAll("[data-fs-page]").length || 1;
4123
+ this._click = (event) => {
4124
+ const button = event.target.closest("[data-fs-page]");
4125
+ if (!button || !this.element.contains(button)) return;
4126
+ event.preventDefault();
4127
+ this.goTo(Number(button.getAttribute("data-fs-page")));
4128
+ };
4129
+ element.addEventListener("click", this._click);
4130
+ instances30.set(element, this);
4131
+ this._render();
4132
+ }
4133
+ static getInstance(el) {
4134
+ return instances30.get(el);
4135
+ }
4136
+ static getOrCreateInstance(el) {
4137
+ var _a;
4138
+ return (_a = this.getInstance(el)) != null ? _a : new _Pagination(el);
4139
+ }
4140
+ goTo(page) {
4141
+ const next = Math.max(1, Math.min(this.total, page));
4142
+ if (next === this.current) return;
4143
+ this.current = next;
4144
+ this.element.setAttribute("data-fs-page", String(next));
4145
+ this._render();
4146
+ this.element.dispatchEvent(new CustomEvent("fs:pagination:change", { bubbles: true, detail: { page: next, total: this.total } }));
4147
+ }
4148
+ _render() {
4149
+ this.element.querySelectorAll("[data-fs-page]").forEach((item) => {
4150
+ const active = Number(item.getAttribute("data-fs-page")) === this.current;
4151
+ item.classList.toggle("is-active", active);
4152
+ item.setAttribute("aria-current", active ? "page" : "false");
4153
+ });
4154
+ }
4155
+ dispose() {
4156
+ this.element.removeEventListener("click", this._click);
4157
+ instances30.delete(this.element);
4158
+ }
4159
+ };
4160
+ autoInit("pagination", Pagination);
3826
4161
  return __toCommonJS(fokus_exports);
3827
4162
  })();
3828
4163
  //# sourceMappingURL=fokus.js.map