UNPKG

@schukai/monster

Version:

Monster is a simple library for creating fast, robust and lightweight websites.

181 lines (162 loc) 5.18 kB
/** * Copyright © Volker Schukai 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 Volker Schukai. * * 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 Volker Schukai * @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);