@graupl/core 1.0.0-beta.20 → 1.0.0-beta.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@graupl/core",
3
- "version": "1.0.0-beta.20",
3
+ "version": "1.0.0-beta.22",
4
4
  "description": "The core module of Graupl, providing essential styles and utilities.",
5
5
  "main": "dist/js/graupl.cjs.js",
6
6
  "module": "dist/js/graupl.es.js",
@@ -120,6 +120,15 @@ class Disclosure {
120
120
  */
121
121
  _open = new TransactionalValue(false);
122
122
 
123
+ /**
124
+ * A value to force the disclosure open when the breakpoint width is passed.
125
+ *
126
+ * @protected
127
+ *
128
+ * @type {boolean}
129
+ */
130
+ _shouldOpen = false;
131
+
123
132
  /**
124
133
  * Whether or not to close the disclosure when it loses focus in the DOM.
125
134
  *
@@ -190,6 +199,15 @@ class Disclosure {
190
199
  */
191
200
  _prefix = "graupl-";
192
201
 
202
+ /**
203
+ * The key used to generate IDs throughout the disclosure.
204
+ *
205
+ * @protected
206
+ *
207
+ * @type {string}
208
+ */
209
+ _key = "";
210
+
193
211
  /**
194
212
  * An array of error messages generated by the disclosure.
195
213
  *
@@ -213,7 +231,8 @@ class Disclosure {
213
231
  * @param {boolean} [options.openDuration = -1] - The duration of the transition from "closed" to "open" states (in milliseconds).
214
232
  * @param {boolean} [options.closeDuration = -1] - The duration of the transition from "open" to "closed" states (in milliseconds).
215
233
  * @param {boolean} [options.closeOnBlur = false] - Whether to close the disclosure when it loses focus in the dom.
216
- * @param {boolean} [options.minWidth = -1] - The width of the screen (in pixels) that the disclosure will automatically open/close itself.
234
+ * @param {boolean} [options.minWidth = -1] - The width of the screen (in pixels) that the disclosure will automatically open/close itself.
235
+ * @param {boolean} [options.autoOpen = false] - Whether to automatically open when above the minWidth.
217
236
  * @param {?string} [options.prefix = graupl-] - The prefix to use for CSS custom properties.
218
237
  * @param {?(string|string[])} [options.initializeClass = initializing] - The class to apply when a disclosure is initialzing.
219
238
  * @param {boolean} [options.initialize = false] - Whether to initialize the disclosure upon construction.
@@ -230,6 +249,7 @@ class Disclosure {
230
249
  closeDuration = -1,
231
250
  closeOnBlur = false,
232
251
  minWidth = -1,
252
+ autoOpen = false,
233
253
  prefix = "graupl-",
234
254
  initializeClass = "initializing",
235
255
  initialize = false,
@@ -255,8 +275,9 @@ class Disclosure {
255
275
  // Set close on blur.
256
276
  this._closeOnBlur = closeOnBlur;
257
277
 
258
- // Set collapse width.
278
+ // Set collapse width and auto open functionality.
259
279
  this._breakpointWidth = minWidth;
280
+ this._shouldOpen = autoOpen;
260
281
 
261
282
  // Set the prefix.
262
283
  this._prefix = prefix;
@@ -301,10 +322,13 @@ class Disclosure {
301
322
  storage.initializeStorage("disclosures");
302
323
  storage.pushToStorage("disclosures", this.dom.disclosure.id, this);
303
324
 
304
- if (this.dom.controller.getAttribute("aria-expanded") === "true") {
305
- this._expand(false, false);
325
+ if (
326
+ this.dom.controller.getAttribute("aria-expanded") === "true" ||
327
+ (this.shouldOpen && window.matchMedia(this.openQuery).matches)
328
+ ) {
329
+ this._expand({ emit: false, transition: false });
306
330
  } else {
307
- this._collapse(false, false);
331
+ this._collapse({ emit: false, transition: false });
308
332
  }
309
333
 
310
334
  requestAnimationFrame(() => {
@@ -613,6 +637,59 @@ class Disclosure {
613
637
  return this._open.committed;
614
638
  }
615
639
 
640
+ /**
641
+ * A value to force opening reguardless of user interaction.
642
+ *
643
+ * @type {boolean}
644
+ *
645
+ * @see _shouldOpen
646
+ */
647
+ get shouldOpen() {
648
+ return this._shouldOpen;
649
+ }
650
+
651
+ set shouldOpen(value) {
652
+ isValidType("boolean", { value });
653
+
654
+ if (this._shouldOpen !== value) {
655
+ this._shouldOpen = value;
656
+ }
657
+ }
658
+
659
+ /**
660
+ * A media query for when the disclosure should open.
661
+ *
662
+ * Will return an empty string if no min width is set.
663
+ *
664
+ * @readonly
665
+ *
666
+ * @type {string}
667
+ */
668
+ get openQuery() {
669
+ if (this.minWidth === -1) {
670
+ return "";
671
+ }
672
+
673
+ return `(width > ${this.minWidth}px)`;
674
+ }
675
+
676
+ /**
677
+ * A media query for when the disclosure should close.
678
+ *
679
+ * Will return an empty string if no min width is set.
680
+ *
681
+ * @readonly
682
+ *
683
+ * @type {string}
684
+ */
685
+ get closeQuery() {
686
+ if (this.minWidth === -1) {
687
+ return "";
688
+ }
689
+
690
+ return `(width <= ${this.minWidth}px)`;
691
+ }
692
+
616
693
  /**
617
694
  * A flag to check if the disclosure's focus methods should _actually_ move the focus in the DOM.
618
695
  *
@@ -633,6 +710,17 @@ class Disclosure {
633
710
  return check;
634
711
  }
635
712
 
713
+ /**
714
+ * The key used to generate IDs throughout the disclosure.
715
+ *
716
+ * @type {string}
717
+ *
718
+ * @see _key
719
+ */
720
+ get key() {
721
+ return this._key;
722
+ }
723
+
636
724
  /**
637
725
  * An array of error messages generated by the disclosure.
638
726
  *
@@ -668,12 +756,17 @@ class Disclosure {
668
756
  }
669
757
 
670
758
  // Query selector checks.
671
- const querySelectorChecks = isQuerySelector({
672
- disclosureContentSelector: this._selectors.content,
673
- });
759
+ const querySelectors = {};
674
760
 
675
- if (!querySelectorChecks.status) {
676
- this._errors.push(querySelectorChecks.error.message);
761
+ for (const querySelector of Object.keys(this._selectors)) {
762
+ querySelectors[`${querySelector}Selector`] =
763
+ this._selectors[querySelector];
764
+ }
765
+
766
+ const querySelectorChecks = isQuerySelector(querySelectors);
767
+
768
+ if (!querySelectorChecks) {
769
+ this._errors.push(querySelectorChecks.message);
677
770
  check = false;
678
771
  }
679
772
 
@@ -721,13 +814,14 @@ class Disclosure {
721
814
  }
722
815
 
723
816
  /**
724
- * Generates a key for the disclosure.
817
+ * Generates a key for the tabs.
725
818
  *
726
- * @param {boolean} [regenerate = false] - A flag to determine if the key should be regenerated.
819
+ * @param {Object<boolean>} [options = {}] - Options for generating the key.
820
+ * @param {boolean} [options.regenerate = false] - A flag to determine if the key should be regenerated.
727
821
  */
728
- _generateKey(regenerate = false) {
822
+ _generateKey({ regenerate = false } = {}) {
729
823
  if (this.key === "" || regenerate) {
730
- this.key = Math.random()
824
+ this._key = Math.random()
731
825
  .toString(36)
732
826
  .replace(/[^a-z]+/g, "")
733
827
  .substring(0, 10);
@@ -916,38 +1010,28 @@ class Disclosure {
916
1010
  *
917
1011
  * @fires grauplDisclosureExpand
918
1012
  *
919
- * @param {boolean} [emit = true] - Emit the expand event once expanded.
920
- * @param {boolean} [transition = true] - Respect the transition class.
1013
+ * @param {Object<boolean>} [options = {}] - Options for expanding the disclosure.
1014
+ * @param {boolean} [options.emit = true] - Emit the expand event once expanded.
1015
+ * @param {boolean} [options.transition = true] - Respect the transition class.
921
1016
  */
922
- _expand(emit = true, transition = true) {
1017
+ _expand({ emit = true, transition = true } = {}) {
923
1018
  this.dom.controller.setAttribute("aria-expanded", "true");
924
1019
 
925
1020
  // If we're dealing with transition classes, then we need to utilize
926
1021
  // requestAnimationFrame to add the transition class, remove the close class,
927
1022
  // add the open class, and finally remove the transition class.
928
1023
  if (transition && this.transitionlass !== "") {
929
- // this.dom.disclosure.style.height = `${this.dom.disclosure.getBoundingClientRect().height}px`;
930
- // console.log(this.dom.disclosure.style.height);
931
1024
  addClass(this.transitionClass, this.dom.disclosure);
932
1025
 
933
1026
  requestAnimationFrame(() => {
934
1027
  removeClass(this.closeClass, this.dom.disclosure);
935
1028
 
936
- // this.dom.disclosure.style.height = `${this.dom.disclosure.getBoundingClientRect().height}px`;
937
- // console.log(this.dom.disclosure.style.height);
938
-
939
1029
  requestAnimationFrame(() => {
940
1030
  addClass(this.openClass, this.dom.disclosure);
941
1031
 
942
- // this.dom.disclosure.style.height = `${this.dom.content.getBoundingClientRect().height}px`;
943
- // console.log(this.dom.disclosure.style.height);
944
-
945
1032
  requestAnimationFrame(() => {
946
1033
  setTimeout(() => {
947
1034
  removeClass(this.transitionClass, this.dom.disclosure);
948
-
949
- // this.dom.disclosure.style.height = "";
950
- // console.log(this.dom.disclosure.style.height);
951
1035
  }, this.openDuration);
952
1036
  });
953
1037
  });
@@ -977,41 +1061,30 @@ class Disclosure {
977
1061
  *
978
1062
  * @fires grauplDisclosureCollapse
979
1063
  *
980
- * @param {boolean} [emit = true] - Emit the collapse event once collapsed.
981
- * @param {boolean} [transition = true] - Respect the transition class.
1064
+ * @param {Object<boolean>} [options = {}] - Options for collapsing the disclosure.
1065
+ * @param {boolean} [options.emit = true] - Emit the collapse event once collapsed.
1066
+ * @param {boolean} [options.transition = true] - Respect the transition class.
982
1067
  */
983
- _collapse(emit = true, transition = true) {
1068
+ _collapse({ emit = true, transition = true } = {}) {
984
1069
  this.dom.controller.setAttribute("aria-expanded", "false");
985
1070
 
986
1071
  // If we're dealing with transition classes, then we need to utilize
987
1072
  // requestAnimationFrame to add the transition class, remove the open class,
988
1073
  // add the close class, and finally remove the transition class.
989
1074
  if (transition && this.transitionClass !== "") {
990
- // this.dom.disclosure.style.height = `${this.dom.content.getBoundingClientRect().height}px`;
991
- // console.log(this.dom.disclosure.style.height);
992
-
993
1075
  addClass(this.transitionClass, this.dom.disclosure);
994
1076
 
995
1077
  requestAnimationFrame(() => {
996
1078
  removeClass(this.openClass, this.dom.disclosure);
997
1079
 
998
- // this.dom.disclosure.style.height = `${this.dom.content.getBoundingClientRect().height}px`;
999
- // console.log(this.dom.disclosure.style.height);
1000
-
1001
1080
  requestAnimationFrame(() => {
1002
1081
  addClass(this.closeClass, this.dom.disclosure);
1003
1082
 
1004
- // this.dom.disclosure.style.height = `${this.dom.disclosure.getBoundingClientRect().height}px`;
1005
- // console.log(this.dom.disclosure.style.height);
1006
-
1007
1083
  requestAnimationFrame(() => {
1008
1084
  setTimeout(() => {
1009
1085
  removeClass(this.transitionClass, this.dom.disclosure);
1010
1086
 
1011
1087
  this.dom.content.innert = true;
1012
-
1013
- // this.dom.disclosure.style.height = "";
1014
- // console.log(this.dom.disclosure.style.height);
1015
1088
  }, this.closeDuration);
1016
1089
  });
1017
1090
  });
@@ -1036,6 +1109,8 @@ class Disclosure {
1036
1109
  return;
1037
1110
  }
1038
1111
 
1112
+ let width = 0;
1113
+
1039
1114
  this._observer = new ResizeObserver((entries) => {
1040
1115
  requestAnimationFrame(() => {
1041
1116
  for (const entry of entries) {
@@ -1049,14 +1124,22 @@ class Disclosure {
1049
1124
 
1050
1125
  if (typeof inlineSize !== "number") continue;
1051
1126
 
1127
+ if (width === inlineSize) continue;
1128
+
1052
1129
  const belowBreakpoint = inlineSize <= this.minWidth;
1053
1130
  const aboveBreakpoint = inlineSize > this.minWidth;
1054
1131
 
1055
1132
  if (belowBreakpoint && this.isOpen) {
1056
1133
  this.close({ preserveState: true });
1057
- } else if (aboveBreakpoint && !this.isOpen && this.hasOpened) {
1134
+ } else if (
1135
+ aboveBreakpoint &&
1136
+ !this.isOpen &&
1137
+ (this.hasOpened || this.shouldOpen)
1138
+ ) {
1058
1139
  this.open();
1059
1140
  }
1141
+
1142
+ width = inlineSize;
1060
1143
  }
1061
1144
  });
1062
1145
  });