Something went wrong on our end
Select Git revision
Monster.Logging.Logger.html
-
Volker Schukai authoredVolker Schukai authored
details.mjs 6.89 KiB
/**
* Copyright © schukai GmbH and all contributing authors, {{copyRightYear}}. All rights reserved.
* Node module: @schukai/monster
*
* This source code is licensed under the GNU Affero General Public License version 3 (AGPLv3).
* The full text of the license can be found at: https://www.gnu.org/licenses/agpl-3.0.en.html
*
* For those who do not wish to adhere to the AGPLv3, a commercial license is available.
* Acquiring a commercial license allows you to use this software without complying with the AGPLv3 terms.
* For more information about purchasing a commercial license, please contact schukai GmbH.
*
* SPDX-License-Identifier: AGPL-3.0
*/
import {
assembleMethodSymbol,
registerCustomElement,
} from "../../dom/customelement.mjs";
import { DetailsStyleSheet } from "./stylesheet/details.mjs";
import { ATTRIBUTE_BUTTON_LABEL } from "../host/constants.mjs";
import { isString } from "../../types/is.mjs";
import { generateUniqueConfigKey } from "../host/util.mjs";
import { Collapse, nameSymbol } from "./collapse.mjs";
import { instanceSymbol } from "../../constants.mjs";
export { Details };
/**
* @private
* @type {symbol}
*/
const buttonElementSymbol = Symbol("buttonElement");
/**
* @private
* @type {symbol}
*/
const buttonEventHandlerSymbol = Symbol("buttonEventHandler");
/**
* The Details component is used to show a details.
*
* <img src="./images/details.png">
*
* Dependencies: the system uses functions of the [monsterjs](https://monsterjs.org/) library
*
* You can create this control either by specifying the HTML tag <monster-details />` directly in the HTML or using
* Javascript via the `document.createElement('monster-details');` method.
*
* ```html
* <monster-details></monster-details>
* ```
*
* Or you can create this CustomControl directly in Javascript:
*
* ```js
* import '@schukai/component-state/source/details.mjs';
* document.createElement('monster-details');
* ```
*
* The Body should have a class "hidden" to ensure that the styles are applied correctly.
*
* ```css
* body.hidden {
* visibility: hidden;
* }
* ```
*
* @startuml details.png
* skinparam monochrome true
* skinparam shadowing false
* HTMLElement <|-- CustomElement
* CustomElement <|-- Collapse
* Collapse <|-- Details
* @enduml
*
* @copyright schukai GmbH
* @memberOf Monster.Components.Layout
* @summary A simple details component
* @fires Monster.Components.Layout.Details.event:monster-details-before-open
* @fires Monster.Components.Layout.Details.event:monster-details-open
* @fires Monster.Components.Layout.Details.event:monster-details-before-close
* @fires Monster.Components.Layout.Details.event:monster-details-closed
*/
class Details extends Collapse {
/**
* This method is called by the `instanceof` operator.
* @returns {symbol}
*/
static get [instanceSymbol]() {
return Symbol.for("@schukai/monster/components/layout/details@@instance");
}
/**
*
*/
constructor() {
super();
// the name is only used for the host config and the event name
this[nameSymbol] = "details";
}
/**
* To set the options via the html tag the attribute `data-monster-options` must be used.
* @see {@link https://monsterjs.org/en/doc/#configurate-a-monster-control}
*
* The individual configuration values can be found in the table.
*
* @property {Object} templates Template definitions
* @property {string} templates.main Main template
* @property {Object} classes CSS classes
* @property {string} classes.button CSS class for the button
* @property {Object} button Button configuration
* @property {string} button.label Button label
* @property {Object} features Feature configuration
* @property {boolean} features.accordion Enable accordion mode
* @property {boolean} features.persistState Persist the state in the host configuration
*/
get defaults() {
return Object.assign({}, super.defaults, {
templates: {
main: getTemplate(),
},
labels: {
button: "Details",
},
});
}
/**
*
* @returns {Monster.Components.Layout.Details}
*/
[assembleMethodSymbol]() {
super[assembleMethodSymbol]();
initButtonLabel.call(this);
initControlReferences.call(this);
initEventHandler.call(this);
}
connectedCallback() {
super.connectedCallback();
const containDocument = this.shadowRoot;
if (containDocument !== null) {
const previousElement = this.previousElementSibling;
if (previousElement && previousElement.tagName === "MONSTER-DETAILS") {
this[buttonElementSymbol].style.borderTop = "0";
}
}
}
/**
*
* @return {string}
*/
static getTag() {
return "monster-details";
}
/**
* @return {Array<CSSStyleSheet>}
*/
static getCSSStyleSheet() {
const css = super.getCSSStyleSheet();
css.push(DetailsStyleSheet);
return css;
}
}
/**
* @private
* @return {Select}
* @throws {Error} no shadow-root is defined
*/
function initControlReferences() {
if (!this.shadowRoot) {
throw new Error("no shadow-root is defined");
}
this[buttonElementSymbol] = this.shadowRoot.querySelector(
"[data-monster-role=button]",
);
}
/**
* @private
*/
function initEventHandler() {
if (!this.shadowRoot) {
throw new Error("no shadow-root is defined");
}
this[buttonEventHandlerSymbol] = (event) => {
this.toggle();
};
this[buttonElementSymbol].addEventListener(
"click",
this[buttonEventHandlerSymbol],
);
return this;
}
/**
* @private
* @return {string}
*/
function initButtonLabel() {
let label;
const setLabel = false;
if (this.hasAttribute(ATTRIBUTE_BUTTON_LABEL)) {
label = this.getAttribute(ATTRIBUTE_BUTTON_LABEL);
} else {
label = this.innerText;
}
if (!isString(label)) {
label = "";
}
label = label.trim();
if (label === "") {
label = this.getOption("labels.button", "Details");
}
if (label.length > 100) {
label = `${label.substring(0, 99)}…`;
}
this.setAttribute(ATTRIBUTE_BUTTON_LABEL, label);
this.setOption("labels.button", label);
return label;
}
/**
* @private
* @returns {string}
*/
function getConfigKey() {
return generateUniqueConfigKey("details", this.id, "state");
}
/**
* @private
* @return {string}
*/
function getTemplate() {
// language=HTML
return `
<div data-monster-role="control" part="control" class="overflow-hidden">
<div data-monster-role="summary" part="summary">
<button part="button" data-monster-attributes="class path:classes.button"
data-monster-role="button"
data-monster-replace="path:labels.button | default:click me">click me
</button>
</div>
<div data-monster-role="detail">
<div data-monster-attributes="class path:classes.container" part="container"
data-monster-role="container">
<slot></slot>
</div>
<div class="deco-line" data-monster-role="deco"></div>
</div>
</div>`;
}
registerCustomElement(Details);