@ucd-lib/theme-elements 0.0.4 → 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,10 @@
1
1
  import { LitElement } from 'lit';
2
2
  import {render, styles} from "./ucd-theme-header.tpl.js";
3
3
 
4
- import { Mixin, MutationObserverElement, BreakPoints, Wait } from "../../utils/index.js";
4
+ import {
5
+ IntersectionObserverController,
6
+ MutationObserverController,
7
+ WaitController } from '../../utils/controllers';
5
8
 
6
9
  /**
7
10
  * @class UcdThemeHeader
@@ -15,6 +18,7 @@ import { Mixin, MutationObserverElement, BreakPoints, Wait } from "../../utils/i
15
18
  * @property {String} figureSrc - Site logo/icon to display next to site name
16
19
  * @property {String} siteUrl - Url to use for links around site name and figure
17
20
  * @property {Boolean} opened - Whether header is open in the mobile view
21
+ * @property {Boolean} preventFixed - Navbar will not be fixed to top of screen in desktop view
18
22
  *
19
23
  * @example
20
24
  * <ucd-theme-header site-name="A UC Davis Website">
@@ -35,8 +39,10 @@ import { Mixin, MutationObserverElement, BreakPoints, Wait } from "../../utils/i
35
39
  * </ucd-theme-header>
36
40
  *
37
41
  */
38
- export default class UcdThemeHeader extends Mixin(LitElement)
39
- .with(MutationObserverElement, BreakPoints, Wait) {
42
+ export default class UcdThemeHeader extends LitElement {
43
+
44
+ mutationObserver = new MutationObserverController(this);
45
+ wait = new WaitController(this);
40
46
 
41
47
  static get properties() {
42
48
  return {
@@ -45,11 +51,13 @@ export default class UcdThemeHeader extends Mixin(LitElement)
45
51
  figureSrc: {type: String, attribute: "figure-src"},
46
52
  siteUrl: {type: String, attribute: "site-url"},
47
53
  opened: {type: Boolean},
54
+ preventFixed: {type: Boolean, attribute: "prevent-fixed"},
48
55
  isDemo: {type: Boolean, attribute: "is-demo"},
49
56
  _transitioning: {type: Boolean, state: true},
50
57
  _hasSlottedBranding: {type: Boolean, state: true},
51
58
  _hasQuickLinks: {type: Boolean, state: true},
52
- _hasSearch: {type: Boolean, state: true}
59
+ _hasSearch: {type: Boolean, state: true},
60
+ _brandingBarInView: {type: Boolean, state: true}
53
61
  };
54
62
  }
55
63
 
@@ -73,9 +81,40 @@ export default class UcdThemeHeader extends Mixin(LitElement)
73
81
  this._hasQuickLinks = false;
74
82
  this._hasSearch = false;
75
83
  this._animationDuration = 500;
84
+ this._brandingBarInView = false;
76
85
 
77
86
  }
78
87
 
88
+ connectedCallback(){
89
+ super.connectedCallback();
90
+ if ( !this.preventFixed ) {
91
+ this.intersectionObserver = new IntersectionObserverController(this, {}, "_onBrandingBarIntersection", false);
92
+ }
93
+ }
94
+
95
+ firstUpdated(){
96
+ if ( !this.preventFixed ) {
97
+ let aboveNav = this.renderRoot.getElementById('branding-bar-container');
98
+ this.intersectionObserver.observer.observe(aboveNav);
99
+ }
100
+ }
101
+
102
+ _onBrandingBarIntersection(entries){
103
+ let offSetValue = 0;
104
+ try {
105
+ offSetValue = this.renderRoot.getElementById('nav-bar').getBoundingClientRect().height;
106
+ } catch (error) {}
107
+ if ( offSetValue > 150 ) offSetValue = 0;
108
+ entries.forEach(entry => {
109
+ this._brandingBarInView = entry.isIntersecting;
110
+ if (this._brandingBarInView) {
111
+ this.style.marginBottom = '0px';
112
+ } else {
113
+ this.style.marginBottom = offSetValue + "px";
114
+ }
115
+ })
116
+ }
117
+
79
118
  /**
80
119
  * @method open
81
120
  * @description Opens header menu in mobile
@@ -86,7 +125,7 @@ export default class UcdThemeHeader extends Mixin(LitElement)
86
125
 
87
126
  this.opened = true;
88
127
  this._transitioning = true;
89
- await this.waitForAnimation();
128
+ await this.wait.wait(this._animationDuration);
90
129
  this._transitioning = false;
91
130
  return true;
92
131
 
@@ -102,7 +141,7 @@ export default class UcdThemeHeader extends Mixin(LitElement)
102
141
 
103
142
  this.opened = false;
104
143
  this._transitioning = true;
105
- await this.waitForAnimation();
144
+ await this.wait.wait(this._animationDuration);
106
145
  this._transitioning = false;
107
146
  return true;
108
147
 
@@ -149,6 +188,24 @@ export default class UcdThemeHeader extends Mixin(LitElement)
149
188
  return classes;
150
189
  }
151
190
 
191
+ /**
192
+ * @method _getHeaderClasses
193
+ * @description Get classes to be assigned to the header element
194
+ * @private
195
+ * @returns {Object}
196
+ */
197
+ _getHeaderClasses(){
198
+ let classes = {
199
+ "l-header": true,
200
+ "header": true
201
+ };
202
+
203
+ classes['fixed-mobile'] = !this.preventFixed;
204
+ classes['fixed-desktop'] = !this.preventFixed && !this._brandingBarInView;
205
+
206
+ return classes;
207
+ }
208
+
152
209
  /**
153
210
  * @method _ucdLogo
154
211
  * @description Returns URI-encoded svg string of UC Davis logo
@@ -23,6 +23,36 @@ export function styles() {
23
23
  ::slotted(ucdlib-branding-bar){
24
24
  width: 100%;
25
25
  }
26
+
27
+ @media (max-width: 991px) {
28
+ .fixed-mobile .mobile-bar {
29
+ position: fixed;
30
+ width: 100%;
31
+ z-index: 1000;
32
+ top: 0;
33
+ }
34
+ .fixed-mobile .off-canvas {
35
+ position: fixed;
36
+ overflow: auto;
37
+ z-index: 1000;
38
+ top: 55px;
39
+ }
40
+ .fixed-mobile .l-header__branding {
41
+ margin-top: 55px;
42
+ }
43
+ }
44
+
45
+ @media (min-width: 992px) {
46
+ .fixed-desktop .l-navbar {
47
+ position: fixed;
48
+ z-index: 1000;
49
+ top: 0;
50
+ right: 0;
51
+ left: 0;
52
+ width: 100%;
53
+ }
54
+ }
55
+
26
56
  `;
27
57
 
28
58
  return [
@@ -44,7 +74,7 @@ ${this.isDemo ? html`
44
74
  .l-navbar { top: auto !important}
45
75
  </style>
46
76
  ` : html``}
47
- <header class="l-header header">
77
+ <header class=${classMap(this._getHeaderClasses())}>
48
78
  <div class="mobile-bar">
49
79
  <div class="mobile-bar__nav-toggle">
50
80
  <button
@@ -64,32 +94,34 @@ ${this.isDemo ? html`
64
94
  </div>
65
95
  </div>
66
96
 
67
- <div class="header__bar">
68
- <div class="header__university">
69
- <a href="https://www.ucdavis.edu/">
70
- <img class="ucd-logo" src='data:image/svg+xml;utf8,${this._ucdLogo()}'>
71
- </a>
72
- </div>
73
- </div>
74
- <div class="l-header__branding">
75
- ${this._hasSlottedBranding ? html`
76
- <slot name="branding-bar"></slot>
77
- ` : html`
78
- <div class="site-branding">
79
- <div class="site-branding__figure" ?hidden=${!this.figureSrc}>
80
- <a href="${this.siteUrl}" class=""><img src=${this.figureSrc} class="site-logo" alt="Site Logo" /></a>
97
+ <div id="branding-bar-container">
98
+ <div class="header__bar">
99
+ <div class="header__university">
100
+ <a href="https://www.ucdavis.edu/">
101
+ <img class="ucd-logo" src='data:image/svg+xml;utf8,${this._ucdLogo()}'>
102
+ </a>
81
103
  </div>
82
- <div class="site-branding__body">
83
- <h1 class="site-branding__site-name" ?hidden=${!this.siteName}>
84
- <a href=${this.siteUrl}>${this.siteName}</a>
85
- </h1>
86
- <div class="site-branding__slogan" ?hidden=${!this.slogan}>${this.slogan}</div>
104
+ </div>
105
+ <div class="l-header__branding">
106
+ ${this._hasSlottedBranding ? html`
107
+ <slot name="branding-bar"></slot>
108
+ ` : html`
109
+ <div class="site-branding">
110
+ <div class="site-branding__figure" ?hidden=${!this.figureSrc}>
111
+ <a href="${this.siteUrl}" class=""><img src=${this.figureSrc} class="site-logo" alt="Site Logo" /></a>
112
+ </div>
113
+ <div class="site-branding__body">
114
+ <h1 class="site-branding__site-name" ?hidden=${!this.siteName}>
115
+ <a href=${this.siteUrl}>${this.siteName}</a>
116
+ </h1>
117
+ <div class="site-branding__slogan" ?hidden=${!this.slogan}>${this.slogan}</div>
118
+ </div>
87
119
  </div>
88
- </div>
89
- `}
120
+ `}
121
+ </div>
90
122
  </div>
91
123
 
92
- <div class="${classMap(this._getNavbarClasses())}">
124
+ <div class="${classMap(this._getNavbarClasses())}" id="nav-bar">
93
125
  <div class="l-container--navigation off-canvas off-canvas--left">
94
126
  <div class="off-canvas__container l-nav-horizontal">
95
127
  ${this._hasSearch ? html`
@@ -1,7 +1,8 @@
1
1
  import { LitElement, html } from 'lit';
2
2
  //import { Page } from 'puppeteer';
3
3
  import {render, styles} from "./ucd-theme-pagination.tpl.js";
4
- import { Mixin, BreakPoints } from "../../utils/index.js";
4
+
5
+ import { BreakPointsController } from '../../utils/controllers';
5
6
 
6
7
  /**
7
8
  * @class UcdThemePagination
@@ -33,8 +34,8 @@ import { Mixin, BreakPoints } from "../../utils/index.js";
33
34
  * </ucd-theme-pagination>
34
35
  *
35
36
  */
36
- export default class UcdThemePagination extends Mixin(LitElement)
37
- .with(BreakPoints) {
37
+ export default class UcdThemePagination extends LitElement {
38
+ breakPoints = new BreakPointsController(this);
38
39
 
39
40
  static get properties() {
40
41
  return {
@@ -101,8 +102,7 @@ export default class UcdThemePagination extends Mixin(LitElement)
101
102
  this.xs_screen = false;
102
103
  this.size = '';
103
104
 
104
- this.screen_check = (window.innerWidth <= this._mobileBreakPoint) ? true : false;
105
- console.log(this.screen_check);
105
+ this.screen_check = (window.innerWidth <= this.breakPoints.mobileBreakPoint) ? true : false;
106
106
 
107
107
  this.render = render.bind(this);
108
108
  }
@@ -4,7 +4,8 @@ import { styleMap } from 'lit/directives/style-map.js';
4
4
  import { classMap } from 'lit/directives/class-map.js';
5
5
  import { ifDefined } from 'lit/directives/if-defined.js';
6
6
 
7
- import { Mixin, MutationObserverElement, BreakPoints, NavElement } from "../../utils/index.js";
7
+ import { Mixin, NavElement } from "../../utils/mixins";
8
+ import { MutationObserverController, BreakPointsController } from '../../utils/controllers';
8
9
 
9
10
  /**
10
11
  * @class UcdThemePrimaryNav
@@ -33,7 +34,10 @@ import { Mixin, MutationObserverElement, BreakPoints, NavElement } from "../../u
33
34
  * </ucd-theme-primary-nav>
34
35
  */
35
36
  export default class UcdThemePrimaryNav extends Mixin(LitElement)
36
- .with(NavElement, MutationObserverElement, BreakPoints) {
37
+ .with(NavElement) {
38
+
39
+ mutationObserver = new MutationObserverController(this, {subtree: true, childList: true});
40
+ breakPoints = new BreakPointsController(this);
37
41
 
38
42
  static get properties() {
39
43
  return {
@@ -97,7 +101,7 @@ export default class UcdThemePrimaryNav extends Mixin(LitElement)
97
101
  if ( !navItem ) return;
98
102
 
99
103
  // Open on mobile
100
- if ( this.isMobile() ) {
104
+ if ( this.breakPoints.isMobile() ) {
101
105
  let nav = this.renderRoot.getElementById(`nav--${navLocation.join("-")}`);
102
106
  if ( !nav ) return;
103
107
  let ul = nav.querySelector('ul');
@@ -160,7 +164,7 @@ export default class UcdThemePrimaryNav extends Mixin(LitElement)
160
164
  if ( !navItem ) return;
161
165
 
162
166
  // close on mobile
163
- if ( this.isMobile() ) {
167
+ if ( this.breakPoints.isMobile() ) {
164
168
  let nav = this.renderRoot.getElementById(`nav--${navLocation.join("-")}`);
165
169
  if ( !nav ) return;
166
170
  let ul = nav.querySelector('ul');
@@ -263,7 +267,7 @@ export default class UcdThemePrimaryNav extends Mixin(LitElement)
263
267
  /**
264
268
  * @method _onChildListMutation
265
269
  * @private
266
- * @description Fires when light dom child list changes. Injected by MutationObserverElement mixin.
270
+ * @description Fires when light dom child list changes. Injected by MutationObserverController.
267
271
  * Sets the 'navItems' property.
268
272
  */
269
273
  _onChildListMutation(){
@@ -345,7 +349,7 @@ export default class UcdThemePrimaryNav extends Mixin(LitElement)
345
349
  this.isMegaMenu() &&
346
350
  depth > 0 &&
347
351
  !this._megaIsOpen &&
348
- this.isDesktop()
352
+ this.breakPoints.isDesktop()
349
353
  ) i = -1;
350
354
 
351
355
  return i;
@@ -375,7 +379,7 @@ export default class UcdThemePrimaryNav extends Mixin(LitElement)
375
379
  * @param {Array} navLocation - Array coordinates of corresponding nav item
376
380
  */
377
381
  async _toggleMobileMenu(navLocation){
378
- if ( this.isDesktop() ) return;
382
+ if ( this.breakPoints.isDesktop() ) return;
379
383
  let navItem = this.getNavItem(navLocation);
380
384
  if ( navItem.isOpen ) {
381
385
  this.closeSubNav(navLocation);
@@ -391,7 +395,7 @@ export default class UcdThemePrimaryNav extends Mixin(LitElement)
391
395
  */
392
396
  _onNavMouseenter(){
393
397
  if (
394
- this.isMobile() ||
398
+ this.breakPoints.isMobile() ||
395
399
  !this.isMegaMenu() )
396
400
  return;
397
401
 
@@ -408,7 +412,7 @@ export default class UcdThemePrimaryNav extends Mixin(LitElement)
408
412
  */
409
413
  _onNavMouseleave(){
410
414
  if (
411
- this.isMobile() ||
415
+ this.breakPoints.isMobile() ||
412
416
  !this.isMegaMenu() )
413
417
  return;
414
418
 
@@ -426,7 +430,7 @@ export default class UcdThemePrimaryNav extends Mixin(LitElement)
426
430
  */
427
431
  _onNavFocusin(){
428
432
  if (
429
- this.isMobile() ||
433
+ this.breakPoints.isMobile() ||
430
434
  !this.isMegaMenu() )
431
435
  return;
432
436
 
@@ -447,7 +451,7 @@ export default class UcdThemePrimaryNav extends Mixin(LitElement)
447
451
  * @param {Event} e
448
452
  */
449
453
  _onItemMouseenter(e){
450
- if ( this.isMobile() ) return;
454
+ if ( this.breakPoints.isMobile() ) return;
451
455
  this.openSubNav(e.target.key);
452
456
  }
453
457
 
@@ -458,7 +462,7 @@ export default class UcdThemePrimaryNav extends Mixin(LitElement)
458
462
  * @param {Event} e
459
463
  */
460
464
  _onItemFocus(e){
461
- if ( this.isMobile() ) return;
465
+ if ( this.breakPoints.isMobile() ) return;
462
466
  const LI = e.target.parentElement.parentElement;
463
467
 
464
468
  if (LI.hasnav) {
@@ -511,7 +515,7 @@ export default class UcdThemePrimaryNav extends Mixin(LitElement)
511
515
  * @param {Event} e
512
516
  */
513
517
  _onItemMouseleave(e){
514
- if ( this.isMobile() || this.isMegaMenu() ) return;
518
+ if ( this.breakPoints.isMobile() || this.isMegaMenu() ) return;
515
519
  this.closeSubNav(e.target.key);
516
520
  }
517
521
 
@@ -521,7 +525,7 @@ export default class UcdThemePrimaryNav extends Mixin(LitElement)
521
525
  * @description Attached to the top-level nav element. Closes subnav if it doesn't contain focused link.
522
526
  */
523
527
  _onNavFocusout(){
524
- if ( this.isMobile() ) return;
528
+ if ( this.breakPoints.isMobile() ) return;
525
529
  if ( this.isMegaMenu() ) {
526
530
  if ( this._megaTimeout ) clearTimeout(this._megaTimeout);
527
531
  requestAnimationFrame(() => {
@@ -574,7 +578,7 @@ export default class UcdThemePrimaryNav extends Mixin(LitElement)
574
578
  * @returns {Object} - Style map
575
579
  */
576
580
  _getItemMobileStyles(location) {
577
- if ( this.isDesktop() ) return {};
581
+ if ( this.breakPoints.isDesktop() ) return {};
578
582
  let navItem = this.getNavItem(location);
579
583
  if ( !navItem.inlineStyles ) return {};
580
584
  return navItem.inlineStyles;
@@ -1,7 +1,7 @@
1
1
  import { LitElement, html } from 'lit';
2
2
  import {render, styles} from "./ucd-theme-quick-links.tpl.js";
3
3
 
4
- import { Mixin, MutationObserverElement, BreakPoints, Wait } from "../../utils/index.js";
4
+ import { MutationObserverController, WaitController } from '../../utils/controllers';
5
5
 
6
6
  /**
7
7
  * @class UcdThemeQuickLinks
@@ -17,8 +17,10 @@ import { Mixin, MutationObserverElement, BreakPoints, Wait } from "../../utils/i
17
17
  * @property {Boolean} opened - Menu is open
18
18
  * @property {Number} animationDuration - Length of animation when opening/closing menu
19
19
  */
20
- export default class UcdThemeQuickLinks extends Mixin(LitElement)
21
- .with(MutationObserverElement, BreakPoints, Wait) {
20
+ export default class UcdThemeQuickLinks extends LitElement {
21
+
22
+ mutationObserver = new MutationObserverController(this);
23
+ wait = new WaitController(this);
22
24
 
23
25
  static get properties() {
24
26
  return {
@@ -67,7 +69,7 @@ export default class UcdThemeQuickLinks extends Mixin(LitElement)
67
69
  this._openedHeight = this.renderRoot.getElementById('menu').scrollHeight + "px";
68
70
  await this.updateComplete;
69
71
 
70
- await this.waitForAnimation();
72
+ await this.wait.wait(this.animationDuration);
71
73
  this._transitioning = false;
72
74
  this.opened = true;
73
75
  return true;
@@ -84,11 +86,11 @@ export default class UcdThemeQuickLinks extends Mixin(LitElement)
84
86
 
85
87
  this._openedHeight = this.renderRoot.getElementById('menu').scrollHeight + "px";
86
88
  await this.updateComplete;
87
- await this.waitForFrames(2);
89
+ await this.wait.waitForFrames(2);
88
90
  this._openedHeight = 0;
89
91
  await this.updateComplete;
90
92
 
91
- await this.waitForAnimation();
93
+ await this.wait.wait(this.animationDuration);
92
94
 
93
95
  this._transitioning = false;
94
96
  this.opened = false;
@@ -229,7 +231,7 @@ export default class UcdThemeQuickLinks extends Mixin(LitElement)
229
231
  * @method _onChildListMutation
230
232
  * @param {Array} mutationsList - List of mutation records
231
233
  * @private
232
- * @description Fires when light dom child list changes. Injected by MutationObserverElement mixin.
234
+ * @description Fires when light dom child list changes. Injected by MutationObserverController.
233
235
  * Sets the '_links' property.
234
236
  */
235
237
  _onChildListMutation(mutationsList){
@@ -1,7 +1,7 @@
1
1
  import { LitElement } from 'lit';
2
2
  import {render, styles} from "./ucd-theme-search-popup.tpl.js";
3
3
 
4
- import { Mixin, MutationObserverElement } from "../../utils/index.js";
4
+ import { MutationObserverController } from '../../utils/controllers';
5
5
 
6
6
  /**
7
7
  * @class UcdThemeSearchPopup
@@ -24,8 +24,8 @@ import { Mixin, MutationObserverElement } from "../../utils/index.js";
24
24
  * <input placeholder="A custom search element">
25
25
  * </ucd-theme-search-popup>
26
26
  */
27
- export default class UcdThemeSearchPopup extends Mixin(LitElement)
28
- .with(MutationObserverElement) {
27
+ export default class UcdThemeSearchPopup extends LitElement {
28
+ mutationObserver = new MutationObserverController(this);
29
29
 
30
30
  static get properties() {
31
31
  return {
@@ -3,7 +3,7 @@ import {render, styles} from "./ucd-theme-slim-select.tpl.js";
3
3
 
4
4
  import SlimSelect from 'slim-select';
5
5
 
6
- import { Mixin, MutationObserverElement } from "../../utils/index.js";
6
+ import { MutationObserverController } from '../../utils/controllers';
7
7
 
8
8
  /**
9
9
  * @class UcdThemeSlimSelect
@@ -12,8 +12,12 @@ import { Mixin, MutationObserverElement } from "../../utils/index.js";
12
12
  * Patternlab URL:
13
13
  * - http://dev.webstyleguide.ucdavis.edu/redesign/?p=atoms-select-menu
14
14
  */
15
- export default class UcdThemeSlimSelect extends Mixin(LitElement)
16
- .with(MutationObserverElement) {
15
+ export default class UcdThemeSlimSelect extends LitElement {
16
+ mutationObserver = new MutationObserverController(
17
+ this,
18
+ {subtree: true, childList: true, attributes: true, characterData: true},
19
+ "_onLightDomMutation"
20
+ );
17
21
 
18
22
  static get properties() {
19
23
  return {
@@ -29,23 +33,13 @@ export default class UcdThemeSlimSelect extends Mixin(LitElement)
29
33
  super();
30
34
  this.render = render.bind(this);
31
35
  }
32
- /**
33
- * @method connectedCallback
34
- * @private
35
- * @description Native lifecycle method called when element is connected
36
- */
37
- connectedCallback(){
38
- super.connectedCallback();
39
- this._childListObserver.disconnect();
40
- this._childListObserver.observe(this, {subtree: true, childList: true, attributes: true, characterData: true});
41
- }
42
36
 
43
37
  /**
44
- * @method _onChildListMutation
38
+ * @method _onLightDomMutation
45
39
  * @private
46
- * @description Fires when light dom child list changes. Injected by MutationObserverElement mixin.
40
+ * @description Fires when light dom child list changes. Called by MutationObserverController.
47
41
  */
48
- _onChildListMutation(){
42
+ _onLightDomMutation(){
49
43
  const children = Array.from(this.children);
50
44
  if (children.length == 0 || children[0].tagName != "SELECT") return;
51
45
  const select = children[0].cloneNode(true);
@@ -4,7 +4,8 @@ import { ifDefined } from 'lit/directives/if-defined.js';
4
4
 
5
5
  import { styleMap } from 'lit/directives/style-map.js';
6
6
 
7
- import {Mixin, MutationObserverElement, NavElement, Wait} from "../../utils";
7
+ import {Mixin, NavElement} from "../../utils/mixins";
8
+ import { MutationObserverController, WaitController } from '../../utils/controllers';
8
9
 
9
10
  /**
10
11
  * @class UcdThemeSubnav
@@ -29,7 +30,10 @@ import {Mixin, MutationObserverElement, NavElement, Wait} from "../../utils";
29
30
  * </ucd-theme-subnav>
30
31
  */
31
32
  export default class UcdThemeSubnav extends Mixin(LitElement)
32
- .with(NavElement, MutationObserverElement, Wait) {
33
+ .with(NavElement) {
34
+
35
+ mutationObserver = new MutationObserverController(this, {subtree: true, childList: true});
36
+ wait = new WaitController(this);
33
37
 
34
38
  static get properties() {
35
39
  return {
@@ -72,15 +76,15 @@ export default class UcdThemeSubnav extends Mixin(LitElement)
72
76
  // Get expanded height
73
77
  navItem.inlineStyles.display = "block";
74
78
  navItem.inlineStyles.height = "0px";
75
- await this.waitForUpdate();
79
+ await this.wait.waitForUpdate();
76
80
  const expandedHeight = navUL.scrollHeight + "px";
77
81
 
78
82
  // Set expanded height
79
83
  navItem.inlineStyles.height = expandedHeight;
80
- await this.waitForUpdate();
84
+ await this.wait.waitForUpdate();
81
85
 
82
86
  // Complete animation
83
- await this.waitForAnimation();
87
+ await this.wait.wait(this.animationDuration);
84
88
  navItem.inlineStyles = {};
85
89
  navItem.isOpen = true;
86
90
  navItem.isTransitioning = false;
@@ -108,15 +112,15 @@ export default class UcdThemeSubnav extends Mixin(LitElement)
108
112
  // Set expanded height
109
113
  navItem.inlineStyles.height = navUL.scrollHeight + "px";
110
114
  navItem.inlineStyles.display = "block";
111
- await this.waitForUpdate();
115
+ await this.wait.waitForUpdate();
112
116
 
113
117
  // Set height to zero
114
- await this.waitForFrames(2);
118
+ await this.wait.waitForFrames(2);
115
119
  navItem.inlineStyles.height = "0px";
116
- await this.waitForUpdate();
120
+ await this.wait.waitForUpdate();
117
121
 
118
122
  // Complete animation
119
- await this.waitForAnimation();
123
+ await this.wait.wait(this.animationDuration);
120
124
  navItem.inlineStyles = {};
121
125
  navItem.isOpen = false;
122
126
  navItem.isTransitioning = false;
@@ -129,7 +133,7 @@ export default class UcdThemeSubnav extends Mixin(LitElement)
129
133
  /**
130
134
  * @method _onChildListMutation
131
135
  * @private
132
- * @description Fires when light dom child list changes. Injected by MutationObserverElement mixin.
136
+ * @description Fires when light dom child list changes. Injected by MutationObserverController.
133
137
  * Sets the 'navItems' property.
134
138
  */
135
139
  _onChildListMutation(){
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ucd-lib/theme-elements",
3
- "version": "0.0.4",
3
+ "version": "0.0.5",
4
4
  "description": "Custom elements for the UCD brand theme",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -10,7 +10,7 @@
10
10
  "license": "MIT",
11
11
  "dependencies": {
12
12
  "@ucd-lib/theme-sass": "^5.0.11",
13
- "lit": "^2.0.0-rc.4",
13
+ "lit": "^2.0.2",
14
14
  "photoswipe": "^4.1.3",
15
15
  "slim-select": "^1.26.2"
16
16
  }
@@ -1,7 +1,8 @@
1
1
  import { LitElement, svg } from 'lit';
2
2
  import {render, styles} from "./ucdlib-branding-bar.tpl.js";
3
3
 
4
- import {Mixin, MutationObserverElement, NavElement} from "../../utils";
4
+ import {Mixin, NavElement} from "../../utils/mixins";
5
+ import { MutationObserverController } from '../../utils/controllers';
5
6
  import logo from "./logo.js";
6
7
  import bookLogo from "./book.js";
7
8
 
@@ -22,7 +23,12 @@ import bookLogo from "./book.js";
22
23
  * </ucdlib-branding-bar>
23
24
  */
24
25
  export default class UcdlibBrandingBar extends Mixin(LitElement)
25
- .with(NavElement, MutationObserverElement) {
26
+ .with(NavElement) {
27
+
28
+ mutationObserver = new MutationObserverController(
29
+ this,
30
+ {childList: true, characterData: true, attributes: true}
31
+ );
26
32
 
27
33
  static get properties() {
28
34
  return {
@@ -82,7 +88,7 @@ export default class UcdlibBrandingBar extends Mixin(LitElement)
82
88
  /**
83
89
  * @method _onChildListMutation
84
90
  * @private
85
- * @description Fires when light dom child list changes. Injected by MutationObserverElement mixin.
91
+ * @description Fires when light dom child list changes. Called by MutationObserverController.
86
92
  * Sets the 'navItems' property.
87
93
  */
88
94
  _onChildListMutation(){
@@ -1,5 +1,7 @@
1
1
  import { LitElement } from 'lit';
2
- import { Mixin, MutationObserverElement, MainDomElement} from "../../utils";
2
+ import { Mixin, MainDomElement} from "../../utils/mixins";
3
+ import { MutationObserverController } from '../../utils/controllers';
4
+
3
5
 
4
6
  /**
5
7
  * @class UcdlibIconset
@@ -18,7 +20,8 @@ import { Mixin, MutationObserverElement, MainDomElement} from "../../utils";
18
20
  </ucdlib-iconset>
19
21
  */
20
22
  export default class UcdlibIconset extends Mixin(LitElement)
21
- .with(MutationObserverElement, MainDomElement) {
23
+ .with(MainDomElement) {
24
+ mutationObserver = new MutationObserverController(this, {subtree: true, childList: true});
22
25
 
23
26
  static get properties() {
24
27
  return {
@@ -1,5 +1,5 @@
1
1
  import { LitElement } from 'lit';
2
- import {Mixin, MutationObserverElement} from '../../utils/index.js';
2
+ import { MutationObserverController } from '../../utils/controllers';
3
3
 
4
4
  /**
5
5
  * @class UcdlibPages
@@ -16,8 +16,8 @@ import {Mixin, MutationObserverElement} from '../../utils/index.js';
16
16
  * <div id="page2">Test 2</div>
17
17
  * </ucdlib-pages>
18
18
  */
19
- export default class UcdlibPages extends Mixin(LitElement)
20
- .with(MutationObserverElement) {
19
+ export default class UcdlibPages extends LitElement {
20
+ mutationObserver = new MutationObserverController(this);
21
21
 
22
22
  static get properties() {
23
23
  return {
@@ -55,7 +55,7 @@ export default class UcdlibPages extends Mixin(LitElement)
55
55
 
56
56
  /**
57
57
  * @method _onChildListMutation
58
- * @description called when children change via MutationObserverElement
58
+ * @description called when children change via MutationObserverController
59
59
  */
60
60
  _onChildListMutation() {
61
61
  this._onChange();
@@ -1,8 +1,9 @@
1
- const BreakPoints = (superClass) => class extends superClass {
1
+ export class BreakPointsController{
2
2
 
3
- constructor() {
4
- super();
5
- this._mobileBreakPoint = 992;
3
+ mobileBreakPoint = 992;
4
+
5
+ constructor(host){
6
+ (this.host = host).addController(this);
6
7
  }
7
8
 
8
9
  /**
@@ -10,8 +11,8 @@ const BreakPoints = (superClass) => class extends superClass {
10
11
  * @description Is the desktop view currently active?
11
12
  * @returns {Boolean}
12
13
  */
13
- isDesktop(){
14
- return window.innerWidth >= this._mobileBreakPoint;
14
+ isDesktop(){
15
+ return window.innerWidth >= this.mobileBreakPoint;
15
16
  }
16
17
 
17
18
  /**
@@ -22,6 +23,4 @@ const BreakPoints = (superClass) => class extends superClass {
22
23
  isMobile(){
23
24
  return !this.isDesktop();
24
25
  }
25
- };
26
-
27
- export {BreakPoints};
26
+ }
@@ -0,0 +1,11 @@
1
+ import { BreakPointsController } from "./break-points";
2
+ import { IntersectionObserverController } from "./intersection-observer";
3
+ import { MutationObserverController } from "./mutation-observer";
4
+ import { WaitController } from "./wait";
5
+
6
+ export {
7
+ BreakPointsController,
8
+ IntersectionObserverController,
9
+ MutationObserverController,
10
+ WaitController,
11
+ };
@@ -0,0 +1,58 @@
1
+ /**
2
+ * @class IntersectionObserverController
3
+ * @classdesc Lit controller that attaches an IntersectionObserver to an element
4
+ *
5
+ * @property {LitElement} host - 'this' from a Lit element
6
+ * @property {Object} options - IntersectionObserver options. Default: {}
7
+ * @property {String} callback - Name of element method called on intersection. Default: '_onIntersection'
8
+ * @property {Boolean} observeSelf - Automatically observes host element on connected. Default: true
9
+ *
10
+ * @examples
11
+ * // To watch for element's intersection with viewport, instantiate class in element constructor:
12
+ * new IntersectionObserverController(this)
13
+ *
14
+ * // Or watch for a specific element within your Lit element:
15
+ * // In constructor:
16
+ * this.intersectionObserver = new IntersectionObserverController(this, {}, "_onMyDivIntersection", false);
17
+ * // In firstUpdated:
18
+ * let myDiv = this.renderRoot.getElementById('my-div');
19
+ * this.intersectionObserver.observer.observe(my-div);
20
+ *
21
+ */
22
+ export class IntersectionObserverController{
23
+ host;
24
+ options;
25
+ callback;
26
+ observer;
27
+ observeSelf;
28
+
29
+ constructor(host, options = {}, callback = "_onIntersection", observeSelf = true){
30
+ (this.host = host).addController(this);
31
+ this.options = options;
32
+ this.callback = callback;
33
+ this.observeSelf = observeSelf;
34
+ }
35
+
36
+ hostConnected(){
37
+ this.observer = new IntersectionObserver(this._callback.bind(this), this.options);
38
+ if ( this.observeSelf ) {
39
+ this.observer.observe(this.host);
40
+ }
41
+ }
42
+
43
+ hostDisconnected(){
44
+ this.observer.disconnect();
45
+ }
46
+
47
+ _callback(entries, observer){
48
+ if ( !this.host[this.callback]){
49
+ console.warn(
50
+ `Element has no '${this.callback}' method.
51
+ Either add this method, or change the 'callback' argument on controller instantiation.`
52
+ );
53
+ return;
54
+ }
55
+ this.host[this.callback](entries, observer);
56
+
57
+ }
58
+ }
@@ -0,0 +1,52 @@
1
+ /**
2
+ * @class MutationObserverController
3
+ * @classdesc Lit controller that attaches a MutationObserver to an element
4
+ *
5
+ * @property {LitElement} host - 'this' from a Lit element
6
+ * @property {Object} options - MutationObserver.observe options. Default: {childList: true}
7
+ * @property {String} callback - Name of element method called on mutation. Default: '_onChildListMutation'
8
+ *
9
+ * @examples
10
+ * // For a basic childlist observer, instantiate this class in your element:
11
+ * mutationObserver = new MutationObserverController(this);
12
+ *
13
+ * // or customize the options/callback:
14
+ * mutationObserver = new MutationObserverController(this, {childList: true, attributes: true}, 'aDifferentCallbackMethod');
15
+ */
16
+ export class MutationObserverController {
17
+ host;
18
+ options;
19
+ callback;
20
+
21
+ _observer;
22
+
23
+ constructor(host, options = {childList: true}, callback = "_onChildListMutation"){
24
+ (this.host = host).addController(this);
25
+ this.options = options;
26
+ this.callback = callback;
27
+ }
28
+
29
+ hostConnected(){
30
+
31
+ this._observer = new MutationObserver(
32
+ (mutationsList, observer) => this._onMutation(mutationsList, observer)
33
+ );
34
+ this._observer.observe(this.host, this.options);
35
+ this._onMutation();
36
+ }
37
+
38
+ hostDisconnected(){
39
+ this._observer.disconnect();
40
+ }
41
+
42
+ _onMutation(mutationsList, observer){
43
+ if ( !this.host[this.callback]){
44
+ console.warn(
45
+ `Element has no '${this.callback}' method.
46
+ Either add this method, or change the 'callback' argument on instantiation.`
47
+ );
48
+ return;
49
+ }
50
+ this.host[this.callback](mutationsList, observer);
51
+ }
52
+ }
@@ -0,0 +1,43 @@
1
+ export class WaitController{
2
+ host;
3
+
4
+ constructor(host){
5
+ (this.host = host).addController(this);
6
+ }
7
+
8
+ /**
9
+ * @method wait
10
+ * @description Wait for the specified amount of time
11
+ * @param {Number} time - Time to wait (ms)
12
+ * @returns
13
+ */
14
+ async wait(time){
15
+ return new Promise(resolve => {
16
+ setTimeout(resolve, time);
17
+ });
18
+ }
19
+
20
+ /**
21
+ * @method waitForUpdate
22
+ * @description Requests and waits for Lit update.
23
+ */
24
+ async waitForUpdate(){
25
+ this.host.requestUpdate();
26
+ await this.host.updateComplete;
27
+ }
28
+
29
+ /**
30
+ * @method waitForFrames
31
+ * @description Wait for specified number of animation frames
32
+ * @param {Number} ct Number of frames
33
+ */
34
+ async waitForFrames(ct=1) {
35
+ for (let i = 0; i < ct; i++) {
36
+ await new Promise(resolve => {
37
+ requestAnimationFrame(resolve);
38
+ });
39
+ }
40
+ }
41
+
42
+
43
+ }
@@ -0,0 +1,8 @@
1
+ import Mixin from './mixin.js';
2
+ import { MainDomElement } from './main-dom-element.js';
3
+ import { NavElement } from './nav-element.js';
4
+
5
+ export {
6
+ Mixin,
7
+ MainDomElement,
8
+ NavElement};
File without changes
@@ -45,6 +45,7 @@ const NavElement = (superClass) => class extends superClass {
45
45
  } else if ( ele.tagName === 'OL' || ele.tagName === 'UL' ) {
46
46
  linkText = ele.getAttribute('link-text');
47
47
  href = ele.getAttribute('href');
48
+ isOpen = ele.hasAttribute('is-open');
48
49
 
49
50
  for (const child of Array.from(ele.children)) {
50
51
  let childItem = this._makeNavItemTree(child);
package/utils/index.js DELETED
@@ -1,14 +0,0 @@
1
- import Mixin from './mixin.js';
2
- import { MutationObserverElement } from './mutation-observer.js';
3
- import { MainDomElement } from './main-dom-element.js';
4
- import { BreakPoints } from './break-points.js';
5
- import { NavElement } from './nav-element.js';
6
- import { Wait } from './wait.js';
7
-
8
- export {
9
- Mixin,
10
- MutationObserverElement,
11
- MainDomElement,
12
- BreakPoints,
13
- Wait,
14
- NavElement};
@@ -1,51 +0,0 @@
1
- /**
2
- * @function MutationObserverElement
3
- * @param {Class} superClass - LitElement or child class.
4
- * @description add default functionality for mutation observer
5
- *
6
- * @returns {Class} LitElement with mutation observer attached.
7
- */
8
- const MutationObserverElement = (superClass) => class extends superClass {
9
-
10
- constructor() {
11
- super();
12
- this._childListObserver = null;
13
- }
14
-
15
- /**
16
- * @method firstUpdated
17
- * @description called on first DOM render. Call the _onChildListMutation method
18
- *
19
- * @param {Set} props
20
- */
21
- firstUpdated(props) {
22
- super.firstUpdated(props);
23
- this._onChildListMutation();
24
- }
25
-
26
- /**
27
- * @method connectedCallback
28
- * @description Native lifecycle method called when element is connected
29
- */
30
- connectedCallback(){
31
- super.connectedCallback();
32
- this._childListObserver = new MutationObserver(
33
- (mutationsList, observer) => this._onChildListMutation(mutationsList, observer));
34
- this._childListObserver.observe(this, {childList: true});
35
- }
36
-
37
- /**
38
- * @method disconnectedCallback
39
- * @description Native lifecycle method called when element is disconnected
40
- */
41
- disconnectedCallback(){
42
- this._childListObserver.disconnect();
43
- super.disconnectedCallback();
44
- }
45
-
46
- _onChildListMutation(){
47
- console.warn("You must create a '_onChildListMutation' method in your element to use the MutationObserverElement mixin");
48
- }
49
- };
50
-
51
- export {MutationObserverElement};
package/utils/wait.js DELETED
@@ -1,65 +0,0 @@
1
- /**
2
- * @function Wait
3
- * @param {Class} superClass - LitElement or child class.
4
- * @description Adds wait methods to Lit element
5
- *
6
- * @returns {Class} LitElement with Wait methods
7
- */
8
- const Wait = (superClass) => class extends superClass {
9
-
10
- /**
11
- * @method wait
12
- * @description Wait for the specified amount of time
13
- * @param {Number} time - Time to wait (ms)
14
- * @returns
15
- */
16
- async wait(time){
17
- return new Promise(resolve => {
18
- setTimeout(resolve, time);
19
- });
20
- }
21
-
22
- /**
23
- * @method waitForUpdate
24
- * @description Requests and waits for Lit update.
25
- */
26
- async waitForUpdate(){
27
- this.requestUpdate();
28
- await this.updateComplete;
29
- }
30
-
31
- /**
32
- * @method waitForFrames
33
- * @description Wait for specified number of animation frames
34
- * @param {Number} ct Number of frames
35
- */
36
- async waitForFrames(ct=1) {
37
- for (let i = 0; i < ct; i++) {
38
- await new Promise(resolve => {
39
- requestAnimationFrame(resolve);
40
- });
41
- }
42
- }
43
-
44
- /**
45
- * @method waitForAnimation
46
- * @description Wait for animation time designated by element
47
- * @returns {Promise}
48
- */
49
- async waitForAnimation() {
50
-
51
- let animationDuration = 0;
52
- if ( this.animationDuration ) {
53
- animationDuration = this.animationDuration;
54
- } else if (this._animationDuration) {
55
- animationDuration = this._animationDuration;
56
- } else {
57
- console.warn("animationDuration property not set!");
58
- }
59
-
60
- return new Promise(resolve => {
61
- setTimeout(resolve, animationDuration);
62
- });
63
- }
64
- };
65
- export {Wait};