@wpmoo/ui 1.1.0-dev.1 → 1.2.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.
- package/ASSET_LICENSE.md +1 -1
- package/README.md +4 -6
- package/certification.json +2 -1
- package/dist/assets/css/moo-ui.css +140 -1
- package/dist/assets/css/moo-ui.min.css +2 -2
- package/dist/assets/css/moo.css +140 -1
- package/dist/assets/css/moo.min.css +2 -2
- package/dist/js/chart.js +1 -1
- package/dist/js/chart.min.js +1 -1
- package/dist/js/combobox.js +1 -1
- package/dist/js/context-menu.js +1 -1
- package/dist/js/datatable.js +1 -1
- package/dist/js/datepicker.js +1 -1
- package/dist/js/datepicker.min.js +1 -1
- package/dist/js/moo-ui.js +2 -2
- package/dist/js/moo-ui.min.js +1 -1
- package/dist/js/sheet.js +1 -1
- package/dist/js/sidebar.js +1 -1
- package/dist/js/slider.js +1 -1
- package/dist/js/state.js +1 -1
- package/dist/js/table-of-contents.js +3 -188
- package/dist/js/toc.js +195 -0
- package/dist/release-manifest.json +4 -4
- package/package.json +3 -1
- package/scss/_components.scss +1 -0
- package/scss/components/_empty.scss +60 -0
- package/scss/components/_tabs.scss +8 -0
- package/scss/layouts/_app.scss +33 -0
- package/scss/mixins/_banner.scss +1 -1
- package/scss/settings/_component_variables.scss +1 -0
package/dist/js/chart.js
CHANGED
package/dist/js/chart.min.js
CHANGED
package/dist/js/combobox.js
CHANGED
package/dist/js/context-menu.js
CHANGED
package/dist/js/datatable.js
CHANGED
package/dist/js/datepicker.js
CHANGED
package/dist/js/moo-ui.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* Moo UI moo-ui.js v1.
|
|
2
|
+
* Moo UI moo-ui.js v1.2.0 (https://wpmoo.org/)
|
|
3
3
|
* Copyright 2026 WPMoo Authors
|
|
4
4
|
* Licensed under MIT (https://github.com/wpmoo-org/ui/blob/main/LICENSE)
|
|
5
5
|
*/
|
|
@@ -3876,7 +3876,7 @@ var MooSlider = class _MooSlider {
|
|
|
3876
3876
|
}
|
|
3877
3877
|
};
|
|
3878
3878
|
|
|
3879
|
-
// src/js/components/
|
|
3879
|
+
// src/js/components/toc.js
|
|
3880
3880
|
var instances6 = /* @__PURE__ */ new WeakMap();
|
|
3881
3881
|
var ownerSelector = '.moo-ui[data-bs-theme="light"], .moo-ui[data-bs-theme="dark"]';
|
|
3882
3882
|
function activationOffset(options, previous = 0) {
|
package/dist/js/moo-ui.min.js
CHANGED
package/dist/js/sheet.js
CHANGED
package/dist/js/sidebar.js
CHANGED
package/dist/js/slider.js
CHANGED
package/dist/js/state.js
CHANGED
|
@@ -1,195 +1,10 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* Moo UI table-of-contents.js v1.
|
|
2
|
+
* Moo UI table-of-contents.js v1.2.0 (https://wpmoo.org/)
|
|
3
3
|
* Copyright 2026 WPMoo Authors
|
|
4
4
|
* Licensed under MIT (https://github.com/wpmoo-org/ui/blob/main/LICENSE)
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
const ownerSelector = '.moo-ui[data-bs-theme="light"], .moo-ui[data-bs-theme="dark"]';
|
|
9
|
-
function activationOffset(options, previous = 0) {
|
|
10
|
-
if (!options || typeof options !== "object" || Array.isArray(options)) {
|
|
11
|
-
throw new TypeError("TableOfContents options must be an object.");
|
|
12
|
-
}
|
|
13
|
-
const value = options.activationOffset === void 0 ? previous : options.activationOffset;
|
|
14
|
-
if (typeof value !== "number" || !Number.isFinite(value) || value < 0) {
|
|
15
|
-
throw new TypeError("TableOfContents activationOffset must be a finite nonnegative number.");
|
|
16
|
-
}
|
|
17
|
-
return value;
|
|
18
|
-
}
|
|
19
|
-
function fragmentId(href) {
|
|
20
|
-
if (!href?.startsWith("#") || href.length === 1) return null;
|
|
21
|
-
try {
|
|
22
|
-
return decodeURIComponent(href.slice(1));
|
|
23
|
-
} catch {
|
|
24
|
-
return null;
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
class TableOfContents {
|
|
28
|
-
static getInstance(element) {
|
|
29
|
-
return element?.nodeType === 1 ? instances.get(element) || null : null;
|
|
30
|
-
}
|
|
31
|
-
static getOrCreateInstance(element, options = {}) {
|
|
32
|
-
return TableOfContents.getInstance(element) || new TableOfContents(element, options);
|
|
33
|
-
}
|
|
34
|
-
constructor(element, options = {}) {
|
|
35
|
-
if (element?.nodeType !== 1 || !element.matches("[data-toc]")) {
|
|
36
|
-
throw new TypeError("TableOfContents requires a [data-toc] root element.");
|
|
37
|
-
}
|
|
38
|
-
const existing = instances.get(element);
|
|
39
|
-
if (existing) return existing;
|
|
40
|
-
this._element = element;
|
|
41
|
-
this._document = element.ownerDocument;
|
|
42
|
-
this._window = this._document.defaultView;
|
|
43
|
-
this._offset = activationOffset(options);
|
|
44
|
-
this._listeners = [];
|
|
45
|
-
this._originalLinks = /* @__PURE__ */ new Map();
|
|
46
|
-
this._originalStatus = /* @__PURE__ */ new Map();
|
|
47
|
-
this._originalMarker = {
|
|
48
|
-
attribute: element.getAttribute("data-toc-marker"),
|
|
49
|
-
properties: ["--moo-toc-marker-offset", "--moo-toc-marker-height"].map((name) => ({
|
|
50
|
-
name,
|
|
51
|
-
value: element.style.getPropertyValue(name),
|
|
52
|
-
priority: element.style.getPropertyPriority(name)
|
|
53
|
-
}))
|
|
54
|
-
};
|
|
55
|
-
this._links = [];
|
|
56
|
-
this._targets = [];
|
|
57
|
-
this._frame = 0;
|
|
58
|
-
this._disposed = false;
|
|
59
|
-
instances.set(element, this);
|
|
60
|
-
this.refresh();
|
|
61
|
-
}
|
|
62
|
-
refresh(options = {}) {
|
|
63
|
-
if (this._disposed) return this;
|
|
64
|
-
const offset = activationOffset(options, this._offset);
|
|
65
|
-
this._clearListeners();
|
|
66
|
-
this._offset = offset;
|
|
67
|
-
const owner = this._element.closest(ownerSelector);
|
|
68
|
-
const contentId = this._element.getAttribute("data-toc-content");
|
|
69
|
-
const scope = contentId ? this._document.getElementById(contentId) : owner;
|
|
70
|
-
const rootId = this._element.getAttribute("data-toc-scroll-root");
|
|
71
|
-
this._scrollElement = rootId ? this._document.getElementById(rootId) : null;
|
|
72
|
-
this._status = Array.from(this._element.querySelectorAll("[data-toc-current]")).find((node) => node.closest("[data-toc]") === this._element) || null;
|
|
73
|
-
if (this._status && !this._originalStatus.has(this._status)) {
|
|
74
|
-
this._originalStatus.set(this._status, this._status.textContent);
|
|
75
|
-
}
|
|
76
|
-
this._overview = this._status ? this._originalStatus.get(this._status) : "";
|
|
77
|
-
this._links = Array.from(this._element.querySelectorAll('a[href^="#"]')).filter((link) => link.closest("[data-toc]") === this._element).map((link) => ({ link, id: fragmentId(link.getAttribute("href")) }));
|
|
78
|
-
this._links.forEach(({ link }) => {
|
|
79
|
-
if (!this._originalLinks.has(link)) {
|
|
80
|
-
this._originalLinks.set(link, {
|
|
81
|
-
active: link.classList.contains("active"),
|
|
82
|
-
current: link.getAttribute("aria-current")
|
|
83
|
-
});
|
|
84
|
-
}
|
|
85
|
-
});
|
|
86
|
-
this._targets = [];
|
|
87
|
-
this._activate(null);
|
|
88
|
-
if (!owner || !scope || scope.closest(ownerSelector) !== owner || rootId && (!this._scrollElement || !this._scrollElement.contains(scope))) {
|
|
89
|
-
return this;
|
|
90
|
-
}
|
|
91
|
-
const seen = /* @__PURE__ */ new Set();
|
|
92
|
-
this._links.forEach(({ id, link }) => {
|
|
93
|
-
const target = id ? this._document.getElementById(id) : null;
|
|
94
|
-
if (!target || seen.has(id) || !scope.contains(target) || target.closest(ownerSelector) !== owner) return;
|
|
95
|
-
seen.add(id);
|
|
96
|
-
this._targets.push({ id, target, label: link.textContent.trim() });
|
|
97
|
-
});
|
|
98
|
-
if (!this._targets.length) return this;
|
|
99
|
-
const queue = () => this._requestUpdate();
|
|
100
|
-
this._listen(this._scrollElement || this._window, "scroll", queue, { passive: true });
|
|
101
|
-
this._listen(this._window, "resize", queue);
|
|
102
|
-
this._listen(this._window, "hashchange", queue);
|
|
103
|
-
this._listen(this._element, "click", queue);
|
|
104
|
-
this._update();
|
|
105
|
-
return this;
|
|
106
|
-
}
|
|
107
|
-
dispose() {
|
|
108
|
-
if (this._disposed) return;
|
|
109
|
-
this._disposed = true;
|
|
110
|
-
this._clearListeners();
|
|
111
|
-
this._originalLinks.forEach(({ active, current }, link) => {
|
|
112
|
-
link.classList.toggle("active", active);
|
|
113
|
-
if (current === null) link.removeAttribute("aria-current");
|
|
114
|
-
else link.setAttribute("aria-current", current);
|
|
115
|
-
});
|
|
116
|
-
this._originalStatus.forEach((text, node) => {
|
|
117
|
-
node.textContent = text;
|
|
118
|
-
});
|
|
119
|
-
const { attribute, properties } = this._originalMarker;
|
|
120
|
-
if (attribute === null) this._element.removeAttribute("data-toc-marker");
|
|
121
|
-
else this._element.setAttribute("data-toc-marker", attribute);
|
|
122
|
-
properties.forEach(({ name, value, priority }) => {
|
|
123
|
-
if (value) this._element.style.setProperty(name, value, priority);
|
|
124
|
-
else this._element.style.removeProperty(name);
|
|
125
|
-
});
|
|
126
|
-
this._originalLinks.clear();
|
|
127
|
-
this._originalStatus.clear();
|
|
128
|
-
this._targets = [];
|
|
129
|
-
this._links = [];
|
|
130
|
-
if (instances.get(this._element) === this) instances.delete(this._element);
|
|
131
|
-
}
|
|
132
|
-
_listen(target, type, handler, options) {
|
|
133
|
-
target.addEventListener(type, handler, options);
|
|
134
|
-
this._listeners.push({ target, type, handler, options });
|
|
135
|
-
}
|
|
136
|
-
_clearListeners() {
|
|
137
|
-
this._listeners.forEach(({ target, type, handler, options }) => target.removeEventListener(type, handler, options));
|
|
138
|
-
this._listeners = [];
|
|
139
|
-
if (this._frame) this._window.cancelAnimationFrame(this._frame);
|
|
140
|
-
this._frame = 0;
|
|
141
|
-
}
|
|
142
|
-
_requestUpdate() {
|
|
143
|
-
if (this._disposed || this._frame) return;
|
|
144
|
-
this._frame = this._window.requestAnimationFrame(() => {
|
|
145
|
-
this._frame = 0;
|
|
146
|
-
this._update();
|
|
147
|
-
});
|
|
148
|
-
}
|
|
149
|
-
_update() {
|
|
150
|
-
if (this._disposed) return;
|
|
151
|
-
const targets = this._targets.filter(({ target }) => target.isConnected && target.getClientRects().length > 0);
|
|
152
|
-
const scroller = this._scrollElement || this._document.scrollingElement;
|
|
153
|
-
const line = (this._scrollElement ? this._scrollElement.getBoundingClientRect().top + this._scrollElement.clientTop : 0) + this._offset;
|
|
154
|
-
let active = null;
|
|
155
|
-
targets.forEach((entry) => {
|
|
156
|
-
if (entry.target.getBoundingClientRect().top <= line + 1) active = entry;
|
|
157
|
-
});
|
|
158
|
-
const canScroll = scroller && scroller.scrollHeight > scroller.clientHeight + 1;
|
|
159
|
-
if (!canScroll) {
|
|
160
|
-
const hashId = fragmentId(this._window.location.hash);
|
|
161
|
-
active = targets.find(({ id }) => id === hashId) || active;
|
|
162
|
-
}
|
|
163
|
-
if (targets.length && canScroll && scroller.scrollTop + scroller.clientHeight >= scroller.scrollHeight - 1) {
|
|
164
|
-
active = targets[targets.length - 1];
|
|
165
|
-
}
|
|
166
|
-
this._activate(active);
|
|
167
|
-
}
|
|
168
|
-
_activate(active) {
|
|
169
|
-
let activeLink = null;
|
|
170
|
-
this._links.forEach(({ link, id }) => {
|
|
171
|
-
const current = active !== null && id === active.id;
|
|
172
|
-
link.classList.toggle("active", current);
|
|
173
|
-
if (current) {
|
|
174
|
-
link.setAttribute("aria-current", "location");
|
|
175
|
-
activeLink || (activeLink = link);
|
|
176
|
-
} else link.removeAttribute("aria-current");
|
|
177
|
-
});
|
|
178
|
-
if (this._status) this._status.textContent = active ? active.label : this._overview;
|
|
179
|
-
this._updateMarker(activeLink);
|
|
180
|
-
}
|
|
181
|
-
_updateMarker(link) {
|
|
182
|
-
const list = this._element.querySelector(":scope > .nav");
|
|
183
|
-
const text = link?.querySelector("span");
|
|
184
|
-
if (!list?.contains(link) || !text?.offsetHeight || !this._element.getClientRects().length) {
|
|
185
|
-
this._element.removeAttribute("data-toc-marker");
|
|
186
|
-
return;
|
|
187
|
-
}
|
|
188
|
-
this._element.style.setProperty("--moo-toc-marker-offset", `${link.offsetTop + text.offsetTop}px`);
|
|
189
|
-
this._element.style.setProperty("--moo-toc-marker-height", `${text.offsetHeight}px`);
|
|
190
|
-
this._element.setAttribute("data-toc-marker", "");
|
|
191
|
-
}
|
|
192
|
-
}
|
|
7
|
+
import { default as default2 } from "./toc.js";
|
|
193
8
|
export {
|
|
194
|
-
|
|
9
|
+
default2 as default
|
|
195
10
|
};
|
package/dist/js/toc.js
ADDED
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Moo UI toc.js v1.2.0 (https://wpmoo.org/)
|
|
3
|
+
* Copyright 2026 WPMoo Authors
|
|
4
|
+
* Licensed under MIT (https://github.com/wpmoo-org/ui/blob/main/LICENSE)
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const instances = /* @__PURE__ */ new WeakMap();
|
|
8
|
+
const ownerSelector = '.moo-ui[data-bs-theme="light"], .moo-ui[data-bs-theme="dark"]';
|
|
9
|
+
function activationOffset(options, previous = 0) {
|
|
10
|
+
if (!options || typeof options !== "object" || Array.isArray(options)) {
|
|
11
|
+
throw new TypeError("TableOfContents options must be an object.");
|
|
12
|
+
}
|
|
13
|
+
const value = options.activationOffset === void 0 ? previous : options.activationOffset;
|
|
14
|
+
if (typeof value !== "number" || !Number.isFinite(value) || value < 0) {
|
|
15
|
+
throw new TypeError("TableOfContents activationOffset must be a finite nonnegative number.");
|
|
16
|
+
}
|
|
17
|
+
return value;
|
|
18
|
+
}
|
|
19
|
+
function fragmentId(href) {
|
|
20
|
+
if (!href?.startsWith("#") || href.length === 1) return null;
|
|
21
|
+
try {
|
|
22
|
+
return decodeURIComponent(href.slice(1));
|
|
23
|
+
} catch {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
class TableOfContents {
|
|
28
|
+
static getInstance(element) {
|
|
29
|
+
return element?.nodeType === 1 ? instances.get(element) || null : null;
|
|
30
|
+
}
|
|
31
|
+
static getOrCreateInstance(element, options = {}) {
|
|
32
|
+
return TableOfContents.getInstance(element) || new TableOfContents(element, options);
|
|
33
|
+
}
|
|
34
|
+
constructor(element, options = {}) {
|
|
35
|
+
if (element?.nodeType !== 1 || !element.matches("[data-toc]")) {
|
|
36
|
+
throw new TypeError("TableOfContents requires a [data-toc] root element.");
|
|
37
|
+
}
|
|
38
|
+
const existing = instances.get(element);
|
|
39
|
+
if (existing) return existing;
|
|
40
|
+
this._element = element;
|
|
41
|
+
this._document = element.ownerDocument;
|
|
42
|
+
this._window = this._document.defaultView;
|
|
43
|
+
this._offset = activationOffset(options);
|
|
44
|
+
this._listeners = [];
|
|
45
|
+
this._originalLinks = /* @__PURE__ */ new Map();
|
|
46
|
+
this._originalStatus = /* @__PURE__ */ new Map();
|
|
47
|
+
this._originalMarker = {
|
|
48
|
+
attribute: element.getAttribute("data-toc-marker"),
|
|
49
|
+
properties: ["--moo-toc-marker-offset", "--moo-toc-marker-height"].map((name) => ({
|
|
50
|
+
name,
|
|
51
|
+
value: element.style.getPropertyValue(name),
|
|
52
|
+
priority: element.style.getPropertyPriority(name)
|
|
53
|
+
}))
|
|
54
|
+
};
|
|
55
|
+
this._links = [];
|
|
56
|
+
this._targets = [];
|
|
57
|
+
this._frame = 0;
|
|
58
|
+
this._disposed = false;
|
|
59
|
+
instances.set(element, this);
|
|
60
|
+
this.refresh();
|
|
61
|
+
}
|
|
62
|
+
refresh(options = {}) {
|
|
63
|
+
if (this._disposed) return this;
|
|
64
|
+
const offset = activationOffset(options, this._offset);
|
|
65
|
+
this._clearListeners();
|
|
66
|
+
this._offset = offset;
|
|
67
|
+
const owner = this._element.closest(ownerSelector);
|
|
68
|
+
const contentId = this._element.getAttribute("data-toc-content");
|
|
69
|
+
const scope = contentId ? this._document.getElementById(contentId) : owner;
|
|
70
|
+
const rootId = this._element.getAttribute("data-toc-scroll-root");
|
|
71
|
+
this._scrollElement = rootId ? this._document.getElementById(rootId) : null;
|
|
72
|
+
this._status = Array.from(this._element.querySelectorAll("[data-toc-current]")).find((node) => node.closest("[data-toc]") === this._element) || null;
|
|
73
|
+
if (this._status && !this._originalStatus.has(this._status)) {
|
|
74
|
+
this._originalStatus.set(this._status, this._status.textContent);
|
|
75
|
+
}
|
|
76
|
+
this._overview = this._status ? this._originalStatus.get(this._status) : "";
|
|
77
|
+
this._links = Array.from(this._element.querySelectorAll('a[href^="#"]')).filter((link) => link.closest("[data-toc]") === this._element).map((link) => ({ link, id: fragmentId(link.getAttribute("href")) }));
|
|
78
|
+
this._links.forEach(({ link }) => {
|
|
79
|
+
if (!this._originalLinks.has(link)) {
|
|
80
|
+
this._originalLinks.set(link, {
|
|
81
|
+
active: link.classList.contains("active"),
|
|
82
|
+
current: link.getAttribute("aria-current")
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
this._targets = [];
|
|
87
|
+
this._activate(null);
|
|
88
|
+
if (!owner || !scope || scope.closest(ownerSelector) !== owner || rootId && (!this._scrollElement || !this._scrollElement.contains(scope))) {
|
|
89
|
+
return this;
|
|
90
|
+
}
|
|
91
|
+
const seen = /* @__PURE__ */ new Set();
|
|
92
|
+
this._links.forEach(({ id, link }) => {
|
|
93
|
+
const target = id ? this._document.getElementById(id) : null;
|
|
94
|
+
if (!target || seen.has(id) || !scope.contains(target) || target.closest(ownerSelector) !== owner) return;
|
|
95
|
+
seen.add(id);
|
|
96
|
+
this._targets.push({ id, target, label: link.textContent.trim() });
|
|
97
|
+
});
|
|
98
|
+
if (!this._targets.length) return this;
|
|
99
|
+
const queue = () => this._requestUpdate();
|
|
100
|
+
this._listen(this._scrollElement || this._window, "scroll", queue, { passive: true });
|
|
101
|
+
this._listen(this._window, "resize", queue);
|
|
102
|
+
this._listen(this._window, "hashchange", queue);
|
|
103
|
+
this._listen(this._element, "click", queue);
|
|
104
|
+
this._update();
|
|
105
|
+
return this;
|
|
106
|
+
}
|
|
107
|
+
dispose() {
|
|
108
|
+
if (this._disposed) return;
|
|
109
|
+
this._disposed = true;
|
|
110
|
+
this._clearListeners();
|
|
111
|
+
this._originalLinks.forEach(({ active, current }, link) => {
|
|
112
|
+
link.classList.toggle("active", active);
|
|
113
|
+
if (current === null) link.removeAttribute("aria-current");
|
|
114
|
+
else link.setAttribute("aria-current", current);
|
|
115
|
+
});
|
|
116
|
+
this._originalStatus.forEach((text, node) => {
|
|
117
|
+
node.textContent = text;
|
|
118
|
+
});
|
|
119
|
+
const { attribute, properties } = this._originalMarker;
|
|
120
|
+
if (attribute === null) this._element.removeAttribute("data-toc-marker");
|
|
121
|
+
else this._element.setAttribute("data-toc-marker", attribute);
|
|
122
|
+
properties.forEach(({ name, value, priority }) => {
|
|
123
|
+
if (value) this._element.style.setProperty(name, value, priority);
|
|
124
|
+
else this._element.style.removeProperty(name);
|
|
125
|
+
});
|
|
126
|
+
this._originalLinks.clear();
|
|
127
|
+
this._originalStatus.clear();
|
|
128
|
+
this._targets = [];
|
|
129
|
+
this._links = [];
|
|
130
|
+
if (instances.get(this._element) === this) instances.delete(this._element);
|
|
131
|
+
}
|
|
132
|
+
_listen(target, type, handler, options) {
|
|
133
|
+
target.addEventListener(type, handler, options);
|
|
134
|
+
this._listeners.push({ target, type, handler, options });
|
|
135
|
+
}
|
|
136
|
+
_clearListeners() {
|
|
137
|
+
this._listeners.forEach(({ target, type, handler, options }) => target.removeEventListener(type, handler, options));
|
|
138
|
+
this._listeners = [];
|
|
139
|
+
if (this._frame) this._window.cancelAnimationFrame(this._frame);
|
|
140
|
+
this._frame = 0;
|
|
141
|
+
}
|
|
142
|
+
_requestUpdate() {
|
|
143
|
+
if (this._disposed || this._frame) return;
|
|
144
|
+
this._frame = this._window.requestAnimationFrame(() => {
|
|
145
|
+
this._frame = 0;
|
|
146
|
+
this._update();
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
_update() {
|
|
150
|
+
if (this._disposed) return;
|
|
151
|
+
const targets = this._targets.filter(({ target }) => target.isConnected && target.getClientRects().length > 0);
|
|
152
|
+
const scroller = this._scrollElement || this._document.scrollingElement;
|
|
153
|
+
const line = (this._scrollElement ? this._scrollElement.getBoundingClientRect().top + this._scrollElement.clientTop : 0) + this._offset;
|
|
154
|
+
let active = null;
|
|
155
|
+
targets.forEach((entry) => {
|
|
156
|
+
if (entry.target.getBoundingClientRect().top <= line + 1) active = entry;
|
|
157
|
+
});
|
|
158
|
+
const canScroll = scroller && scroller.scrollHeight > scroller.clientHeight + 1;
|
|
159
|
+
if (!canScroll) {
|
|
160
|
+
const hashId = fragmentId(this._window.location.hash);
|
|
161
|
+
active = targets.find(({ id }) => id === hashId) || active;
|
|
162
|
+
}
|
|
163
|
+
if (targets.length && canScroll && scroller.scrollTop + scroller.clientHeight >= scroller.scrollHeight - 1) {
|
|
164
|
+
active = targets[targets.length - 1];
|
|
165
|
+
}
|
|
166
|
+
this._activate(active);
|
|
167
|
+
}
|
|
168
|
+
_activate(active) {
|
|
169
|
+
let activeLink = null;
|
|
170
|
+
this._links.forEach(({ link, id }) => {
|
|
171
|
+
const current = active !== null && id === active.id;
|
|
172
|
+
link.classList.toggle("active", current);
|
|
173
|
+
if (current) {
|
|
174
|
+
link.setAttribute("aria-current", "location");
|
|
175
|
+
activeLink || (activeLink = link);
|
|
176
|
+
} else link.removeAttribute("aria-current");
|
|
177
|
+
});
|
|
178
|
+
if (this._status) this._status.textContent = active ? active.label : this._overview;
|
|
179
|
+
this._updateMarker(activeLink);
|
|
180
|
+
}
|
|
181
|
+
_updateMarker(link) {
|
|
182
|
+
const list = this._element.querySelector(":scope > .nav");
|
|
183
|
+
const text = link?.querySelector("span");
|
|
184
|
+
if (!list?.contains(link) || !text?.offsetHeight || !this._element.getClientRects().length) {
|
|
185
|
+
this._element.removeAttribute("data-toc-marker");
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
this._element.style.setProperty("--moo-toc-marker-offset", `${link.offsetTop + text.offsetTop}px`);
|
|
189
|
+
this._element.style.setProperty("--moo-toc-marker-height", `${text.offsetHeight}px`);
|
|
190
|
+
this._element.setAttribute("data-toc-marker", "");
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
export {
|
|
194
|
+
TableOfContents as default
|
|
195
|
+
};
|
|
@@ -3,22 +3,22 @@
|
|
|
3
3
|
{
|
|
4
4
|
"export": "./moo.css",
|
|
5
5
|
"path": "dist/assets/css/moo.css",
|
|
6
|
-
"sha256": "
|
|
6
|
+
"sha256": "087ab8cdeef74e15187f8c884b1d3921d38ef3a11730cc903e560a105af64de8"
|
|
7
7
|
},
|
|
8
8
|
{
|
|
9
9
|
"export": "./moo-ui.css",
|
|
10
10
|
"path": "dist/assets/css/moo-ui.css",
|
|
11
|
-
"sha256": "
|
|
11
|
+
"sha256": "eff5375117972db09813817e3302a98c349bdefcef736a27449f597c2446abfd"
|
|
12
12
|
},
|
|
13
13
|
{
|
|
14
14
|
"export": "./state.js",
|
|
15
15
|
"path": "dist/js/state.js",
|
|
16
|
-
"sha256": "
|
|
16
|
+
"sha256": "b41ee62bf48eb2e141f145dc987d80e1ad40ba0ee364ca47f9aa8427aff4fb42"
|
|
17
17
|
}
|
|
18
18
|
],
|
|
19
19
|
"package": {
|
|
20
20
|
"name": "@wpmoo/ui",
|
|
21
|
-
"version": "1.
|
|
21
|
+
"version": "1.2.0"
|
|
22
22
|
},
|
|
23
23
|
"schemaVersion": 1
|
|
24
24
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wpmoo/ui",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "Bootstrap markup. shadcn feel. A frontend-framework-free component system for server-rendered apps.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "WPMoo (https://wpmoo.org)",
|
|
@@ -38,6 +38,7 @@
|
|
|
38
38
|
"./context-menu.js": "./dist/js/context-menu.js",
|
|
39
39
|
"./datatable.js": "./dist/js/datatable.js",
|
|
40
40
|
"./slider.js": "./dist/js/slider.js",
|
|
41
|
+
"./toc.js": "./dist/js/toc.js",
|
|
41
42
|
"./table-of-contents.js": "./dist/js/table-of-contents.js",
|
|
42
43
|
"./sheet.js": "./dist/js/sheet.js",
|
|
43
44
|
"./chart.js": "./dist/js/chart.js",
|
|
@@ -66,6 +67,7 @@
|
|
|
66
67
|
"dist/js/context-menu.js",
|
|
67
68
|
"dist/js/datatable.js",
|
|
68
69
|
"dist/js/slider.js",
|
|
70
|
+
"dist/js/toc.js",
|
|
69
71
|
"dist/js/table-of-contents.js",
|
|
70
72
|
"dist/js/sheet.js",
|
|
71
73
|
"dist/js/chart.js",
|
package/scss/_components.scss
CHANGED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/* Empty */
|
|
2
|
+
.empty-state {
|
|
3
|
+
display: flex;
|
|
4
|
+
flex-direction: column;
|
|
5
|
+
align-items: center;
|
|
6
|
+
justify-content: center;
|
|
7
|
+
width: 100%;
|
|
8
|
+
min-width: 0;
|
|
9
|
+
gap: $spacer * 1.5;
|
|
10
|
+
padding: $spacer * 1.5;
|
|
11
|
+
text-align: center;
|
|
12
|
+
border-width: var(--bs-border-width);
|
|
13
|
+
border-style: $moo-empty-border-style;
|
|
14
|
+
border-color: var(--bs-border-color);
|
|
15
|
+
border-radius: var(--bs-border-radius-lg);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
.empty-state-header {
|
|
19
|
+
display: flex;
|
|
20
|
+
flex-direction: column;
|
|
21
|
+
align-items: inherit;
|
|
22
|
+
gap: $spacer * 0.5;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.empty-state-icon {
|
|
26
|
+
display: inline-flex;
|
|
27
|
+
align-items: center;
|
|
28
|
+
justify-content: center;
|
|
29
|
+
padding: $spacer * 0.75;
|
|
30
|
+
font-size: $h3-font-size;
|
|
31
|
+
line-height: 1;
|
|
32
|
+
color: var(--bs-secondary-color);
|
|
33
|
+
background-color: var(--bs-tertiary-bg);
|
|
34
|
+
border-radius: var(--bs-border-radius-lg);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.empty-state-icon > [data-icon] {
|
|
38
|
+
width: $spacer * 1.5;
|
|
39
|
+
height: $spacer * 1.5;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.empty-state-title {
|
|
43
|
+
margin: 0;
|
|
44
|
+
font-size: $h5-font-size;
|
|
45
|
+
font-weight: $headings-font-weight;
|
|
46
|
+
line-height: $headings-line-height;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.empty-state-description {
|
|
50
|
+
margin: 0;
|
|
51
|
+
font-size: $font-size-base;
|
|
52
|
+
color: var(--bs-secondary-color);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.empty-state-actions {
|
|
56
|
+
display: flex;
|
|
57
|
+
flex-wrap: wrap;
|
|
58
|
+
justify-content: inherit;
|
|
59
|
+
gap: $spacer * 0.5;
|
|
60
|
+
}
|