/** * Copyright schukai GmbH and contributors 2023. All Rights Reserved. * Node module: @schukai/monster * This file is licensed under the AGPLv3 License. * License text available at https://www.gnu.org/licenses/agpl-3.0.en.html */ 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 }; /** * This CustomControl creates a button element with a variety of options. * * <img src="./images/state-button.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-state-button />` directly in the HTML or using * Javascript via the `document.createElement('monster-state-button');` method. * * ```html * <monster-state-button></monster-state-button> * ``` * * Or you can create this CustomControl directly in Javascript: * * ```js * import {StateButton} from '@schukai/component-form/source/state-button.js'; * document.createElement('monster-state-button'); * ``` * * The `data-monster-button-class` attribute can be used to change the CSS class of the button. * * @startuml state-button.png * skinparam monochrome true * skinparam shadowing false * HTMLElement <|-- CustomElement * CustomElement <|-- CustomControl * CustomControl <|-- Button * Button <|-- StateButton * @enduml * * @since 1.5.0 * @copyright schukai GmbH * @memberOf Monster.Components.Form * @summary A state button with icons */ class StateButton extends Button { /** * This method is called by the `instanceof` operator. * @returns {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 {Monster.Components.Form.Types.State} states.successful= successful * @property {Monster.Components.Form.Types.State} states.activity= activity * @property {Monster.Components.Form.Types.State} states.failed= failed * @property {Monster.Components.Form.Types.State} current current status * @property {Monster.Components.Form~exampleActionCallback} actions.click * @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"), }); } /** * 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 {state} state * @param {number} timeout * @return {Monster.Components.Form.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("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 {Monster.Components.Form.StateButton} */ removeState() { this.setOption("current", getStateInstanceFor("stateless")); return this; } /** * @return {Monster.Components.Form.Types.State|undefined} */ getState() { return this.getOption("current"); } /** * * @return {string} */ static getTag() { return "monster-state-button"; } /** * * @return {Array<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" data-monster-role="button" 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>`; } registerCustomElement(StateButton);