Skip to content
Snippets Groups Projects
Verified Commit f67212aa authored by Volker Schukai's avatar Volker Schukai :alien:
Browse files

feat: new toc control finished #189

parent 11fca424
Branches
Tags 3.65.0
No related merge requests found
...@@ -18,8 +18,8 @@ ...@@ -18,8 +18,8 @@
<div> <div>
<monster-table-of-content style="border:1px solid red;display:flex"> <monster-table-of-content style="display:flex;padding:15px">
<div style="padding:45px">
<h1>Headline 1</h1> <h1>Headline 1</h1>
<p>Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore <p>Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore
et et
...@@ -155,7 +155,7 @@ ...@@ -155,7 +155,7 @@
<hr> <hr>
<p><strong>ENDE</strong></p> <p><strong>ENDE</strong></p>
</div>
</monster-table-of-content> </monster-table-of-content>
......
...@@ -230,16 +230,16 @@ document.body.appendChild(element);</code></pre> ...@@ -230,16 +230,16 @@ document.body.appendChild(element);</code></pre>
<div class="option-headline">Type</div> <div class="option-headline">Type</div>
<div class="option-headline">Default</div> <div class="option-headline">Default</div>
<div class="option-headline">Description</div> <div class="option-headline">Description</div>
<div>templates</div><div>object</div><div></div><div>templates - The templates for the control.</div> <div>templates</div><div>object</div><div></div><div>templates The templates for the control.</div>
<div>templates.main</div><div>string</div><div></div><div>templates.main - The main template.</div> <div>templates.main</div><div>string</div><div></div><div>templates.main The main template.</div>
<div>mode</div><div>string</div><div></div><div>mode - The mode of the popper. Possible values are `click`, `enter`, `manual`, `focus`, "auto" or a combination of them.</div> <div>mode</div><div>string</div><div></div><div>mode The mode of the popper. Possible values are `click`, `enter`, `manual`, `focus`, "auto" or a combination of them.</div>
<div>content</div><div>string</div><div></div><div>content - The content of the popper.</div> <div>content</div><div>string</div><div></div><div>content The content of the popper.</div>
<div>popper</div><div>object</div><div></div><div>popper - The popper options.</div> <div>popper</div><div>object</div><div></div><div>popper The popper options.</div>
<div>popper.placement</div><div>string</div><div></div><div>popper.placement - The placement of the popper. Possible values are `top`, `bottom`, `left` and `right`.</div> <div>popper.placement</div><div>string</div><div></div><div>popper.placement The placement of the popper. Possible values are `top`, `bottom`, `left` and `right`.</div>
<div>popper.middleware</div><div>array<function></div><div></div><div>popper.middleware - The middleware functions of the popper.</div> <div>popper.middleware</div><div>function[]</div><div></div><div>popper.middleware The middleware functions of the popper.</div>
<div>popper.middlewareInit</div><div>array<function></div><div></div><div>popper.middlewareInit - The middleware init functions of the popper.</div> <div>popper.middlewareInit</div><div>function[]</div><div></div><div>popper.middlewareInit The middleware init functions of the popper.</div>
<div>features</div><div>object</div><div></div><div>features - The features of the popper.</div> <div>features</div><div>object</div><div></div><div>features The features of the popper.</div>
<div>features.preventPropagateOpenEvents</div><div>boolean</div><div></div><div>features.preventPropagateOpenEvents - Prevents the open event from being sent.</div> <div>features.preventPropagateOpenEvents</div><div>boolean</div><div></div><div>features.preventPropagateOpenEvents Prevents the open event from being sent.</div>
</div><br> </div><br>
<h2>Properties and Attributes</h2> <h2>Properties and Attributes</h2>
<ul> <ul>
......
...@@ -118,17 +118,16 @@ class Popper extends CustomControl { ...@@ -118,17 +118,16 @@ class Popper extends CustomControl {
* *
* The individual configuration values can be found in the table. * The individual configuration values can be found in the table.
* *
* @property {Object} templates - The templates for the control. * @property {Object} templates The templates for the control.
* @property {string} templates.main - The main template. * @property {string} templates.main The main template.
* @property {string} mode - The mode of the popper. Possible values are `click`, `enter`, `manual`, `focus`, "auto" or a combination of them. * @property {string} mode The mode of the popper. Possible values are `click`, `enter`, `manual`, `focus`, "auto" or a combination of them.
* @property {string} content - The content of the popper. * @property {string} content The content of the popper.
* @property {object} popper - The popper options. * @property {object} popper The popper options.
* @property {string} popper.placement - The placement of the popper. Possible values are `top`, `bottom`, `left` and `right`. * @property {string} popper.placement The placement of the popper. Possible values are `top`, `bottom`, `left` and `right`.
* @property {Array<function>} popper.middleware - The middleware functions of the popper. * @property {function[]} popper.middleware The middleware functions of the popper.
* @property {Array<function>} popper.middlewareInit - The middleware init functions of the popper. * @property {function[]} popper.middlewareInit The middleware init functions of the popper.
* @property {Object} features - The features of the popper. * @property {Object} features The features of the popper.
* @property {boolean} features.preventPropagateOpenEvents - Prevents the open event from being sent. * @property {boolean} features.preventPropagateOpenEvents Prevents the open event from being sent.
* @extends {Button}
*/ */
get defaults() { get defaults() {
return Object.assign({}, super.defaults, { return Object.assign({}, super.defaults, {
......
...@@ -17,7 +17,36 @@ ...@@ -17,7 +17,36 @@
cursor: pointer; cursor: pointer;
width: 20px; width: 20px;
transition: top 0.3s ease, visibility 0.1s ease; transition: top 0.2s ease, visibility 0.1s ease;
& [data-monster-role="navigation-list"] {
& ul {
margin: 0;
padding: 0 0 0 10px;
list-style-type: none;
}
& ul li {
position: relative;
padding-left: 10px;
}
& ul li:before {
content: "";
position: absolute;
left: 0;
top: 0;
bottom: 0;
width: 10px;
border-left: 1px dotted var(--monster-color-primary-2);
margin-top: 0;
}
}
& [data-monster-role=navigation-control] {
width: 20px;
}
& .heading-strip { & .heading-strip {
display: flex; display: flex;
...@@ -52,7 +81,4 @@ ...@@ -52,7 +81,4 @@
} }
} }
...@@ -26,6 +26,7 @@ import {isFunction} from "../../types/is.mjs"; ...@@ -26,6 +26,7 @@ import {isFunction} from "../../types/is.mjs";
import {TableOfContentStyleSheet} from "./stylesheet/table-of-content.mjs"; import {TableOfContentStyleSheet} from "./stylesheet/table-of-content.mjs";
import {fireCustomEvent} from "../../dom/events.mjs"; import {fireCustomEvent} from "../../dom/events.mjs";
import {getWindow} from "../../dom/util.mjs"; import {getWindow} from "../../dom/util.mjs";
import "../layout/popper.mjs";
export {TableOfContent}; export {TableOfContent};
...@@ -33,15 +34,27 @@ export {TableOfContent}; ...@@ -33,15 +34,27 @@ export {TableOfContent};
* @private * @private
* @type {symbol} * @type {symbol}
*/ */
export const tableOfContentElementSymbol = Symbol("tableOfContentElement"); const tableOfContentElementSymbol = Symbol("tableOfContentElement");
/** /**
* @private * @private
* @type {symbol} * @type {symbol}
*/ */
export const navigationElementSymbol = Symbol("navigation"); const navigationElementSymbol = Symbol("navigation");
/**
* @private
* @type {symbol}
*/
const navigationControlElementSymbol = Symbol("navigationControlElement");
/**
* @private
* @type {symbol}
*/
const navigationListElementSymbol = Symbol("navigationListElement");
/** /**
* @private * @private
* @type {symbol} * @type {symbol}
...@@ -181,6 +194,7 @@ class TableOfContent extends CustomElement { ...@@ -181,6 +194,7 @@ class TableOfContent extends CustomElement {
* @private * @private
*/ */
function calcAndSetNavigationTopWindowContext() { function calcAndSetNavigationTopWindowContext() {
const thisTop = this.getBoundingClientRect().top; const thisTop = this.getBoundingClientRect().top;
const topViewport = window.scrollY; const topViewport = window.scrollY;
let top = Math.max(topViewport, thisTop); let top = Math.max(topViewport, thisTop);
...@@ -196,11 +210,13 @@ function calcAndSetNavigationTopWindowContext() { ...@@ -196,11 +210,13 @@ function calcAndSetNavigationTopWindowContext() {
* @private * @private
*/ */
function calcAndSetNavigationTopScrollableParentContext() { function calcAndSetNavigationTopScrollableParentContext() {
const windowTop = getWindow().scrollY;
const thisRect = this.getBoundingClientRect(); const thisRect = this.getBoundingClientRect();
const thisTop = thisRect.top; const thisTop = thisRect.top;
const thisBottom = thisRect.bottom; const thisBottom = thisRect.bottom;
const scrollTop = this[scrollableParentSymbol].scrollTop; const scrollTop = this[scrollableParentSymbol].scrollTop;
let top = thisTop + scrollTop; let top = windowTop + thisTop + scrollTop;
if (thisBottom < top) { if (thisBottom < top) {
top = thisBottom; top = thisBottom;
...@@ -227,10 +243,10 @@ function initNavigation() { ...@@ -227,10 +243,10 @@ function initNavigation() {
const div = document.createElement('div'); const div = document.createElement('div');
div.classList.add('heading-strip'); div.classList.add('heading-strip');
div.classList.add('level-' + heading.tagName.toLowerCase()); div.classList.add('level-' + heading.tagName.toLowerCase());
this[navigationElementSymbol].appendChild(div); this[navigationControlElementSymbol].appendChild(div);
} }
this[navigationListElementSymbol].appendChild(createListFromHeadings.call(this, headings).sublist);
} }
/** /**
...@@ -240,6 +256,7 @@ function initNavigation() { ...@@ -240,6 +256,7 @@ function initNavigation() {
* @returns {{sublist: HTMLUListElement, lastIndex: number}} An object containing the sublist and the index of the last processed element. * @returns {{sublist: HTMLUListElement, lastIndex: number}} An object containing the sublist and the index of the last processed element.
*/ */
function createListFromHeadings(nodeList, currentLevel = 1) { function createListFromHeadings(nodeList, currentLevel = 1) {
const self = this;
let ul = document.createElement('ul'); let ul = document.createElement('ul');
let i = 0; let i = 0;
...@@ -250,11 +267,22 @@ function createListFromHeadings(nodeList, currentLevel = 1) { ...@@ -250,11 +267,22 @@ function createListFromHeadings(nodeList, currentLevel = 1) {
if (level === currentLevel) { if (level === currentLevel) {
const li = document.createElement('li'); const li = document.createElement('li');
li.textContent = node.textContent; li.textContent = node.textContent;
li.addEventListener('click', (e) => {
e.stopPropagation();
getWindow().requestAnimationFrame(() => {
window.scrollTo(0, 0);
// https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView
// mostly supported
node?.scrollIntoView({behavior: "smooth"});
});
});
ul.appendChild(li); ul.appendChild(li);
i++; i++;
} else if (level > currentLevel) { } else if (level > currentLevel) {
if (ul.lastChild) { if (ul.lastChild) {
const {sublist, lastIndex} = createListFromHeadings(nodeList.slice(i), level); const {sublist, lastIndex} = createListFromHeadings.call(self, nodeList.slice(i), level);
ul.lastChild.appendChild(sublist); ul.lastChild.appendChild(sublist);
i += lastIndex; i += lastIndex;
} else { } else {
...@@ -305,7 +333,7 @@ function initEventHandler() { ...@@ -305,7 +333,7 @@ function initEventHandler() {
this[windowEventHandlerSymbol] = function () { this[windowEventHandlerSymbol] = function () {
if (!ticking) { if (!ticking) {
window.requestAnimationFrame(() => { getWindow().requestAnimationFrame(() => {
calcAndSetNavigationTopWindowContext.call(self); calcAndSetNavigationTopWindowContext.call(self);
ticking = false; ticking = false;
}); });
...@@ -315,7 +343,7 @@ function initEventHandler() { ...@@ -315,7 +343,7 @@ function initEventHandler() {
this[scrollableEventHandlerSymbol] = function () { this[scrollableEventHandlerSymbol] = function () {
if (!ticking) { if (!ticking) {
window.requestAnimationFrame(() => { getWindow().requestAnimationFrame(() => {
calcAndSetNavigationTopScrollableParentContext.call(self); calcAndSetNavigationTopScrollableParentContext.call(self);
ticking = false; ticking = false;
}); });
...@@ -335,7 +363,7 @@ function findScrollableParent(element) { ...@@ -335,7 +363,7 @@ function findScrollableParent(element) {
let parent = element.parentElement; let parent = element.parentElement;
while (parent) { while (parent) {
const overflowY = window.getComputedStyle(parent).overflowY; const overflowY = getWindow().getComputedStyle(parent).overflowY;
if (overflowY === 'scroll' || overflowY === 'auto') { if (overflowY === 'scroll' || overflowY === 'auto') {
return parent; return parent;
} }
...@@ -356,6 +384,14 @@ function initControlReferences() { ...@@ -356,6 +384,14 @@ function initControlReferences() {
this[navigationElementSymbol] = this.shadowRoot.querySelector( this[navigationElementSymbol] = this.shadowRoot.querySelector(
`[${ATTRIBUTE_ROLE}="navigation"]`, `[${ATTRIBUTE_ROLE}="navigation"]`,
); );
this[navigationControlElementSymbol] = this.shadowRoot.querySelector(
`[${ATTRIBUTE_ROLE}="navigation-control"]`,
);
this[navigationListElementSymbol] = this.shadowRoot.querySelector(
`[${ATTRIBUTE_ROLE}="navigation-list"]`,
);
} }
/** /**
...@@ -366,8 +402,14 @@ function getTemplate() { ...@@ -366,8 +402,14 @@ function getTemplate() {
// language=HTML // language=HTML
return ` return `
<div data-monster-role="control" part="control"> <div data-monster-role="control" part="control">
<div class="navigation" data-monster-role="navigation"></div> <div class="navigation" data-monster-role="navigation">
<monster-popper>sdfsdfsdf</monster-popper> <monster-popper data-monster-option-mode="enter">
<div slot="button" data-monster-role="navigation-control">
</div>
<div data-monster-role="navigation-list">
</div>
</monster-popper>
</div>
<slot></slot> <slot></slot>
</div>`; </div>`;
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment