@carbon/ibmdotcom-services 2.10.0 → 2.11.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.
@@ -7,27 +7,19 @@ function _typeof(o) {
7
7
  return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;
8
8
  }, _typeof(o);
9
9
  }
10
- function _classCallCheck(instance, Constructor) {
11
- if (!(instance instanceof Constructor)) {
12
- throw new TypeError("Cannot call a class as a function");
13
- }
10
+ function _classCallCheck(a, n) {
11
+ if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function");
14
12
  }
15
- function _defineProperties(target, props) {
16
- for (var i = 0; i < props.length; i++) {
17
- var descriptor = props[i];
18
- descriptor.enumerable = descriptor.enumerable || false;
19
- descriptor.configurable = true;
20
- if ("value" in descriptor) descriptor.writable = true;
21
- Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor);
13
+ function _defineProperties(e, r) {
14
+ for (var t = 0; t < r.length; t++) {
15
+ var o = r[t];
16
+ o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, _toPropertyKey(o.key), o);
22
17
  }
23
18
  }
24
- function _createClass(Constructor, protoProps, staticProps) {
25
- if (protoProps) _defineProperties(Constructor.prototype, protoProps);
26
- if (staticProps) _defineProperties(Constructor, staticProps);
27
- Object.defineProperty(Constructor, "prototype", {
28
- writable: false
29
- });
30
- return Constructor;
19
+ function _createClass(e, r, t) {
20
+ return r && _defineProperties(e.prototype, r), t && _defineProperties(e, t), Object.defineProperty(e, "prototype", {
21
+ writable: !1
22
+ }), e;
31
23
  }
32
24
  function _toPropertyKey(t) {
33
25
  var i = _toPrimitive(t, "string");
@@ -55,25 +47,39 @@ import root from 'window-or-global';
55
47
  import settings from '../settings/settings.js';
56
48
  var prefix = settings.prefix,
57
49
  c4dPrefix = settings.stablePrefix;
50
+ var ddsPrefix = 'dds';
51
+ var bxPrefix = 'bx';
58
52
  var gridBreakpoint = parseFloat(breakpoints.lg.width) * baseFontSize;
59
53
  var StickyHeader = /*#__PURE__*/function () {
60
54
  function StickyHeader() {
61
55
  _classCallCheck(this, StickyHeader);
62
56
  this.ownerDocument = root.document;
63
- this._banner = undefined;
64
- this._cumulativeHeight = 0;
65
- this._hasBanner = false;
66
- this._lastScrollPosition = 0;
67
- this._leadspaceWithSearch = undefined;
68
- this._leadspaceSearchBar = undefined;
69
- this._leadspaceWithSearchStickyThreshold = 0;
70
- this._localeModal = undefined;
71
- this._masthead = undefined;
72
- this._mastheadL0 = undefined;
73
- this._mastheadL1 = undefined;
74
- this._tableOfContents = undefined;
75
- this._tableOfContentsInnerBar = undefined;
76
- this._tableOfContentsLayout = undefined;
57
+ this._state = {
58
+ cumulativeOffset: 0,
59
+ hasBanner: false,
60
+ leadspaceSearchThreshold: 0,
61
+ mastheadL0IsActive: false,
62
+ mastheadL1IsActive: false,
63
+ maxScrollaway: 0,
64
+ scrollPosPrevious: 0,
65
+ scrollPos: 0,
66
+ searchIsAtTop: false,
67
+ tocShouldStick: false,
68
+ tocIsAtTop: false,
69
+ tocIsAtSearch: false
70
+ };
71
+ this._elements = {
72
+ banner: undefined,
73
+ leadspaceSearch: undefined,
74
+ leadspaceSearchBar: undefined,
75
+ leadspaceSearchInput: undefined,
76
+ localeModal: undefined,
77
+ masthead: undefined,
78
+ mastheadL0: undefined,
79
+ mastheadL1: undefined,
80
+ tableOfContents: undefined,
81
+ tableOfContentsInnerBar: undefined
82
+ };
77
83
  this._throttled = false;
78
84
  this._resizeObserver = new ResizeObserver(this._handleResize.bind(this));
79
85
  root.addEventListener('scroll', this._throttledHandler.bind(this));
@@ -85,7 +91,7 @@ var StickyHeader = /*#__PURE__*/function () {
85
91
  return _createClass(StickyHeader, [{
86
92
  key: "height",
87
93
  get: function get() {
88
- return this._cumulativeHeight;
94
+ return this._state.cumulativeOffset;
89
95
  }
90
96
 
91
97
  /**
@@ -101,78 +107,176 @@ var StickyHeader = /*#__PURE__*/function () {
101
107
  value: function _validateComponent(component, expected) {
102
108
  var received = component.tagName.toLowerCase();
103
109
  if (received !== expected) {
104
- throw new TypeError("".concat(expected, " expected, ").concat(received, " provided"));
110
+ // TODO: don't check for v1/v2 compatibility after v1 EOL.
111
+ if (received.split('-').splice(1).join('-') !== expected.split('-').splice(1).join('-')) {
112
+ throw new TypeError("".concat(expected, " expected, ").concat(received, " provided"));
113
+ } else {
114
+ var message = ["Mixed prefixes detected.\n", "expected ".concat(expected, ", found ").concat(received, ".")];
115
+ console.warn(message.join(''));
116
+ return true;
117
+ }
105
118
  } else {
106
119
  return true;
107
120
  }
108
121
  }
122
+
123
+ /**
124
+ * Helper method to query for either C4IBM v1.x or v2.x sub-elements;
125
+ *
126
+ * @param {*} element The C4IBM element.
127
+ * @param {*} v1Func The querying function to run if using a C4IBM v1.x element.
128
+ * @param {*} v2Func The querying function to run if using a C4IBM v2.x element.
129
+ */
130
+ }, {
131
+ key: "_updateRefsV1orV2",
132
+ value: function _updateRefsV1orV2(element, v1Func, v2Func) {
133
+ var elementPrefix = element.tagName.toLowerCase().split('-')[0];
134
+ if (elementPrefix === ddsPrefix) {
135
+ v1Func.bind(this)();
136
+ } else if (elementPrefix === c4dPrefix) {
137
+ v2Func.bind(this)();
138
+ } else {
139
+ throw new Error("\n Could not find sub-elements for ".concat(element.tagName.toLowerCase(), ".\n "));
140
+ }
141
+ }
142
+
143
+ /**
144
+ * Temporary method to find v1 leadspace sub-elements.
145
+ */
146
+ }, {
147
+ key: "_updateLeadspaceRefsV1",
148
+ value: function _updateLeadspaceRefsV1() {
149
+ var leadspaceSearch = this._elements.leadspaceSearch;
150
+ this._elements.leadspaceSearchBar = leadspaceSearch.shadowRoot.querySelector(".".concat(bxPrefix, "--search-container"));
151
+ this._elements.leadspaceSearchInput = leadspaceSearch.querySelector("".concat(ddsPrefix, "-search-with-typeahead"));
152
+ }
153
+
154
+ /**
155
+ * Temporary method to find v2 leadspace sub-elements.
156
+ */
157
+ }, {
158
+ key: "_updateLeadspaceRefsV2",
159
+ value: function _updateLeadspaceRefsV2() {
160
+ var leadspaceSearch = this._elements.leadspaceSearch;
161
+ this._elements.leadspaceSearchBar = leadspaceSearch.shadowRoot.querySelector(".".concat(prefix, "--search-container"));
162
+ this._elements.leadspaceSearchInput = leadspaceSearch.querySelector("".concat(c4dPrefix, "-search-with-typeahead"));
163
+ }
164
+
165
+ /**
166
+ * Temporary method to find v1 masthead sub-elements.
167
+ */
168
+ }, {
169
+ key: "_updateMastheadRefsV1",
170
+ value: function _updateMastheadRefsV1() {
171
+ var masthead = this._elements.masthead;
172
+ this._elements.mastheadL0 = masthead.shadowRoot.querySelector(".".concat(bxPrefix, "--masthead__l0"));
173
+ this._elements.mastheadL1 = masthead.querySelector("".concat(ddsPrefix, "-masthead-l1"));
174
+ }
175
+
176
+ /**
177
+ * Temporary method to find v2 masthead sub-elements.
178
+ */
109
179
  }, {
110
- key: "_tableOfContentsStickyUpdate",
111
- value: function _tableOfContentsStickyUpdate() {
112
- var toc = this._tableOfContents;
180
+ key: "_updateMastheadRefsV2",
181
+ value: function _updateMastheadRefsV2() {
182
+ var masthead = this._elements.masthead;
183
+ this._elements.mastheadL0 = masthead.shadowRoot.querySelector(".".concat(prefix, "--masthead__l0"));
184
+ this._elements.mastheadL1 = masthead.querySelector("".concat(c4dPrefix, "-masthead-l1"));
185
+ }
186
+
187
+ /**
188
+ * Temporary method to find v1 table of contents sub-elements.
189
+ */
190
+ }, {
191
+ key: "_updateTableOfContentsRefsV1",
192
+ value: function _updateTableOfContentsRefsV1() {
193
+ var toc = this._elements.tableOfContents;
113
194
  var tocRoot = toc.shadowRoot;
114
- this._tableOfContentsInnerBar = tocRoot.querySelector(".".concat(prefix, "--tableofcontents__navbar"));
115
- if (window.innerWidth > gridBreakpoint) {
116
- if (toc.layout === 'horizontal') {
117
- this._tableOfContentsLayout = 'horizontal';
118
- } else {
119
- this._tableOfContentsInnerBar = tocRoot.querySelector(".".concat(c4dPrefix, "-ce--table-of-contents__items-container"));
195
+ var selectors = {
196
+ desktop: {
197
+ vertical: ".".concat(ddsPrefix, "-ce--table-of-contents__items-container"),
198
+ horizontal: ".".concat(bxPrefix, "--tableofcontents__navbar")
199
+ },
200
+ mobile: {
201
+ vertical: ".".concat(bxPrefix, "--tableofcontents__sidebar"),
202
+ horizontal: ".".concat(bxPrefix, "--tableofcontents__navbar")
120
203
  }
121
- }
204
+ };
205
+ var viewportDimension = window.innerWidth >= gridBreakpoint ? 'desktop' : 'mobile';
206
+ this._elements.tableOfContentsInnerBar = tocRoot.querySelector(selectors[viewportDimension][toc.layout || 'vertical']);
207
+ }
208
+
209
+ /**
210
+ * Temporary method to find v2 table of contents sub-elements.
211
+ */
212
+ }, {
213
+ key: "_updateTableOfContentsRefsV2",
214
+ value: function _updateTableOfContentsRefsV2() {
215
+ var toc = this._elements.tableOfContents;
216
+ var tocRoot = toc.shadowRoot;
217
+ this._elements.tableOfContentsInnerBar = tocRoot.querySelector(window.innerWidth >= gridBreakpoint && (toc === null || toc === void 0 ? void 0 : toc.layout) !== 'horizontal' ? ".".concat(c4dPrefix, "-ce--table-of-contents__items-container") : ".".concat(prefix, "--tableofcontents__navbar"));
218
+ }
219
+
220
+ /**
221
+ * Stores references to TOC sub-elements that are relevant to current viewport
222
+ * dimensions.
223
+ */
224
+ }, {
225
+ key: "_updateTableOfContentsRefs",
226
+ value: function _updateTableOfContentsRefs() {
227
+ var toc = this._elements.tableOfContents;
228
+ this._updateRefsV1orV2(toc, this._updateTableOfContentsRefsV1, this._updateTableOfContentsRefsV2);
122
229
  }
123
230
  }, {
124
231
  key: "banner",
125
232
  set: function set(component) {
126
233
  if (this._validateComponent(component, "".concat(c4dPrefix, "-global-banner"))) {
127
- this._banner = component;
128
- this.hasBanner = true;
129
- if (this._masthead) {
130
- this._masthead.setAttribute('with-banner', '');
234
+ this._elements.banner = component;
235
+ this._state.hasBanner = true;
236
+ if (this._elements.masthead) {
237
+ this._elements.masthead.setAttribute('with-banner', '');
131
238
  }
132
- this._calculateCumulativeHeight();
239
+ this._manageStickyElements();
133
240
  }
134
241
  }
135
242
  }, {
136
- key: "leadspaceWithSearch",
243
+ key: "leadspaceSearch",
137
244
  set: function set(component) {
138
245
  if (this._validateComponent(component, "".concat(c4dPrefix, "-leadspace-with-search"))) {
139
- this._leadspaceWithSearch = component;
140
- var leadspaceSearchBar = component.shadowRoot.querySelector(".".concat(prefix, "--search-container"));
141
- this._leadspaceSearchBar = leadspaceSearchBar;
142
- this._leadspaceWithSearchInput = component.querySelector("".concat(c4dPrefix, "-search-with-typeahead"));
143
- this._leadspaceWithSearchStickyThreshold = parseInt(window.getComputedStyle(leadspaceSearchBar).paddingBottom) - 16;
144
- this._calculateCumulativeHeight();
246
+ this._elements.leadspaceSearch = component;
247
+ this._updateRefsV1orV2(component, this._updateLeadspaceRefsV1, this._updateLeadspaceRefsV2);
248
+ this._state.leadspaceSearchThreshold = parseInt(window.getComputedStyle(this._elements.leadspaceSearchBar).paddingBottom) - 16;
249
+ this._manageStickyElements();
145
250
  }
146
251
  }
147
252
  }, {
148
253
  key: "localeModal",
149
254
  set: function set(component) {
150
255
  if (this._validateComponent(component, "".concat(c4dPrefix, "-locale-modal"))) {
151
- this._localeModal = component;
152
- this._calculateCumulativeHeight();
256
+ this._elements.localeModal = component;
257
+ this._manageStickyElements();
153
258
  }
154
259
  }
155
260
  }, {
156
261
  key: "masthead",
157
262
  set: function set(component) {
158
263
  if (this._validateComponent(component, "".concat(c4dPrefix, "-masthead"))) {
159
- this._masthead = component;
160
- if (this._banner) {
161
- this._masthead.setAttribute('with-banner', '');
264
+ this._elements.masthead = component;
265
+ if (this._elements.banner) {
266
+ this._elements.masthead.setAttribute('with-banner', '');
162
267
  }
163
- this._mastheadL0 = component.shadowRoot.querySelector(".".concat(prefix, "--masthead__l0"));
164
- this._mastheadL1 = component.querySelector("".concat(c4dPrefix, "-masthead-l1"));
165
- this._calculateCumulativeHeight();
268
+ this._updateRefsV1orV2(component, this._updateMastheadRefsV1, this._updateMastheadRefsV2);
269
+ this._manageStickyElements();
166
270
  }
167
271
  }
168
272
  }, {
169
273
  key: "tableOfContents",
170
274
  set: function set(component) {
171
275
  if (this._validateComponent(component, "".concat(c4dPrefix, "-table-of-contents"))) {
172
- this._tableOfContents = component;
173
- this._tableOfContentsStickyUpdate();
174
- this._resizeObserver.observe(this._tableOfContents);
175
- this._calculateCumulativeHeight();
276
+ this._elements.tableOfContents = component;
277
+ this._updateTableOfContentsRefs();
278
+ this._resizeObserver.observe(this._elements.tableOfContents);
279
+ this._manageStickyElements();
176
280
  }
177
281
  }
178
282
 
@@ -185,7 +289,7 @@ var StickyHeader = /*#__PURE__*/function () {
185
289
  var _this = this;
186
290
  if (!this._throttled) {
187
291
  this._throttled = true;
188
- this._calculateCumulativeHeight();
292
+ this._manageStickyElements();
189
293
  setTimeout(function () {
190
294
  _this._throttled = false;
191
295
  }, 20);
@@ -194,95 +298,197 @@ var StickyHeader = /*#__PURE__*/function () {
194
298
  }, {
195
299
  key: "_handleResize",
196
300
  value: function _handleResize() {
197
- var hasBanner = this._hasBanner,
198
- masthead = this._masthead,
199
- toc = this._tableOfContents,
200
- tocLayout = this._tableOfContentsLayout,
201
- leadspaceSearchBar = this._leadspaceSearchBar;
301
+ var hasBanner = this._state._hasBanner;
302
+ var _this$_elements = this._elements,
303
+ masthead = _this$_elements.masthead,
304
+ toc = _this$_elements.tableOfContents,
305
+ leadspaceSearchBar = _this$_elements.leadspaceSearchBar;
202
306
  if (toc && masthead) {
203
- this._tableOfContentsStickyUpdate();
204
- if (window.innerWidth >= gridBreakpoint && tocLayout !== 'horizontal' && !hasBanner) {
205
- masthead.style.top = '0';
307
+ this._updateTableOfContentsRefs();
308
+ if (window.innerWidth >= gridBreakpoint && toc.layout !== 'horizontal' && !hasBanner) {
309
+ masthead.style.insetBlockStart = '0';
206
310
  } else {
207
- // This has to happen after the tocStickyUpdate method.
208
- var tocInner = this._tableOfContentsInnerBar;
311
+ // This has to happen after the _updateTableOfContentsRefs method.
312
+ var tocInner = this._elements.tableOfContentsInnerBar;
209
313
  if (masthead.offsetTop === 0) {
210
- tocInner.style.top = "".concat(masthead.offsetHeight, "px");
314
+ tocInner.style.insetBlockStart = "".concat(masthead.offsetHeight, "px");
211
315
  }
212
316
  }
213
- this._calculateCumulativeHeight();
317
+ this._manageStickyElements();
214
318
  }
215
319
  if (leadspaceSearchBar) {
216
- this._leadspaceWithSearchStickyThreshold = parseInt(window.getComputedStyle(leadspaceSearchBar).paddingBottom) - 16;
320
+ this._state.leadspaceSearchThreshold = parseInt(window.getComputedStyle(leadspaceSearchBar).paddingBottom) - 16;
217
321
  }
218
322
  }
323
+
324
+ /**
325
+ * Handles the banner given the current scroll position.
326
+ */
219
327
  }, {
220
- key: "_calculateCumulativeHeight",
221
- value: function _calculateCumulativeHeight() {
222
- var _StickyHeader$global = StickyHeader.global,
223
- oldY = _StickyHeader$global._lastScrollPosition,
224
- banner = _StickyHeader$global._banner,
225
- masthead = _StickyHeader$global._masthead,
226
- mastheadL0 = _StickyHeader$global._mastheadL0,
227
- mastheadL1 = _StickyHeader$global._mastheadL1,
228
- localeModal = _StickyHeader$global._localeModal,
229
- toc = _StickyHeader$global._tableOfContents,
230
- tocInner = _StickyHeader$global._tableOfContentsInnerBar,
231
- leadspaceSearch = _StickyHeader$global._leadspaceWithSearch,
232
- leadspaceSearchBar = _StickyHeader$global._leadspaceSearchBar,
233
- leadspaceSearchInput = _StickyHeader$global._leadspaceWithSearchInput,
234
- leadspaceSearchThreshold = _StickyHeader$global._leadspaceWithSearchStickyThreshold;
235
- var customPropertyName = this.constructor.customPropertyName;
236
- if (localeModal && localeModal.hasAttribute('open')) {
237
- return;
238
- }
239
- var newY = window.scrollY;
240
- this._lastScrollPosition = Math.max(0, newY);
328
+ key: "_handleBanner",
329
+ value: function _handleBanner() {
330
+ var banner = this._elements.banner;
331
+ var scrollPos = this._state.scrollPos;
332
+ this._state.cumulativeOffset += Math.max(banner.offsetHeight - scrollPos, 0);
333
+ }
241
334
 
242
- /**
243
- * maxScrollaway is a calculated value matching the height of all components
244
- * that are allowed to hide above the viewport.
245
- *
246
- * We should only have one sticky header showing as the page scrolls down.
247
- *
248
- * Items that stick, in order
249
- * - L0
250
- * - L1
251
- * - The TOC in horizontal bar form
252
- * - The leadspace with search (if no TOC)
253
- */
254
- var maxScrollaway = 0;
335
+ /**
336
+ * Handles the masthead given the current scroll position.
337
+ */
338
+ }, {
339
+ key: "_handleMasthead",
340
+ value: function _handleMasthead() {
341
+ var masthead = this._elements.masthead;
342
+ masthead.style.transition = 'none';
343
+ masthead.style.insetBlockStart = "".concat(this._state.cumulativeOffset, "px");
255
344
 
256
- // Calculate maxScrollaway values based on TOC positon
257
- var tocIsAtTop = false;
258
- var tocShouldStick = false;
259
- if (tocInner) {
260
- tocIsAtTop = tocInner.getBoundingClientRect().top <= (masthead ? masthead.offsetTop + masthead.offsetHeight : 0) + 1;
261
- tocShouldStick = toc.layout === 'horizontal' || window.innerWidth < gridBreakpoint;
262
- if (masthead && tocIsAtTop && (tocShouldStick || mastheadL1)) {
263
- maxScrollaway += masthead.offsetHeight;
264
- if (mastheadL1 && !tocShouldStick) {
265
- maxScrollaway -= mastheadL1.offsetHeight;
266
- }
267
- } else if (mastheadL0 && mastheadL1) {
268
- maxScrollaway += mastheadL0.offsetHeight;
345
+ // Masthead always sticks, therefore always add its height.
346
+ this._state.cumulativeOffset += masthead.offsetHeight;
347
+ }
348
+
349
+ /**
350
+ * Handles the table of contents given the current scroll position.
351
+ */
352
+ }, {
353
+ key: "_handleToc",
354
+ value: function _handleToc() {
355
+ var tableOfContentsInnerBar = this._elements.tableOfContentsInnerBar;
356
+ var tocShouldStick = this._state.tocShouldStick;
357
+ tableOfContentsInnerBar.style.transition = 'none';
358
+ tableOfContentsInnerBar.style.insetBlockStart = "".concat(this._state.cumulativeOffset, "px");
359
+ var tocIsStuck = Math.round(tableOfContentsInnerBar.getBoundingClientRect().top) <= this._state.cumulativeOffset + 1;
360
+ if (tocShouldStick && tocIsStuck) {
361
+ this._state.cumulativeOffset += tableOfContentsInnerBar.offsetHeight;
362
+ }
363
+ }
364
+
365
+ /**
366
+ * Handles the leadspace search given the current scroll position.
367
+ */
368
+ }, {
369
+ key: "_handleLeadspaceSearch",
370
+ value: function _handleLeadspaceSearch() {
371
+ var _this$_elements2 = this._elements,
372
+ leadspaceSearch = _this$_elements2.leadspaceSearch,
373
+ leadspaceSearchBar = _this$_elements2.leadspaceSearchBar,
374
+ leadspaceSearchInput = _this$_elements2.leadspaceSearchInput;
375
+ var leadspaceSearchThreshold = this._state.leadspaceSearchThreshold;
376
+ var searchShouldBeSticky = leadspaceSearch.getBoundingClientRect().bottom <= leadspaceSearchThreshold;
377
+ var searchIsSticky = leadspaceSearch.hasAttribute('sticky-search');
378
+ if (searchShouldBeSticky) {
379
+ if (!searchIsSticky) {
380
+ leadspaceSearch.style.paddingBottom = "".concat(leadspaceSearchBar.offsetHeight, "px");
381
+ leadspaceSearch.setAttribute('sticky-search', '');
382
+ leadspaceSearchInput.setAttribute('large', '');
383
+ window.requestAnimationFrame(function () {
384
+ leadspaceSearchBar.style.transitionDuration = '110ms';
385
+ leadspaceSearchBar.style.transform = 'translateY(0)';
386
+ });
269
387
  }
388
+ leadspaceSearchBar.style.insetBlockStart = "".concat(this._state.cumulativeOffset, "px");
389
+ this._state.cumulativeOffset += leadspaceSearchBar.offsetHeight;
390
+ } else if (searchIsSticky) {
391
+ leadspaceSearch.style.paddingBottom = '';
392
+ leadspaceSearch.removeAttribute('sticky-search');
393
+ leadspaceSearchInput.removeAttribute('large');
394
+ leadspaceSearchBar.style.transitionDuration = '';
395
+ leadspaceSearchBar.style.transform = '';
396
+ leadspaceSearchBar.style.insetBlockStart = '';
270
397
  }
398
+ }
399
+
400
+ /**
401
+ * Calculates a value matching the height of all components that are allowed
402
+ * to hide above the viewport.
403
+ *
404
+ * Adding an item's height to this value indicates we expect it to be hidden
405
+ * above the viewport.
406
+ *
407
+ * Items that stick, in order
408
+ * - L0
409
+ * - L1
410
+ * - The TOC in horizontal bar form
411
+ * - The leadspace with search (if no TOC)
412
+ */
413
+ }, {
414
+ key: "_calculateMaxScrollaway",
415
+ value: function _calculateMaxScrollaway() {
416
+ var _this$_elements3 = this._elements,
417
+ masthead = _this$_elements3.masthead,
418
+ mastheadL0 = _this$_elements3.mastheadL0,
419
+ mastheadL1 = _this$_elements3.mastheadL1,
420
+ tableOfContents = _this$_elements3.tableOfContents,
421
+ tableOfContentsInnerBar = _this$_elements3.tableOfContentsInnerBar,
422
+ leadspaceSearchBar = _this$_elements3.leadspaceSearchBar;
423
+
424
+ // Reset the value before performing any further calculations.
425
+ this._state.maxScrollaway = 0;
426
+
427
+ // Collect conditions we may want to test for to make logic easier to read.
428
+ this._state.tocShouldStick = tableOfContents ? tableOfContents.layout === 'horizontal' || window.innerWidth < gridBreakpoint : false;
429
+ this._state.tocIsAtTop = tableOfContentsInnerBar ? tableOfContentsInnerBar.getBoundingClientRect().top <= this.height + 1 : false;
430
+ this._state.searchIsAtTop = leadspaceSearchBar ? leadspaceSearchBar.getBoundingClientRect().top <= this.height + 1 : false;
431
+ this._state.tocIsAtSearch = leadspaceSearchBar && tableOfContentsInnerBar ? tableOfContentsInnerBar.getBoundingClientRect().top <= leadspaceSearchBar.getBoundingClientRect().bottom : false;
432
+ this._state.mastheadL0IsActive = Boolean(masthead === null || masthead === void 0 ? void 0 : masthead.querySelector('[expanded]'));
433
+ this._state.mastheadL1IsActive = mastheadL1 && mastheadL1.hasAttribute('active');
434
+ var _this$_state = this._state,
435
+ tocShouldStick = _this$_state.tocShouldStick,
436
+ tocIsAtTop = _this$_state.tocIsAtTop,
437
+ searchIsAtTop = _this$_state.searchIsAtTop,
438
+ tocIsAtSearch = _this$_state.tocIsAtSearch,
439
+ mastheadL0IsActive = _this$_state.mastheadL0IsActive,
440
+ mastheadL1IsActive = _this$_state.mastheadL1IsActive;
271
441
 
272
- // Calculate maxScrollaway values based on leadspace search position
273
- if (!tocInner && leadspaceSearchBar) {
274
- var searchIsAtTop = leadspaceSearchBar.getBoundingClientRect().top <= (masthead ? masthead.offsetTop + masthead.offsetHeight : 0) + 1;
275
- if (masthead && searchIsAtTop) {
276
- maxScrollaway += masthead.offsetHeight;
442
+ // Begin calculating maxScrollAway.
443
+
444
+ // If L0 is open, lock it to the top of the page.
445
+ if (mastheadL0 && mastheadL0IsActive) {
446
+ this._state.maxScrollaway = 0;
447
+ }
448
+ // If L1 is open, lock it to the top of the page.
449
+ else if (mastheadL1IsActive && mastheadL0) {
450
+ this._state.maxScrollaway = mastheadL0.offsetHeight;
451
+ } else {
452
+ // In cases where we have both an eligible ToC and leadspace search, we want
453
+ // the ToC to take precedence. Scroll away leadspace search.
454
+ if (searchIsAtTop && tocIsAtSearch && tocShouldStick) {
455
+ this._state.maxScrollaway += leadspaceSearchBar.offsetHeight;
456
+ }
457
+
458
+ // Scroll away entire masthead if either ToC or leadspace search is eligible
459
+ // to be the stuck element (unless L1 is open). Otherwise, scroll away the
460
+ // L0 if we have an L1.
461
+ if (searchIsAtTop || tocIsAtTop && tocShouldStick) {
462
+ if (masthead) {
463
+ this._state.maxScrollaway += masthead.offsetHeight;
464
+ }
465
+ } else if (masthead && mastheadL0 && mastheadL1) {
466
+ this._state.maxScrollaway += mastheadL0.offsetHeight;
277
467
  }
278
468
  }
469
+ }
470
+
471
+ /**
472
+ * Positions sticky elements. Does so by checking the scroll position and where
473
+ * tracked elements are in relation to it, then applying the correct styles to
474
+ * each element in succession to ensure that only one element is stuck to the
475
+ * top of the page, and all other elements that have been scrolled past can be
476
+ * revealed when scrolling back up.
477
+ */
478
+ }, {
479
+ key: "_positionElements",
480
+ value: function _positionElements() {
481
+ var _this$_elements4 = this._elements,
482
+ banner = _this$_elements4.banner,
483
+ masthead = _this$_elements4.masthead,
484
+ tocInner = _this$_elements4.tableOfContentsInnerBar,
485
+ leadspaceSearchBar = _this$_elements4.leadspaceSearchBar;
486
+ var oldY = this._state.scrollPosPrevious;
279
487
 
280
488
  /**
281
- * Cumulative offset is a calculated value used to set the `top` property of
282
- * components that stick to the top of the viewport.
283
- *
284
- * This value is equal to the difference between the previous scrollY and
285
- * the current scrollY values, but is positively and negatively limited.
489
+ * Reset to a value that is equal to the difference between the previous
490
+ * scrollY and the current scrollY values, but is positively and negatively
491
+ * limited.
286
492
  *
287
493
  * Positive limit: 0
288
494
  * all elements visible, starting at the top of the viewport.
@@ -292,55 +498,58 @@ var StickyHeader = /*#__PURE__*/function () {
292
498
  * with the elements that should be visible starting at the top of the
293
499
  * viewport.
294
500
  */
295
- var cumulativeOffset = Math.max(Math.min((masthead ? masthead.offsetTop : 0) + oldY - newY, 0), maxScrollaway * -1);
501
+ this._state.cumulativeOffset = Math.max(Math.min((masthead ? masthead.offsetTop : 0) + oldY - this._state.scrollPos, 0), this._state.maxScrollaway * -1);
502
+
503
+ /**
504
+ * Handle each potentially sticky element in the order we expect them to
505
+ * appear on the page. Important to do this sequentially for
506
+ * cumulativeOffset to be correctly calculated by the time each of these
507
+ * methods accesses it.
508
+ *
509
+ * To-do: One idea for improving this so the execution order doesn't matter
510
+ * is to collect our elements into an array ordered by document position,
511
+ * then loop over that array and execute a corresponding handler method.
512
+ */
296
513
  if (banner) {
297
- cumulativeOffset += Math.max(banner.offsetHeight - newY, 0);
514
+ this._handleBanner();
298
515
  }
299
516
  if (masthead) {
300
- masthead.style.transition = 'none';
301
- masthead.style.top = "".concat(cumulativeOffset, "px");
302
- cumulativeOffset += masthead.offsetHeight;
517
+ this._handleMasthead();
518
+ }
519
+ if (leadspaceSearchBar) {
520
+ this._handleLeadspaceSearch();
303
521
  }
304
522
  if (tocInner) {
305
- tocInner.style.transition = 'none';
306
- tocInner.style.top = "".concat(cumulativeOffset, "px");
307
- tocShouldStick = toc.layout === 'horizontal' || window.innerWidth < gridBreakpoint;
308
- var tocIsStuck = Math.round(tocInner.getBoundingClientRect().top) <= cumulativeOffset + 1;
309
- if (tocShouldStick && tocIsStuck) {
310
- cumulativeOffset += tocInner.offsetHeight;
311
- }
523
+ this._handleToc();
312
524
  }
313
- if (!tocInner && leadspaceSearchBar) {
314
- var searchShouldBeSticky = leadspaceSearch.getBoundingClientRect().bottom <= leadspaceSearchThreshold;
315
- var searchIsSticky = leadspaceSearch.hasAttribute('sticky-search');
316
- if (searchShouldBeSticky) {
317
- if (!searchIsSticky) {
318
- leadspaceSearch.style.paddingBottom = "".concat(leadspaceSearchBar.offsetHeight, "px");
319
- leadspaceSearch.setAttribute('sticky-search', '');
320
- leadspaceSearchInput.setAttribute('large', '');
321
- window.requestAnimationFrame(function () {
322
- leadspaceSearchBar.style.transitionDuration = '110ms';
323
- leadspaceSearchBar.style.transform = 'translateY(0)';
324
- });
325
- }
326
- leadspaceSearchBar.style.top = "".concat(cumulativeOffset, "px");
327
- cumulativeOffset += leadspaceSearchBar.offsetHeight;
328
- }
329
- if (!searchShouldBeSticky && searchIsSticky) {
330
- leadspaceSearch.removeAttribute('sticky-search');
331
- leadspaceSearch.style.paddingBottom = '';
332
- leadspaceSearchBar.style.top = '';
333
- leadspaceSearchBar.style.transitionDuration = '';
334
- leadspaceSearchBar.style.transform = '';
335
- leadspaceSearchInput.removeAttribute('large');
336
- }
525
+ }
526
+
527
+ /**
528
+ * Manages which elements are stuck and where they are positioned. We should
529
+ * only have one element stuck to the top of the viewport as the page scrolls
530
+ * down.
531
+ */
532
+ }, {
533
+ key: "_manageStickyElements",
534
+ value: function _manageStickyElements() {
535
+ var localeModal = this._elements.localeModal;
536
+ var scrollPosPrevious = this._state.scrollPos;
537
+
538
+ // Exit early if locale modal is open.
539
+ if (localeModal && localeModal.hasAttribute('open')) {
540
+ return;
337
541
  }
338
542
 
339
- // Set internal property for use in scripts
340
- this._cumulativeHeight = cumulativeOffset;
543
+ // Store scroll positions.
544
+ this._state.scrollPosPrevious = scrollPosPrevious;
545
+ this._state.scrollPos = Math.max(0, window.scrollY);
546
+
547
+ // Given the current state, calculate how elements should be positioned.
548
+ this._calculateMaxScrollaway();
549
+ this._positionElements();
341
550
 
342
551
  // Set custom property for use in stylesheets
343
- root.document.documentElement.style.setProperty(customPropertyName, "".concat(this._cumulativeHeight, "px"));
552
+ root.document.documentElement.style.setProperty(this.constructor.customPropertyName, "".concat(this._state.cumulativeOffset, "px"));
344
553
  }
345
554
  }], [{
346
555
  key: "global",