feat: Implement unified input component architecture with standardized margins and layout modes
This commit is contained in:
314
readme.plan.md
314
readme.plan.md
@ -1,202 +1,174 @@
|
|||||||
# dees-appui-appbar Improvement Plan
|
# Input Component Unification Plan
|
||||||
|
|
||||||
## Phase 1: Core Menu System
|
Command to reread guidelines: `cat /home/philkunz/.claude/CLAUDE.md`
|
||||||
|
|
||||||
### Menu Data Structure
|
## Problem Summary
|
||||||
- [x] Extend existing `plugins.tsclass.website.IMenuItem` to create `IAppBarMenuItem` with additional properties: id, shortcut, submenu, divider, disabled
|
|
||||||
- [x] Create `IMenuBar` interface with menuItems array and onMenuSelect callback
|
|
||||||
- [x] Add `@property() menuItems` to accept menu configuration
|
|
||||||
- [x] Add `@property() onMenuSelect` event handler
|
|
||||||
- [ ] Consider reusing existing `interfaces.ITab` for simpler menu scenarios
|
|
||||||
|
|
||||||
### Basic Menu Rendering
|
The dees-input components have inconsistent margin behavior causing vertical alignment issues in horizontal flexbox layouts:
|
||||||
- [x] Replace hardcoded menu items with dynamic rendering from menuItems property
|
|
||||||
- [x] Add support for menu item icons
|
|
||||||
- [x] Implement menu item disabled state styling
|
|
||||||
- [x] Add menu separator/divider support
|
|
||||||
|
|
||||||
### Dropdown Implementation
|
- **dees-input-text**: 8px top, 24px bottom margin
|
||||||
- [x] Create dropdown container component (consider reusing logic from dees-contextmenu)
|
- **dees-input-dropdown**: 0px top, 24px bottom margin
|
||||||
- [x] Implement click to open/close dropdown
|
- **dees-input-checkbox/radio**: 20px top, 20px bottom margin
|
||||||
- [x] Add dropdown positioning logic (below menu item)
|
- Different components use different label implementations (some use dees-label, others have built-in labels)
|
||||||
- [x] Implement click outside to close
|
|
||||||
- [x] Add dropdown arrow/caret indicator
|
|
||||||
- [x] Style dropdown with shadows and borders
|
|
||||||
- [ ] Ensure visual consistency with existing dees-contextmenu component
|
|
||||||
|
|
||||||
### Keyboard Navigation
|
## Proposed Solution
|
||||||
- [x] Add tabindex to menu items
|
|
||||||
- [x] Implement Tab navigation between top-level items
|
|
||||||
- [x] Add Enter key to open dropdown
|
|
||||||
- [x] Implement arrow keys for dropdown navigation
|
|
||||||
- [x] Add Escape key to close dropdown
|
|
||||||
- [x] Implement Home/End keys for first/last item
|
|
||||||
|
|
||||||
### Submenu Support
|
### 1. Standardize Margin System
|
||||||
- [ ] Detect submenu items and add arrow indicator
|
|
||||||
- [ ] Implement submenu positioning (to the right)
|
|
||||||
- [ ] Add hover delay before opening submenu
|
|
||||||
- [ ] Handle nested keyboard navigation
|
|
||||||
- [ ] Prevent submenus from going off-screen
|
|
||||||
|
|
||||||
## Phase 2: Breadcrumb Navigation & Theming
|
Create a unified margin approach for all input components:
|
||||||
|
|
||||||
### Breadcrumb System
|
```css
|
||||||
- [ ] Define `IBreadcrumb` interface with label, path, icon
|
/* Default vertical stacking mode (for forms) */
|
||||||
- [x] Add `@property() breadcrumbs` array
|
:host {
|
||||||
- [x] Add `@property() breadcrumbSeparator` (default '>')
|
margin: 0;
|
||||||
- [x] Implement breadcrumb rendering with separators
|
margin-bottom: 16px; /* Reduced from 24px for better density */
|
||||||
- [x] Add click handlers for navigation
|
}
|
||||||
- [x] Emit 'breadcrumb-navigate' custom event
|
|
||||||
- [ ] Add breadcrumb truncation for long paths
|
|
||||||
- [ ] Implement breadcrumb overflow with horizontal scroll
|
|
||||||
|
|
||||||
### Theme Support
|
/* Last child in container should have no bottom margin */
|
||||||
- [x] Add CSS variables for all colors and sizes
|
:host(:last-child) {
|
||||||
- [x] Create `--appbar-height` variable (default 40px)
|
margin-bottom: 0;
|
||||||
- [x] Add `--appbar-bg`, `--appbar-text`, `--appbar-border` variables
|
}
|
||||||
- [x] Implement `--appbar-hover` and `--appbar-active` states
|
|
||||||
- [x] Add `@property() theme` with 'light' | 'dark' options
|
|
||||||
- [x] Create light theme CSS variables
|
|
||||||
- [x] Add theme toggle to demo
|
|
||||||
|
|
||||||
### Visual Improvements
|
/* Horizontal layout mode - activated by parent context or attribute */
|
||||||
- [x] Add smooth transitions for hover states
|
:host([horizontal-layout]) {
|
||||||
- [ ] Implement ripple effect on click
|
margin: 0;
|
||||||
- [x] Add focus ring styles for accessibility
|
margin-right: 16px;
|
||||||
- [x] Improve menu item padding and spacing
|
margin-bottom: 0;
|
||||||
- [ ] Add subtle gradient or texture to appbar
|
}
|
||||||
|
|
||||||
## Phase 3: Search & User Account
|
:host([horizontal-layout]:last-child) {
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### Search Integration
|
### 2. Unified Label Architecture
|
||||||
- [x] Add search icon in center section
|
|
||||||
- [ ] Create expandable search input
|
|
||||||
- [x] Add `@property() showSearch` boolean
|
|
||||||
- [ ] Implement Cmd/Ctrl+K keyboard shortcut
|
|
||||||
- [ ] Add search input with placeholder
|
|
||||||
- [x] Emit 'search-submit' event
|
|
||||||
- [ ] Add search suggestions dropdown
|
|
||||||
- [ ] Implement recent searches storage
|
|
||||||
|
|
||||||
### User Account Section
|
All input components should use the `dees-label` component for consistency:
|
||||||
- [ ] Define `IUserAccount` interface
|
|
||||||
- [x] Add `@property() user` for user data
|
|
||||||
- [x] Render user avatar (with fallback to initials)
|
|
||||||
- [x] Display user name
|
|
||||||
- [x] Add status indicator (online/offline/busy/away)
|
|
||||||
- [ ] Create user dropdown menu
|
|
||||||
- [ ] Add logout/settings options
|
|
||||||
- [x] Emit 'user-menu-open' event
|
|
||||||
|
|
||||||
## Phase 4: Platform & Accessibility
|
- Move label rendering from built-in implementations to `dees-label` usage
|
||||||
|
- Add a `labelPosition` property to all inputs: `'top' | 'left' | 'right' | 'none'`
|
||||||
|
- Default to 'top' for text/dropdown, 'right' for checkbox/radio
|
||||||
|
|
||||||
### Platform-Specific Features
|
### 3. Layout Mode Support
|
||||||
- [ ] Add `@property() platform` detection
|
|
||||||
- [x] Conditionally show window controls
|
|
||||||
- [ ] Implement platform-specific styling (macOS/Windows/Linux)
|
|
||||||
- [ ] Add platform-specific keyboard shortcuts
|
|
||||||
- [ ] Handle window dragging per platform
|
|
||||||
- [ ] Add fullscreen toggle button
|
|
||||||
|
|
||||||
### Window Controls Integration
|
Add a `layoutMode` property to all input components:
|
||||||
- [ ] Make window controls position configurable
|
|
||||||
- [x] Add `@property() showWindowControls`
|
|
||||||
- [ ] Handle window controls on different platforms
|
|
||||||
- [ ] Add minimize/maximize/close functionality
|
|
||||||
- [ ] Style window controls to match theme
|
|
||||||
|
|
||||||
### Accessibility (A11Y)
|
```typescript
|
||||||
- [x] Add proper ARIA roles (menubar, menuitem)
|
@property({ type: String })
|
||||||
- [x] Implement aria-haspopup for dropdowns
|
public layoutMode: 'vertical' | 'horizontal' | 'auto' = 'auto';
|
||||||
- [x] Add aria-expanded state
|
```
|
||||||
- [ ] Include aria-label for navigation
|
|
||||||
- [ ] Support screen reader announcements
|
|
||||||
- [ ] Add high contrast mode support
|
|
||||||
- [ ] Implement focus trap in dropdowns
|
|
||||||
- [ ] Add skip navigation link
|
|
||||||
|
|
||||||
### Responsive Design
|
- `vertical`: Traditional form layout (label on top)
|
||||||
- [ ] Add breakpoint detection
|
- `horizontal`: Inline layout (label position configurable)
|
||||||
- [ ] Implement hamburger menu for mobile
|
- `auto`: Detect from parent context
|
||||||
- [ ] Create slide-out menu drawer
|
|
||||||
- [ ] Make breadcrumbs responsive
|
|
||||||
- [ ] Hide non-essential items on small screens
|
|
||||||
- [ ] Add touch gesture support
|
|
||||||
|
|
||||||
## Phase 5: Advanced Features
|
### 4. Implementation Steps
|
||||||
|
|
||||||
### Notification System
|
1. **Create base input class** (`DeesInputBase`):
|
||||||
- [ ] Add notification icon with badge
|
- Common margin styles
|
||||||
- [ ] Create `@property() notifications` array
|
- Layout mode detection
|
||||||
- [ ] Implement notification dropdown
|
- Label position handling
|
||||||
- [ ] Add notification actions (mark read, dismiss)
|
- Shared properties (key, required, disabled, value)
|
||||||
- [ ] Emit notification events
|
|
||||||
- [ ] Add notification sound option
|
|
||||||
- [ ] Implement notification grouping
|
|
||||||
|
|
||||||
### Plugin System
|
2. **Update dees-input-text**:
|
||||||
- [ ] Define `IAppBarPlugin` interface
|
- Extend from DeesInputBase
|
||||||
- [ ] Add plugin registration method
|
- Remove hardcoded margins
|
||||||
- [ ] Implement plugin rendering slots
|
- Keep using dees-label component
|
||||||
- [ ] Add plugin positioning (left/center/right)
|
|
||||||
- [ ] Support plugin weight for ordering
|
|
||||||
- [ ] Create plugin lifecycle hooks
|
|
||||||
|
|
||||||
### Custom Slots
|
3. **Update dees-input-dropdown**:
|
||||||
- [ ] Add named slots for sections
|
- Extend from DeesInputBase
|
||||||
- [ ] Implement slot change detection
|
- Remove hardcoded margins
|
||||||
- [ ] Style slotted content appropriately
|
- Switch from built-in label to dees-label
|
||||||
- [ ] Document slot usage
|
|
||||||
|
|
||||||
### Context Menus
|
4. **Update dees-input-checkbox**:
|
||||||
- [ ] Add right-click context menu support
|
- Extend from DeesInputBase
|
||||||
- [ ] Implement context menu positioning
|
- Remove hardcoded margins
|
||||||
- [ ] Add context-specific menu items
|
- Add support for label position (keep default as 'right')
|
||||||
- [ ] Support custom context menus
|
- Switch to dees-label component
|
||||||
|
|
||||||
## Phase 6: Performance & Polish
|
5. **Update dees-input-radio**:
|
||||||
|
- Same as checkbox
|
||||||
|
|
||||||
### Performance Optimizations
|
6. **Update dees-form**:
|
||||||
- [ ] Implement virtual scrolling for long menus
|
- Add property to control child input layout mode
|
||||||
- [ ] Add lazy loading for submenu content
|
- Ensure proper spacing context
|
||||||
- [ ] Debounce search input
|
|
||||||
- [ ] Memoize menu rendering
|
|
||||||
- [ ] Optimize re-renders with lit's `guard` directive
|
|
||||||
- [ ] Add loading states for async operations
|
|
||||||
|
|
||||||
### Testing
|
### 5. CSS Variable System
|
||||||
- [x] Create comprehensive demo page
|
|
||||||
- [ ] Add unit tests for menu logic
|
|
||||||
- [ ] Test keyboard navigation
|
|
||||||
- [ ] Test platform-specific behavior
|
|
||||||
- [ ] Add visual regression tests
|
|
||||||
- [ ] Test accessibility with screen readers
|
|
||||||
- [ ] Performance benchmark tests
|
|
||||||
|
|
||||||
### Documentation
|
Introduce CSS variables for consistent spacing:
|
||||||
- [ ] Document all properties and methods
|
|
||||||
- [x] Create usage examples
|
|
||||||
- [ ] Add migration guide from current version
|
|
||||||
- [ ] Document keyboard shortcuts
|
|
||||||
- [ ] Create accessibility guide
|
|
||||||
- [ ] Add troubleshooting section
|
|
||||||
|
|
||||||
### Polish
|
```css
|
||||||
- [ ] Add loading skeletons
|
:host {
|
||||||
- [ ] Implement error states
|
--dees-input-spacing-unit: 8px;
|
||||||
- [ ] Add empty states
|
--dees-input-vertical-gap: calc(var(--dees-input-spacing-unit) * 2); /* 16px */
|
||||||
- [ ] Create onboarding tooltips
|
--dees-input-horizontal-gap: calc(var(--dees-input-spacing-unit) * 2); /* 16px */
|
||||||
- [ ] Add animation preferences (reduced motion)
|
--dees-input-label-gap: var(--dees-input-spacing-unit); /* 8px */
|
||||||
- [ ] Implement print styles
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## Completion Tracking
|
### 6. Backward Compatibility
|
||||||
|
|
||||||
- Phase 1: 20/22 tasks
|
- Keep existing properties and methods
|
||||||
- Phase 2: 10/15 tasks
|
- Add deprecation notices for properties that will be removed
|
||||||
- Phase 3: 6/16 tasks
|
- Provide migration guide in documentation
|
||||||
- Phase 4: 6/24 tasks
|
|
||||||
- Phase 5: 0/18 tasks
|
|
||||||
- Phase 6: 2/20 tasks
|
|
||||||
|
|
||||||
**Total: 44/115 tasks completed**
|
### 7. Testing Requirements
|
||||||
|
|
||||||
|
- Test all inputs in vertical form layouts
|
||||||
|
- Test all inputs in horizontal flexbox containers
|
||||||
|
- Test mixed input types in same container
|
||||||
|
- Test with and without labels
|
||||||
|
- Test theme switching (light/dark)
|
||||||
|
- Test responsive behavior
|
||||||
|
|
||||||
|
## Expected Outcome
|
||||||
|
|
||||||
|
- All input components will align properly in horizontal layouts
|
||||||
|
- Consistent spacing in vertical forms
|
||||||
|
- Unified label handling across all inputs
|
||||||
|
- Better developer experience with predictable behavior
|
||||||
|
- Maintained backward compatibility
|
||||||
|
|
||||||
|
## Timeline
|
||||||
|
|
||||||
|
1. Phase 1: Create DeesInputBase class and update dees-input-text ✅
|
||||||
|
2. Phase 2: Update remaining input components ✅
|
||||||
|
3. Phase 3: Update documentation and examples
|
||||||
|
4. Phase 4: Testing and refinement ✅
|
||||||
|
|
||||||
|
## Implementation Status
|
||||||
|
|
||||||
|
### Completed:
|
||||||
|
|
||||||
|
1. **Created DeesInputBase class** (`dees-input-base.ts`):
|
||||||
|
- Generic base class with unified margin system
|
||||||
|
- Layout mode support (vertical/horizontal/auto)
|
||||||
|
- Label position control
|
||||||
|
- Common properties and methods
|
||||||
|
- CSS variables for consistent spacing
|
||||||
|
|
||||||
|
2. **Updated all input components**:
|
||||||
|
- `dees-input-text`: Now extends DeesInputBase, margins removed
|
||||||
|
- `dees-input-dropdown`: Now extends DeesInputBase, uses dees-label
|
||||||
|
- `dees-input-checkbox`: Now extends DeesInputBase, uses dees-label (default label position: right)
|
||||||
|
- `dees-input-radio`: Now extends DeesInputBase, uses dees-label (default label position: right)
|
||||||
|
|
||||||
|
3. **Updated dees-form**:
|
||||||
|
- Added `horizontal-layout` property
|
||||||
|
- Auto-detection of layout mode for child inputs
|
||||||
|
- Added dropdown to form input types
|
||||||
|
|
||||||
|
4. **Fixed TypeScript errors**:
|
||||||
|
- Added value property to dropdown for form compatibility
|
||||||
|
- Fixed changeSubject typing
|
||||||
|
- Updated form value type to include dropdown options
|
||||||
|
|
||||||
|
### Result:
|
||||||
|
|
||||||
|
All input components now have:
|
||||||
|
- Unified 16px bottom margin in vertical layouts
|
||||||
|
- 16px right margin in horizontal layouts
|
||||||
|
- No margin on last child
|
||||||
|
- Consistent label handling via dees-label
|
||||||
|
- Flexible layout modes
|
||||||
|
- Better alignment in flexbox containers
|
@ -4,6 +4,7 @@ import {
|
|||||||
type TemplateResult,
|
type TemplateResult,
|
||||||
DeesElement,
|
DeesElement,
|
||||||
type CSSResult,
|
type CSSResult,
|
||||||
|
property,
|
||||||
} from '@design.estate/dees-element';
|
} from '@design.estate/dees-element';
|
||||||
import * as domtools from '@design.estate/dees-domtools';
|
import * as domtools from '@design.estate/dees-domtools';
|
||||||
|
|
||||||
@ -11,6 +12,7 @@ import { DeesInputCheckbox } from './dees-input-checkbox.js';
|
|||||||
import { DeesInputText } from './dees-input-text.js';
|
import { DeesInputText } from './dees-input-text.js';
|
||||||
import { DeesInputQuantitySelector } from './dees-input-quantityselector.js';
|
import { DeesInputQuantitySelector } from './dees-input-quantityselector.js';
|
||||||
import { DeesInputRadio } from './dees-input-radio.js';
|
import { DeesInputRadio } from './dees-input-radio.js';
|
||||||
|
import { DeesInputDropdown } from './dees-input-dropdown.js';
|
||||||
import { DeesFormSubmit } from './dees-form-submit.js';
|
import { DeesFormSubmit } from './dees-form-submit.js';
|
||||||
import { DeesTable } from './dees-table.js';
|
import { DeesTable } from './dees-table.js';
|
||||||
import { demoFunc } from './dees-form.demo.js';
|
import { demoFunc } from './dees-form.demo.js';
|
||||||
@ -19,6 +21,7 @@ import { DeesInputIban } from './dees-input-iban.js';
|
|||||||
// Unified set for form input types
|
// Unified set for form input types
|
||||||
const FORM_INPUT_TYPES = [
|
const FORM_INPUT_TYPES = [
|
||||||
DeesInputCheckbox,
|
DeesInputCheckbox,
|
||||||
|
DeesInputDropdown,
|
||||||
DeesInputIban,
|
DeesInputIban,
|
||||||
DeesInputText,
|
DeesInputText,
|
||||||
DeesInputQuantitySelector,
|
DeesInputQuantitySelector,
|
||||||
@ -28,6 +31,7 @@ const FORM_INPUT_TYPES = [
|
|||||||
|
|
||||||
export type TFormInputElement =
|
export type TFormInputElement =
|
||||||
| DeesInputCheckbox
|
| DeesInputCheckbox
|
||||||
|
| DeesInputDropdown
|
||||||
| DeesInputIban
|
| DeesInputIban
|
||||||
| DeesInputText
|
| DeesInputText
|
||||||
| DeesInputQuantitySelector
|
| DeesInputQuantitySelector
|
||||||
@ -48,6 +52,13 @@ export class DeesForm extends DeesElement {
|
|||||||
public changeSubject = new domtools.plugins.smartrx.rxjs.Subject();
|
public changeSubject = new domtools.plugins.smartrx.rxjs.Subject();
|
||||||
public readyDeferred = domtools.plugins.smartpromise.defer();
|
public readyDeferred = domtools.plugins.smartpromise.defer();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Controls the layout mode of child input components
|
||||||
|
* When true, sets all child inputs to horizontal layout
|
||||||
|
*/
|
||||||
|
@property({ type: Boolean, reflect: true, attribute: 'horizontal-layout' })
|
||||||
|
public horizontalLayout: boolean = false;
|
||||||
|
|
||||||
public render(): TemplateResult {
|
public render(): TemplateResult {
|
||||||
return html`
|
return html`
|
||||||
<style>
|
<style>
|
||||||
@ -62,6 +73,7 @@ export class DeesForm extends DeesElement {
|
|||||||
public async firstUpdated() {
|
public async firstUpdated() {
|
||||||
const formChildren = this.getFormElements();
|
const formChildren = this.getFormElements();
|
||||||
this.updateRequiredStatus();
|
this.updateRequiredStatus();
|
||||||
|
this.updateChildrenLayoutMode();
|
||||||
|
|
||||||
for (const child of formChildren) {
|
for (const child of formChildren) {
|
||||||
child.changeSubject.subscribe(async () => {
|
child.changeSubject.subscribe(async () => {
|
||||||
@ -107,7 +119,7 @@ export class DeesForm extends DeesElement {
|
|||||||
*/
|
*/
|
||||||
public async collectFormData() {
|
public async collectFormData() {
|
||||||
const children = this.getFormElements();
|
const children = this.getFormElements();
|
||||||
const valueObject: { [key: string]: string | number | boolean | any[] } = {};
|
const valueObject: { [key: string]: string | number | boolean | any[] | { option: string; key: string; payload?: any } } = {};
|
||||||
for (const child of children) {
|
for (const child of children) {
|
||||||
if (!child.key) {
|
if (!child.key) {
|
||||||
console.log(`form element with label "${child.label}" has no key. skipping.`);
|
console.log(`form element with label "${child.label}" has no key. skipping.`);
|
||||||
@ -202,4 +214,28 @@ export class DeesForm extends DeesElement {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the layout mode of child input components based on form's horizontalLayout property
|
||||||
|
*/
|
||||||
|
private updateChildrenLayoutMode() {
|
||||||
|
const formChildren = this.getFormElements();
|
||||||
|
for (const child of formChildren) {
|
||||||
|
if ('layoutMode' in child) {
|
||||||
|
// The child's auto mode will detect this form's horizontal-layout attribute
|
||||||
|
(child as any).layoutMode = 'auto';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when properties change
|
||||||
|
*/
|
||||||
|
updated(changedProperties: Map<string, any>) {
|
||||||
|
super.updated(changedProperties);
|
||||||
|
|
||||||
|
if (changedProperties.has('horizontalLayout')) {
|
||||||
|
this.updateChildrenLayoutMode();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
184
ts_web/elements/dees-input-base.ts
Normal file
184
ts_web/elements/dees-input-base.ts
Normal file
@ -0,0 +1,184 @@
|
|||||||
|
import {
|
||||||
|
DeesElement,
|
||||||
|
property,
|
||||||
|
css,
|
||||||
|
type CSSResult,
|
||||||
|
cssManager,
|
||||||
|
} from '@design.estate/dees-element';
|
||||||
|
import * as domtools from '@design.estate/dees-domtools';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base class for all dees-input components
|
||||||
|
* Provides unified margin system and layout mode support
|
||||||
|
*/
|
||||||
|
export abstract class DeesInputBase<T = any> extends DeesElement {
|
||||||
|
/**
|
||||||
|
* Layout mode for the input component
|
||||||
|
* - vertical: Traditional form layout (label on top)
|
||||||
|
* - horizontal: Inline layout (label position configurable)
|
||||||
|
* - auto: Detect from parent context
|
||||||
|
*/
|
||||||
|
@property({ type: String })
|
||||||
|
public layoutMode: 'vertical' | 'horizontal' | 'auto' = 'auto';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Position of the label relative to the input
|
||||||
|
*/
|
||||||
|
@property({ type: String })
|
||||||
|
public labelPosition: 'top' | 'left' | 'right' | 'none' = 'top';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Common properties for all inputs
|
||||||
|
*/
|
||||||
|
@property({ type: String })
|
||||||
|
public key: string;
|
||||||
|
|
||||||
|
@property({ type: String })
|
||||||
|
public label: string;
|
||||||
|
|
||||||
|
@property({ type: Boolean })
|
||||||
|
public required: boolean = false;
|
||||||
|
|
||||||
|
@property({ type: Boolean })
|
||||||
|
public disabled: boolean = false;
|
||||||
|
|
||||||
|
@property({ type: String })
|
||||||
|
public description: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Common styles for all input components
|
||||||
|
*/
|
||||||
|
public static get baseStyles(): CSSResult[] {
|
||||||
|
return [
|
||||||
|
css`
|
||||||
|
/* CSS Variables for consistent spacing */
|
||||||
|
:host {
|
||||||
|
--dees-input-spacing-unit: 8px;
|
||||||
|
--dees-input-vertical-gap: calc(var(--dees-input-spacing-unit) * 2); /* 16px */
|
||||||
|
--dees-input-horizontal-gap: calc(var(--dees-input-spacing-unit) * 2); /* 16px */
|
||||||
|
--dees-input-label-gap: var(--dees-input-spacing-unit); /* 8px */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Default vertical stacking mode (for forms) */
|
||||||
|
:host {
|
||||||
|
display: block;
|
||||||
|
margin: 0;
|
||||||
|
margin-bottom: var(--dees-input-vertical-gap);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Last child in container should have no bottom margin */
|
||||||
|
:host(:last-child) {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Horizontal layout mode - activated by attribute */
|
||||||
|
:host([layout-mode="horizontal"]) {
|
||||||
|
display: inline-block;
|
||||||
|
margin: 0;
|
||||||
|
margin-right: var(--dees-input-horizontal-gap);
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
:host([layout-mode="horizontal"]:last-child) {
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Auto mode - inherit from parent dees-form if present */
|
||||||
|
|
||||||
|
/* Label position variations */
|
||||||
|
:host([label-position="left"]) .input-wrapper {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: auto 1fr;
|
||||||
|
gap: var(--dees-input-label-gap);
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
:host([label-position="right"]) .input-wrapper {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr auto;
|
||||||
|
gap: var(--dees-input-label-gap);
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
:host([label-position="top"]) .input-wrapper {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
:host([label-position="none"]) dees-label {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subject for value changes that all inputs should implement
|
||||||
|
*/
|
||||||
|
public changeSubject = new domtools.plugins.smartrx.rxjs.Subject<T>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when the element is connected to the DOM
|
||||||
|
* Sets up layout mode detection
|
||||||
|
*/
|
||||||
|
async connectedCallback() {
|
||||||
|
await super.connectedCallback();
|
||||||
|
this.detectLayoutMode();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Detects the appropriate layout mode based on parent context
|
||||||
|
*/
|
||||||
|
private detectLayoutMode() {
|
||||||
|
if (this.layoutMode !== 'auto') {
|
||||||
|
this.setAttribute('layout-mode', this.layoutMode);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if parent is a form with horizontal layout
|
||||||
|
const parentForm = this.closest('dees-form');
|
||||||
|
if (parentForm && parentForm.hasAttribute('horizontal-layout')) {
|
||||||
|
this.setAttribute('layout-mode', 'horizontal');
|
||||||
|
} else {
|
||||||
|
this.setAttribute('layout-mode', 'vertical');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the layout mode attribute when property changes
|
||||||
|
*/
|
||||||
|
updated(changedProperties: Map<string, any>) {
|
||||||
|
super.updated(changedProperties);
|
||||||
|
|
||||||
|
if (changedProperties.has('layoutMode')) {
|
||||||
|
this.detectLayoutMode();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (changedProperties.has('labelPosition')) {
|
||||||
|
this.setAttribute('label-position', this.labelPosition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Standard method for freezing input (disabling)
|
||||||
|
*/
|
||||||
|
public async freeze() {
|
||||||
|
this.disabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Standard method for unfreezing input (enabling)
|
||||||
|
*/
|
||||||
|
public async unfreeze() {
|
||||||
|
this.disabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstract method that child classes must implement to get their value
|
||||||
|
*/
|
||||||
|
public abstract getValue(): any;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstract method that child classes must implement to set their value
|
||||||
|
*/
|
||||||
|
public abstract setValue(value: any): void;
|
||||||
|
}
|
@ -1,14 +1,13 @@
|
|||||||
import {
|
import {
|
||||||
customElement,
|
customElement,
|
||||||
DeesElement,
|
|
||||||
type TemplateResult,
|
type TemplateResult,
|
||||||
property,
|
property,
|
||||||
html,
|
html,
|
||||||
css,
|
css,
|
||||||
cssManager,
|
cssManager,
|
||||||
type CSSResult,
|
|
||||||
} from '@design.estate/dees-element';
|
} from '@design.estate/dees-element';
|
||||||
import * as domtools from '@design.estate/dees-domtools';
|
import * as domtools from '@design.estate/dees-domtools';
|
||||||
|
import { DeesInputBase } from './dees-input-base.js';
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface HTMLElementTagNameMap {
|
interface HTMLElementTagNameMap {
|
||||||
@ -17,51 +16,33 @@ declare global {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@customElement('dees-input-checkbox')
|
@customElement('dees-input-checkbox')
|
||||||
export class DeesInputCheckbox extends DeesElement {
|
export class DeesInputCheckbox extends DeesInputBase<DeesInputCheckbox> {
|
||||||
// STATIC
|
// STATIC
|
||||||
public static demo = () => html`<dees-input-checkbox></dees-input-checkbox>`;
|
public static demo = () => html`<dees-input-checkbox></dees-input-checkbox>`;
|
||||||
|
|
||||||
// INSTANCE
|
// INSTANCE
|
||||||
public changeSubject = new domtools.plugins.smartrx.rxjs.Subject();
|
|
||||||
|
|
||||||
@property({
|
|
||||||
type: String,
|
|
||||||
reflect: true,
|
|
||||||
})
|
|
||||||
public key: string;
|
|
||||||
|
|
||||||
@property({
|
|
||||||
type: String,
|
|
||||||
})
|
|
||||||
public label: string = 'Label';
|
|
||||||
|
|
||||||
@property({
|
@property({
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
})
|
})
|
||||||
public value: boolean = false;
|
public value: boolean = false;
|
||||||
|
|
||||||
@property({
|
|
||||||
type: Boolean,
|
|
||||||
})
|
|
||||||
public required: boolean = false;
|
|
||||||
|
|
||||||
@property({
|
constructor() {
|
||||||
type: Boolean
|
super();
|
||||||
})
|
this.labelPosition = 'right'; // Checkboxes default to label on the right
|
||||||
public disabled: boolean = false;
|
}
|
||||||
|
|
||||||
public render(): TemplateResult {
|
public static styles = [
|
||||||
return html`
|
...DeesInputBase.baseStyles,
|
||||||
${domtools.elementBasic.styles}
|
cssManager.defaultStyles,
|
||||||
<style>
|
css`
|
||||||
* {
|
* {
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
:host {
|
:host {
|
||||||
display: block;
|
|
||||||
position: relative;
|
position: relative;
|
||||||
margin: 20px 0px;
|
|
||||||
cursor: default;
|
cursor: default;
|
||||||
}
|
}
|
||||||
:host(:hover) {
|
:host(:hover) {
|
||||||
@ -69,21 +50,12 @@ export class DeesInputCheckbox extends DeesElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.maincontainer {
|
.maincontainer {
|
||||||
display: grid;
|
|
||||||
grid-template-columns: 25px auto;
|
|
||||||
padding: 5px 0px;
|
padding: 5px 0px;
|
||||||
color: ${this.goBright ? '#333' : '#ccc'};
|
color: ${cssManager.bdTheme('#333', '#ccc')};
|
||||||
}
|
}
|
||||||
|
|
||||||
.maincontainer:hover {
|
.maincontainer:hover {
|
||||||
${this.goBright ? '#000' : '#ccc'};
|
color: ${cssManager.bdTheme('#000', '#fff')};
|
||||||
}
|
|
||||||
|
|
||||||
.label {
|
|
||||||
margin-left: 15px;
|
|
||||||
line-height: 25px;
|
|
||||||
font-size: 14px;
|
|
||||||
font-weight: normal;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
input:focus {
|
input:focus {
|
||||||
@ -94,12 +66,12 @@ export class DeesInputCheckbox extends DeesElement {
|
|||||||
.checkbox {
|
.checkbox {
|
||||||
transition: all 0.1s;
|
transition: all 0.1s;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
border: 1px solid ${this.goBright ? '#CCC' : '#999'};
|
border: 1px solid ${cssManager.bdTheme('#CCC', '#999')};
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
height: 24px;
|
height: 24px;
|
||||||
width: 24px;
|
width: 24px;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
background: ${this.goBright ? '#fafafa' : '#222'};
|
background: ${cssManager.bdTheme('#fafafa', '#222')};
|
||||||
}
|
}
|
||||||
|
|
||||||
.checkbox.selected {
|
.checkbox.selected {
|
||||||
@ -146,7 +118,12 @@ export class DeesInputCheckbox extends DeesElement {
|
|||||||
img {
|
img {
|
||||||
padding: 4px;
|
padding: 4px;
|
||||||
}
|
}
|
||||||
</style>
|
`,
|
||||||
|
];
|
||||||
|
|
||||||
|
public render(): TemplateResult {
|
||||||
|
return html`
|
||||||
|
<div class="input-wrapper">
|
||||||
<div class="maincontainer" @click="${this.toggleSelected}">
|
<div class="maincontainer" @click="${this.toggleSelected}">
|
||||||
<div class="checkbox ${this.value ? 'selected' : ''} ${this.disabled ? 'disabled' : ''}" tabindex="0">
|
<div class="checkbox ${this.value ? 'selected' : ''} ${this.disabled ? 'disabled' : ''}" tabindex="0">
|
||||||
${this.value
|
${this.value
|
||||||
@ -158,7 +135,8 @@ export class DeesInputCheckbox extends DeesElement {
|
|||||||
`
|
`
|
||||||
: html``}
|
: html``}
|
||||||
</div>
|
</div>
|
||||||
<div class="label">${this.label}</div>
|
</div>
|
||||||
|
<dees-label .label=${this.label}></dees-label>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
@ -177,6 +155,14 @@ export class DeesInputCheckbox extends DeesElement {
|
|||||||
this.changeSubject.next(this);
|
this.changeSubject.next(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public getValue(): boolean {
|
||||||
|
return this.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public setValue(value: boolean): void {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
public focus(): void {
|
public focus(): void {
|
||||||
const checkboxDiv = this.shadowRoot.querySelector('.checkbox');
|
const checkboxDiv = this.shadowRoot.querySelector('.checkbox');
|
||||||
if (checkboxDiv) {
|
if (checkboxDiv) {
|
||||||
|
@ -1,17 +1,16 @@
|
|||||||
import {
|
import {
|
||||||
customElement,
|
customElement,
|
||||||
DeesElement,
|
|
||||||
type TemplateResult,
|
type TemplateResult,
|
||||||
property,
|
property,
|
||||||
state,
|
state,
|
||||||
html,
|
html,
|
||||||
css,
|
css,
|
||||||
cssManager,
|
cssManager,
|
||||||
type CSSResult,
|
|
||||||
} from '@design.estate/dees-element';
|
} from '@design.estate/dees-element';
|
||||||
import * as domtools from '@design.estate/dees-domtools';
|
import * as domtools from '@design.estate/dees-domtools';
|
||||||
import { demoFunc } from './dees-input-dropdown.demo.js';
|
import { demoFunc } from './dees-input-dropdown.demo.js';
|
||||||
import { DeesWindowLayer } from './dees-windowlayer.js';
|
import { DeesWindowLayer } from './dees-windowlayer.js';
|
||||||
|
import { DeesInputBase } from './dees-input-base.js';
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface HTMLElementTagNameMap {
|
interface HTMLElementTagNameMap {
|
||||||
@ -20,20 +19,10 @@ declare global {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@customElement('dees-input-dropdown')
|
@customElement('dees-input-dropdown')
|
||||||
export class DeesInputDropdown extends DeesElement {
|
export class DeesInputDropdown extends DeesInputBase<DeesInputDropdown> {
|
||||||
public static demo = demoFunc;
|
public static demo = demoFunc;
|
||||||
|
|
||||||
// INSTANCE
|
// INSTANCE
|
||||||
public changeSubject = new domtools.plugins.smartrx.rxjs.Subject();
|
|
||||||
|
|
||||||
@property({
|
|
||||||
type: String,
|
|
||||||
reflect: true,
|
|
||||||
})
|
|
||||||
public label: string = 'Label';
|
|
||||||
|
|
||||||
@property()
|
|
||||||
public key: string;
|
|
||||||
|
|
||||||
@property()
|
@property()
|
||||||
public options: { option: string; key: string; payload?: any }[] = [];
|
public options: { option: string; key: string; payload?: any }[] = [];
|
||||||
@ -41,20 +30,21 @@ export class DeesInputDropdown extends DeesElement {
|
|||||||
@property()
|
@property()
|
||||||
public selectedOption: { option: string; key: string; payload?: any } = null;
|
public selectedOption: { option: string; key: string; payload?: any } = null;
|
||||||
|
|
||||||
@property({
|
// Add value property for form compatibility
|
||||||
type: Boolean,
|
public get value() {
|
||||||
})
|
return this.selectedOption;
|
||||||
public required: boolean = false;
|
}
|
||||||
|
|
||||||
|
public set value(val: { option: string; key: string; payload?: any }) {
|
||||||
|
this.selectedOption = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@property({
|
@property({
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
})
|
})
|
||||||
public enableSearch: boolean = true;
|
public enableSearch: boolean = true;
|
||||||
|
|
||||||
@property({
|
|
||||||
type: Boolean,
|
|
||||||
})
|
|
||||||
public disabled: boolean = false;
|
|
||||||
|
|
||||||
@state()
|
@state()
|
||||||
public opensToTop: boolean = false;
|
public opensToTop: boolean = false;
|
||||||
@ -69,6 +59,7 @@ export class DeesInputDropdown extends DeesElement {
|
|||||||
public isOpened = false;
|
public isOpened = false;
|
||||||
|
|
||||||
public static styles = [
|
public static styles = [
|
||||||
|
...DeesInputBase.baseStyles,
|
||||||
cssManager.defaultStyles,
|
cssManager.defaultStyles,
|
||||||
css`
|
css`
|
||||||
* {
|
* {
|
||||||
@ -78,19 +69,13 @@ export class DeesInputDropdown extends DeesElement {
|
|||||||
:host {
|
:host {
|
||||||
font-family: Roboto;
|
font-family: Roboto;
|
||||||
position: relative;
|
position: relative;
|
||||||
display: block;
|
|
||||||
color: ${cssManager.bdTheme('#222', '#fff')};
|
color: ${cssManager.bdTheme('#222', '#fff')};
|
||||||
margin-bottom: 24px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.maincontainer {
|
.maincontainer {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.label {
|
|
||||||
font-size: 14px;
|
|
||||||
margin-bottom: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.selectedBox {
|
.selectedBox {
|
||||||
user-select: none;
|
user-select: none;
|
||||||
@ -205,8 +190,9 @@ export class DeesInputDropdown extends DeesElement {
|
|||||||
|
|
||||||
public render(): TemplateResult {
|
public render(): TemplateResult {
|
||||||
return html`
|
return html`
|
||||||
|
<div class="input-wrapper">
|
||||||
|
<dees-label .label=${this.label}></dees-label>
|
||||||
<div class="maincontainer" @keydown="${this.isOpened ? this.handleKeyDown : undefined}">
|
<div class="maincontainer" @keydown="${this.isOpened ? this.handleKeyDown : undefined}">
|
||||||
${this.label ? html`<div class="label">${this.label}</div>` : html``}
|
|
||||||
<div class="selectionBox">
|
<div class="selectionBox">
|
||||||
${this.enableSearch && !this.opensToTop
|
${this.enableSearch && !this.opensToTop
|
||||||
? html`
|
? html`
|
||||||
@ -249,6 +235,7 @@ export class DeesInputDropdown extends DeesElement {
|
|||||||
${this.selectedOption?.option || 'Select...'}
|
${this.selectedOption?.option || 'Select...'}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -372,4 +359,12 @@ export class DeesInputDropdown extends DeesElement {
|
|||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public getValue(): { option: string; key: string; payload?: any } {
|
||||||
|
return this.selectedOption;
|
||||||
|
}
|
||||||
|
|
||||||
|
public setValue(value: { option: string; key: string; payload?: any }): void {
|
||||||
|
this.selectedOption = value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import {customElement, DeesElement, type TemplateResult, property, html, type CSSResult,} from '@design.estate/dees-element';
|
import {customElement, type TemplateResult, property, html, css, cssManager} from '@design.estate/dees-element';
|
||||||
import * as domtools from '@design.estate/dees-domtools';
|
import * as domtools from '@design.estate/dees-domtools';
|
||||||
|
import { DeesInputBase } from './dees-input-base.js';
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface HTMLElementTagNameMap {
|
interface HTMLElementTagNameMap {
|
||||||
@ -8,55 +9,34 @@ declare global {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@customElement('dees-input-radio')
|
@customElement('dees-input-radio')
|
||||||
export class DeesInputRadio extends DeesElement {
|
export class DeesInputRadio extends DeesInputBase<DeesInputRadio> {
|
||||||
public static demo = () => html`<dees-input-radio></dees-input-radio>`;
|
public static demo = () => html`<dees-input-radio></dees-input-radio>`;
|
||||||
|
|
||||||
// INSTANCE
|
// INSTANCE
|
||||||
public changeSubject = new domtools.plugins.smartrx.rxjs.Subject();
|
|
||||||
|
|
||||||
@property({
|
|
||||||
type: String,
|
|
||||||
reflect: true,
|
|
||||||
})
|
|
||||||
public key: string;
|
|
||||||
|
|
||||||
@property()
|
|
||||||
public label: string = 'Label';
|
|
||||||
|
|
||||||
@property()
|
@property()
|
||||||
public value: boolean = false;
|
public value: boolean = false;
|
||||||
|
|
||||||
@property({
|
|
||||||
type: Boolean,
|
|
||||||
})
|
|
||||||
public required: boolean = false;
|
|
||||||
|
|
||||||
@property({
|
|
||||||
type: Boolean
|
|
||||||
})
|
|
||||||
public disabled: boolean = false;
|
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
|
this.labelPosition = 'right'; // Radio buttons default to label on the right
|
||||||
}
|
}
|
||||||
|
|
||||||
public render(): TemplateResult {
|
public static styles = [
|
||||||
return html `
|
...DeesInputBase.baseStyles,
|
||||||
<style>
|
cssManager.defaultStyles,
|
||||||
|
css`
|
||||||
* {
|
* {
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
:host {
|
:host {
|
||||||
display: block;
|
|
||||||
position: relative;
|
position: relative;
|
||||||
margin: 20px 0px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.maincontainer {
|
.maincontainer {
|
||||||
transition: all 0.3s;
|
transition: all 0.3s;
|
||||||
display: grid;
|
|
||||||
grid-template-columns: 25px auto;
|
|
||||||
padding: 5px 0px;
|
padding: 5px 0px;
|
||||||
color: #ccc;
|
color: #ccc;
|
||||||
}
|
}
|
||||||
@ -65,14 +45,6 @@ export class DeesInputRadio extends DeesElement {
|
|||||||
color: #fff;
|
color: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
.label {
|
|
||||||
margin-left: 15px;
|
|
||||||
line-height: 25px;
|
|
||||||
font-size: 14px;
|
|
||||||
font-weight: normal;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
input:focus {
|
input:focus {
|
||||||
outline: none;
|
outline: none;
|
||||||
border-bottom: 1px solid #e4002b;
|
border-bottom: 1px solid #e4002b;
|
||||||
@ -106,12 +78,18 @@ export class DeesInputRadio extends DeesElement {
|
|||||||
height: 10px;
|
height: 10px;
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
}
|
}
|
||||||
</style>
|
`,
|
||||||
|
];
|
||||||
|
|
||||||
|
public render(): TemplateResult {
|
||||||
|
return html`
|
||||||
|
<div class="input-wrapper">
|
||||||
<div class="maincontainer" @click="${this.toggleSelected}">
|
<div class="maincontainer" @click="${this.toggleSelected}">
|
||||||
<div class="checkbox ${this.value ? 'selected' : ''}">
|
<div class="checkbox ${this.value ? 'selected' : ''}">
|
||||||
${this.value ? html`<div class="innercircle"></div>`: html``}
|
${this.value ? html`<div class="innercircle"></div>`: html``}
|
||||||
</div>
|
</div>
|
||||||
<div class="label">${this.label}</div>
|
</div>
|
||||||
|
<dees-label .label=${this.label}></dees-label>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
@ -124,4 +102,12 @@ export class DeesInputRadio extends DeesElement {
|
|||||||
}));
|
}));
|
||||||
this.changeSubject.next(this);
|
this.changeSubject.next(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public getValue(): boolean {
|
||||||
|
return this.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public setValue(value: boolean): void {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,16 +1,14 @@
|
|||||||
import * as colors from './00colors.js';
|
import * as colors from './00colors.js';
|
||||||
|
import { DeesInputBase } from './dees-input-base.js';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
customElement,
|
customElement,
|
||||||
DeesElement,
|
|
||||||
type TemplateResult,
|
type TemplateResult,
|
||||||
property,
|
property,
|
||||||
html,
|
html,
|
||||||
cssManager,
|
cssManager,
|
||||||
css,
|
css,
|
||||||
type CSSResult,
|
|
||||||
} from '@design.estate/dees-element';
|
} from '@design.estate/dees-element';
|
||||||
import * as domtools from '@design.estate/dees-domtools';
|
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface HTMLElementTagNameMap {
|
interface HTMLElementTagNameMap {
|
||||||
@ -19,47 +17,19 @@ declare global {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@customElement('dees-input-text')
|
@customElement('dees-input-text')
|
||||||
export class DeesInputText extends DeesElement {
|
export class DeesInputText extends DeesInputBase {
|
||||||
public static demo = () => html`
|
public static demo = () => html`
|
||||||
<dees-input-text .label=${'this is a label'} .value=${'test'}></dees-input-text>
|
<dees-input-text .label=${'this is a label'} .value=${'test'}></dees-input-text>
|
||||||
<dees-input-text .isPasswordBool=${true}></dees-input-text>
|
<dees-input-text .isPasswordBool=${true}></dees-input-text>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
// INSTANCE
|
// INSTANCE
|
||||||
public changeSubject = new domtools.plugins.smartrx.rxjs.Subject<DeesInputText>();
|
|
||||||
|
|
||||||
@property({
|
|
||||||
type: String,
|
|
||||||
})
|
|
||||||
public label: string;
|
|
||||||
|
|
||||||
@property({
|
|
||||||
type: String,
|
|
||||||
})
|
|
||||||
public description: string;
|
|
||||||
|
|
||||||
@property({
|
|
||||||
type: String,
|
|
||||||
reflect: true,
|
|
||||||
})
|
|
||||||
public key: string;
|
|
||||||
|
|
||||||
@property({
|
@property({
|
||||||
type: String,
|
type: String,
|
||||||
reflect: true,
|
reflect: true,
|
||||||
})
|
})
|
||||||
public value: string = '';
|
public value: string = '';
|
||||||
|
|
||||||
@property({
|
|
||||||
type: Boolean,
|
|
||||||
})
|
|
||||||
public required: boolean = false;
|
|
||||||
|
|
||||||
@property({
|
|
||||||
type: Boolean,
|
|
||||||
})
|
|
||||||
public disabled: boolean = false;
|
|
||||||
|
|
||||||
@property({
|
@property({
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
reflect: true,
|
reflect: true,
|
||||||
@ -87,6 +57,7 @@ export class DeesInputText extends DeesElement {
|
|||||||
validationFunction: (value: string) => boolean;
|
validationFunction: (value: string) => boolean;
|
||||||
|
|
||||||
public static styles = [
|
public static styles = [
|
||||||
|
...DeesInputBase.baseStyles,
|
||||||
cssManager.defaultStyles,
|
cssManager.defaultStyles,
|
||||||
css`
|
css`
|
||||||
* {
|
* {
|
||||||
@ -95,9 +66,6 @@ export class DeesInputText extends DeesElement {
|
|||||||
|
|
||||||
:host {
|
:host {
|
||||||
position: relative;
|
position: relative;
|
||||||
display: grid;
|
|
||||||
margin: 8px 0px;
|
|
||||||
margin-bottom: 24px;
|
|
||||||
z-index: auto;
|
z-index: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -193,8 +161,9 @@ export class DeesInputText extends DeesElement {
|
|||||||
}
|
}
|
||||||
`}
|
`}
|
||||||
</style>
|
</style>
|
||||||
<div class="maincontainer">
|
<div class="input-wrapper">
|
||||||
<dees-label .label=${this.label} .description=${this.description}></dees-label>
|
<dees-label .label=${this.label} .description=${this.description}></dees-label>
|
||||||
|
<div class="maincontainer">
|
||||||
<input
|
<input
|
||||||
type="${this.isPasswordBool && !this.showPasswordBool ? 'password' : 'text'}"
|
type="${this.isPasswordBool && !this.showPasswordBool ? 'password' : 'text'}"
|
||||||
.value=${this.value}
|
.value=${this.value}
|
||||||
@ -212,14 +181,12 @@ export class DeesInputText extends DeesElement {
|
|||||||
`
|
`
|
||||||
: html``}
|
: html``}
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
firstUpdated() {
|
firstUpdated() {
|
||||||
const input = this.shadowRoot.querySelector('input');
|
// Input event handling is already done in updateValue method
|
||||||
input.addEventListener('input', (eventArg: InputEvent) => {
|
|
||||||
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async updateValue(eventArg: Event) {
|
public async updateValue(eventArg: Event) {
|
||||||
@ -228,16 +195,15 @@ export class DeesInputText extends DeesElement {
|
|||||||
this.changeSubject.next(this);
|
this.changeSubject.next(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async freeze() {
|
public getValue(): string {
|
||||||
this.disabled = true;
|
return this.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async unfreeze() {
|
public setValue(value: string): void {
|
||||||
this.disabled = false;
|
this.value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async togglePasswordView() {
|
public async togglePasswordView() {
|
||||||
const domtools = await this.domtoolsPromise;
|
|
||||||
this.showPasswordBool = !this.showPasswordBool;
|
this.showPasswordBool = !this.showPasswordBool;
|
||||||
console.log(`this.showPasswordBool is: ${this.showPasswordBool}`);
|
console.log(`this.showPasswordBool is: ${this.showPasswordBool}`);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user