184 lines
4.7 KiB
TypeScript
184 lines
4.7 KiB
TypeScript
![]() |
import {
|
||
|
DeesElement,
|
||
|
property,
|
||
|
css,
|
||
|
type CSSResult,
|
||
|
cssManager,
|
||
|
} from '@design.estate/dees-element';
|
||
|
import * as domtools from '@design.estate/dees-domtools';
|
||
|
|
||
|
/**
|
||
|
* Base class for all dees-input components
|
||
|
* Provides unified margin system and layout mode support
|
||
|
*/
|
||
|
export abstract class DeesInputBase<T = any> extends DeesElement {
|
||
|
/**
|
||
|
* Layout mode for the input component
|
||
|
* - vertical: Traditional form layout (label on top)
|
||
|
* - horizontal: Inline layout (label position configurable)
|
||
|
* - auto: Detect from parent context
|
||
|
*/
|
||
|
@property({ type: String })
|
||
|
public layoutMode: 'vertical' | 'horizontal' | 'auto' = 'auto';
|
||
|
|
||
|
/**
|
||
|
* Position of the label relative to the input
|
||
|
*/
|
||
|
@property({ type: String })
|
||
|
public labelPosition: 'top' | 'left' | 'right' | 'none' = 'top';
|
||
|
|
||
|
/**
|
||
|
* Common properties for all inputs
|
||
|
*/
|
||
|
@property({ type: String })
|
||
|
public key: string;
|
||
|
|
||
|
@property({ type: String })
|
||
|
public label: string;
|
||
|
|
||
|
@property({ type: Boolean })
|
||
|
public required: boolean = false;
|
||
|
|
||
|
@property({ type: Boolean })
|
||
|
public disabled: boolean = false;
|
||
|
|
||
|
@property({ type: String })
|
||
|
public description: string;
|
||
|
|
||
|
/**
|
||
|
* Common styles for all input components
|
||
|
*/
|
||
|
public static get baseStyles(): CSSResult[] {
|
||
|
return [
|
||
|
css`
|
||
|
/* CSS Variables for consistent spacing */
|
||
|
:host {
|
||
|
--dees-input-spacing-unit: 8px;
|
||
|
--dees-input-vertical-gap: calc(var(--dees-input-spacing-unit) * 2); /* 16px */
|
||
|
--dees-input-horizontal-gap: calc(var(--dees-input-spacing-unit) * 2); /* 16px */
|
||
|
--dees-input-label-gap: var(--dees-input-spacing-unit); /* 8px */
|
||
|
}
|
||
|
|
||
|
/* Default vertical stacking mode (for forms) */
|
||
|
:host {
|
||
|
display: block;
|
||
|
margin: 0;
|
||
|
margin-bottom: var(--dees-input-vertical-gap);
|
||
|
}
|
||
|
|
||
|
/* Last child in container should have no bottom margin */
|
||
|
:host(:last-child) {
|
||
|
margin-bottom: 0;
|
||
|
}
|
||
|
|
||
|
/* Horizontal layout mode - activated by attribute */
|
||
|
:host([layout-mode="horizontal"]) {
|
||
|
display: inline-block;
|
||
|
margin: 0;
|
||
|
margin-right: var(--dees-input-horizontal-gap);
|
||
|
margin-bottom: 0;
|
||
|
}
|
||
|
|
||
|
:host([layout-mode="horizontal"]:last-child) {
|
||
|
margin-right: 0;
|
||
|
}
|
||
|
|
||
|
/* Auto mode - inherit from parent dees-form if present */
|
||
|
|
||
|
/* Label position variations */
|
||
|
:host([label-position="left"]) .input-wrapper {
|
||
|
display: grid;
|
||
|
grid-template-columns: auto 1fr;
|
||
|
gap: var(--dees-input-label-gap);
|
||
|
align-items: center;
|
||
|
}
|
||
|
|
||
|
:host([label-position="right"]) .input-wrapper {
|
||
|
display: grid;
|
||
|
grid-template-columns: 1fr auto;
|
||
|
gap: var(--dees-input-label-gap);
|
||
|
align-items: center;
|
||
|
}
|
||
|
|
||
|
:host([label-position="top"]) .input-wrapper {
|
||
|
display: block;
|
||
|
}
|
||
|
|
||
|
:host([label-position="none"]) dees-label {
|
||
|
display: none;
|
||
|
}
|
||
|
`,
|
||
|
];
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Subject for value changes that all inputs should implement
|
||
|
*/
|
||
|
public changeSubject = new domtools.plugins.smartrx.rxjs.Subject<T>();
|
||
|
|
||
|
/**
|
||
|
* Called when the element is connected to the DOM
|
||
|
* Sets up layout mode detection
|
||
|
*/
|
||
|
async connectedCallback() {
|
||
|
await super.connectedCallback();
|
||
|
this.detectLayoutMode();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Detects the appropriate layout mode based on parent context
|
||
|
*/
|
||
|
private detectLayoutMode() {
|
||
|
if (this.layoutMode !== 'auto') {
|
||
|
this.setAttribute('layout-mode', this.layoutMode);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Check if parent is a form with horizontal layout
|
||
|
const parentForm = this.closest('dees-form');
|
||
|
if (parentForm && parentForm.hasAttribute('horizontal-layout')) {
|
||
|
this.setAttribute('layout-mode', 'horizontal');
|
||
|
} else {
|
||
|
this.setAttribute('layout-mode', 'vertical');
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Updates the layout mode attribute when property changes
|
||
|
*/
|
||
|
updated(changedProperties: Map<string, any>) {
|
||
|
super.updated(changedProperties);
|
||
|
|
||
|
if (changedProperties.has('layoutMode')) {
|
||
|
this.detectLayoutMode();
|
||
|
}
|
||
|
|
||
|
if (changedProperties.has('labelPosition')) {
|
||
|
this.setAttribute('label-position', this.labelPosition);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Standard method for freezing input (disabling)
|
||
|
*/
|
||
|
public async freeze() {
|
||
|
this.disabled = true;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Standard method for unfreezing input (enabling)
|
||
|
*/
|
||
|
public async unfreeze() {
|
||
|
this.disabled = false;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Abstract method that child classes must implement to get their value
|
||
|
*/
|
||
|
public abstract getValue(): any;
|
||
|
|
||
|
/**
|
||
|
* Abstract method that child classes must implement to set their value
|
||
|
*/
|
||
|
public abstract setValue(value: any): void;
|
||
|
}
|