282 lines
		
	
	
		
			8.2 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			282 lines
		
	
	
		
			8.2 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
| import * as colors from './00colors.js';
 | |
| import { DeesInputBase } from './dees-input-base.js';
 | |
| import { demoFunc } from './dees-input-text.demo.js';
 | |
| import { cssGeistFontFamily, cssMonoFontFamily } from './00fonts.js';
 | |
| 
 | |
| import {
 | |
|   customElement,
 | |
|   type TemplateResult,
 | |
|   property,
 | |
|   html,
 | |
|   cssManager,
 | |
|   css,
 | |
| } from '@design.estate/dees-element';
 | |
| 
 | |
| declare global {
 | |
|   interface HTMLElementTagNameMap {
 | |
|     'dees-input-text': DeesInputText;
 | |
|   }
 | |
| }
 | |
| 
 | |
| @customElement('dees-input-text')
 | |
| export class DeesInputText extends DeesInputBase {
 | |
|   public static demo = demoFunc;
 | |
| 
 | |
|   // INSTANCE
 | |
|   @property({
 | |
|     type: String,
 | |
|     reflect: true,
 | |
|   })
 | |
|   public value: string = '';
 | |
| 
 | |
|   @property({
 | |
|     type: Boolean,
 | |
|     reflect: true,
 | |
|   })
 | |
|   public isPasswordBool = false;
 | |
| 
 | |
|   @property({
 | |
|     type: Boolean,
 | |
|     reflect: true,
 | |
|   })
 | |
|   public showPasswordBool = false;
 | |
| 
 | |
|   @property({
 | |
|     type: Boolean,
 | |
|     reflect: true,
 | |
|   })
 | |
|   public validationState: 'valid' | 'warn' | 'invalid';
 | |
| 
 | |
|   @property({
 | |
|     reflect: true,
 | |
|   })
 | |
|   public validationText: string = '';
 | |
| 
 | |
|   @property({})
 | |
|   validationFunction: (value: string) => boolean;
 | |
| 
 | |
|   public static styles = [
 | |
|     ...DeesInputBase.baseStyles,
 | |
|     cssManager.defaultStyles,
 | |
|     css`
 | |
|       * {
 | |
|         box-sizing: border-box;
 | |
|       }
 | |
| 
 | |
|       :host {
 | |
|         position: relative;
 | |
|         z-index: auto;
 | |
|         font-family: ${cssGeistFontFamily};
 | |
|       }
 | |
| 
 | |
|       .maincontainer {
 | |
|         position: relative;
 | |
|         color: ${cssManager.bdTheme('hsl(0 0% 15%)', 'hsl(0 0% 90%)')};
 | |
|       }
 | |
| 
 | |
|       input {
 | |
|         display: flex;
 | |
|         height: 40px;
 | |
|         width: 100%;
 | |
|         padding: 0 12px;
 | |
|         font-size: 14px;
 | |
|         line-height: 40px;
 | |
|         background: ${cssManager.bdTheme('hsl(0 0% 100%)', 'hsl(0 0% 9%)')};
 | |
|         border: 1px solid ${cssManager.bdTheme('hsl(0 0% 89.8%)', 'hsl(0 0% 14.9%)')};
 | |
|         border-radius: 6px;
 | |
|         transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
 | |
|         outline: none;
 | |
|         cursor: text;
 | |
|         font-family: inherit;
 | |
|         color: ${cssManager.bdTheme('hsl(0 0% 3.9%)', 'hsl(0 0% 98%)')};
 | |
|       }
 | |
| 
 | |
|       input::placeholder {
 | |
|         color: ${cssManager.bdTheme('hsl(0 0% 45.1%)', 'hsl(0 0% 63.9%)')};
 | |
|       }
 | |
| 
 | |
|       input:hover:not(:disabled):not(:focus) {
 | |
|         border-color: ${cssManager.bdTheme('hsl(0 0% 79.8%)', 'hsl(0 0% 20.9%)')};
 | |
|       }
 | |
| 
 | |
|       input:focus {
 | |
|         outline: none;
 | |
|         border-color: ${cssManager.bdTheme('hsl(0 0% 9%)', 'hsl(0 0% 98%)')};
 | |
|         box-shadow: 0 0 0 2px ${cssManager.bdTheme('hsl(0 0% 9% / 0.05)', 'hsl(0 0% 98% / 0.05)')};
 | |
|       }
 | |
| 
 | |
|       input:disabled {
 | |
|         background: ${cssManager.bdTheme('hsl(0 0% 95.1%)', 'hsl(0 0% 14.9%)')};
 | |
|         border-color: ${cssManager.bdTheme('hsl(0 0% 89.8%)', 'hsl(0 0% 14.9%)')};
 | |
|         color: ${cssManager.bdTheme('hsl(0 0% 45.1%)', 'hsl(0 0% 63.9%)')};
 | |
|         cursor: not-allowed;
 | |
|         opacity: 0.5;
 | |
|       }
 | |
| 
 | |
|       /* Password toggle button */
 | |
|       .showPassword {
 | |
|         position: absolute;
 | |
|         right: 1px;
 | |
|         top: 50%;
 | |
|         transform: translateY(-50%);
 | |
|         display: flex;
 | |
|         align-items: center;
 | |
|         justify-content: center;
 | |
|         width: 38px;
 | |
|         height: 38px;
 | |
|         cursor: pointer;
 | |
|         color: ${cssManager.bdTheme('hsl(0 0% 45.1%)', 'hsl(0 0% 63.9%)')};
 | |
|         transition: all 0.15s ease;
 | |
|         border-radius: 0 5px 5px 0;
 | |
|       }
 | |
| 
 | |
|       .showPassword:hover {
 | |
|         background: ${cssManager.bdTheme('hsl(0 0% 95.1%)', 'hsl(0 0% 14.9%)')};
 | |
|         color: ${cssManager.bdTheme('hsl(0 0% 15%)', 'hsl(0 0% 93.9%)')};
 | |
|       }
 | |
| 
 | |
|       /* Validation styles */
 | |
|       .validationContainer {
 | |
|         margin-top: 4px;
 | |
|         padding: 4px 8px;
 | |
|         font-size: 12px;
 | |
|         font-weight: 500;
 | |
|         border-radius: 4px;
 | |
|         transition: all 0.2s ease;
 | |
|         overflow: hidden;
 | |
|       }
 | |
| 
 | |
|       .validationContainer.error {
 | |
|         background: ${cssManager.bdTheme('hsl(0 84.2% 60.2% / 0.1)', 'hsl(0 72.2% 50.6% / 0.1)')};
 | |
|         color: ${cssManager.bdTheme('hsl(0 84.2% 60.2%)', 'hsl(0 72.2% 50.6%)')};
 | |
|       }
 | |
| 
 | |
|       .validationContainer.warn {
 | |
|         background: ${cssManager.bdTheme('hsl(25 95% 53% / 0.1)', 'hsl(25 95% 63% / 0.1)')};
 | |
|         color: ${cssManager.bdTheme('hsl(25 95% 53%)', 'hsl(25 95% 63%)')};
 | |
|       }
 | |
| 
 | |
|       .validationContainer.valid {
 | |
|         background: ${cssManager.bdTheme('hsl(142.1 76.2% 36.3% / 0.1)', 'hsl(142.1 70.6% 45.3% / 0.1)')};
 | |
|         color: ${cssManager.bdTheme('hsl(142.1 76.2% 36.3%)', 'hsl(142.1 70.6% 45.3%)')};
 | |
|       }
 | |
| 
 | |
|       /* Error state for input */
 | |
|       :host([validation-state="invalid"]) input {
 | |
|         border-color: ${cssManager.bdTheme('hsl(0 84.2% 60.2%)', 'hsl(0 72.2% 50.6%)')};
 | |
|       }
 | |
| 
 | |
|       :host([validation-state="invalid"]) input:focus {
 | |
|         border-color: ${cssManager.bdTheme('hsl(0 84.2% 60.2%)', 'hsl(0 72.2% 50.6%)')};
 | |
|         box-shadow: 0 0 0 2px ${cssManager.bdTheme('hsl(0 84.2% 60.2% / 0.05)', 'hsl(0 72.2% 50.6% / 0.05)')};
 | |
|       }
 | |
| 
 | |
|       /* Warning state for input */
 | |
|       :host([validation-state="warn"]) input {
 | |
|         border-color: ${cssManager.bdTheme('hsl(25 95% 53%)', 'hsl(25 95% 63%)')};
 | |
|       }
 | |
| 
 | |
|       :host([validation-state="warn"]) input:focus {
 | |
|         border-color: ${cssManager.bdTheme('hsl(25 95% 53%)', 'hsl(25 95% 63%)')};
 | |
|         box-shadow: 0 0 0 2px ${cssManager.bdTheme('hsl(25 95% 53% / 0.05)', 'hsl(25 95% 63% / 0.05)')};
 | |
|       }
 | |
| 
 | |
|       /* Valid state for input */
 | |
|       :host([validation-state="valid"]) input {
 | |
|         border-color: ${cssManager.bdTheme('hsl(142.1 76.2% 36.3%)', 'hsl(142.1 70.6% 45.3%)')};
 | |
|       }
 | |
| 
 | |
|       :host([validation-state="valid"]) input:focus {
 | |
|         border-color: ${cssManager.bdTheme('hsl(142.1 76.2% 36.3%)', 'hsl(142.1 70.6% 45.3%)')};
 | |
|         box-shadow: 0 0 0 2px ${cssManager.bdTheme('hsl(142.1 76.2% 36.3% / 0.05)', 'hsl(142.1 70.6% 45.3% / 0.05)')};
 | |
|       }
 | |
|     `,
 | |
|   ];
 | |
| 
 | |
|   public render(): TemplateResult {
 | |
|     return html`
 | |
|       <style>
 | |
|         input {
 | |
|           font-family: ${this.isPasswordBool ? cssMonoFontFamily : 'inherit'};
 | |
|           letter-spacing: ${this.isPasswordBool ? '0.5px' : 'normal'};
 | |
|           padding-right: ${this.isPasswordBool ? '48px' : '12px'};
 | |
|         }
 | |
|         ${this.validationText
 | |
|           ? css`
 | |
|               .validationContainer {
 | |
|                 height: auto;
 | |
|                 opacity: 1;
 | |
|                 transform: translateY(0);
 | |
|               }
 | |
|             `
 | |
|           : css`
 | |
|               .validationContainer {
 | |
|                 height: 0;
 | |
|                 padding: 0 !important;
 | |
|                 opacity: 0;
 | |
|                 transform: translateY(-4px);
 | |
|               }
 | |
|             `}
 | |
|       </style>
 | |
|       <div class="input-wrapper">
 | |
|         <dees-label .label=${this.label} .description=${this.description} .required=${this.required}></dees-label>
 | |
|         <div class="maincontainer">
 | |
|           <input
 | |
|             type="${this.isPasswordBool && !this.showPasswordBool ? 'password' : 'text'}"
 | |
|             .value=${this.value}
 | |
|             @input="${this.updateValue}"
 | |
|             .disabled=${this.disabled}
 | |
|             placeholder="${this.label ? '' : 'Enter text...'}"
 | |
|           />
 | |
|           ${this.isPasswordBool
 | |
|             ? html`
 | |
|                 <div class="showPassword" @click=${this.togglePasswordView}>
 | |
|                   <dees-icon .icon=${this.showPasswordBool ? 'lucide:Eye' : 'lucide:EyeOff'}></dees-icon>
 | |
|                 </div>
 | |
|               `
 | |
|             : html``}
 | |
|           ${this.validationText
 | |
|             ? html`
 | |
|                 <div class="validationContainer ${this.validationState || 'error'}">
 | |
|                   ${this.validationText}
 | |
|                 </div>
 | |
|               `
 | |
|             : html`<div class="validationContainer"></div>`}
 | |
|         </div>
 | |
|       </div>
 | |
|     `;
 | |
|   }
 | |
| 
 | |
|   firstUpdated() {
 | |
|     // Input event handling is already done in updateValue method
 | |
|   }
 | |
| 
 | |
|   public async updateValue(eventArg: Event) {
 | |
|     const target: any = eventArg.target;
 | |
|     this.value = target.value;
 | |
|     this.changeSubject.next(this);
 | |
|   }
 | |
| 
 | |
|   public getValue(): string {
 | |
|     return this.value;
 | |
|   }
 | |
| 
 | |
|   public setValue(value: string): void {
 | |
|     this.value = value;
 | |
|   }
 | |
| 
 | |
|   public async togglePasswordView() {
 | |
|     this.showPasswordBool = !this.showPasswordBool;
 | |
|   }
 | |
| 
 | |
|   public async focus() {
 | |
|     const textInput = this.shadowRoot.querySelector('input');
 | |
|     textInput.focus();
 | |
|   }
 | |
| 
 | |
|   public async blur() {
 | |
|     const textInput = this.shadowRoot.querySelector('input');
 | |
|     textInput.blur();
 | |
|   }
 | |
| }
 |