UNPKG

passbolt-styleguide

Version:

Passbolt styleguide contains common styling assets used by the different sites, plugin, etc.

258 lines (234 loc) 8.11 kB
/** * Passbolt ~ Open source password manager for teams * Copyright (c) 2022 Passbolt SA (https://www.passbolt.com) * * Licensed under GNU Affero General Public License version 3 of the or any later version. * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice. * * @copyright Copyright (c) 2022 Passbolt SA (https://www.passbolt.com) * @license https://opensource.org/licenses/AGPL-3.0 AGPL License * @link https://www.passbolt.com Passbolt(tm) * @since 3.6.0 */ import React, { Component } from "react"; import PropTypes from "prop-types"; import EyeOpenSVG from "../../../img/svg/eye_open.svg"; import EyeCloseSVG from "../../../img/svg/eye_close.svg"; import { Trans, withTranslation } from "react-i18next"; /** * This component represent a password input field with some additional properties */ class Password extends Component { /** * Constructor * @param {Object} props */ constructor(props) { super(props); this.state = this.defaultState; this.bindCallbacks(); } get defaultState() { return { viewPassword: false, // view password hasPassphraseFocus: false, // password input has focus isPassphraseActive: false, // password input is active }; } /** * Bind callbacks methods * @return {void} */ bindCallbacks() { this.handleInputChange = this.handleInputChange.bind(this); this.handlePasswordInputFocus = this.handlePasswordInputFocus.bind(this); this.handlePasswordInputBlur = this.handlePasswordInputBlur.bind(this); this.handleViewPasswordButtonClick = this.handleViewPasswordButtonClick.bind(this); this.handleMouseDown = this.handleMouseDown.bind(this); // Bind here this.handleMouseUp = this.handleMouseUp.bind(this); } /** * Handle form input change. * @params {ReactEvent} The react event. */ handleInputChange(event) { if (this.props.onChange) { this.props.onChange(event); } } /** * Whenever the user focus on the password input */ handlePasswordInputFocus() { this.setState({ hasPassphraseFocus: true }); } /** * Whenever the user blurs on the password input */ handlePasswordInputBlur() { this.setState({ hasPassphraseFocus: false }); } /** * Handle view password button click. */ handleViewPasswordButtonClick() { if (this.props.disabled) { return; } this.setState({ viewPassword: !this.state.viewPassword }); } /** * Returns the style of the security token (color and text color) */ get securityTokenStyle() { const inverseStyle = { background: this.props.securityToken.textColor, color: this.props.securityToken.backgroundColor, }; const fullStyle = { background: this.props.securityToken.backgroundColor, color: this.props.securityToken.textColor, }; return this.state.hasPassphraseFocus ? inverseStyle : fullStyle; } /** * Get the passphrase input style. * @return {Object} */ get passphraseInputStyle() { if (!this.state.hasPassphraseFocus) { return undefined; } const { backgroundColor } = this.props.securityToken; const textColor = this.getContrastTextColor(backgroundColor); return { background: backgroundColor, color: textColor, "--passphrase-placeholder-color": textColor, }; } /** * Returns the style of preview (icon color and icon background color) */ get previewStyle() { if (!this.state.hasPassphraseFocus) { return undefined; } const { backgroundColor } = this.props.securityToken; const textColor = this.getContrastTextColor(backgroundColor); return { "--icon-color": textColor, "--icon-background-color": backgroundColor, }; } /** * Calculate the luminance of a color and return the appropriate text color variable. * @param {string} backgroundColor - The background color in hex format. * @returns {string} - The CSS variable for text color. */ getContrastTextColor(backgroundColor) { // Convert hex color to RGB const hex = backgroundColor.replace("#", ""); const bigint = parseInt(hex, 16); const red = (bigint >> 16) & 255; const green = (bigint >> 8) & 255; const blue = bigint & 255; // Calculate luminance const luminance = (0.299 * red + 0.587 * green + 0.114 * blue) / 255; // Return the appropriate CSS variable based on luminance return luminance > 0.5 ? "var(--Token-Token-text-and-icon)" : "var(--Token-Token-text-and-icon-reversed)"; } /** * Handle the mouse down to set active item */ handleMouseDown() { this.setState({ isPassphraseActive: true }); } /** * Handle the mouse down to set active item to false */ handleMouseUp() { this.setState({ isPassphraseActive: false }); } /** * Render the component * @return {JSX} */ render() { return ( <div className={`input password ${this.props.disabled ? "disabled" : ""} ${this.state.hasPassphraseFocus ? "" : "no-focus"} ${this.state.isPassphraseActive ? "active" : ""} ${this.props.securityToken ? "security" : ""}`} style={this.props.securityToken ? this.passphraseInputStyle : undefined} > <input id={this.props.id} name={this.props.name} maxLength="4096" placeholder={this.props.placeholder} type={this.state.viewPassword && !this.props.disabled ? "text" : "password"} onKeyUp={this.props.onKeyUp} value={this.props.value} onFocus={this.handlePasswordInputFocus} onBlur={this.handlePasswordInputBlur} onChange={this.handleInputChange} disabled={this.props.disabled} readOnly={this.props.readOnly} autoComplete={this.props.autoComplete} onMouseDown={this.handleMouseDown} onMouseUp={this.handleMouseUp} aria-required={true} ref={this.props.inputRef} /> {this.props.preview && ( <div className="password-view-wrapper"> <button type="button" onClick={this.handleViewPasswordButtonClick} style={this.props.securityToken ? this.previewStyle : undefined} className={`password-view infield button-transparent ${this.props.disabled ? "disabled" : ""}`} > {!this.state.viewPassword && <EyeOpenSVG className="svg-icon eye-open" />} {this.state.viewPassword && <EyeCloseSVG className="svg-icon eye-close" />} <span className="visually-hidden"> <Trans>View</Trans> </span> </button> </div> )} {this.props.securityToken && ( <div className="security-token-wrapper"> <span className="security-token" style={this.securityTokenStyle}> {this.props.securityToken.code} </span> </div> )} </div> ); } } Password.defaultProps = { id: "", name: "", autoComplete: "off", }; Password.propTypes = { context: PropTypes.any, // The application context id: PropTypes.string, // The id of the the input name: PropTypes.string, // The name of the the input value: PropTypes.string, // The value of the input placeholder: PropTypes.string, // Placeholder of the input autoComplete: PropTypes.string, // The auto complete of the input inputRef: PropTypes.object, // The forwarded ref of the input disabled: PropTypes.bool, // Disabled input readOnly: PropTypes.bool, // Disabled input preview: PropTypes.bool, // Display preview button for the password onChange: PropTypes.func, // Function onChange of the input onKeyUp: PropTypes.func, // Function onKeyUp of the input securityToken: PropTypes.shape({ code: PropTypes.string, backgroundColor: PropTypes.string, textColor: PropTypes.string, }), // The securityTokenDto }; export default withTranslation("common")(Password);