@schukai/monster
Version:
Monster is a simple library for creating fast, robust and lightweight websites.
280 lines (248 loc) • 8.51 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.
*/
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 schukai GmbH
* @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);