UNPKG

@schukai/monster

Version:

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

280 lines (248 loc) 8.52 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. */ import { instanceSymbol } from "../../constants.mjs"; import { ATTRIBUTE_ROLE } from "../../dom/constants.mjs"; import { CustomControl } from "../../dom/customcontrol.mjs"; import { assembleMethodSymbol, registerCustomElement, } from "../../dom/customelement.mjs"; import { PasswordStyleSheet } from "./stylesheet/password.mjs"; import { fireCustomEvent } from "../../dom/events.mjs"; import "./input-group.mjs"; export { Password }; /** * @private * @type {symbol} */ export const passwordElementSymbol = Symbol("passwordElement"); /** * @private * @type {symbol} */ export const visibleIconElementSymbol = Symbol("visibleIconElement"); /** * @private * @type {symbol} */ export const hiddenIconElementSymbol = Symbol("hiddenIconElement"); /** * @private * @type {symbol} */ export const inputElementSymbol = Symbol("inputIconElement"); /** * A password field * * @fragments /fragments/components/form/password * * @example /examples/components/form/password-simple * * @since 3.89.0 * @copyright Volker Schukai * @summary A beautiful Password field that can make your life easier and also looks good. * @fires monster-password-hide * @fires monster-password-show */ class Password extends CustomControl { /** * This method is called by the `instanceof` operator. * @returns {symbol} */ static get [instanceSymbol]() { return Symbol.for("@schukai/monster/components/form/password@@instance"); } /** * * @return {Components.Form.Password */ [assembleMethodSymbol]() { super[assembleMethodSymbol](); initControlReferences.call(this); initEventHandler.call(this); initPasswordState.call(this); return this; } /** * The current value of the Switch * @return {string} */ get value() { return this.getOption("value"); } /** * Set value * @property {string} value */ set value(value) { this.setOption("value", value); this[inputElementSymbol].value = value; this.setFormValue(value); } /** * 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 {string} templateMapping.hidden-icon The hidden icon template (without svg tag) * @property {string} templateMapping.visible-icon The visible icon template (without svg tag) * @property {string} type="password" The type of the input field * @property {string} placeholder="" The placeholder of the input field * @property {boolean} required=false The required state of the input field * @property {string} autocomplete="off" The autocomplete state of the input field * @property {string} inputmode="text" The inputmode state of the input field * @property {Object} aria Aria attributes * @property {boolean} aria.required=false The required state of the input field * @property {string} aria.placeholder="" The placeholder of the input field * @property {boolean} disabled=false Disabled state */ get defaults() { return Object.assign({}, super.defaults, { templates: { main: getTemplate(), }, templateMapping: { "hidden-icon": ` <path d="M13.359 11.238C15.06 9.72 16 8 16 8s-3-5.5-8-5.5a7 7 0 0 0-2.79.588l.77.771A6 6 0 0 1 8 3.5c2.12 0 3.879 1.168 5.168 2.457A13 13 0 0 1 14.828 8q-.086.13-.195.288c-.335.48-.83 1.12-1.465 1.755q-.247.248-.517.486z"/> <path d="M11.297 9.176a3.5 3.5 0 0 0-4.474-4.474l.823.823a2.5 2.5 0 0 1 2.829 2.829zm-2.943 1.299.822.822a3.5 3.5 0 0 1-4.474-4.474l.823.823a2.5 2.5 0 0 0 2.829 2.829"/> <path d="M3.35 5.47q-.27.24-.518.487A13 13 0 0 0 1.172 8l.195.288c.335.48.83 1.12 1.465 1.755C4.121 11.332 5.881 12.5 8 12.5c.716 0 1.39-.133 2.02-.36l.77.772A7 7 0 0 1 8 13.5C3 13.5 0 8 0 8s.939-1.721 2.641-3.238l.708.709zm10.296 8.884-12-12 .708-.708 12 12z"/>`, "visible-icon": ` <path d="M16 8s-3-5.5-8-5.5S0 8 0 8s3 5.5 8 5.5S16 8 16 8M1.173 8a13 13 0 0 1 1.66-2.043C4.12 4.668 5.88 3.5 8 3.5s3.879 1.168 5.168 2.457A13 13 0 0 1 14.828 8q-.086.13-.195.288c-.335.48-.83 1.12-1.465 1.755C11.879 11.332 10.119 12.5 8 12.5s-3.879-1.168-5.168-2.457A13 13 0 0 1 1.172 8z"/> <path d="M8 5.5a2.5 2.5 0 1 0 0 5 2.5 2.5 0 0 0 0-5M4.5 8a3.5 3.5 0 1 1 7 0 3.5 3.5 0 0 1-7 0"/>`, }, type: "password", placeholder: "", required: false, autocomplete: "off", inputmode: "text", aria: { required: false, placeholder: "", }, disabled: false, value: null, eventProcessing: true, }); } /** * @return {string} */ static getTag() { return "monster-password"; } /** * @return {CSSStyleSheet[]} */ static getCSSStyleSheet() { return [PasswordStyleSheet]; } } /** * @private * @return {initEventHandler} * @fires monster-password-hide * @fires monster-password-show */ function initEventHandler() { const self = this; const element = this[passwordElementSymbol]; const type = "click"; this[hiddenIconElementSymbol].addEventListener(type, function (event) { fireCustomEvent(self, "monster-password-show", { element: self, }); requestAnimationFrame(() => { self[visibleIconElementSymbol].classList.remove("hidden"); self[hiddenIconElementSymbol].classList.add("hidden"); self.setOption("type", "text"); }); }); this[visibleIconElementSymbol].addEventListener(type, function (event) { fireCustomEvent(self, "monster-password-hide", { element: self, }); requestAnimationFrame(() => { self[visibleIconElementSymbol].classList.add("hidden"); self[hiddenIconElementSymbol].classList.remove("hidden"); self.setOption("type", "password"); }); }); this[inputElementSymbol].addEventListener("input", function (event) { self.setFormValue(self.value); self.setOption("value", this.value); }); return this; } /** * @private */ function initPasswordState() { if (this.getOption("type") === "password") { this[visibleIconElementSymbol].classList.add("hidden"); this[hiddenIconElementSymbol].classList.remove("hidden"); } else { this[visibleIconElementSymbol].classList.remove("hidden"); this[hiddenIconElementSymbol].classList.add("hidden"); } } /** * @private * @return {void} */ function initControlReferences() { this[passwordElementSymbol] = this.shadowRoot.querySelector( `[${ATTRIBUTE_ROLE}="control"]`, ); this[visibleIconElementSymbol] = this.shadowRoot.querySelector( `[${ATTRIBUTE_ROLE}="visible-icon"]`, ); this[hiddenIconElementSymbol] = this.shadowRoot.querySelector( `[${ATTRIBUTE_ROLE}="hidden-icon"]`, ); this[inputElementSymbol] = this.shadowRoot.querySelector( `[${ATTRIBUTE_ROLE}="input"]`, ); } /** * @private * @return {string} */ function getTemplate() { // language=HTML return ` <div data-monster-role="control" part="control"> <monster-input-group part="input-group"> <input data-monster-role="input" part="input" style="border:0" data-monster-attributes=" type path:type, placeholder path:placeholder, required path:required, autocomplete path:autocomplete, inputmode path:inputmode, aria-required path:aria.required, aria-placeholder path:aria.placeholder"> <svg viewBox="0 0 16 16" data-monster-role="visible-icon" class="hidden"> \${visible-icon} </svg> <svg viewBox="0 0 16 16" data-monster-role="hidden-icon" class="hidden"> \${hidden-icon} </svg> </monster-input-group> </div> `; } registerCustomElement(Password);