update
This commit is contained in:
@ -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%)')};
|
||||
}
|
||||
`}
|
||||
</style>
|
||||
|
||||
<div class="demo-container">
|
||||
<div class="demo-section">
|
||||
<h3>Basic Checkboxes</h3>
|
||||
<p>Standard checkbox inputs for boolean selections</p>
|
||||
|
||||
<dees-input-checkbox
|
||||
.label=${'I agree to the Terms and Conditions'}
|
||||
.value=${true}
|
||||
.key=${'terms'}
|
||||
></dees-input-checkbox>
|
||||
|
||||
<dees-input-checkbox
|
||||
.label=${'Subscribe to newsletter'}
|
||||
.value=${false}
|
||||
.key=${'newsletter'}
|
||||
></dees-input-checkbox>
|
||||
|
||||
<dees-input-checkbox
|
||||
.label=${'Enable notifications'}
|
||||
.required=${true}
|
||||
.key=${'notifications'}
|
||||
></dees-input-checkbox>
|
||||
</div>
|
||||
<dees-panel .title=${'Basic Checkboxes'} .subtitle=${'Simple checkbox examples with various labels'}>
|
||||
<div class="checkbox-group">
|
||||
<dees-input-checkbox
|
||||
.label=${'I agree to the Terms and Conditions'}
|
||||
.value=${true}
|
||||
.key=${'terms'}
|
||||
></dees-input-checkbox>
|
||||
|
||||
<dees-input-checkbox
|
||||
.label=${'Subscribe to newsletter'}
|
||||
.value=${false}
|
||||
.key=${'newsletter'}
|
||||
></dees-input-checkbox>
|
||||
|
||||
<dees-input-checkbox
|
||||
.label=${'Enable notifications'}
|
||||
.value=${false}
|
||||
.description=${'Receive email updates about your account'}
|
||||
.key=${'notifications'}
|
||||
></dees-input-checkbox>
|
||||
</div>
|
||||
</dees-panel>
|
||||
|
||||
<div class="demo-section">
|
||||
<h3>Horizontal Layout</h3>
|
||||
<p>Checkboxes arranged horizontally for compact forms</p>
|
||||
|
||||
<div class="horizontal-group">
|
||||
<dees-panel .title=${'Checkbox States'} .subtitle=${'Different checkbox states and configurations'}>
|
||||
<div class="checkbox-group">
|
||||
<dees-input-checkbox
|
||||
.label=${'Default state'}
|
||||
.value=${false}
|
||||
></dees-input-checkbox>
|
||||
|
||||
<dees-input-checkbox
|
||||
.label=${'Checked state'}
|
||||
.value=${true}
|
||||
></dees-input-checkbox>
|
||||
|
||||
<dees-input-checkbox
|
||||
.label=${'Disabled unchecked'}
|
||||
.value=${false}
|
||||
.disabled=${true}
|
||||
></dees-input-checkbox>
|
||||
|
||||
<dees-input-checkbox
|
||||
.label=${'Disabled checked'}
|
||||
.value=${true}
|
||||
.disabled=${true}
|
||||
></dees-input-checkbox>
|
||||
|
||||
<dees-input-checkbox
|
||||
.label=${'Required checkbox'}
|
||||
.required=${true}
|
||||
.key=${'required'}
|
||||
></dees-input-checkbox>
|
||||
</div>
|
||||
</dees-panel>
|
||||
|
||||
<dees-panel .title=${'Horizontal Layout'} .subtitle=${'Checkboxes arranged horizontally for compact forms'}>
|
||||
<div class="horizontal-checkboxes">
|
||||
<dees-input-checkbox
|
||||
.label=${'Option A'}
|
||||
.value=${false}
|
||||
.layoutMode=${'horizontal'}
|
||||
.key=${'optionA'}
|
||||
></dees-input-checkbox>
|
||||
|
||||
<dees-input-checkbox
|
||||
.label=${'Option B'}
|
||||
.layoutMode=${'horizontal'}
|
||||
.value=${true}
|
||||
.layoutMode=${'horizontal'}
|
||||
.key=${'optionB'}
|
||||
></dees-input-checkbox>
|
||||
|
||||
<dees-input-checkbox
|
||||
.label=${'Option C'}
|
||||
.value=${false}
|
||||
.layoutMode=${'horizontal'}
|
||||
.key=${'optionC'}
|
||||
></dees-input-checkbox>
|
||||
|
||||
<dees-input-checkbox
|
||||
.label=${'Option D'}
|
||||
.layoutMode=${'horizontal'}
|
||||
.value=${true}
|
||||
.layoutMode=${'horizontal'}
|
||||
.key=${'optionD'}
|
||||
></dees-input-checkbox>
|
||||
</div>
|
||||
</div>
|
||||
</dees-panel>
|
||||
|
||||
<div class="demo-section">
|
||||
<h3>Feature Selection Example</h3>
|
||||
<p>Common use case for feature toggles with batch operations</p>
|
||||
|
||||
<dees-panel .title=${'Feature Selection Example'} .subtitle=${'Common use case for feature toggles with batch operations'}>
|
||||
<div class="button-group">
|
||||
<dees-button id="select-all-btn" type="secondary">Select All</dees-button>
|
||||
<dees-button id="clear-all-btn" type="secondary">Clear All</dees-button>
|
||||
@ -206,62 +236,72 @@ export const demoFunc = () => html`
|
||||
></dees-input-checkbox>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</dees-panel>
|
||||
|
||||
<div class="demo-section">
|
||||
<h3>States</h3>
|
||||
<p>Different checkbox states and configurations</p>
|
||||
|
||||
<dees-input-checkbox
|
||||
.label=${'Disabled Unchecked'}
|
||||
.disabled=${true}
|
||||
.key=${'disabled1'}
|
||||
></dees-input-checkbox>
|
||||
|
||||
<dees-input-checkbox
|
||||
.label=${'Disabled Checked'}
|
||||
.disabled=${true}
|
||||
.value=${true}
|
||||
.key=${'disabled2'}
|
||||
></dees-input-checkbox>
|
||||
|
||||
<dees-input-checkbox
|
||||
.label=${'Required Checkbox'}
|
||||
.required=${true}
|
||||
.key=${'required'}
|
||||
></dees-input-checkbox>
|
||||
</div>
|
||||
<dees-panel .title=${'Privacy Settings Example'} .subtitle=${'Checkboxes in a typical form context'}>
|
||||
<div class="form-section">
|
||||
<h4 class="section-title">Privacy Preferences</h4>
|
||||
|
||||
<div class="checkbox-group">
|
||||
<dees-input-checkbox
|
||||
.label=${'Share analytics data'}
|
||||
.value=${true}
|
||||
.description=${'Help us improve by sharing anonymous usage data'}
|
||||
></dees-input-checkbox>
|
||||
|
||||
<dees-input-checkbox
|
||||
.label=${'Personalized recommendations'}
|
||||
.value=${true}
|
||||
.description=${'Get suggestions based on your activity'}
|
||||
></dees-input-checkbox>
|
||||
|
||||
<dees-input-checkbox
|
||||
.label=${'Marketing communications'}
|
||||
.value=${false}
|
||||
.description=${'Receive promotional emails and special offers'}
|
||||
></dees-input-checkbox>
|
||||
|
||||
<dees-input-checkbox
|
||||
.label=${'Third-party integrations'}
|
||||
.value=${false}
|
||||
.description=${'Allow approved partners to access your data'}
|
||||
></dees-input-checkbox>
|
||||
</div>
|
||||
</div>
|
||||
</dees-panel>
|
||||
|
||||
<div class="demo-section">
|
||||
<h3>Real-world Examples</h3>
|
||||
<p>Common checkbox patterns in applications</p>
|
||||
|
||||
<dees-panel .title=${'Interactive Example'} .subtitle=${'Click checkboxes to see value changes'}>
|
||||
<div class="checkbox-group">
|
||||
<dees-input-checkbox
|
||||
.label=${'Remember me on this device'}
|
||||
.value=${true}
|
||||
.key=${'rememberMe'}
|
||||
></dees-input-checkbox>
|
||||
|
||||
<dees-input-checkbox
|
||||
.label=${'Make my profile public'}
|
||||
.label=${'Feature toggle'}
|
||||
.value=${false}
|
||||
.key=${'publicProfile'}
|
||||
@changeSubject=${(event) => {
|
||||
const output = document.querySelector('#checkbox-output');
|
||||
if (output && event.detail) {
|
||||
const isChecked = event.detail.getValue();
|
||||
output.textContent = \`Feature is \${isChecked ? 'enabled' : 'disabled'}\`;
|
||||
}
|
||||
}}
|
||||
></dees-input-checkbox>
|
||||
|
||||
<dees-input-checkbox
|
||||
.label=${'Allow others to find me by email'}
|
||||
.label=${'Debug mode'}
|
||||
.value=${false}
|
||||
.key=${'findByEmail'}
|
||||
></dees-input-checkbox>
|
||||
|
||||
<dees-input-checkbox
|
||||
.label=${'Send me product updates and announcements'}
|
||||
.value=${true}
|
||||
.key=${'productUpdates'}
|
||||
@changeSubject=${(event) => {
|
||||
const output = document.querySelector('#debug-output');
|
||||
if (output && event.detail) {
|
||||
const isChecked = event.detail.getValue();
|
||||
output.textContent = \`Debug mode: \${isChecked ? 'ON' : 'OFF'}\`;
|
||||
}
|
||||
}}
|
||||
></dees-input-checkbox>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="interactive-section">
|
||||
<div id="checkbox-output" class="output-text">Feature is disabled</div>
|
||||
<div id="debug-output" class="output-text" style="margin-top: 8px;">Debug mode: OFF</div>
|
||||
</div>
|
||||
</dees-panel>
|
||||
</div>
|
||||
</dees-demowrapper>
|
||||
`;
|
@ -44,120 +44,106 @@ export class DeesInputCheckbox extends DeesInputBase<DeesInputCheckbox> {
|
||||
: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<DeesInputCheckbox> {
|
||||
return html`
|
||||
<div class="input-wrapper">
|
||||
<div class="maincontainer ${this.disabled ? 'disabled' : ''}" @click="${this.toggleSelected}">
|
||||
<div class="checkbox ${this.value ? 'selected' : ''} ${this.disabled ? 'disabled' : ''}" tabindex="0">
|
||||
<div
|
||||
class="checkbox ${this.value ? 'selected' : ''} ${this.disabled ? 'disabled' : ''}"
|
||||
tabindex="${this.disabled ? '-1' : '0'}"
|
||||
@keydown="${this.handleKeydown}"
|
||||
>
|
||||
${this.value
|
||||
? html`
|
||||
<span class="checkmark">
|
||||
<div class="checkmark_stem"></div>
|
||||
<div class="checkmark_kick"></div>
|
||||
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M20 6L9 17L4 12" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
</span>
|
||||
`
|
||||
: html``}
|
||||
</div>
|
||||
${this.label ? html`<div class="checkbox-label">${this.label}</div>` : ''}
|
||||
<div class="label-container">
|
||||
${this.label ? html`<div class="checkbox-label">${this.label}</div>` : ''}
|
||||
${this.description ? html`<div class="description-text">${this.description}</div>` : ''}
|
||||
</div>
|
||||
</div>
|
||||
${this.description ? html`
|
||||
<div class="description-text">${this.description}</div>
|
||||
` : ''}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
@ -213,4 +204,11 @@ export class DeesInputCheckbox extends DeesInputBase<DeesInputCheckbox> {
|
||||
(checkboxDiv as any).focus();
|
||||
}
|
||||
}
|
||||
|
||||
private handleKeydown(event: KeyboardEvent) {
|
||||
if (event.key === ' ' || event.key === 'Enter') {
|
||||
event.preventDefault();
|
||||
this.toggleSelected();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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<DeesInputDropdown> {
|
||||
this.selectedOption = val;
|
||||
}
|
||||
|
||||
|
||||
@property({
|
||||
type: Boolean,
|
||||
})
|
||||
public enableSearch: boolean = true;
|
||||
|
||||
|
||||
@state()
|
||||
public opensToTop: boolean = false;
|
||||
|
||||
@ -58,6 +55,9 @@ export class DeesInputDropdown extends DeesInputBase<DeesInputDropdown> {
|
||||
@state()
|
||||
public isOpened = false;
|
||||
|
||||
@state()
|
||||
private searchValue: string = '';
|
||||
|
||||
public static styles = [
|
||||
...DeesInputBase.baseStyles,
|
||||
cssManager.defaultStyles,
|
||||
@ -67,123 +67,201 @@ export class DeesInputDropdown extends DeesInputBase<DeesInputDropdown> {
|
||||
}
|
||||
|
||||
: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<DeesInputDropdown> {
|
||||
public render(): TemplateResult {
|
||||
return html`
|
||||
<div class="input-wrapper">
|
||||
<dees-label .label=${this.label}></dees-label>
|
||||
<div class="maincontainer" @keydown="${this.isOpened ? this.handleKeyDown : undefined}">
|
||||
<div class="selectionBox">
|
||||
${this.enableSearch && !this.opensToTop
|
||||
? html`
|
||||
<div class="search top">
|
||||
<input type="text" placeholder="Search" @input="${this.handleSearch}" />
|
||||
</div>
|
||||
`
|
||||
: null}
|
||||
${this.filteredOptions.map((option, index) => {
|
||||
const isHighlighted = this.highlightedIndex === index;
|
||||
return html`
|
||||
<div
|
||||
class="option ${isHighlighted ? 'highlighted' : ''}"
|
||||
@click=${() => {
|
||||
this.updateSelection(option);
|
||||
}}
|
||||
>
|
||||
${option.option}
|
||||
</div>
|
||||
`;
|
||||
})}
|
||||
${this.enableSearch && this.opensToTop
|
||||
? html`
|
||||
<div class="search bottom">
|
||||
<input type="text" placeholder="Search" @input="${this.handleSearch}" />
|
||||
</div>
|
||||
`
|
||||
: null}
|
||||
</div>
|
||||
<div
|
||||
class="selectedBox"
|
||||
@click="${(event) => {
|
||||
if (!this.isElevated) {
|
||||
this.toggleSelectionBox();
|
||||
} else {
|
||||
this.updateSelection(this.selectedOption);
|
||||
}
|
||||
}}"
|
||||
>
|
||||
${this.selectedOption?.option || 'Select...'}
|
||||
<dees-label .label=${this.label} .description=${this.description} .required=${this.required}></dees-label>
|
||||
<div class="maincontainer">
|
||||
<div
|
||||
class="selectedBox ${this.isOpened ? 'open' : ''} ${this.disabled ? 'disabled' : ''}"
|
||||
@click="${() => !this.disabled && this.toggleSelectionBox()}"
|
||||
tabindex="${this.disabled ? '-1' : '0'}"
|
||||
@keydown="${this.handleSelectedBoxKeydown}"
|
||||
>
|
||||
${this.selectedOption?.option || 'Select an option'}
|
||||
</div>
|
||||
<div class="selectionBox ${this.isOpened ? 'show' : ''} ${this.opensToTop ? 'top' : 'bottom'}">
|
||||
${this.enableSearch
|
||||
? html`
|
||||
<div class="search">
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Search options..."
|
||||
.value="${this.searchValue}"
|
||||
@input="${this.handleSearch}"
|
||||
@click="${(e: Event) => e.stopPropagation()}"
|
||||
@keydown="${this.handleSearchKeydown}"
|
||||
/>
|
||||
</div>
|
||||
`
|
||||
: null}
|
||||
<div class="options-container">
|
||||
${this.filteredOptions.length === 0
|
||||
? html`<div class="no-options">No options found</div>`
|
||||
: this.filteredOptions.map((option, index) => {
|
||||
const isHighlighted = this.highlightedIndex === index;
|
||||
return html`
|
||||
<div
|
||||
class="option ${isHighlighted ? 'highlighted' : ''}"
|
||||
@click="${() => this.updateSelection(option)}"
|
||||
@mouseenter="${() => this.highlightedIndex = index}"
|
||||
>
|
||||
${option.option}
|
||||
</div>
|
||||
`;
|
||||
})
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
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<string, any>) {
|
||||
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<DeesInputDropdown> {
|
||||
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<DeesInputDropdown> {
|
||||
public setValue(value: { option: string; key: string; payload?: any }): void {
|
||||
this.selectedOption = value;
|
||||
}
|
||||
}
|
||||
|
||||
async disconnectedCallback() {
|
||||
await super.disconnectedCallback();
|
||||
document.removeEventListener('click', this.handleClickOutside);
|
||||
}
|
||||
}
|
@ -69,80 +69,97 @@ export class DeesInputRadiogroup extends DeesInputBase<string | object> {
|
||||
: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<string | object> {
|
||||
}
|
||||
|
||||
: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<string | object> {
|
||||
<div
|
||||
class="radio-option ${isSelected ? 'selected' : ''}"
|
||||
@click="${() => this.selectOption(optionKey)}"
|
||||
@keydown="${(e: KeyboardEvent) => this.handleKeydown(e, optionKey)}"
|
||||
>
|
||||
<div class="radio-circle"></div>
|
||||
<div
|
||||
class="radio-circle"
|
||||
tabindex="${this.disabled ? '-1' : '0'}"
|
||||
role="radio"
|
||||
aria-checked="${isSelected}"
|
||||
aria-label="${optionLabel}"
|
||||
></div>
|
||||
<div class="radio-label">${optionLabel}</div>
|
||||
</div>
|
||||
`;
|
||||
@ -292,4 +325,33 @@ export class DeesInputRadiogroup extends DeesInputBase<string | object> {
|
||||
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();
|
||||
}
|
||||
}
|
@ -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`
|
||||
<dees-demowrapper>
|
||||
@ -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;
|
||||
}
|
||||
`}
|
||||
</style>
|
||||
|
||||
<div class="demo-container">
|
||||
<div class="demo-section">
|
||||
<h3>Basic Text Inputs</h3>
|
||||
<p>Standard text inputs with labels and descriptions</p>
|
||||
|
||||
<dees-panel .title=${'Basic Text Inputs'} .subtitle=${'Standard text inputs with labels and descriptions'}>
|
||||
<dees-input-text
|
||||
.label=${'Username'}
|
||||
.value=${'johndoe'}
|
||||
@ -91,12 +82,9 @@ export const demoFunc = () => html`
|
||||
.value=${'secret123'}
|
||||
.key=${'password'}
|
||||
></dees-input-text>
|
||||
</div>
|
||||
</dees-panel>
|
||||
|
||||
<div class="demo-section">
|
||||
<h3>Horizontal Layout</h3>
|
||||
<p>Multiple inputs arranged horizontally for compact forms</p>
|
||||
|
||||
<dees-panel .title=${'Horizontal Layout'} .subtitle=${'Multiple inputs arranged horizontally for compact forms'}>
|
||||
<div class="horizontal-group">
|
||||
<dees-input-text
|
||||
.label=${'First Name'}
|
||||
@ -119,12 +107,9 @@ export const demoFunc = () => html`
|
||||
.key=${'age'}
|
||||
></dees-input-text>
|
||||
</div>
|
||||
</div>
|
||||
</dees-panel>
|
||||
|
||||
<div class="demo-section">
|
||||
<h3>Label Positions</h3>
|
||||
<p>Different label positioning options for various layouts</p>
|
||||
|
||||
<dees-panel .title=${'Label Positions'} .subtitle=${'Different label positioning options for various layouts'}>
|
||||
<dees-input-text
|
||||
.label=${'Label on Top (Default)'}
|
||||
.value=${'Standard layout'}
|
||||
@ -150,12 +135,9 @@ export const demoFunc = () => html`
|
||||
.labelPosition=${'left'}
|
||||
></dees-input-text>
|
||||
</div>
|
||||
</div>
|
||||
</dees-panel>
|
||||
|
||||
<div class="demo-section">
|
||||
<h3>Validation & States</h3>
|
||||
<p>Different validation states and input configurations</p>
|
||||
|
||||
<dees-panel .title=${'Validation & States'} .subtitle=${'Different validation states and input configurations'}>
|
||||
<dees-input-text
|
||||
.label=${'Required Field'}
|
||||
.required=${true}
|
||||
@ -174,12 +156,9 @@ export const demoFunc = () => html`
|
||||
.validationText=${'Please enter a valid email address'}
|
||||
.validationState=${'invalid'}
|
||||
></dees-input-text>
|
||||
</div>
|
||||
</dees-panel>
|
||||
|
||||
<div class="demo-section">
|
||||
<h3>Advanced Features</h3>
|
||||
<p>Password visibility toggle and other advanced features</p>
|
||||
|
||||
<dees-panel .title=${'Advanced Features'} .subtitle=${'Password visibility toggle and other advanced features'}>
|
||||
<dees-input-text
|
||||
.label=${'Password with Toggle'}
|
||||
.isPasswordBool=${true}
|
||||
@ -193,7 +172,24 @@ export const demoFunc = () => html`
|
||||
.value=${'sk-1234567890abcdef'}
|
||||
.description=${'Keep this key secure and never share it'}
|
||||
></dees-input-text>
|
||||
</div>
|
||||
</dees-panel>
|
||||
|
||||
<dees-panel .title=${'Interactive Example'} .subtitle=${'Try typing in the inputs to see real-time value changes'}>
|
||||
<dees-input-text
|
||||
.label=${'Dynamic Input'}
|
||||
.placeholder=${'Type something here...'}
|
||||
@changeSubject=${(event) => {
|
||||
const output = document.querySelector('#text-input-output');
|
||||
if (output && event.detail) {
|
||||
output.textContent = `Current value: "${event.detail.getValue()}"`;
|
||||
}
|
||||
}}
|
||||
></dees-input-text>
|
||||
|
||||
<div class="interactive-section">
|
||||
<div id="text-input-output" class="output-text">Current value: ""</div>
|
||||
</div>
|
||||
</dees-panel>
|
||||
</div>
|
||||
</dees-demowrapper>
|
||||
`;
|
@ -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`
|
||||
<style>
|
||||
input {
|
||||
font-family: ${this.isPasswordBool ? 'monospace' : 'Geist Sans'};
|
||||
letter-spacing: ${this.isPasswordBool ? '1px' : 'normal'};
|
||||
color: ${this.goBright ? '#333' : '#ccc'};
|
||||
font-family: ${this.isPasswordBool ? 'SF Mono, Monaco, Consolas, Liberation Mono, Courier New, monospace' : 'inherit'};
|
||||
letter-spacing: ${this.isPasswordBool ? '0.5px' : 'normal'};
|
||||
padding-right: ${this.isPasswordBool ? '48px' : '12px'};
|
||||
}
|
||||
${this.validationText
|
||||
? css`
|
||||
.validationContainer {
|
||||
height: 22px;
|
||||
height: auto;
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
`
|
||||
: css`
|
||||
.validationContainer {
|
||||
height: 4px;
|
||||
padding: 2px !important;
|
||||
height: 0;
|
||||
padding: 0 !important;
|
||||
opacity: 0;
|
||||
transform: translateY(-4px);
|
||||
}
|
||||
`}
|
||||
</style>
|
||||
<div class="input-wrapper">
|
||||
<dees-label .label=${this.label} .description=${this.description}></dees-label>
|
||||
<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...'}"
|
||||
/>
|
||||
<div class="validationContainer">${this.validationText}</div>
|
||||
${this.isPasswordBool
|
||||
? html`
|
||||
<div class="showPassword" @click=${this.togglePasswordView}>
|
||||
<dees-icon .iconFA=${this.showPasswordBool ? 'eye' : 'eyeSlash'}></dees-icon>
|
||||
<dees-icon .iconName=${this.showPasswordBool ? 'lucideEye' : 'lucideEyeOff'}></dees-icon>
|
||||
</div>
|
||||
`
|
||||
: html``}
|
||||
${this.validationText
|
||||
? html`
|
||||
<div class="validationContainer ${this.validationState || 'error'}">
|
||||
${this.validationText}
|
||||
</div>
|
||||
`
|
||||
: html`<div class="validationContainer"></div>`}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
@ -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() {
|
||||
|
@ -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`
|
||||
<div class="label">
|
||||
${this.label}
|
||||
${this.required ? html`<span class="required">*</span>` : ''}
|
||||
${this.description
|
||||
? html`
|
||||
<dees-icon .iconFA=${'circleInfo'}></dees-icon>
|
||||
<dees-icon .iconName=${'lucideInfo'}></dees-icon>
|
||||
<dees-speechbubble .text=${this.description}></dees-speechbubble>
|
||||
`
|
||||
: html``}
|
||||
|
Reference in New Issue
Block a user