-
-
-
- ${this.enableSearch && !this.opensToTop
- ? html`
-
-
-
- `
- : null}
- ${this.filteredOptions.map((option, index) => {
- const isHighlighted = this.highlightedIndex === index;
- return html`
-
{
- this.updateSelection(option);
- }}
- >
- ${option.option}
-
- `;
- })}
- ${this.enableSearch && this.opensToTop
- ? html`
-
-
-
- `
- : null}
-
-
{
- if (!this.isElevated) {
- this.toggleSelectionBox();
- } else {
- this.updateSelection(this.selectedOption);
- }
- }}"
- >
- ${this.selectedOption?.option || 'Select...'}
+
+
+
!this.disabled && this.toggleSelectionBox()}"
+ tabindex="${this.disabled ? '-1' : '0'}"
+ @keydown="${this.handleSelectedBoxKeydown}"
+ >
+ ${this.selectedOption?.option || 'Select an option'}
+
+
+ ${this.enableSearch
+ ? html`
+
+ e.stopPropagation()}"
+ @keydown="${this.handleSearchKeydown}"
+ />
+
+ `
+ : null}
+
+ ${this.filteredOptions.length === 0
+ ? html`
No options found
`
+ : this.filteredOptions.map((option, index) => {
+ const isHighlighted = this.highlightedIndex === index;
+ return html`
+
this.updateSelection(option)}"
+ @mouseenter="${() => this.highlightedIndex = index}"
+ >
+ ${option.option}
+
+ `;
+ })
+ }
+
`;
}
- firstUpdated() {
- this.selectedOption = this.selectedOption || null;
- this.filteredOptions = this.options; // Initialize filteredOptions
+ async connectedCallback() {
+ super.connectedCallback();
+ this.handleClickOutside = this.handleClickOutside.bind(this);
}
- public async updateSelection(selectedOption) {
+ firstUpdated() {
+ this.selectedOption = this.selectedOption || null;
+ this.filteredOptions = this.options;
+ }
+
+ updated(changedProperties: Map
) {
+ super.updated(changedProperties);
+
+ if (changedProperties.has('options')) {
+ this.filteredOptions = this.options;
+ }
+ }
+
+ public async updateSelection(selectedOption: { option: string; key: string; payload?: any }) {
this.selectedOption = selectedOption;
+ this.isOpened = false;
+ this.searchValue = '';
+ this.filteredOptions = this.options;
+ this.highlightedIndex = 0;
this.dispatchEvent(
new CustomEvent('selectedOption', {
@@ -253,135 +348,105 @@ export class DeesInputDropdown extends DeesInputBase {
bubbles: true,
})
);
- if (this.isElevated) {
- this.toggleSelectionBox();
- }
+
this.changeSubject.next(this);
}
- private isElevated: boolean = false;
- private windowOverlay: DeesWindowLayer;
+ private handleClickOutside = (event: MouseEvent) => {
+ const path = event.composedPath();
+ if (!path.includes(this)) {
+ this.isOpened = false;
+ this.searchValue = '';
+ this.filteredOptions = this.options;
+ document.removeEventListener('click', this.handleClickOutside);
+ }
+ };
+
public async toggleSelectionBox() {
this.isOpened = !this.isOpened;
- const domtoolsInstance = await this.domtoolsPromise;
- const selectedBox: HTMLElement = this.shadowRoot.querySelector('.selectedBox');
- const selectionBox: HTMLElement = this.shadowRoot.querySelector('.selectionBox');
- if (!this.isElevated) {
- this.windowOverlay = await DeesWindowLayer.createAndShow({
- blur: false,
- });
- const elevatedDropdown = new DeesInputDropdown();
- elevatedDropdown.isElevated = true;
- elevatedDropdown.label = this.label;
- elevatedDropdown.enableSearch = this.enableSearch;
- elevatedDropdown.required = this.required;
- elevatedDropdown.disabled = this.disabled;
- elevatedDropdown.style.position = 'fixed';
- elevatedDropdown.style.top = this.getBoundingClientRect().top + 'px';
- elevatedDropdown.style.left = this.getBoundingClientRect().left + 'px';
- elevatedDropdown.style.width = this.clientWidth + 'px';
+
+ if (this.isOpened) {
+ // Check available space and set position
+ const selectedBox = this.shadowRoot.querySelector('.selectedBox') as HTMLElement;
+ const rect = selectedBox.getBoundingClientRect();
+ const spaceBelow = window.innerHeight - rect.bottom;
+ const spaceAbove = rect.top;
- // Get z-index from registry for the elevated dropdown
- const dropdownZIndex = (await import('./00zindex.js')).zIndexRegistry.getNextZIndex();
- elevatedDropdown.style.zIndex = dropdownZIndex.toString();
- (await import('./00zindex.js')).zIndexRegistry.register(elevatedDropdown, dropdownZIndex);
- elevatedDropdown.options = this.options;
- elevatedDropdown.selectedOption = this.selectedOption;
- elevatedDropdown.highlightedIndex = elevatedDropdown.selectedOption ? elevatedDropdown.options.indexOf(
- elevatedDropdown.options.find((option) => option.key === this.selectedOption.key)
- ) : -1;
- console.log(elevatedDropdown.options);
- console.log(elevatedDropdown.selectedOption);
- console.log(elevatedDropdown.highlightedIndex);
- this.windowOverlay.appendChild(elevatedDropdown);
+ // Determine if we should open upwards
+ this.opensToTop = spaceBelow < 300 && spaceAbove > spaceBelow;
- // Prevent clicks on the dropdown from closing it
- elevatedDropdown.addEventListener('click', (e: Event) => {
- e.stopPropagation();
- });
-
- await domtoolsInstance.convenience.smartdelay.delayFor(0);
- elevatedDropdown.toggleSelectionBox();
- const destroyOverlay = async () => {
- (elevatedDropdown.shadowRoot.querySelector('.selectionBox') as HTMLElement).style.opacity =
- '0';
- elevatedDropdown.removeEventListener('selectedOption', handleSelection);
- this.windowOverlay.removeEventListener('clicked', destroyOverlay);
-
- // Unregister elevated dropdown from z-index registry
- (await import('./00zindex.js')).zIndexRegistry.unregister(elevatedDropdown);
-
- this.windowOverlay.destroy();
- };
- const handleSelection = async () => {
- await this.updateSelection(elevatedDropdown.selectedOption);
- destroyOverlay();
- };
- elevatedDropdown.addEventListener('selectedOption', handleSelection);
- this.windowOverlay.addEventListener('clicked', destroyOverlay);
- } else {
- if (!selectionBox.classList.contains('show')) {
- selectionBox.style.width = selectedBox.clientWidth + 'px';
- const spaceData = selectedBox.getBoundingClientRect();
- if (300 > window.innerHeight - spaceData.bottom) {
- this.opensToTop = true;
- selectedBox.classList.add('accentTop');
- selectionBox.classList.add('top');
- selectionBox.style.bottom = selectedBox.clientHeight + 2 + 'px';
- } else {
- selectedBox.classList.add('accentBottom');
- selectionBox.classList.add('bottom');
- this.opensToTop = false;
- const labelOffset = this.label ? 24 : 0;
- selectionBox.style.top = selectedBox.clientHeight + labelOffset + 'px';
- }
- await domtoolsInstance.convenience.smartdelay.delayFor(0);
- const searchInput = selectionBox.querySelector('input');
- searchInput?.focus();
-
- // Get z-index from registry for the selection box
- const selectionBoxZIndex = (await import('./00zindex.js')).zIndexRegistry.getNextZIndex();
- selectionBox.style.zIndex = selectionBoxZIndex.toString();
- (await import('./00zindex.js')).zIndexRegistry.register(selectionBox as HTMLElement, selectionBoxZIndex);
-
- selectionBox.classList.add('show');
- } else {
- selectedBox.style.pointerEvents = 'none';
- selectionBox.classList.remove('show');
-
- // Unregister selection box from z-index registry
- (await import('./00zindex.js')).zIndexRegistry.unregister(selectionBox as HTMLElement);
-
- // selectedBox.style.opacity = '0';
+ // Focus search input if present
+ await this.updateComplete;
+ const searchInput = this.shadowRoot.querySelector('.search input') as HTMLInputElement;
+ if (searchInput) {
+ searchInput.focus();
}
+
+ // Add click outside listener
+ setTimeout(() => {
+ document.addEventListener('click', this.handleClickOutside);
+ }, 0);
+ } else {
+ // Cleanup
+ this.searchValue = '';
+ this.filteredOptions = this.options;
+ document.removeEventListener('click', this.handleClickOutside);
}
}
private handleSearch(event: Event): void {
- const searchTerm = (event.target as HTMLInputElement).value.toLowerCase();
+ const searchTerm = (event.target as HTMLInputElement).value;
+ this.searchValue = searchTerm;
+ const searchLower = searchTerm.toLowerCase();
this.filteredOptions = this.options.filter((option) =>
- option.option.toLowerCase().includes(searchTerm)
+ option.option.toLowerCase().includes(searchLower)
);
- this.highlightedIndex = 0; // Reset highlighted index
+ this.highlightedIndex = 0;
}
private handleKeyDown(event: KeyboardEvent): void {
- if (!this.isOpened) {
- console.log('discarded key event. Check why this function is called.');
- return;
- }
const key = event.key;
const maxIndex = this.filteredOptions.length - 1;
if (key === 'ArrowDown') {
+ event.preventDefault();
this.highlightedIndex = this.highlightedIndex + 1 > maxIndex ? 0 : this.highlightedIndex + 1;
- event.preventDefault();
} else if (key === 'ArrowUp') {
+ event.preventDefault();
this.highlightedIndex = this.highlightedIndex - 1 < 0 ? maxIndex : this.highlightedIndex - 1;
- event.preventDefault();
} else if (key === 'Enter') {
- this.updateSelection(this.filteredOptions[this.highlightedIndex]);
event.preventDefault();
+ if (this.filteredOptions[this.highlightedIndex]) {
+ this.updateSelection(this.filteredOptions[this.highlightedIndex]);
+ }
+ } else if (key === 'Escape') {
+ event.preventDefault();
+ this.isOpened = false;
+ }
+ }
+
+ private handleSearchKeydown(event: KeyboardEvent): void {
+ if (event.key === 'ArrowDown' || event.key === 'ArrowUp' || event.key === 'Enter') {
+ this.handleKeyDown(event);
+ }
+ }
+
+ private handleSelectedBoxKeydown(event: KeyboardEvent) {
+ if (this.disabled) return;
+
+ if (event.key === 'Enter' || event.key === ' ') {
+ event.preventDefault();
+ this.toggleSelectionBox();
+ } else if (event.key === 'ArrowDown' || event.key === 'ArrowUp') {
+ event.preventDefault();
+ if (!this.isOpened) {
+ this.toggleSelectionBox();
+ }
+ } else if (event.key === 'Escape') {
+ event.preventDefault();
+ if (this.isOpened) {
+ this.isOpened = false;
+ }
}
}
@@ -392,4 +457,9 @@ export class DeesInputDropdown extends DeesInputBase {
public setValue(value: { option: string; key: string; payload?: any }): void {
this.selectedOption = value;
}
-}
+
+ async disconnectedCallback() {
+ await super.disconnectedCallback();
+ document.removeEventListener('click', this.handleClickOutside);
+ }
+}
\ No newline at end of file
diff --git a/ts_web/elements/dees-input-radiogroup.ts b/ts_web/elements/dees-input-radiogroup.ts
index 14215b6..1ff6e99 100644
--- a/ts_web/elements/dees-input-radiogroup.ts
+++ b/ts_web/elements/dees-input-radiogroup.ts
@@ -69,80 +69,97 @@ export class DeesInputRadiogroup extends DeesInputBase {
:host {
display: block;
position: relative;
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif;
}
.maincontainer {
display: flex;
flex-direction: column;
- gap: 8px;
+ gap: 10px;
}
.maincontainer.horizontal {
flex-direction: row;
flex-wrap: wrap;
- gap: 16px;
+ gap: 20px;
}
.radio-option {
display: flex;
align-items: center;
- gap: 12px;
- padding: 8px 0;
+ gap: 10px;
+ padding: 6px 0;
cursor: pointer;
- transition: all 0.2s ease;
+ transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
user-select: none;
position: relative;
+ border-radius: 4px;
}
.maincontainer.horizontal .radio-option {
- padding: 8px 16px 8px 0;
+ padding: 6px 20px 6px 0;
}
.radio-option:hover .radio-circle {
- border-color: ${cssManager.bdTheme('#0050b9', '#0084ff')};
+ border-color: ${cssManager.bdTheme('hsl(215 20.2% 65.1%)', 'hsl(215 20.2% 35.1%)')};
+ background: ${cssManager.bdTheme('hsl(210 40% 96.1%)', 'hsl(215 20.2% 11.8%)')};
}
.radio-option:hover .radio-label {
- color: ${cssManager.bdTheme('#1a1a1a', '#ffffff')};
+ color: ${cssManager.bdTheme('hsl(215.3 25% 8.8%)', 'hsl(210 40% 98%)')};
}
.radio-circle {
width: 20px;
height: 20px;
border-radius: 50%;
- border: 2px solid ${cssManager.bdTheme('#999', '#666')};
- background: ${cssManager.bdTheme('#fff', '#1a1a1a')};
- transition: all 0.2s ease;
+ border: 2px solid ${cssManager.bdTheme('hsl(215 20.2% 65.1%)', 'hsl(215 20.2% 35.1%)')};
+ background: ${cssManager.bdTheme('hsl(0 0% 100%)', 'hsl(215 30% 6.8%)')};
+ transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
position: relative;
flex-shrink: 0;
+ display: flex;
+ align-items: center;
+ justify-content: center;
}
.radio-option.selected .radio-circle {
- border-color: ${cssManager.bdTheme('#0050b9', '#0084ff')};
- background: ${cssManager.bdTheme('#0050b9', '#0084ff')};
+ border-color: ${cssManager.bdTheme('hsl(217.2 91.2% 59.8%)', 'hsl(213.1 93.9% 67.8%)')};
+ background: ${cssManager.bdTheme('hsl(217.2 91.2% 59.8%)', 'hsl(213.1 93.9% 67.8%)')};
}
.radio-option.selected .radio-circle::after {
content: '';
position: absolute;
- top: 50%;
- left: 50%;
- transform: translate(-50%, -50%);
width: 8px;
height: 8px;
border-radius: 50%;
- background: white;
+ background: ${cssManager.bdTheme('hsl(0 0% 100%)', 'hsl(215 30% 6.8%)')};
+ transform: scale(0);
+ transition: transform 0.2s cubic-bezier(0.4, 0, 0.2, 1);
+ }
+
+ .radio-option.selected .radio-circle::after {
+ transform: scale(1);
+ }
+
+ .radio-circle:focus-visible {
+ outline: none;
+ box-shadow: 0 0 0 2px ${cssManager.bdTheme('hsl(0 0% 100%)', 'hsl(215 30% 3.9%)')},
+ 0 0 0 4px ${cssManager.bdTheme('hsl(217.2 91.2% 59.8%)', 'hsl(213.1 93.9% 67.8%)')};
}
.radio-label {
font-size: 14px;
- color: ${cssManager.bdTheme('#666', '#999')};
- transition: color 0.2s ease;
+ font-weight: 500;
+ color: ${cssManager.bdTheme('hsl(215.3 25% 26.7%)', 'hsl(217.9 10.6% 74.9%)')};
+ transition: color 0.2s cubic-bezier(0.4, 0, 0.2, 1);
+ letter-spacing: -0.006em;
+ line-height: 20px;
}
.radio-option.selected .radio-label {
- color: ${cssManager.bdTheme('#1a1a1a', '#ffffff')};
- font-weight: 500;
+ color: ${cssManager.bdTheme('hsl(215.3 25% 8.8%)', 'hsl(210 40% 98%)')};
}
:host([disabled]) .radio-option {
@@ -151,40 +168,49 @@ export class DeesInputRadiogroup extends DeesInputBase {
}
:host([disabled]) .radio-option:hover .radio-circle {
- border-color: ${cssManager.bdTheme('#999', '#666')};
+ border-color: ${cssManager.bdTheme('hsl(215 20.2% 65.1%)', 'hsl(215 20.2% 35.1%)')};
+ background: ${cssManager.bdTheme('hsl(0 0% 100%)', 'hsl(215 30% 6.8%)')};
}
:host([disabled]) .radio-option:hover .radio-label {
- color: ${cssManager.bdTheme('#666', '#999')};
+ color: ${cssManager.bdTheme('hsl(215.3 25% 26.7%)', 'hsl(217.9 10.6% 74.9%)')};
}
.label-text {
font-size: 14px;
font-weight: 500;
- color: ${cssManager.bdTheme('#333', '#ccc')};
- margin-bottom: 8px;
+ color: ${cssManager.bdTheme('hsl(215.3 25% 8.8%)', 'hsl(210 40% 98%)')};
+ margin-bottom: 10px;
+ letter-spacing: -0.006em;
+ line-height: 20px;
}
.description-text {
- font-size: 12px;
- color: ${cssManager.bdTheme('#666', '#999')};
- margin-top: 8px;
- line-height: 1.4;
+ font-size: 13px;
+ color: ${cssManager.bdTheme('hsl(215.4 16.3% 56.9%)', 'hsl(215 20.2% 55.1%)')};
+ margin-top: 10px;
+ line-height: 1.5;
+ letter-spacing: -0.003em;
}
/* Validation styles */
:host([validationState="invalid"]) .radio-circle {
- border-color: #e74c3c;
+ border-color: ${cssManager.bdTheme('hsl(0 72.2% 50.6%)', 'hsl(0 62.8% 30.6%)')};
+ }
+
+ :host([validationState="invalid"]) .radio-option.selected .radio-circle {
+ border-color: ${cssManager.bdTheme('hsl(0 72.2% 50.6%)', 'hsl(0 62.8% 30.6%)')};
+ background: ${cssManager.bdTheme('hsl(0 72.2% 50.6%)', 'hsl(0 62.8% 30.6%)')};
}
:host([validationState="valid"]) .radio-option.selected .radio-circle {
- border-color: #27ae60;
- background: #27ae60;
+ border-color: ${cssManager.bdTheme('hsl(142.1 70.6% 45.3%)', 'hsl(142.1 76.2% 36.3%)')};
+ background: ${cssManager.bdTheme('hsl(142.1 70.6% 45.3%)', 'hsl(142.1 76.2% 36.3%)')};
}
:host([validationState="warn"]) .radio-option.selected .radio-circle {
- border-color: #f39c12;
- background: #f39c12;
+ border-color: ${cssManager.bdTheme('hsl(45.4 93.4% 47.5%)', 'hsl(45.4 93.4% 47.5%)')};
+ background: ${cssManager.bdTheme('hsl(45.4 93.4% 47.5%)', 'hsl(45.4 93.4% 47.5%)')};
}
/* Override base grid layout for radiogroup to prevent large gaps */
@@ -212,8 +238,15 @@ export class DeesInputRadiogroup extends DeesInputBase {
this.selectOption(optionKey)}"
+ @keydown="${(e: KeyboardEvent) => this.handleKeydown(e, optionKey)}"
>
-
+
${optionLabel}
`;
@@ -292,4 +325,33 @@ export class DeesInputRadiogroup extends DeesInputBase {
this.selectedOption = this.getOptionKey(firstOption);
}
}
+
+ private handleKeydown(event: KeyboardEvent, optionKey: string) {
+ if (this.disabled) return;
+
+ if (event.key === ' ' || event.key === 'Enter') {
+ event.preventDefault();
+ this.selectOption(optionKey);
+ } else if (event.key === 'ArrowDown' || event.key === 'ArrowRight') {
+ event.preventDefault();
+ this.focusNextOption();
+ } else if (event.key === 'ArrowUp' || event.key === 'ArrowLeft') {
+ event.preventDefault();
+ this.focusPreviousOption();
+ }
+ }
+
+ private focusNextOption() {
+ const radioCircles = Array.from(this.shadowRoot.querySelectorAll('.radio-circle'));
+ const currentIndex = radioCircles.findIndex(el => el === this.shadowRoot.activeElement);
+ const nextIndex = (currentIndex + 1) % radioCircles.length;
+ (radioCircles[nextIndex] as HTMLElement).focus();
+ }
+
+ private focusPreviousOption() {
+ const radioCircles = Array.from(this.shadowRoot.querySelectorAll('.radio-circle'));
+ const currentIndex = radioCircles.findIndex(el => el === this.shadowRoot.activeElement);
+ const prevIndex = currentIndex <= 0 ? radioCircles.length - 1 : currentIndex - 1;
+ (radioCircles[prevIndex] as HTMLElement).focus();
+ }
}
\ No newline at end of file
diff --git a/ts_web/elements/dees-input-text.demo.ts b/ts_web/elements/dees-input-text.demo.ts
index 472a076..e1cfc36 100644
--- a/ts_web/elements/dees-input-text.demo.ts
+++ b/ts_web/elements/dees-input-text.demo.ts
@@ -1,5 +1,6 @@
-import { html, css } from '@design.estate/dees-element';
+import { html, css, cssManager } from '@design.estate/dees-element';
import '@design.estate/dees-wcctools/demotools';
+import './dees-panel.js';
export const demoFunc = () => html`
@@ -14,36 +15,12 @@ export const demoFunc = () => html`
margin: 0 auto;
}
- .demo-section {
- background: #f8f9fa;
- border-radius: 8px;
- padding: 24px;
+ dees-panel {
+ margin-bottom: 24px;
}
- @media (prefers-color-scheme: dark) {
- .demo-section {
- background: #1a1a1a;
- }
- }
-
- .demo-section h3 {
- margin-top: 0;
- margin-bottom: 16px;
- color: #0069f2;
- font-size: 18px;
- }
-
- .demo-section p {
- margin-top: 0;
- margin-bottom: 16px;
- color: #666;
- font-size: 14px;
- }
-
- @media (prefers-color-scheme: dark) {
- .demo-section p {
- color: #999;
- }
+ dees-panel:last-child {
+ margin-bottom: 0;
}
.horizontal-group {
@@ -64,14 +41,28 @@ export const demoFunc = () => html`
grid-template-columns: 1fr;
}
}
+
+ .interactive-section {
+ background: ${cssManager.bdTheme('hsl(210 40% 96.1%)', 'hsl(215 20.2% 16.8%)')};
+ border-radius: 8px;
+ padding: 16px;
+ margin-top: 16px;
+ }
+
+ .output-text {
+ font-family: monospace;
+ font-size: 13px;
+ color: ${cssManager.bdTheme('hsl(215.3 25% 26.7%)', 'hsl(210 40% 80%)')};
+ padding: 8px;
+ background: ${cssManager.bdTheme('hsl(210 40% 98%)', 'hsl(215 20.2% 11.8%)')};
+ border-radius: 4px;
+ min-height: 24px;
+ }
`}
-
-
Basic Text Inputs
-
Standard text inputs with labels and descriptions
-
+
html`
.value=${'secret123'}
.key=${'password'}
>
-
+
-
-
Horizontal Layout
-
Multiple inputs arranged horizontally for compact forms
-
+
html`
.key=${'age'}
>
-
+
-
-
Label Positions
-
Different label positioning options for various layouts
-
+
html`
.labelPosition=${'left'}
>
-
+
-
-
Validation & States
-
Different validation states and input configurations
-
+
html`
.validationText=${'Please enter a valid email address'}
.validationState=${'invalid'}
>
-
+
-
-
Advanced Features
-
Password visibility toggle and other advanced features
-
+
html`
.value=${'sk-1234567890abcdef'}
.description=${'Keep this key secure and never share it'}
>
-
+
+
+
+ {
+ const output = document.querySelector('#text-input-output');
+ if (output && event.detail) {
+ output.textContent = `Current value: "${event.detail.getValue()}"`;
+ }
+ }}
+ >
+
+
+
`;
\ No newline at end of file
diff --git a/ts_web/elements/dees-input-text.ts b/ts_web/elements/dees-input-text.ts
index 9d9466c..6a6e3a9 100644
--- a/ts_web/elements/dees-input-text.ts
+++ b/ts_web/elements/dees-input-text.ts
@@ -65,77 +65,126 @@ export class DeesInputText extends DeesInputBase {
:host {
position: relative;
z-index: auto;
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif;
}
.maincontainer {
- color: ${cssManager.bdTheme('#333', '#ccc')};
+ position: relative;
+ color: ${cssManager.bdTheme('hsl(0 0% 15%)', 'hsl(0 0% 90%)')};
}
input {
- margin-top: 0px;
- background: ${cssManager.bdTheme('#fafafa', '#222')};
- border-top: ${cssManager.bdTheme('1px solid #CCC', '1px solid #ffffff10')};
- border-bottom: ${cssManager.bdTheme('1px solid #CCC', '1px solid #222')};
- border-right: ${cssManager.bdTheme('1px solid #CCC', 'none')};
- border-left: ${cssManager.bdTheme('1px solid #CCC', 'none')};
- padding-left: 10px;
- padding-right: 10px;
- border-radius: 2px;
+ display: flex;
+ height: 40px;
width: 100%;
- line-height: 36px;
- transition: all 0.2s;
+ padding: 0 12px;
+ font-size: 14px;
+ line-height: 40px;
+ background: transparent;
+ border: 1px solid ${cssManager.bdTheme('hsl(0 0% 89.8%)', 'hsl(0 0% 14.9%)')};
+ border-radius: 6px;
+ transition: all 0.15s ease;
outline: none;
- font-size: 16px;
- position: relative;
- z-index: 2;
- cursor: default;
+ cursor: text;
+ font-family: inherit;
+ color: ${cssManager.bdTheme('hsl(0 0% 9%)', 'hsl(0 0% 95%)')};
}
- input:disabled {
- background: ${cssManager.bdTheme('#ffffff00', '#11111100')};
- border: 1px dashed ${cssManager.bdTheme('#666666', '#666666')};
- color: #9b9b9e;
- cursor: default;
+ input::placeholder {
+ color: ${cssManager.bdTheme('hsl(0 0% 63.9%)', 'hsl(0 0% 45.1%)')};
+ }
+
+ 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-bottom: 1px solid
- ${cssManager.bdTheme(colors.bright.blueActive, colors.dark.blueActive)};
- cursor: text;
+ border-color: ${cssManager.bdTheme('hsl(222.2 47.4% 51.2%)', 'hsl(217.2 91.2% 59.8%)')};
+ box-shadow: 0 0 0 3px ${cssManager.bdTheme('hsl(222.2 47.4% 51.2% / 0.1)', 'hsl(217.2 91.2% 59.8% / 0.1)')};
}
- input:hover {
- filter: ${cssManager.bdTheme('brightness(0.95)', 'brightness(1.1)')};
+ 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% 63.9%)', 'hsl(0 0% 45.1%)')};
+ cursor: not-allowed;
+ opacity: 0.5;
}
+ /* Password toggle button */
.showPassword {
position: absolute;
- bottom: 7px;
- right: 10px;
- border: 1px dashed #444;
- border-radius: 7px;
- padding: 4px 0px;
- width: 40px;
- z-index: 3;
- text-align: center;
+ 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('#00000010', '#ffffff10')};
+ 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 {
- text-align: center;
- padding: 6px 2px 2px 2px;
- margin-top: -4px;
+ margin-top: 4px;
+ padding: 4px 8px;
font-size: 12px;
- color: #fff;
- background: #e4002b;
- position: relative;
- z-index: 1;
- border-radius: 3px;
- transition: all 0.2s;
+ 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 {
+ box-shadow: 0 0 0 3px ${cssManager.bdTheme('hsl(0 84.2% 60.2% / 0.1)', 'hsl(0 72.2% 50.6% / 0.1)')};
+ }
+
+ /* 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 {
+ box-shadow: 0 0 0 3px ${cssManager.bdTheme('hsl(25 95% 53% / 0.1)', 'hsl(25 95% 63% / 0.1)')};
+ }
+
+ /* 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 {
+ box-shadow: 0 0 0 3px ${cssManager.bdTheme('hsl(142.1 76.2% 36.3% / 0.1)', 'hsl(142.1 70.6% 45.3% / 0.1)')};
}
`,
];
@@ -144,42 +193,51 @@ export class DeesInputText extends DeesInputBase {
return html`
`;
@@ -205,7 +263,6 @@ export class DeesInputText extends DeesInputBase {
public async togglePasswordView() {
this.showPasswordBool = !this.showPasswordBool;
- console.log(`this.showPasswordBool is: ${this.showPasswordBool}`);
}
public async focus() {
diff --git a/ts_web/elements/dees-label.ts b/ts_web/elements/dees-label.ts
index 80ef4d9..f5b7b97 100644
--- a/ts_web/elements/dees-label.ts
+++ b/ts_web/elements/dees-label.ts
@@ -32,20 +32,43 @@ export class DeesLabel extends DeesElement {
})
public description: string;
+ @property({
+ type: Boolean,
+ reflect: true,
+ })
+ public required: boolean = false;
+
public static styles = [
cssManager.defaultStyles,
css`
+ :host {
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif;
+ }
+
.label {
- color: ${cssManager.bdTheme('#333', '#ccc')};
+ display: inline-block;
+ color: ${cssManager.bdTheme('hsl(0 0% 15%)', 'hsl(0 0% 90%)')};
font-size: 14px;
- margin-bottom: 8px;
+ font-weight: 500;
+ line-height: 1.5;
+ margin-bottom: 6px;
cursor: default;
user-select: none;
+ letter-spacing: -0.01em;
}
+
+ .required {
+ color: ${cssManager.bdTheme('hsl(0 84.2% 60.2%)', 'hsl(0 72.2% 50.6%)')};
+ margin-left: 2px;
+ }
+
dees-icon {
display: inline-block;
- font-size: 14px;
- transform: translateY(1.5px);
+ font-size: 12px;
+ transform: translateY(1px);
+ margin-left: 4px;
+ color: ${cssManager.bdTheme('hsl(0 0% 45.1%)', 'hsl(0 0% 63.9%)')};
+ cursor: help;
}
`,
];
@@ -56,9 +79,10 @@ export class DeesLabel extends DeesElement {
? html`
${this.label}
+ ${this.required ? html`*` : ''}
${this.description
? html`
-
+
`
: html``}