@pacem/pacem-ui 1.0.0-abel

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 (56) hide show
  1. package/LICENSE +191 -0
  2. package/NOTICE +4 -0
  3. package/dist/browser/pacem-ui.js +6343 -0
  4. package/dist/browser/pacem-ui.js.map +1 -0
  5. package/dist/browser/pacem-ui.min.js +2 -0
  6. package/dist/browser/pacem-ui.min.js.map +1 -0
  7. package/dist/bundle/pacem-ui.min.mjs +168 -0
  8. package/dist/bundle/pacem-ui.mjs +6276 -0
  9. package/dist/bundle/pacem-ui.mjs.map +7 -0
  10. package/dist/esm/adapter.js +360 -0
  11. package/dist/esm/anchor.js +149 -0
  12. package/dist/esm/balloon.js +583 -0
  13. package/dist/esm/binder.js +678 -0
  14. package/dist/esm/blade.js +31 -0
  15. package/dist/esm/bottom-sheet.js +277 -0
  16. package/dist/esm/button.js +100 -0
  17. package/dist/esm/buttonset.js +41 -0
  18. package/dist/esm/calendar.js +662 -0
  19. package/dist/esm/collapse.js +72 -0
  20. package/dist/esm/dialog-abstractions.js +61 -0
  21. package/dist/esm/dialog.js +102 -0
  22. package/dist/esm/divider.js +48 -0
  23. package/dist/esm/icon.js +131 -0
  24. package/dist/esm/image.js +109 -0
  25. package/dist/esm/index-components-ui.js +41 -0
  26. package/dist/esm/index-components.js +1 -0
  27. package/dist/esm/index-iife.js +3 -0
  28. package/dist/esm/index.js +1 -0
  29. package/dist/esm/infinite-scroller.js +137 -0
  30. package/dist/esm/iterative.js +45 -0
  31. package/dist/esm/lightbox-abstractions.js +6 -0
  32. package/dist/esm/lightbox.js +203 -0
  33. package/dist/esm/loader.js +100 -0
  34. package/dist/esm/markdown-svc.js +235 -0
  35. package/dist/esm/markdown.js +35 -0
  36. package/dist/esm/marquee.js +87 -0
  37. package/dist/esm/media-query.js +85 -0
  38. package/dist/esm/menu.js +165 -0
  39. package/dist/esm/pager.js +111 -0
  40. package/dist/esm/picture.js +157 -0
  41. package/dist/esm/progressbar.js +54 -0
  42. package/dist/esm/sidebar.js +60 -0
  43. package/dist/esm/slideshow.js +27 -0
  44. package/dist/esm/social-twitter.js +39 -0
  45. package/dist/esm/sticky-header.js +113 -0
  46. package/dist/esm/tabs.js +187 -0
  47. package/dist/esm/ticker.js +78 -0
  48. package/dist/esm/toast.js +171 -0
  49. package/dist/esm/toc.js +171 -0
  50. package/dist/esm/tuner.js +200 -0
  51. package/dist/esm/types.js +7 -0
  52. package/dist/esm/vibration.js +33 -0
  53. package/dist/esm/view.js +206 -0
  54. package/dist/esm/window.js +181 -0
  55. package/package.json +38 -0
  56. package/typings/index.d.ts +1165 -0
@@ -0,0 +1,187 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ import { P, PCSS, CustomElement, Watch, ViewChild, PropertyConverters, Components, Utils, PropertyChangeEvent, Animations } from '@pacem/pacem-core';
8
+ import { AdapterOrientation } from './adapter';
9
+ //namespace Pacem.Components.UI {
10
+ const PACEM_TAB_FOCUS_CSS = 'tab-focus';
11
+ const StringOrNodePropertyConverter = {
12
+ convert: (attr, e) => {
13
+ return attr.startsWith('#') ? PropertyConverters.Element.convert(attr, e) : PropertyConverters.String.convert(attr, e);
14
+ },
15
+ convertBack: (prop, e) => {
16
+ return (prop instanceof Node) ? PropertyConverters.Element.convertBack(prop, e) : PropertyConverters.String.convertBack(prop, e);
17
+ },
18
+ retryConversionWhenReady: true
19
+ };
20
+ let PacemTabElement = class PacemTabElement extends Components.PacemIterableElement {
21
+ constructor() {
22
+ super('tab');
23
+ this._slotChangeHandler = (_) => {
24
+ const old = this.#content;
25
+ const val = this.#content = this.content;
26
+ this.dispatchEvent(new PropertyChangeEvent({ propertyName: 'content', currentValue: val, oldValue: old }));
27
+ };
28
+ }
29
+ viewActivatedCallback() {
30
+ super.viewActivatedCallback();
31
+ this._slotLabel.addEventListener('slotchange', this._slotChangeHandler, false);
32
+ }
33
+ disconnectedCallback() {
34
+ const lbl = this._slotLabel;
35
+ if (!Utils.isNull(lbl)) {
36
+ lbl.removeEventListener('slotchange', this._slotChangeHandler, false);
37
+ }
38
+ super.disconnectedCallback();
39
+ }
40
+ #content;
41
+ get content() {
42
+ return this.querySelectorAll('*[slot=label]');
43
+ }
44
+ };
45
+ __decorate([
46
+ ViewChild('slot[name=label]')
47
+ ], PacemTabElement.prototype, "_slotLabel", void 0);
48
+ __decorate([
49
+ Watch({ converter: StringOrNodePropertyConverter })
50
+ ], PacemTabElement.prototype, "label", void 0);
51
+ __decorate([
52
+ Watch({ converter: PropertyConverters.String })
53
+ ], PacemTabElement.prototype, "key", void 0);
54
+ PacemTabElement = __decorate([
55
+ CustomElement({
56
+ tagName: P + '-tab', shadow: true, template: `<slot name="label" part="label"></slot><slot></slot>`
57
+ })
58
+ ], PacemTabElement);
59
+ export { PacemTabElement };
60
+ let PacemTabsElement = class PacemTabsElement extends Components.PacemIterativeElement {
61
+ constructor(_tweener = new Animations.TweenService()) {
62
+ super("tablist");
63
+ this._tweener = _tweener;
64
+ }
65
+ _labelCallback(item, index) {
66
+ const content = item.content;
67
+ if (content.length > 0) {
68
+ let assembled = '';
69
+ content.forEach((node) => {
70
+ assembled += node.outerHTML;
71
+ });
72
+ return assembled;
73
+ }
74
+ if (item.label instanceof Node) {
75
+ return item.label;
76
+ }
77
+ return `<span class="${(item.key || 'tab')}">${item.label}</span>`;
78
+ }
79
+ _syncOrientation(val = this.orientation) {
80
+ if (!Utils.isNull(this._defaultTabAdapter)) {
81
+ this._defaultTabAdapter.orientation = val;
82
+ }
83
+ if (!Utils.isNull(this._tabs)) {
84
+ const fn = val === AdapterOrientation.Vertical ? Utils.addClass : Utils.removeClass;
85
+ fn(this._tabs, 'tabs-vertical');
86
+ }
87
+ }
88
+ _syncVisibility(val = this.index, old = -1) {
89
+ const timeout = 500;
90
+ // lock height
91
+ const container = this._container, height = container.clientHeight;
92
+ const style = getComputedStyle(container), padding = style.boxSizing === 'border-box' ? 0 : parseInt(style.paddingTop) + parseInt(style.paddingBottom);
93
+ container.style.height = (height - padding) + 'px';
94
+ let ndx = 0;
95
+ for (let tab of this.items || []) {
96
+ if (ndx === val) {
97
+ Utils.addClass(tab, 'tab-in');
98
+ requestAnimationFrame(() => {
99
+ // wait for visibility digestion
100
+ Utils.addClass(tab, PACEM_TAB_FOCUS_CSS);
101
+ Utils.removeClass(tab, 'tab-in');
102
+ Utils.addAnimationEndCallback(tab, (t) => {
103
+ Utils.removeClass(t, 'tab-previous tab-next');
104
+ const tgetH = Utils.offset(t).height /* + padding*/;
105
+ this._tweener.run(parseInt(container.style.height), tgetH, 100, 0, Animations.Easings.sineOut, (_, v) => {
106
+ container.style.height = Math.round(v) + 'px';
107
+ })
108
+ .then(_ => {
109
+ // unlock height
110
+ container.style.height = '';
111
+ });
112
+ }, timeout);
113
+ });
114
+ tab.aria.attributes.set('selected', 'true');
115
+ }
116
+ else {
117
+ Utils.removeClass(tab, 'tab-previous tab-next');
118
+ Utils.addClass(tab, ndx < val ? 'tab-previous' : 'tab-next');
119
+ if (ndx === old) {
120
+ Utils.addClass(tab, 'tab-out');
121
+ Utils.removeClass(tab, PACEM_TAB_FOCUS_CSS);
122
+ Utils.addAnimationEndCallback(tab, (t) => {
123
+ Utils.removeClass(t, 'tab-out');
124
+ }, timeout);
125
+ tab.aria.attributes.set('selected', 'false');
126
+ }
127
+ }
128
+ ndx++;
129
+ }
130
+ }
131
+ viewActivatedCallback() {
132
+ super.viewActivatedCallback();
133
+ //this._defaultTabAdapter.labelCallback = this._labelCallback;
134
+ if (Utils.isNull(this.adapter)) {
135
+ this._syncOrientation();
136
+ this._syncVisibility();
137
+ this.adapter = this._defaultTabAdapter;
138
+ }
139
+ }
140
+ propertyChangedCallback(name, old, val, first) {
141
+ super.propertyChangedCallback(name, old, val, first);
142
+ switch (name) {
143
+ case 'adapter':
144
+ if (Utils.isNull(val)) {
145
+ this.adapter = this._defaultTabAdapter;
146
+ }
147
+ this._isUsingDefaultTabAdapter = this.adapter === this._defaultTabAdapter;
148
+ break;
149
+ case 'index':
150
+ this._syncVisibility(val, old);
151
+ break;
152
+ case 'orientation':
153
+ this._syncOrientation(val);
154
+ break;
155
+ }
156
+ }
157
+ validate(item) {
158
+ return item instanceof PacemTabElement;
159
+ }
160
+ };
161
+ __decorate([
162
+ ViewChild(P + '-adapter')
163
+ ], PacemTabsElement.prototype, "_defaultTabAdapter", void 0);
164
+ __decorate([
165
+ ViewChild('.' + PCSS + '-tabs')
166
+ ], PacemTabsElement.prototype, "_tabs", void 0);
167
+ __decorate([
168
+ ViewChild('.' + PCSS + '-tabs-content')
169
+ ], PacemTabsElement.prototype, "_container", void 0);
170
+ __decorate([
171
+ Watch()
172
+ ], PacemTabsElement.prototype, "_isUsingDefaultTabAdapter", void 0);
173
+ __decorate([
174
+ Watch({ converter: PropertyConverters.String })
175
+ ], PacemTabsElement.prototype, "orientation", void 0);
176
+ PacemTabsElement = __decorate([
177
+ CustomElement({
178
+ tagName: P + '-tabs', shadow: false,
179
+ template: `<div class="${PCSS}-tabs">
180
+ <${P}-adapter class="${PCSS}-tabs-adapter" swipe-enabled="false" hide="{{ !:host._isUsingDefaultTabAdapter }}" label-callback="{{ :host._labelCallback }}"></${P}-adapter>
181
+ <div class="${PCSS}-tabs-content">
182
+ <${P}-content></${P}-content>
183
+ </div>
184
+ </div>`
185
+ })
186
+ ], PacemTabsElement);
187
+ export { PacemTabsElement };
@@ -0,0 +1,78 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ import { P, CustomElement, ViewChild, Components, Utils } from '@pacem/pacem-core';
8
+ //namespace Pacem.Components.UI {
9
+ let PacemTickerElement = class PacemTickerElement extends Components.PacemSafeContentElement {
10
+ constructor() {
11
+ super(...arguments);
12
+ this._contentChangeHandler = (evt) => {
13
+ this._incoming.replaceChildren(...this.#newContent);
14
+ Utils.addClass(this, 'ticking');
15
+ Utils.addAnimationEndCallback(this._incoming, element => {
16
+ Utils.removeClass(this, 'ticking');
17
+ // swap content
18
+ this._outgoing.replaceChildren(...this.#newContent);
19
+ //this.#newContent = null;
20
+ });
21
+ };
22
+ }
23
+ #newContent;
24
+ _tickContent(content = this.content) {
25
+ if (typeof content === 'number') {
26
+ content = content.toLocaleString();
27
+ }
28
+ if (typeof content === 'string') {
29
+ const safeContent = this.sanitize(content);
30
+ this.#newContent = this._buildMarkupNode(safeContent);
31
+ }
32
+ else if (content instanceof Node) {
33
+ const safeContent = this.sanitize(content);
34
+ this.replaceChildren(...(this.#newContent = [safeContent]));
35
+ }
36
+ else {
37
+ const safeContent = content.map(a => this.sanitize(a));
38
+ this.replaceChildren(...(this.#newContent = safeContent));
39
+ }
40
+ }
41
+ _buildMarkupNode(html) {
42
+ const tmpl = document.createElement('template');
43
+ tmpl.innerHTML = html;
44
+ return Array.from(tmpl.content.childNodes);
45
+ }
46
+ propertyChangedCallback(name, old, val, first) {
47
+ super.propertyChangedCallback(name, old, val, first);
48
+ if (name === 'content' && !first) {
49
+ this._tickContent(val);
50
+ }
51
+ }
52
+ viewActivatedCallback() {
53
+ super.viewActivatedCallback();
54
+ this._slot.addEventListener('slotchange', this._contentChangeHandler, false);
55
+ const content = this.content ?? this._slot.assignedNodes();
56
+ this._tickContent(content);
57
+ }
58
+ disconnectedCallback() {
59
+ const slot = this._slot;
60
+ if (!Utils.isNull(slot)) {
61
+ slot.removeEventListener('slotchange', this._contentChangeHandler);
62
+ }
63
+ super.disconnectedCallback();
64
+ }
65
+ };
66
+ __decorate([
67
+ ViewChild('slot')
68
+ ], PacemTickerElement.prototype, "_slot", void 0);
69
+ __decorate([
70
+ ViewChild('div[part=ticker-outgoing]')
71
+ ], PacemTickerElement.prototype, "_outgoing", void 0);
72
+ __decorate([
73
+ ViewChild('div[part=ticker-incoming]')
74
+ ], PacemTickerElement.prototype, "_incoming", void 0);
75
+ PacemTickerElement = __decorate([
76
+ CustomElement({ tagName: P + '-ticker', shadow: true, template: `<div part="ticker-outgoing"></div><div part="ticker-incoming"></div><slot hidden></slot>` })
77
+ ], PacemTickerElement);
78
+ export { PacemTickerElement };
@@ -0,0 +1,171 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var PacemToastElement_1;
8
+ import { P, PCSS, CustomElement, Watch, Components, Utils, PropertyConverters, CustomElementUtils, Transformer } from '@pacem/pacem-core';
9
+ //namespace Pacem.Components.UI {
10
+ const PACEM_TOAST_POPS = "pacem:toast:pops";
11
+ let PacemToastElement = PacemToastElement_1 = class PacemToastElement extends Components.PacemElement {
12
+ constructor() {
13
+ super(...arguments);
14
+ this.autohide = true;
15
+ this.timeout = 3000;
16
+ this._doHide = (evt) => {
17
+ window.clearTimeout(this._handle);
18
+ this.show = false;
19
+ };
20
+ }
21
+ connectedCallback() {
22
+ super.connectedCallback();
23
+ this.addEventListener('click', this._doHide, false);
24
+ }
25
+ propertyChangedCallback(name, old, val, first) {
26
+ super.propertyChangedCallback(name, old, val, first);
27
+ if (name === 'show') {
28
+ if (val !== true) {
29
+ Utils.removeClass(this, 'toast-show');
30
+ Utils.addClass(this, 'toast-hide');
31
+ this.dispatchEvent(new CustomEvent('close'));
32
+ Utils.waitForAnimationEnd(this, 1000).then(() => {
33
+ Utils.removeClass(this, 'toast-hide');
34
+ });
35
+ }
36
+ else {
37
+ let order = CustomElementUtils.getAttachedPropertyValue(PacemToastElement_1, PACEM_TOAST_POPS, 0) - 1;
38
+ CustomElementUtils.setAttachedPropertyValue(PacemToastElement_1, PACEM_TOAST_POPS, order);
39
+ this.style.order = '' + order;
40
+ Utils.addClass(this, 'toast-show');
41
+ this._show();
42
+ }
43
+ }
44
+ }
45
+ disconnectedCallback() {
46
+ this.removeEventListener('click', this._doHide, false);
47
+ super.disconnectedCallback();
48
+ }
49
+ _show() {
50
+ window.clearTimeout(this._handle);
51
+ if (this.disabled) {
52
+ return;
53
+ }
54
+ if (this.autohide) {
55
+ this._handle = window.setTimeout(() => { this.show = false; }, this.timeout);
56
+ }
57
+ }
58
+ popup() {
59
+ if (this.show) {
60
+ this._show();
61
+ }
62
+ else {
63
+ this.show = true;
64
+ }
65
+ }
66
+ /**
67
+ * Opinionated shortcut/utility for toast spinning.
68
+ * @param toaster Toast container
69
+ * @param level Message criticity level
70
+ * @param message The message
71
+ * @param options Further options object
72
+ */
73
+ static toast(toaster, level, message, options) {
74
+ var toast = new PacemToastElement_1();
75
+ if (!Utils.isNullOrEmpty(options?.cssClass)) {
76
+ const cssClass = Utils.isArray(options.cssClass) ? options.cssClass.join(' ') : options.cssClass;
77
+ Utils.addClass(toast, cssClass);
78
+ }
79
+ else {
80
+ toast.className = 'toast-' + level;
81
+ }
82
+ if (!Utils.isNull(options?.autohide)) {
83
+ toast.autohide = options.autohide;
84
+ }
85
+ if (options?.timeout > 0) {
86
+ toast.timeout = options.timeout;
87
+ }
88
+ // icon
89
+ const icon = document.createElement('i');
90
+ icon.className = PCSS + '-icon text-bigger-steady ' + PCSS + '-margin margin-right-1 flex-auto';
91
+ var ligature = 'info';
92
+ switch (level) {
93
+ case 'danger':
94
+ case 'error':
95
+ ligature = 'error';
96
+ break;
97
+ case 'warning':
98
+ ligature = 'warning';
99
+ break;
100
+ case 'success':
101
+ ligature = 'check_circle';
102
+ break;
103
+ }
104
+ icon.textContent = ligature;
105
+ const container = document.createElement('div');
106
+ Utils.addClass(container, 'display-flex flex-stretch flex-start flex-nowrap');
107
+ container.appendChild(icon);
108
+ // caption
109
+ const caption = document.createElement('span');
110
+ Utils.addClass(caption, 'text-small text-pre');
111
+ if (typeof message === 'string') {
112
+ caption.innerHTML = message;
113
+ }
114
+ else {
115
+ caption.appendChild(message);
116
+ }
117
+ container.appendChild(caption);
118
+ toast.appendChild(container);
119
+ toaster.appendChild(toast);
120
+ // promise
121
+ return new Promise((resolve, _) => {
122
+ window.setTimeout(() => {
123
+ toast.popup();
124
+ }, // needs some time to digest
125
+ // state and transition
126
+ 100);
127
+ const callback = () => {
128
+ toast.removeEventListener('close', callback, false);
129
+ resolve();
130
+ Utils.waitForAnimationEnd(toast, 1000).then(_ => {
131
+ toast.remove();
132
+ });
133
+ };
134
+ toast.addEventListener('close', callback, false);
135
+ });
136
+ }
137
+ static toast2(toaster, level, message, options) {
138
+ let cssClass = options?.cssClass;
139
+ let cssArray = ['fill-' + level + '-container', 'fill-glass', 'border-solid', 'border-size--2', 'border-round', 'border-radius--6'];
140
+ if (!Utils.isNullOrEmpty(cssClass)) {
141
+ if (Utils.isArray(cssClass)) {
142
+ Array.prototype.push.apply(cssArray, cssClass);
143
+ }
144
+ else {
145
+ Array.prototype.push.apply(cssArray, cssClass.split(' '));
146
+ }
147
+ }
148
+ return PacemToastElement_1.toast(toaster, level, message, Utils.extend({}, options ?? {}, { cssClass: cssArray }));
149
+ }
150
+ };
151
+ __decorate([
152
+ Watch({ emit: false, converter: PropertyConverters.Boolean })
153
+ ], PacemToastElement.prototype, "autohide", void 0);
154
+ __decorate([
155
+ Watch({ emit: false, converter: PropertyConverters.Number })
156
+ ], PacemToastElement.prototype, "timeout", void 0);
157
+ __decorate([
158
+ Watch({ converter: PropertyConverters.Boolean })
159
+ ], PacemToastElement.prototype, "show", void 0);
160
+ __decorate([
161
+ Transformer("poptoast")
162
+ ], PacemToastElement, "toast", null);
163
+ __decorate([
164
+ Transformer("poptoastcontainer")
165
+ ], PacemToastElement, "toast2", null);
166
+ PacemToastElement = PacemToastElement_1 = __decorate([
167
+ CustomElement({
168
+ tagName: P + '-toast'
169
+ })
170
+ ], PacemToastElement);
171
+ export { PacemToastElement };
@@ -0,0 +1,171 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ import { P, PCSS, CustomElement, Watch, ViewChild, Components, Utils, PropertyConverters, Defaults, Animations, Debounce, avoidHandler } from '@pacem/pacem-core';
8
+ //namespace Components.UI {
9
+ let PacemTocElement = class PacemTocElement extends Components.PacemElement {
10
+ constructor(_tweener = new Animations.TweenService()) {
11
+ super();
12
+ this._tweener = _tweener;
13
+ this._items = [];
14
+ this._scrollToSelf = (evt) => {
15
+ this._scrollTo('#' + evt.target.id);
16
+ };
17
+ this._hashChange = (evt) => {
18
+ evt.preventDefault();
19
+ this._scrollTo(window.location.hash, false);
20
+ };
21
+ }
22
+ propertyChangedCallback(name, old, val, first) {
23
+ super.propertyChangedCallback(name, old, val, first);
24
+ // url
25
+ switch (name) {
26
+ case 'target':
27
+ if (!Utils.isNull(this._observer))
28
+ this._observe();
29
+ break;
30
+ case 'selector':
31
+ this.refresh();
32
+ break;
33
+ }
34
+ }
35
+ connectedCallback() {
36
+ super.connectedCallback();
37
+ window.addEventListener('hashchange', this._hashChange, false);
38
+ }
39
+ disconnectedCallback() {
40
+ window.removeEventListener('hashchange', this._hashChange, false);
41
+ if (!Utils.isNull(this._observer))
42
+ this._observer.disconnect();
43
+ super.disconnectedCallback();
44
+ }
45
+ viewActivatedCallback() {
46
+ super.viewActivatedCallback();
47
+ this._observer = new MutationObserver((e) => { this.refresh(); });
48
+ this._observe();
49
+ }
50
+ _onScroll(evt) {
51
+ this._update(Utils.scrollTop);
52
+ }
53
+ _observe() {
54
+ this._observer.observe(this.target || document.body, { subtree: true, childList: true });
55
+ }
56
+ _getTop(dom) {
57
+ return Utils.offset(dom).top;
58
+ }
59
+ _scrollTo(selector, tween = true) {
60
+ if (/^#[^&=]+$/.test(selector)) {
61
+ const dom = !Utils.isNullOrEmpty(selector) && document.querySelector(selector), item = !Utils.isNull(dom) && this._items.find(i => i.dom === dom);
62
+ if (item && !Utils.isNull(item.dom)) {
63
+ const tget = this._getTop(item.dom) - (this.offset || 0);
64
+ if (tween) {
65
+ let from = Utils.scrollTop;
66
+ window.location.hash = item.dom.id;
67
+ this._tweener.run(from, tget, 500, 0, Animations.Easings.sineInOut, (t, v) => {
68
+ window.scrollTo(0, v);
69
+ });
70
+ }
71
+ else {
72
+ window.scrollTo(0, tget);
73
+ }
74
+ }
75
+ }
76
+ }
77
+ _startScrollTo(item, evt) {
78
+ avoidHandler(evt);
79
+ this._scrollTo(item.url);
80
+ }
81
+ _update(top) {
82
+ // pick focused item (fallback: first item)
83
+ const zero = top + (this.offset || 0);
84
+ var current = this._items && this._items.length > 0 && this._items[0];
85
+ for (var item of this._items) {
86
+ if (Utils.offset(item.dom).top <= zero)
87
+ current = item;
88
+ else
89
+ break;
90
+ }
91
+ // update css
92
+ const datasource = [];
93
+ for (var item of this._items) {
94
+ if (Utils.isNullOrEmpty(item.dom.id)) {
95
+ item.dom.id = item.dom.innerText.trim().replace(/[^a-zA-Z0-9]/g, '-').replace(/-*$/, '').replace(/^-*/, '').toLowerCase();
96
+ }
97
+ datasource.push({ focus: item === current, label: item.dom.innerText, url: '#' + item.dom.id });
98
+ }
99
+ if (!Utils.isNull(this._repeater))
100
+ this._repeater.datasource = datasource;
101
+ }
102
+ /** DOM might change while interacting with the page, this method allows extemporary resets. */
103
+ refresh() {
104
+ // reset items
105
+ for (let item of this._items) {
106
+ item.dom.removeEventListener('click', this._scrollToSelf, false);
107
+ Utils.removeClass(item.dom, PCSS + '-toc-item');
108
+ }
109
+ //
110
+ const selector = this.selector;
111
+ if (Utils.isNullOrEmpty(selector)) {
112
+ this._repeater && (this._repeater.datasource = []);
113
+ this.hasContent = false;
114
+ return;
115
+ }
116
+ const items = (this.target || document).querySelectorAll(selector), elements = [];
117
+ for (let j = 0; j < items.length; j++) {
118
+ const dom = items.item(j);
119
+ dom.addEventListener('click', this._scrollToSelf, false);
120
+ Utils.addClass(dom, PCSS + '-toc-item');
121
+ elements.push({ dom: dom, top: this._getTop(dom) });
122
+ }
123
+ // bootstrap TOC
124
+ this._items = elements;
125
+ this._update(Utils.scrollTop);
126
+ this.hasContent = !Utils.isNullOrEmpty(elements);
127
+ // initial state
128
+ let initialTarget = window.location.hash;
129
+ if (!Utils.isNullOrEmpty(initialTarget)) {
130
+ // in case of hash
131
+ setTimeout(() => {
132
+ this._scrollTo(initialTarget, true);
133
+ }, 1000);
134
+ }
135
+ }
136
+ };
137
+ __decorate([
138
+ Watch({ emit: false, converter: PropertyConverters.String })
139
+ ], PacemTocElement.prototype, "selector", void 0);
140
+ __decorate([
141
+ Watch({ emit: false, converter: PropertyConverters.Number })
142
+ ], PacemTocElement.prototype, "offset", void 0);
143
+ __decorate([
144
+ Watch({ emit: false, converter: PropertyConverters.Element })
145
+ ], PacemTocElement.prototype, "target", void 0);
146
+ __decorate([
147
+ Watch({ converter: PropertyConverters.Element })
148
+ ], PacemTocElement.prototype, "router", void 0);
149
+ __decorate([
150
+ Watch({ converter: PropertyConverters.Boolean })
151
+ ], PacemTocElement.prototype, "hasContent", void 0);
152
+ __decorate([
153
+ ViewChild(P + '-repeater')
154
+ ], PacemTocElement.prototype, "_repeater", void 0);
155
+ __decorate([
156
+ Debounce(100)
157
+ ], PacemTocElement.prototype, "_onScroll", null);
158
+ __decorate([
159
+ Debounce(250)
160
+ /** DOM might change while interacting with the page, this method allows extemporary resets. */
161
+ ], PacemTocElement.prototype, "refresh", null);
162
+ PacemTocElement = __decorate([
163
+ CustomElement({
164
+ tagName: P + '-toc', shadow: Defaults.USE_SHADOW_ROOT,
165
+ template: `<${P}-scroll-aware on-${Components.ScrollEventName}=":host._onScroll($event)" url="{{ :host.url }}"></${P}-scroll-aware>
166
+ <${P}-repeater><nav class="${PCSS}-toc"><template>
167
+ <${P}-a on-click=":host._startScrollTo(^item, $event)" router="{{ :host.router }}" css-class="{{ {'toc-focus': ^item.focus} }}" href="{{ ^item.url }}"><${P}-text text="{{ ^item.label }}"></${P}-text></${P}-a>
168
+ </template></nav></${P}-repeater>`
169
+ })
170
+ ], PacemTocElement);
171
+ export { PacemTocElement };