@schukai/monster
Version:
Monster is a simple library for creating fast, robust and lightweight websites.
181 lines (162 loc) • 5.17 kB
JavaScript
/**
* 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 { instanceSymbol } from "../../constants.mjs";
import { registerCustomElement } from "../../dom/customelement.mjs";
import { isInteger } from "../../types/is.mjs";
import { validateInstance, validateString } from "../../types/validate.mjs";
import { Button } from "./button.mjs";
import { StateButtonStyleSheet } from "./stylesheet/state-button.mjs";
import { getStateInstanceFor, State } from "./types/state.mjs";
export { StateButton };
/**
* A state button with icons
*
* @fragments /fragments/components/form/state-button/
*
* @example /examples/components/form/state-button-simple
*
* @since 1.5.0
* @copyright schukai GmbH
* @summary A beautiful button with icons
*/
class StateButton extends Button {
/**
* This method is called by the `instanceof` operator.
* @return {symbol}
* @since 2.1.0
*/
static get [instanceSymbol]() {
return Symbol.for(
"@schukai/monster/components/form/state-button@@instance",
);
}
/**
* 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} states Available status
* @property {State} states.successful= successful
* @property {State} states.activity= activity
* @property {State} states.failed= failed
* @property {State} current current status
* @property {object} aria Aria attributes
* @property {string} aria.role Aria role, only if the button is not a button
* @property {string} aria.label Aria label
* @extends {Button}
* @see {@link https://github.com/twbs/icons/blob/main/LICENSE.md|Bootstrap icons license}
*/
get defaults() {
return Object.assign({}, super.defaults, {
templates: {
main: getTemplate(),
},
states: {
successful: getStateInstanceFor("successful"),
activity: getStateInstanceFor("activity"),
failed: getStateInstanceFor("failed"),
},
current: getStateInstanceFor("stateless"),
aria: {
role: null,
label: null,
},
});
}
/**
* This method sets the current state of the button.
* If a timeout is set, the state is automatically removed after the
* specified time.
*
* @since 3.18.0 a previously set timeout is cleared
*
* @param {string} state
* @param {number} timeout
* @return {StateButton}
* @throws {TypeError} value is not a string
* @throws {TypeError} value is not an instance
*/
setState(state, timeout) {
const timeoutSymbol = Symbol.for("timeout");
if (this[timeoutSymbol] !== undefined) {
clearTimeout(this[timeoutSymbol]);
delete this[timeoutSymbol];
}
const obj = this.getOption(`states.${validateString(state)}`);
if (obj === undefined) {
throw new Error("state not found");
}
this.setOption("current", validateInstance(obj, State));
if (isInteger(timeout) && timeout > 0) {
this[timeoutSymbol] = setTimeout(() => {
this.removeState();
delete this[timeoutSymbol];
}, timeout);
}
return this;
}
/**
*
* @return {StateButton}
*/
removeState() {
this.setOption("current", getStateInstanceFor("stateless"));
return this;
}
/**
* @return {State|undefined}
*/
getState() {
return this.getOption("current");
}
/**
* @return {string}
*/
static getTag() {
return "monster-state-button";
}
/**
* @return {CSSStyleSheet[]}
*/
static getCSSStyleSheet() {
const styles = Button.getCSSStyleSheet();
styles.push(StateButtonStyleSheet);
return styles;
}
}
/**
* @private
* @return {string}
*/
function getTemplate() {
// language=HTML
return `<div data-monster-role="control" part="control">
<button data-monster-attributes="disabled path:disabled | if:true, class path:classes.button, aria-role path:aria.role"
data-monster-role="button"
aria-labelledby="monster-state-button-aria-label"
part="button">
<div data-monster-role="label" data-monster-replace="path:labels.button"></div>
<div data-monster-role="state"
data-monster-attributes="class path:current.state"
data-monster-replace="path:current.presentation"></div>
</button>
<div id="monster-state-button-aria-label"
class="visually-hidden" data-monster-replace="path:aria.label">click me
</div>
</div>`;
}
registerCustomElement(StateButton);