From 65aa9f3c060c25a1d65a99e925bdb8dd6a5e58b7 Mon Sep 17 00:00:00 2001 From: Juergen Kunz Date: Fri, 27 Jun 2025 16:20:06 +0000 Subject: [PATCH] update --- ts_web/elements/dees-input-checkbox.demo.ts | 288 +++++++----- ts_web/elements/dees-input-checkbox.ts | 170 ++++--- ts_web/elements/dees-input-dropdown.ts | 496 +++++++++++--------- ts_web/elements/dees-input-radiogroup.ts | 132 ++++-- ts_web/elements/dees-input-text.demo.ts | 104 ++-- ts_web/elements/dees-input-text.ts | 165 ++++--- ts_web/elements/dees-label.ts | 34 +- 7 files changed, 818 insertions(+), 571 deletions(-) diff --git a/ts_web/elements/dees-input-checkbox.demo.ts b/ts_web/elements/dees-input-checkbox.demo.ts index ad2c70a..4940b56 100644 --- a/ts_web/elements/dees-input-checkbox.demo.ts +++ b/ts_web/elements/dees-input-checkbox.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'; import type { DeesInputCheckbox } from './dees-input-checkbox.js'; import './dees-button.js'; @@ -41,62 +42,49 @@ 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; - } - } - - .horizontal-group { - display: flex; - align-items: center; - gap: 16px; - flex-wrap: wrap; + dees-panel:last-child { + margin-bottom: 0; } .checkbox-group { display: flex; flex-direction: column; - gap: 8px; + gap: 12px; } - .feature-list { - background: #f0f0f0; - border-radius: 4px; + .horizontal-checkboxes { + display: flex; + gap: 24px; + flex-wrap: wrap; + } + + .interactive-section { + background: ${cssManager.bdTheme('hsl(210 40% 96.1%)', 'hsl(215 20.2% 16.8%)')}; + border-radius: 8px; padding: 16px; - margin-bottom: 16px; + margin-top: 16px; } - @media (prefers-color-scheme: dark) { - .feature-list { - background: #0a0a0a; - } + .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; + } + + .form-section { + background: ${cssManager.bdTheme('hsl(0 0% 97%)', 'hsl(0 0% 7%)')}; + border: 1px solid ${cssManager.bdTheme('hsl(0 0% 89.8%)', 'hsl(0 0% 14.9%)')}; + border-radius: 8px; + padding: 20px; + margin-top: 16px; } .button-group { @@ -104,70 +92,112 @@ export const demoFunc = () => html` gap: 8px; margin-bottom: 16px; } + + .feature-list { + background: ${cssManager.bdTheme('hsl(210 40% 96.1%)', 'hsl(215 20.2% 11.8%)')}; + border: 1px solid ${cssManager.bdTheme('hsl(214.3 31.8% 91.4%)', 'hsl(215 20.2% 16.8%)')}; + border-radius: 6px; + padding: 16px; + } + + .section-title { + font-size: 16px; + font-weight: 600; + margin-bottom: 16px; + color: ${cssManager.bdTheme('hsl(215.3 25% 8.8%)', 'hsl(210 40% 98%)')}; + } `}
-
-

Basic Checkboxes

-

Standard checkbox inputs for boolean selections

- - - - - - -
+ +
+ + + + + +
+
-
-

Horizontal Layout

-

Checkboxes arranged horizontally for compact forms

- -
+ +
+ + + + + + + + + +
+
+ + +
-
+ -
-

Feature Selection Example

-

Common use case for feature toggles with batch operations

- +
Select All Clear All @@ -206,62 +236,72 @@ export const demoFunc = () => html` >
-
+ -
-

States

-

Different checkbox states and configurations

- - - - - - -
+ +
+

Privacy Preferences

+ +
+ + + + + + + +
+
+
-
-

Real-world Examples

-

Common checkbox patterns in applications

- +
- - { + const output = document.querySelector('#checkbox-output'); + if (output && event.detail) { + const isChecked = event.detail.getValue(); + output.textContent = \`Feature is \${isChecked ? 'enabled' : 'disabled'}\`; + } + }} > - - { + const output = document.querySelector('#debug-output'); + if (output && event.detail) { + const isChecked = event.detail.getValue(); + output.textContent = \`Debug mode: \${isChecked ? 'ON' : 'OFF'}\`; + } + }} >
-
+ +
+
Feature is disabled
+
Debug mode: OFF
+
+
`; \ No newline at end of file diff --git a/ts_web/elements/dees-input-checkbox.ts b/ts_web/elements/dees-input-checkbox.ts index 3a894a4..3c10a79 100644 --- a/ts_web/elements/dees-input-checkbox.ts +++ b/ts_web/elements/dees-input-checkbox.ts @@ -44,120 +44,106 @@ export class DeesInputCheckbox extends DeesInputBase { :host { position: relative; cursor: default; - } - :host(:hover) { - filter: ${cssManager.bdTheme('brightness(0.95)', 'brightness(1.1)')}; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif; } .maincontainer { - display: flex; - align-items: center; - gap: 12px; - padding: 8px 0px; - color: ${cssManager.bdTheme('#333', '#ccc')}; + display: inline-flex; + align-items: flex-start; + gap: 8px; cursor: pointer; user-select: none; - transition: all 0.2s; - } - - .maincontainer:hover { - color: ${cssManager.bdTheme('#000', '#fff')}; - } - - .maincontainer:hover .checkbox { - border-color: ${cssManager.bdTheme('#999', '#888')}; - } - - input:focus { - outline: none; - border-bottom: 1px solid #e4002b; + transition: all 0.15s ease; } .checkbox { - transition: all 0.1s; - box-sizing: border-box; - border: 1px solid ${cssManager.bdTheme('#CCC', '#999')}; - border-radius: 2px; - height: 24px; - width: 24px; - display: inline-block; - background: ${cssManager.bdTheme('#fafafa', '#222')}; + position: relative; + height: 18px; + width: 18px; flex-shrink: 0; + border-radius: 4px; + border: 1px solid ${cssManager.bdTheme('hsl(0 0% 89.8%)', 'hsl(0 0% 14.9%)')}; + background: ${cssManager.bdTheme('hsl(0 0% 100%)', 'hsl(0 0% 3.9%)')}; + transition: all 0.15s ease; + margin-top: 1px; + } + + .maincontainer:hover .checkbox { + border-color: ${cssManager.bdTheme('hsl(0 0% 79.8%)', 'hsl(0 0% 20.9%)')}; } .checkbox.selected { - background: #0050b9; - border: 1px solid #0050b9; + background: ${cssManager.bdTheme('hsl(222.2 47.4% 51.2%)', 'hsl(217.2 91.2% 59.8%)')}; + border-color: ${cssManager.bdTheme('hsl(222.2 47.4% 51.2%)', 'hsl(217.2 91.2% 59.8%)')}; } - .checkbox.disabled { - background: none; - border: 1px dashed ${cssManager.bdTheme('#666666', '#666666')}; + .checkbox:focus-visible { + outline: none; + 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)')}; } + /* Checkmark using Lucide icon style */ .checkbox .checkmark { - display: inline-block; - width: 22px; - height: 22px; - -ms-transform: rotate(45deg); /* IE 9 */ - -webkit-transform: rotate(45deg); /* Chrome, Safari, Opera */ - transform: rotate(45deg); - } - - .checkbox .checkmark_stem { position: absolute; - width: 3px; - height: 9px; - background-color: #fff; - left: 11px; - top: 6px; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + opacity: 0; + transition: opacity 0.15s ease; } - .checkbox .checkmark_kick { - position: absolute; - width: 3px; - height: 3px; - background-color: #fff; - left: 8px; - top: 12px; + .checkbox.selected .checkmark { + opacity: 1; } - .checkbox.disabled .checkmark_stem, .checkbox.disabled .checkmark_kick { - background-color: ${cssManager.bdTheme('#333', '#fff')}; - } - - img { - padding: 4px; - } - - .checkbox-label { - font-size: 14px; - transition: color 0.2s ease; - } - - .maincontainer:hover .checkbox-label { - color: ${cssManager.bdTheme('#1a1a1a', '#ffffff')}; + .checkbox .checkmark svg { + width: 12px; + height: 12px; + stroke: white; + stroke-width: 3; } + /* Disabled state */ .maincontainer.disabled { cursor: not-allowed; opacity: 0.5; } - .maincontainer.disabled:hover { - color: ${cssManager.bdTheme('#333', '#ccc')}; + .checkbox.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%)')}; } - .maincontainer.disabled:hover .checkbox { - border-color: ${cssManager.bdTheme('#ccc', '#333')}; + /* Label */ + .label-container { + display: flex; + flex-direction: column; + gap: 2px; + flex: 1; } + .checkbox-label { + font-size: 14px; + font-weight: 500; + line-height: 20px; + color: ${cssManager.bdTheme('hsl(0 0% 15%)', 'hsl(0 0% 90%)')}; + transition: color 0.15s ease; + letter-spacing: -0.01em; + } + + .maincontainer:hover .checkbox-label { + color: ${cssManager.bdTheme('hsl(0 0% 9%)', 'hsl(0 0% 95%)')}; + } + + .maincontainer.disabled:hover .checkbox-label { + color: ${cssManager.bdTheme('hsl(0 0% 15%)', 'hsl(0 0% 90%)')}; + } + + /* Description */ .description-text { font-size: 12px; - color: ${cssManager.bdTheme('#666', '#999')}; - margin-top: 4px; - line-height: 1.4; - padding-left: 36px; + color: ${cssManager.bdTheme('hsl(0 0% 45.1%)', 'hsl(0 0% 63.9%)')}; + line-height: 1.5; } `, ]; @@ -166,21 +152,26 @@ export class DeesInputCheckbox extends DeesInputBase { return html`
-
+
${this.value ? html` -
-
+ + +
` : html``}
- ${this.label ? html`
${this.label}
` : ''} +
+ ${this.label ? html`
${this.label}
` : ''} + ${this.description ? html`
${this.description}
` : ''} +
- ${this.description ? html` -
${this.description}
- ` : ''}
`; } @@ -213,4 +204,11 @@ export class DeesInputCheckbox extends DeesInputBase { (checkboxDiv as any).focus(); } } + + private handleKeydown(event: KeyboardEvent) { + if (event.key === ' ' || event.key === 'Enter') { + event.preventDefault(); + this.toggleSelected(); + } + } } diff --git a/ts_web/elements/dees-input-dropdown.ts b/ts_web/elements/dees-input-dropdown.ts index 86744f3..02e0140 100644 --- a/ts_web/elements/dees-input-dropdown.ts +++ b/ts_web/elements/dees-input-dropdown.ts @@ -9,7 +9,6 @@ import { } from '@design.estate/dees-element'; import * as domtools from '@design.estate/dees-domtools'; import { demoFunc } from './dees-input-dropdown.demo.js'; -import { DeesWindowLayer } from './dees-windowlayer.js'; import { DeesInputBase } from './dees-input-base.js'; declare global { @@ -39,13 +38,11 @@ export class DeesInputDropdown extends DeesInputBase { this.selectedOption = val; } - @property({ type: Boolean, }) public enableSearch: boolean = true; - @state() public opensToTop: boolean = false; @@ -58,6 +55,9 @@ export class DeesInputDropdown extends DeesInputBase { @state() public isOpened = false; + @state() + private searchValue: string = ''; + public static styles = [ ...DeesInputBase.baseStyles, cssManager.defaultStyles, @@ -67,123 +67,201 @@ export class DeesInputDropdown extends DeesInputBase { } :host { - font-family: Roboto; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif; position: relative; - color: ${cssManager.bdTheme('#222', '#fff')}; + color: ${cssManager.bdTheme('hsl(0 0% 15%)', 'hsl(0 0% 90%)')}; } .maincontainer { display: block; + position: relative; } - .selectedBox { user-select: none; position: relative; - max-width: 420px; + width: 100%; height: 40px; - line-height: 40px; - padding: 0px 8px; - background: ${cssManager.bdTheme('#fafafa', '#222222')}; - box-shadow: ${cssManager.bdTheme('0px 1px 4px rgba(0,0,0,0.3)', 'none')}; - border-radius: 3px; - border-top: ${cssManager.bdTheme('1px solid #CCC', '1px solid #ffffff10')}; - border-bottom: ${cssManager.bdTheme('1px solid #CCC', '1px solid #222')}; - transition: all 0.2s ease; - font-size: 16px; - color: ${cssManager.bdTheme('#222', '#ccc')}; + line-height: 38px; + padding: 0 40px 0 12px; + 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; + font-size: 14px; + color: ${cssManager.bdTheme('hsl(0 0% 9%)', 'hsl(0 0% 95%)')}; + cursor: pointer; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; } - .selectedBox:hover { - filter: ${cssManager.bdTheme('brightness(0.95)', 'brightness(1.1)')}; + .selectedBox:hover:not(.disabled) { + border-color: ${cssManager.bdTheme('hsl(0 0% 79.8%)', 'hsl(0 0% 20.9%)')}; } - .accentBottom { - filter: none !important; + .selectedBox:focus-visible { + outline: none; + 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)')}; } - .accentTop { - filter: none !important; + .selectedBox.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; + } + + /* Dropdown arrow */ + .selectedBox::after { + content: ''; + position: absolute; + right: 12px; + top: 50%; + transform: translateY(-50%); + width: 0; + height: 0; + border-left: 4px solid transparent; + border-right: 4px solid transparent; + border-top: 4px solid ${cssManager.bdTheme('hsl(0 0% 45.1%)', 'hsl(0 0% 63.9%)')}; + transition: transform 0.15s ease; + } + + .selectedBox.open::after { + transform: translateY(-50%) rotate(180deg); } .selectionBox { - will-change: transform; + will-change: transform, opacity; pointer-events: none; - transition: all 0.2s ease; + transition: all 0.15s ease; opacity: 0; - background: ${cssManager.bdTheme('#ffffff', '#222222')}; - max-width: 420px; - box-shadow: 0px 0px 5px rgba(0, 0, 0, 0.2); + transform: translateY(-8px) scale(0.98); + background: ${cssManager.bdTheme('hsl(0 0% 100%)', 'hsl(0 0% 3.9%)')}; + border: 1px solid ${cssManager.bdTheme('hsl(0 0% 89.8%)', 'hsl(0 0% 14.9%)')}; + box-shadow: 0 4px 6px -1px hsl(0 0% 0% / 0.1), 0 2px 4px -2px hsl(0 0% 0% / 0.1); min-height: 40px; - border-radius: 8px; - padding: 4px 8px; + max-height: 300px; + overflow: hidden; + border-radius: 6px; position: absolute; user-select: none; - margin: 3px 0px 0px 0px; - border-top: ${cssManager.bdTheme('1px solid #CCC', '1px solid #ffffff10')}; + margin-top: 4px; + z-index: 50; + left: 0; + right: 0; } + .selectionBox.top { - transform: translate(0px, 4px); + bottom: calc(100% + 4px); + top: auto; + margin-top: 0; + margin-bottom: 4px; + transform: translateY(8px) scale(0.98); } + .selectionBox.bottom { - transform: translate(0px, -4px); + top: 100%; } .selectionBox.show { pointer-events: all; - transform: scale(1, 1) translate(0px, 0px); + transform: translateY(0) scale(1); opacity: 1; - box-shadow: 0px 0px 8px rgba(0, 0, 0, 0.8); } + /* Options container */ + .options-container { + max-height: 250px; + overflow-y: auto; + padding: 4px; + } + + /* Options */ .option { - transition: all 0.1s; + transition: all 0.15s ease; line-height: 32px; - padding: 0px 4px; - border-radius: 3px; - margin: 4px 0px; + padding: 0 8px; + border-radius: 4px; + margin: 2px 0; + cursor: pointer; + font-size: 14px; + color: ${cssManager.bdTheme('hsl(0 0% 15%)', 'hsl(0 0% 90%)')}; } .option.highlighted { - border-left: 2px solid #0069f2; - padding-left: 6px; - background: #ffffff20; + background: ${cssManager.bdTheme('hsl(0 0% 95.1%)', 'hsl(0 0% 14.9%)')}; } .option:hover { - color: #fff; - padding-left: 8px; - background: #0069f2; + background: ${cssManager.bdTheme('hsl(0 0% 95.1%)', 'hsl(0 0% 14.9%)')}; + color: ${cssManager.bdTheme('hsl(0 0% 9%)', 'hsl(0 0% 95%)')}; } - .search.top { - padding-top: 4px; + /* No options message */ + .no-options { + padding: 8px; + text-align: center; + font-size: 14px; + color: ${cssManager.bdTheme('hsl(0 0% 45.1%)', 'hsl(0 0% 63.9%)')}; + font-style: italic; } + + /* Search */ + .search { + padding: 4px; + border-bottom: 1px solid ${cssManager.bdTheme('hsl(0 0% 89.8%)', 'hsl(0 0% 14.9%)')}; + margin-bottom: 4px; + } + .search.bottom { - padding-bottom: 4px; + border-bottom: none; + border-top: 1px solid ${cssManager.bdTheme('hsl(0 0% 89.8%)', 'hsl(0 0% 14.9%)')}; + margin-bottom: 0; + margin-top: 4px; } + .search input { display: block; - background: none; - border: none; - height: 24px; - color: inherit; - text-align: left; - font-size: 12px; - font-weight: 600; width: 100%; - margin: auto; + height: 32px; + padding: 0 8px; + background: transparent; + border: 1px solid ${cssManager.bdTheme('hsl(0 0% 89.8%)', 'hsl(0 0% 14.9%)')}; + border-radius: 4px; + color: inherit; + font-size: 14px; + font-family: inherit; + outline: none; + transition: border-color 0.15s ease; } - .search.top input { - border-bottom: 1px dotted #333; - } - .search.bottom input { - border-top: 1px dotted #333; + .search input::placeholder { + color: ${cssManager.bdTheme('hsl(0 0% 63.9%)', 'hsl(0 0% 45.1%)')}; } .search input:focus { - outline: none; + border-color: ${cssManager.bdTheme('hsl(222.2 47.4% 51.2%)', 'hsl(217.2 91.2% 59.8%)')}; + } + + /* Scrollbar styling */ + .options-container::-webkit-scrollbar { + width: 8px; + } + + .options-container::-webkit-scrollbar-track { + background: transparent; + } + + .options-container::-webkit-scrollbar-thumb { + background: ${cssManager.bdTheme('hsl(0 0% 89.8%)', 'hsl(0 0% 14.9%)')}; + border-radius: 4px; + } + + .options-container::-webkit-scrollbar-thumb:hover { + background: ${cssManager.bdTheme('hsl(0 0% 79.8%)', 'hsl(0 0% 20.9%)')}; } `, ]; @@ -191,61 +269,78 @@ export class DeesInputDropdown extends DeesInputBase { public render(): TemplateResult { return html`
- -
-
- ${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} -
-
- ${this.selectedOption?.option || 'Select...'} + +
+
+ ${this.selectedOption?.option || 'Select an option'} +
+
+ ${this.enableSearch + ? html` + + ` + : null} +
+ ${this.filteredOptions.length === 0 + ? html`
No options found
` + : this.filteredOptions.map((option, index) => { + const isHighlighted = this.highlightedIndex === index; + return html` +
+ ${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 {
-
+
${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()}"`; + } + }} + > + +
+
Current value: ""
+
+
`; \ 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`
- +
-
${this.validationText}
${this.isPasswordBool ? html`
- +
` : html``} + ${this.validationText + ? html` +
+ ${this.validationText} +
+ ` + : 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``}