update
This commit is contained in:
263
readme.md
263
readme.md
@ -1,5 +1,5 @@
|
||||
# @design.estate/dees-catalog
|
||||
An extensive library for building modern web applications with dynamic components using Web Components, JavaScript, and TypeScript.
|
||||
A comprehensive web components library built with TypeScript and LitElement, providing 75+ UI components for building modern web applications with consistent design and behavior.
|
||||
|
||||
## Install
|
||||
To install the `@design.estate/dees-catalog` library, you can use npm or any other compatible JavaScript package manager:
|
||||
@ -12,15 +12,16 @@ npm install @design.estate/dees-catalog
|
||||
|
||||
| Category | Components |
|
||||
|----------|------------|
|
||||
| Core UI | `DeesButton`, `DeesButtonExit`, `DeesButtonGroup`, `DeesBadge`, `DeesChips`, `DeesHeading`, `DeesHint`, `DeesIcon`, `DeesLabel`, `DeesPanel`, `DeesSearchbar`, `DeesSpinner`, `DeesToast`, `DeesWindowcontrols` |
|
||||
| Forms | `DeesForm`, `DeesInputText`, `DeesInputCheckbox`, `DeesInputDropdown`, `DeesInputRadiogroup`, `DeesInputFileupload`, `DeesInputIban`, `DeesInputPhone`, `DeesInputQuantitySelector`, `DeesInputMultitoggle`, `DeesInputTags`, `DeesInputTypelist`, `DeesInputRichtext`, `DeesInputWysiwyg`, `DeesFormSubmit` |
|
||||
| Layout | `DeesAppuiBase`, `DeesAppuiMainmenu`, `DeesAppuiMainselector`, `DeesAppuiMaincontent`, `DeesAppuiAppbar`, `DeesAppuiActivitylog`, `DeesAppuiProfiledropdown`, `DeesAppuiTabs`, `DeesAppuiView`, `DeesMobileNavigation` |
|
||||
| Data Display | `DeesTable`, `DeesDataviewCodebox`, `DeesDataviewStatusobject`, `DeesPdf`, `DeesStatsGrid`, `DeesPagination` |
|
||||
| Visualization | `DeesChartArea`, `DeesChartLog` |
|
||||
| Dialogs & Overlays | `DeesModal`, `DeesContextmenu`, `DeesSpeechbubble`, `DeesWindowlayer` |
|
||||
| Navigation | `DeesStepper`, `DeesProgressbar`, `DeesMobileNavigation` |
|
||||
| Development | `DeesEditor`, `DeesEditorMarkdown`, `DeesEditorMarkdownoutlet`, `DeesTerminal`, `DeesUpdater` |
|
||||
| Auth & Utilities | `DeesSimpleAppdash`, `DeesSimpleLogin` |
|
||||
| Core UI | [`DeesButton`](#deesbutton), [`DeesButtonExit`](#deesbuttonexit), [`DeesButtonGroup`](#deesbuttongroup), [`DeesBadge`](#deesbadge), [`DeesChips`](#deeschips), [`DeesHeading`](#deesheading), [`DeesHint`](#deeshint), [`DeesIcon`](#deesicon), [`DeesLabel`](#deeslabel), [`DeesPanel`](#deespanel), [`DeesSearchbar`](#deessearchbar), [`DeesSpinner`](#deesspinner), [`DeesToast`](#deestoast), [`DeesWindowcontrols`](#deeswindowcontrols) |
|
||||
| Forms | [`DeesForm`](#deesform), [`DeesInputText`](#deesinputtext), [`DeesInputCheckbox`](#deesinputcheckbox), [`DeesInputDropdown`](#deesinputdropdown), [`DeesInputRadiogroup`](#deesinputradiogroup), [`DeesInputFileupload`](#deesinputfileupload), [`DeesInputIban`](#deesinputiban), [`DeesInputPhone`](#deesinputphone), [`DeesInputQuantitySelector`](#deesinputquantityselector), [`DeesInputMultitoggle`](#deesinputmultitoggle), [`DeesInputTags`](#deesinputtags), [`DeesInputTypelist`](#deesinputtypelist), [`DeesInputRichtext`](#deesinputrichtext), [`DeesInputWysiwyg`](#deesinputwysiwyg), [`DeesInputDatepicker`](#deesinputdatepicker), [`DeesInputSearchselect`](#deesinputsearchselect), [`DeesFormSubmit`](#deesformsubmit) |
|
||||
| Layout | [`DeesAppuiBase`](#deesappuibase), [`DeesAppuiMainmenu`](#deesappuimainmenu), [`DeesAppuiMainselector`](#deesappuimainselector), [`DeesAppuiMaincontent`](#deesappuimaincontent), [`DeesAppuiAppbar`](#deesappuiappbar), [`DeesAppuiActivitylog`](#deesappuiactivitylog), [`DeesAppuiProfiledropdown`](#deesappuiprofiledropdown), [`DeesAppuiTabs`](#deesappuitabs), [`DeesAppuiView`](#deesappuiview), [`DeesMobileNavigation`](#deesmobilenavigation), [`DeesDashboardGrid`](#deesdashboardgrid) |
|
||||
| Data Display | [`DeesTable`](#deestable), [`DeesDataviewCodebox`](#deesdataviewcodebox), [`DeesDataviewStatusobject`](#deesdataviewstatusobject), [`DeesPdf`](#deespdf), [`DeesStatsGrid`](#deesstatsgrid), [`DeesPagination`](#deespagination) |
|
||||
| Visualization | [`DeesChartArea`](#deeschartarea), [`DeesChartLog`](#deeschartlog) |
|
||||
| Dialogs & Overlays | [`DeesModal`](#deesmodal), [`DeesContextmenu`](#deescontextmenu), [`DeesSpeechbubble`](#deesspeechbubble), [`DeesWindowlayer`](#deeswindowlayer) |
|
||||
| Navigation | [`DeesStepper`](#deesstepper), [`DeesProgressbar`](#deesprogressbar) |
|
||||
| Development | [`DeesEditor`](#deeseditor), [`DeesEditorMarkdown`](#deeseditormarkdown), [`DeesEditorMarkdownoutlet`](#deeseditormarkdownoutlet), [`DeesTerminal`](#deesterminal), [`DeesUpdater`](#deesupdater) |
|
||||
| Auth & Utilities | [`DeesSimpleAppdash`](#deessimpleappdash), [`DeesSimpleLogin`](#deessimplelogin) |
|
||||
| Shopping | [`DeesShoppingProductcard`](#deesshoppingproductcard) |
|
||||
|
||||
## Detailed Component Documentation
|
||||
|
||||
@ -70,14 +71,36 @@ Interactive chips/tags with selection capabilities.
|
||||
```
|
||||
|
||||
#### `DeesIcon`
|
||||
Display icons from various icon sets including FontAwesome.
|
||||
Display icons from FontAwesome and Lucide icon libraries with library prefixes.
|
||||
|
||||
```typescript
|
||||
// FontAwesome icons - use 'fa:' prefix
|
||||
<dees-icon
|
||||
icon="home" // FontAwesome icon name
|
||||
type="solid" // Options: solid, regular, brands
|
||||
size="1.5rem" // Optional: custom size
|
||||
icon="fa:check" // FontAwesome icon with fa: prefix
|
||||
iconSize="24" // Size in pixels
|
||||
color="#22c55e" // Optional: custom color
|
||||
></dees-icon>
|
||||
|
||||
// Lucide icons - use 'lucide:' prefix
|
||||
<dees-icon
|
||||
icon="lucide:menu" // Lucide icon with lucide: prefix
|
||||
iconSize="24" // Size in pixels
|
||||
color="#007bff" // Optional: custom color
|
||||
strokeWidth="2" // Optional: stroke width for Lucide icons
|
||||
></dees-icon>
|
||||
|
||||
// Available FontAwesome icons include:
|
||||
// fa:check, fa:bell, fa:gear, fa:trash, fa:copy, fa:paste, fa:eye, fa:eyeSlash,
|
||||
// fa:plus, fa:minus, fa:circleInfo, fa:circleCheck, fa:circleXmark, fa:message,
|
||||
// fa:arrowRight, fa:facebook, fa:twitter, fa:linkedin, fa:instagram, etc.
|
||||
|
||||
// Available Lucide icons include:
|
||||
// lucide:menu, lucide:settings, lucide:home, lucide:file, lucide:folder,
|
||||
// lucide:search, lucide:user, lucide:heart, lucide:star, lucide:download, etc.
|
||||
|
||||
// Legacy API (deprecated but still supported)
|
||||
<dees-icon
|
||||
iconFA="check" // Without prefix - assumes FontAwesome
|
||||
></dees-icon>
|
||||
```
|
||||
|
||||
@ -431,6 +454,61 @@ Dynamic list input for managing arrays of typed values.
|
||||
></dees-input-typelist>
|
||||
```
|
||||
|
||||
#### `DeesInputDatepicker`
|
||||
Date and time picker component with calendar interface.
|
||||
|
||||
```typescript
|
||||
<dees-input-datepicker
|
||||
key="eventDate"
|
||||
label="Event Date"
|
||||
placeholder="Select date"
|
||||
value="2025-01-15T14:30:00Z" // ISO string format
|
||||
dateFormat="DD/MM/YYYY" // Display format
|
||||
enableTime={true} // Enable time selection
|
||||
timeFormat="24h" // Options: 24h, 12h
|
||||
minuteIncrement={15} // Time step in minutes
|
||||
minDate="2025-01-01" // Minimum selectable date
|
||||
maxDate="2025-12-31" // Maximum selectable date
|
||||
.disabledDates=${[ // Array of disabled dates
|
||||
'2025-01-10',
|
||||
'2025-01-11'
|
||||
]}
|
||||
weekStartsOn={1} // 0 = Sunday, 1 = Monday
|
||||
required
|
||||
@change=${handleDateChange}
|
||||
></dees-input-datepicker>
|
||||
```
|
||||
|
||||
Key Features:
|
||||
- Interactive calendar popup
|
||||
- Optional time selection
|
||||
- Configurable date format
|
||||
- Min/max date constraints
|
||||
- Disable specific dates
|
||||
- Keyboard navigation
|
||||
- Today button
|
||||
- Clear functionality
|
||||
- 12/24 hour time formats
|
||||
- Theme-aware styling
|
||||
|
||||
#### `DeesInputSearchselect`
|
||||
Search-enabled dropdown selection component.
|
||||
|
||||
```typescript
|
||||
<dees-input-searchselect
|
||||
key="category"
|
||||
label="Select Category"
|
||||
placeholder="Search categories..."
|
||||
.options=${[
|
||||
{ key: 'tech', label: 'Technology' },
|
||||
{ key: 'health', label: 'Healthcare' },
|
||||
{ key: 'finance', label: 'Finance' }
|
||||
]}
|
||||
required
|
||||
@change=${handleCategoryChange}
|
||||
></dees-input-searchselect>
|
||||
```
|
||||
|
||||
#### `DeesInputRichtext`
|
||||
Rich text editor with formatting toolbar powered by TipTap.
|
||||
|
||||
@ -919,6 +997,100 @@ Responsive navigation component for mobile devices.
|
||||
></dees-mobile-navigation>
|
||||
```
|
||||
|
||||
#### `DeesDashboardGrid`
|
||||
Drag-and-drop grid layout system for creating customizable dashboards.
|
||||
|
||||
```typescript
|
||||
<dees-dashboardgrid
|
||||
.widgets=${[
|
||||
{
|
||||
id: 'widget1',
|
||||
x: 0, // Grid column position
|
||||
y: 0, // Grid row position
|
||||
w: 4, // Width in grid units
|
||||
h: 3, // Height in grid units
|
||||
minW: 2, // Minimum width
|
||||
minH: 2, // Minimum height
|
||||
maxW: 6, // Maximum width
|
||||
title: 'Sales Overview',
|
||||
icon: 'fa:chart-line',
|
||||
content: html`<div>Widget content here</div>`,
|
||||
noMove: false, // Allow moving
|
||||
noResize: false // Allow resizing
|
||||
},
|
||||
{
|
||||
id: 'widget2',
|
||||
x: 4,
|
||||
y: 0,
|
||||
w: 4,
|
||||
h: 3,
|
||||
title: 'Recent Activity',
|
||||
content: html`<dees-table .data=${activityData}></dees-table>`,
|
||||
autoPosition: true // Auto-find position
|
||||
}
|
||||
]}
|
||||
columns={12} // Number of grid columns
|
||||
cellHeight={80} // Height of each grid cell in pixels
|
||||
cellHeightUnit="px" // Options: px, em, rem, auto
|
||||
margin={10} // Gap between widgets
|
||||
editable={true} // Enable drag and resize
|
||||
showGridLines={false} // Show grid guidelines
|
||||
enableAnimation={true} // Smooth transitions
|
||||
rtl={false} // Right-to-left support
|
||||
@widget-move=${handleWidgetMove}
|
||||
@widget-resize=${handleWidgetResize}
|
||||
></dees-dashboardgrid>
|
||||
|
||||
// Programmatic methods
|
||||
const grid = document.querySelector('dees-dashboardgrid');
|
||||
|
||||
// Add a new widget
|
||||
grid.addWidget({
|
||||
id: 'newWidget',
|
||||
x: 0,
|
||||
y: 0,
|
||||
w: 3,
|
||||
h: 2,
|
||||
content: html`<div>New widget</div>`
|
||||
}, true); // true = auto-position
|
||||
|
||||
// Remove widget
|
||||
grid.removeWidget('widget1');
|
||||
|
||||
// Update widget
|
||||
grid.updateWidget('widget2', {
|
||||
title: 'Updated Title',
|
||||
w: 6
|
||||
});
|
||||
|
||||
// Get/set layout
|
||||
const layout = grid.getLayout(); // Returns position data
|
||||
grid.setLayout(savedLayout); // Restore positions
|
||||
|
||||
// Compact widgets
|
||||
grid.compact('vertical'); // Or 'horizontal'
|
||||
|
||||
// Lock/unlock editing
|
||||
grid.lockGrid();
|
||||
grid.unlockGrid();
|
||||
```
|
||||
|
||||
Key Features:
|
||||
- Drag-and-drop widget repositioning
|
||||
- Resize handles on edges and corners
|
||||
- Grid-based layout system
|
||||
- Collision detection
|
||||
- Auto-positioning for new widgets
|
||||
- Configurable constraints (min/max dimensions)
|
||||
- Lock individual widgets or entire grid
|
||||
- Compact layout algorithm
|
||||
- Save/restore layout positions
|
||||
- RTL layout support
|
||||
- Optional grid lines for alignment
|
||||
- Smooth animations
|
||||
- Responsive sizing
|
||||
- Empty state display
|
||||
|
||||
### Data Display Components
|
||||
|
||||
#### `DeesTable`
|
||||
@ -1913,6 +2085,69 @@ Key Features:
|
||||
- Responsive layout
|
||||
- Loading states
|
||||
|
||||
### Shopping Components
|
||||
|
||||
#### `DeesShoppingProductcard`
|
||||
Product card component for e-commerce applications.
|
||||
|
||||
```typescript
|
||||
<dees-shopping-productcard
|
||||
.productData=${{
|
||||
name: 'Premium Headphones',
|
||||
category: 'Electronics',
|
||||
description: 'High-quality wireless headphones with noise cancellation',
|
||||
price: 199.99,
|
||||
originalPrice: 249.99, // Shows strikethrough price
|
||||
currency: '$',
|
||||
inStock: true,
|
||||
stockText: 'In Stock', // Custom stock text
|
||||
imageUrl: '/images/headphones.jpg',
|
||||
iconName: 'lucide:headphones' // Fallback icon if no image
|
||||
}}
|
||||
quantity={1} // Current quantity
|
||||
showQuantitySelector={true} // Show quantity selector
|
||||
selectable={false} // Enable selection mode
|
||||
selected={false} // Selection state
|
||||
@quantityChange=${(e) => handleQuantityChange(e.detail)}
|
||||
@selectionChange=${(e) => handleSelectionChange(e.detail)}
|
||||
></dees-shopping-productcard>
|
||||
```
|
||||
|
||||
Key Features:
|
||||
- Product image with fallback icon
|
||||
- Category label
|
||||
- Product name and description
|
||||
- Price display with original price strikethrough
|
||||
- Stock status indicator
|
||||
- Built-in quantity selector
|
||||
- Selection mode for bulk operations
|
||||
- Hover effects
|
||||
- Responsive design
|
||||
- Theme-aware styling
|
||||
|
||||
Product Data Interface:
|
||||
```typescript
|
||||
interface IProductData {
|
||||
name: string;
|
||||
category?: string;
|
||||
description?: string;
|
||||
price: number;
|
||||
originalPrice?: number;
|
||||
currency?: string;
|
||||
inStock?: boolean;
|
||||
stockText?: string;
|
||||
imageUrl?: string;
|
||||
iconName?: string;
|
||||
}
|
||||
```
|
||||
|
||||
Common Use Cases:
|
||||
- Product listings
|
||||
- Shopping carts
|
||||
- Order summaries
|
||||
- Product comparisons
|
||||
- Wishlist displays
|
||||
|
||||
## License and Legal Information
|
||||
|
||||
This repository contains open-source code that is licensed under the MIT License. A copy of the MIT License can be found in the license file within this repository.
|
||||
|
@ -1,83 +1,93 @@
|
||||
import { html, css, cssManager } from '@design.estate/dees-element';
|
||||
import { html, css, cssManager, domtools } from '@design.estate/dees-element';
|
||||
import '@design.estate/dees-wcctools/demotools';
|
||||
import './dees-panel.js';
|
||||
import './dees-form.js';
|
||||
import './dees-form-submit.js';
|
||||
import './dees-input-text.js';
|
||||
import './dees-icon.js';
|
||||
import type { DeesButton } from './dees-button.js';
|
||||
|
||||
export const demoFunc = () => html`
|
||||
<dees-demowrapper>
|
||||
<style>
|
||||
${css`
|
||||
.demo-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 24px;
|
||||
padding: 24px;
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
dees-panel {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
dees-panel:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.button-group {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.vertical-group {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
max-width: 300px;
|
||||
}
|
||||
|
||||
.horizontal-group {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.demo-output {
|
||||
margin-top: 16px;
|
||||
padding: 12px;
|
||||
background: ${cssManager.bdTheme('hsl(210 40% 96.1%)', 'hsl(215 20.2% 16.8%)')};
|
||||
border-radius: 6px;
|
||||
font-size: 14px;
|
||||
font-family: monospace;
|
||||
color: ${cssManager.bdTheme('hsl(215.3 25% 8.8%)', 'hsl(210 40% 98%)')};
|
||||
}
|
||||
|
||||
.icon-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
margin: 8px 0;
|
||||
}
|
||||
|
||||
.code-snippet {
|
||||
background: ${cssManager.bdTheme('hsl(210 40% 96.1%)', 'hsl(215 20.2% 11.8%)')};
|
||||
padding: 8px 12px;
|
||||
border-radius: 4px;
|
||||
font-family: monospace;
|
||||
font-size: 13px;
|
||||
display: inline-block;
|
||||
margin: 4px 0;
|
||||
}
|
||||
`}
|
||||
</style>
|
||||
|
||||
<div class="demo-container">
|
||||
<style>
|
||||
${css`
|
||||
.demo-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 24px;
|
||||
padding: 24px;
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
dees-panel {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
dees-panel:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.button-group {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.vertical-group {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
max-width: 300px;
|
||||
}
|
||||
|
||||
.horizontal-group {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.demo-output {
|
||||
margin-top: 16px;
|
||||
padding: 12px;
|
||||
background: ${cssManager.bdTheme('hsl(210 40% 96.1%)', 'hsl(215 20.2% 16.8%)')};
|
||||
border-radius: 6px;
|
||||
font-size: 14px;
|
||||
font-family: monospace;
|
||||
color: ${cssManager.bdTheme('hsl(215.3 25% 8.8%)', 'hsl(210 40% 98%)')};
|
||||
}
|
||||
|
||||
.icon-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
margin: 8px 0;
|
||||
}
|
||||
|
||||
.code-snippet {
|
||||
background: ${cssManager.bdTheme('hsl(210 40% 96.1%)', 'hsl(215 20.2% 11.8%)')};
|
||||
padding: 8px 12px;
|
||||
border-radius: 4px;
|
||||
font-family: monospace;
|
||||
font-size: 13px;
|
||||
display: inline-block;
|
||||
margin: 4px 0;
|
||||
}
|
||||
`}
|
||||
</style>
|
||||
|
||||
<div class="demo-container">
|
||||
<dees-demowrapper .runAfterRender=${async (elementArg: HTMLElement) => {
|
||||
// Log button clicks for demo purposes
|
||||
const buttons = elementArg.querySelectorAll('dees-button');
|
||||
buttons.forEach((button) => {
|
||||
button.addEventListener('clicked', () => {
|
||||
const type = button.getAttribute('type') || 'default';
|
||||
console.log(`Button variant clicked: ${type}`);
|
||||
});
|
||||
});
|
||||
}}>
|
||||
<dees-panel .title=${'1. Button Variants'} .subtitle=${'Different visual styles for various use cases'}>
|
||||
<div class="button-group">
|
||||
<dees-button type="default">Default</dees-button>
|
||||
@ -88,7 +98,18 @@ export const demoFunc = () => html`
|
||||
<dees-button type="link">Link Button</dees-button>
|
||||
</div>
|
||||
</dees-panel>
|
||||
|
||||
</dees-demowrapper>
|
||||
|
||||
<dees-demowrapper .runAfterRender=${async (elementArg: HTMLElement) => {
|
||||
// Demonstrate size differences programmatically
|
||||
const buttons = elementArg.querySelectorAll('dees-button');
|
||||
buttons.forEach((button) => {
|
||||
button.addEventListener('clicked', () => {
|
||||
const size = button.getAttribute('size') || 'default';
|
||||
console.log(`Button size: ${size}`);
|
||||
});
|
||||
});
|
||||
}}>
|
||||
<dees-panel .title=${'2. Button Sizes'} .subtitle=${'Multiple sizes for different contexts and use cases'}>
|
||||
<div class="button-group">
|
||||
<dees-button size="sm">Small Button</dees-button>
|
||||
@ -103,7 +124,21 @@ export const demoFunc = () => html`
|
||||
<dees-button size="lg" type="outline">Large Outline</dees-button>
|
||||
</div>
|
||||
</dees-panel>
|
||||
|
||||
</dees-demowrapper>
|
||||
|
||||
<dees-demowrapper .runAfterRender=${async (elementArg: HTMLElement) => {
|
||||
// Track icon button clicks
|
||||
const iconButtons = elementArg.querySelectorAll('dees-button');
|
||||
iconButtons.forEach((button) => {
|
||||
button.addEventListener('clicked', () => {
|
||||
const hasIcon = button.querySelector('dees-icon');
|
||||
if (hasIcon) {
|
||||
const iconName = hasIcon.getAttribute('iconFA') || 'unknown';
|
||||
console.log(`Icon button clicked: ${iconName}`);
|
||||
}
|
||||
});
|
||||
});
|
||||
}}>
|
||||
<dees-panel .title=${'3. Buttons with Icons'} .subtitle=${'Combining icons with text for enhanced visual communication'}>
|
||||
<div class="icon-row">
|
||||
<dees-button>
|
||||
@ -153,7 +188,33 @@ export const demoFunc = () => html`
|
||||
</dees-button>
|
||||
</div>
|
||||
</dees-panel>
|
||||
</dees-demowrapper>
|
||||
|
||||
<dees-demowrapper .runAfterRender=${async (elementArg: HTMLElement) => {
|
||||
// Demonstrate status changes
|
||||
const pendingButton = elementArg.querySelector('dees-button[status="pending"]');
|
||||
const successButton = elementArg.querySelector('dees-button[status="success"]');
|
||||
const errorButton = elementArg.querySelector('dees-button[status="error"]');
|
||||
|
||||
// Simulate status changes
|
||||
if (pendingButton) {
|
||||
setTimeout(() => {
|
||||
console.log('Pending button is showing loading state');
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
if (successButton) {
|
||||
successButton.addEventListener('clicked', () => {
|
||||
console.log('Success state button clicked');
|
||||
});
|
||||
}
|
||||
|
||||
if (errorButton) {
|
||||
errorButton.addEventListener('clicked', () => {
|
||||
console.log('Error state button clicked');
|
||||
});
|
||||
}
|
||||
}}>
|
||||
<dees-panel .title=${'4. Button States'} .subtitle=${'Different states to indicate button status and loading conditions'}>
|
||||
<div class="button-group">
|
||||
<dees-button status="normal">Normal</dees-button>
|
||||
@ -169,61 +230,81 @@ export const demoFunc = () => html`
|
||||
<dees-button type="destructive" status="pending" size="lg">Large Loading</dees-button>
|
||||
</div>
|
||||
</dees-panel>
|
||||
</dees-demowrapper>
|
||||
|
||||
<dees-demowrapper .runAfterRender=${async (elementArg: HTMLElement) => {
|
||||
// Set up click handlers with the output element
|
||||
const output = elementArg.querySelector('#click-output');
|
||||
|
||||
const clickMeBtn = elementArg.querySelector('dees-button:first-of-type');
|
||||
const dataBtn = elementArg.querySelector('dees-button[type="secondary"]');
|
||||
const asyncBtn = elementArg.querySelector('dees-button[type="destructive"]');
|
||||
|
||||
if (clickMeBtn && output) {
|
||||
clickMeBtn.addEventListener('clicked', () => {
|
||||
output.textContent = `Clicked: Default button at ${new Date().toLocaleTimeString()}`;
|
||||
});
|
||||
}
|
||||
|
||||
if (dataBtn && output) {
|
||||
dataBtn.addEventListener('clicked', (e: CustomEvent) => {
|
||||
output.textContent = `Clicked: Secondary button with data: ${e.detail.data}`;
|
||||
});
|
||||
}
|
||||
|
||||
if (asyncBtn && output) {
|
||||
asyncBtn.addEventListener('clicked', async () => {
|
||||
output.textContent = 'Processing...';
|
||||
await domtools.plugins.smartdelay.delayFor(2000);
|
||||
output.textContent = 'Action completed!';
|
||||
});
|
||||
}
|
||||
}}>
|
||||
<dees-panel .title=${'5. Event Handling'} .subtitle=${'Interactive examples with click event handling'}>
|
||||
<div class="button-group">
|
||||
<dees-button
|
||||
@clicked=${() => {
|
||||
const output = document.querySelector('#click-output');
|
||||
if (output) {
|
||||
output.textContent = `Clicked: Default button at ${new Date().toLocaleTimeString()}`;
|
||||
}
|
||||
}}
|
||||
>
|
||||
Click Me
|
||||
</dees-button>
|
||||
|
||||
<dees-button
|
||||
type="secondary"
|
||||
.eventDetailData=${'custom-data-123'}
|
||||
@clicked=${(e: CustomEvent) => {
|
||||
const output = document.querySelector('#click-output');
|
||||
if (output) {
|
||||
output.textContent = `Clicked: Secondary button with data: ${e.detail.data}`;
|
||||
}
|
||||
}}
|
||||
>
|
||||
<dees-button>Click Me</dees-button>
|
||||
<dees-button type="secondary" .eventDetailData=${'custom-data-123'}>
|
||||
Click with Data
|
||||
</dees-button>
|
||||
|
||||
<dees-button
|
||||
type="destructive"
|
||||
@clicked=${async () => {
|
||||
const output = document.querySelector('#click-output');
|
||||
if (output) {
|
||||
output.textContent = 'Processing...';
|
||||
await new Promise(resolve => setTimeout(resolve, 2000));
|
||||
output.textContent = 'Action completed!';
|
||||
}
|
||||
}}
|
||||
>
|
||||
Async Action
|
||||
</dees-button>
|
||||
<dees-button type="destructive">Async Action</dees-button>
|
||||
</div>
|
||||
|
||||
<div id="click-output" class="demo-output">
|
||||
<em>Click a button to see the result...</em>
|
||||
</div>
|
||||
</dees-panel>
|
||||
</dees-demowrapper>
|
||||
|
||||
<dees-demowrapper .runAfterRender=${async (elementArg: HTMLElement) => {
|
||||
// Set up form submission handling
|
||||
const form = elementArg.querySelector('dees-form');
|
||||
const output = elementArg.querySelector('#form-output');
|
||||
|
||||
if (form && output) {
|
||||
form.addEventListener('formData', (e: CustomEvent) => {
|
||||
output.innerHTML = '<strong>Form submitted with data:</strong><br>' +
|
||||
JSON.stringify(e.detail.data, null, 2);
|
||||
});
|
||||
}
|
||||
|
||||
// Track non-submit button clicks
|
||||
const draftBtn = elementArg.querySelector('dees-button[type="secondary"]');
|
||||
const cancelBtn = elementArg.querySelector('dees-button[type="ghost"]');
|
||||
|
||||
if (draftBtn) {
|
||||
draftBtn.addEventListener('clicked', () => {
|
||||
console.log('Save Draft clicked');
|
||||
});
|
||||
}
|
||||
|
||||
if (cancelBtn) {
|
||||
cancelBtn.addEventListener('clicked', () => {
|
||||
console.log('Cancel clicked');
|
||||
});
|
||||
}
|
||||
}}>
|
||||
<dees-panel .title=${'6. Form Integration'} .subtitle=${'Buttons working within forms with automatic spacing'}>
|
||||
<dees-form @formData=${(e: CustomEvent) => {
|
||||
const output = document.querySelector('#form-output');
|
||||
if (output) {
|
||||
output.innerHTML = '<strong>Form submitted with data:</strong><br>' +
|
||||
JSON.stringify(e.detail.data, null, 2);
|
||||
}
|
||||
}}>
|
||||
<dees-form>
|
||||
<dees-input-text label="Name" key="name" required></dees-input-text>
|
||||
<dees-input-text label="Email" key="email" type="email" required></dees-input-text>
|
||||
<dees-input-text label="Message" key="message" isMultiline></dees-input-text>
|
||||
@ -237,7 +318,18 @@ export const demoFunc = () => html`
|
||||
<em>Submit the form to see the data...</em>
|
||||
</div>
|
||||
</dees-panel>
|
||||
|
||||
</dees-demowrapper>
|
||||
|
||||
<dees-demowrapper .runAfterRender=${async (elementArg: HTMLElement) => {
|
||||
// Log legacy type mappings
|
||||
const buttons = elementArg.querySelectorAll('dees-button');
|
||||
buttons.forEach((button) => {
|
||||
const type = button.getAttribute('type');
|
||||
if (type) {
|
||||
console.log(`Legacy type "${type}" is supported for backward compatibility`);
|
||||
}
|
||||
});
|
||||
}}>
|
||||
<dees-panel .title=${'7. Backward Compatibility'} .subtitle=${'Old button types are automatically mapped to new variants'}>
|
||||
<div class="button-group">
|
||||
<dees-button type="normal">Normal → Default</dees-button>
|
||||
@ -250,7 +342,35 @@ export const demoFunc = () => html`
|
||||
These legacy type values are maintained for backward compatibility but we recommend using the new variant system.
|
||||
</p>
|
||||
</dees-panel>
|
||||
</dees-demowrapper>
|
||||
|
||||
<dees-demowrapper .runAfterRender=${async (elementArg: HTMLElement) => {
|
||||
// Track action group clicks
|
||||
const actionGroup = elementArg.querySelectorAll('.vertical-group')[0];
|
||||
const dangerGroup = elementArg.querySelectorAll('.vertical-group')[1];
|
||||
|
||||
if (actionGroup) {
|
||||
const buttons = actionGroup.querySelectorAll('dees-button');
|
||||
buttons.forEach((button, index) => {
|
||||
button.addEventListener('clicked', () => {
|
||||
const action = ['Save Changes', 'Discard', 'Help'][index];
|
||||
console.log(`Action group: ${action} clicked`);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if (dangerGroup) {
|
||||
const buttons = dangerGroup.querySelectorAll('dees-button');
|
||||
buttons.forEach((button, index) => {
|
||||
button.addEventListener('clicked', () => {
|
||||
const action = ['Delete Account', 'Archive Data', 'Not Available'][index];
|
||||
if (index !== 2) { // Skip disabled button
|
||||
console.log(`Danger zone: ${action} clicked`);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}}>
|
||||
<dees-panel .title=${'8. Advanced Examples'} .subtitle=${'Complex button configurations and real-world use cases'}>
|
||||
<div class="horizontal-group">
|
||||
<div class="vertical-group">
|
||||
@ -296,6 +416,6 @@ export const demoFunc = () => html`
|
||||
</div>
|
||||
</div>
|
||||
</dees-panel>
|
||||
</div>
|
||||
</dees-demowrapper>
|
||||
`;
|
||||
</dees-demowrapper>
|
||||
</div>
|
||||
`;
|
@ -3,40 +3,91 @@ import type { DeesForm } from './dees-form.js';
|
||||
import '@design.estate/dees-wcctools/demotools';
|
||||
|
||||
export const demoFunc = () => html`
|
||||
<dees-demowrapper>
|
||||
<style>
|
||||
${css`
|
||||
.demo-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 24px;
|
||||
padding: 24px;
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
<style>
|
||||
${css`
|
||||
.demo-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 24px;
|
||||
padding: 24px;
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
dees-panel {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
dees-panel:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.form-output {
|
||||
margin-top: 16px;
|
||||
padding: 12px;
|
||||
background: ${cssManager.bdTheme('hsl(210 40% 96.1%)', 'hsl(215 20.2% 16.8%)')};
|
||||
border-radius: 6px;
|
||||
font-size: 14px;
|
||||
font-family: monospace;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
.status-message {
|
||||
margin-top: 16px;
|
||||
padding: 12px;
|
||||
border-radius: 6px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.status-message.success {
|
||||
background: ${cssManager.bdTheme('hsl(142.1 70.6% 45.3% / 0.1)', 'hsl(142.1 70.6% 45.3% / 0.2)')};
|
||||
color: ${cssManager.bdTheme('hsl(142.1 70.6% 35.3%)', 'hsl(142.1 70.6% 65.3%)')};
|
||||
}
|
||||
|
||||
.status-message.error {
|
||||
background: ${cssManager.bdTheme('hsl(0 72.2% 50.6% / 0.1)', 'hsl(0 72.2% 50.6% / 0.2)')};
|
||||
color: ${cssManager.bdTheme('hsl(0 72.2% 40.6%)', 'hsl(0 72.2% 60.6%)')};
|
||||
}
|
||||
`}
|
||||
</style>
|
||||
|
||||
<div class="demo-container">
|
||||
<dees-demowrapper .runAfterRender=${async (elementArg: HTMLElement) => {
|
||||
const form = elementArg.querySelector('dees-form') as DeesForm;
|
||||
const outputDiv = elementArg.querySelector('.form-output');
|
||||
|
||||
if (form && outputDiv) {
|
||||
form.addEventListener('formData', async (eventArg: CustomEvent) => {
|
||||
const data = eventArg.detail.data;
|
||||
console.log('Form submitted with data:', data);
|
||||
|
||||
// Show processing state
|
||||
form.setStatus('pending', 'Processing your registration...');
|
||||
outputDiv.innerHTML = `<strong>Submitted Data:</strong>\n${JSON.stringify(data, null, 2)}`;
|
||||
|
||||
// Simulate API call
|
||||
await domtools.plugins.smartdelay.delayFor(2000);
|
||||
|
||||
// Show success
|
||||
form.setStatus('success', 'Registration completed successfully!');
|
||||
|
||||
// Reset form after delay
|
||||
await domtools.plugins.smartdelay.delayFor(2000);
|
||||
form.reset();
|
||||
outputDiv.innerHTML = '<em>Form has been reset</em>';
|
||||
});
|
||||
|
||||
dees-panel {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
dees-panel:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
`}
|
||||
</style>
|
||||
|
||||
<div class="demo-container">
|
||||
// Track individual field changes
|
||||
const inputs = form.querySelectorAll('dees-input-text, dees-input-dropdown, dees-input-checkbox');
|
||||
inputs.forEach((input) => {
|
||||
input.addEventListener('changeSubject', () => {
|
||||
console.log('Field changed:', input.getAttribute('key'));
|
||||
});
|
||||
});
|
||||
}
|
||||
}}>
|
||||
<dees-panel .heading="Complete Form Example" .description="A comprehensive form with various input types, validation, and form submission handling">
|
||||
<dees-form
|
||||
@formData=${async (eventArg) => {
|
||||
const form: DeesForm = eventArg.currentTarget;
|
||||
form.setStatus('pending', 'Processing...');
|
||||
await domtools.plugins.smartdelay.delayFor(2000);
|
||||
form.setStatus('success', 'Form submitted successfully!');
|
||||
await domtools.plugins.smartdelay.delayFor(2000);
|
||||
form.reset();
|
||||
}}
|
||||
>
|
||||
<dees-form>
|
||||
<dees-input-text
|
||||
.required=${true}
|
||||
key="firstName"
|
||||
@ -92,13 +143,47 @@ export const demoFunc = () => html`
|
||||
|
||||
<dees-form-submit>Create Account</dees-form-submit>
|
||||
</dees-form>
|
||||
|
||||
<div class="form-output">
|
||||
<em>Submit the form to see the collected data...</em>
|
||||
</div>
|
||||
</dees-panel>
|
||||
</dees-demowrapper>
|
||||
|
||||
<dees-demowrapper .runAfterRender=${async (elementArg: HTMLElement) => {
|
||||
const form = elementArg.querySelector('dees-form') as DeesForm;
|
||||
|
||||
if (form) {
|
||||
// Track horizontal layout behavior
|
||||
console.log('Horizontal form layout active');
|
||||
|
||||
// Monitor filter changes
|
||||
form.addEventListener('formData', (event: CustomEvent) => {
|
||||
const filters = event.detail.data;
|
||||
console.log('Filter applied:', filters);
|
||||
|
||||
// Simulate search
|
||||
const resultsCount = Math.floor(Math.random() * 100) + 1;
|
||||
console.log(`Found ${resultsCount} results with filters:`, filters);
|
||||
});
|
||||
|
||||
// Setup real-time filter updates
|
||||
const inputs = form.querySelectorAll('[key]');
|
||||
inputs.forEach((input) => {
|
||||
input.addEventListener('changeSubject', async () => {
|
||||
// Get current form data
|
||||
const formData = await form.collectFormData();
|
||||
console.log('Live filter update:', formData);
|
||||
});
|
||||
});
|
||||
}
|
||||
}}>
|
||||
<dees-panel .heading="Horizontal Form Layout" .description="Compact form with inputs arranged horizontally - perfect for filters and quick forms">
|
||||
<dees-form horizontal-layout>
|
||||
<dees-input-text
|
||||
key="search"
|
||||
label="Search"
|
||||
placeholder="Enter keywords..."
|
||||
></dees-input-text>
|
||||
|
||||
<dees-input-dropdown
|
||||
@ -132,16 +217,55 @@ export const demoFunc = () => html`
|
||||
></dees-input-checkbox>
|
||||
</dees-form>
|
||||
</dees-panel>
|
||||
</dees-demowrapper>
|
||||
|
||||
<dees-demowrapper .runAfterRender=${async (elementArg: HTMLElement) => {
|
||||
const form = elementArg.querySelector('dees-form') as DeesForm;
|
||||
const statusDiv = elementArg.querySelector('#status-display');
|
||||
|
||||
if (form) {
|
||||
form.addEventListener('formData', async (eventArg: CustomEvent) => {
|
||||
const data = eventArg.detail.data;
|
||||
console.log('Advanced form data:', data);
|
||||
|
||||
// Show validation in progress
|
||||
form.setStatus('pending', 'Validating your information...');
|
||||
|
||||
// Simulate validation
|
||||
await domtools.plugins.smartdelay.delayFor(1500);
|
||||
|
||||
// Check IBAN validity (simple check)
|
||||
if (data.iban && data.iban.length > 15) {
|
||||
form.setStatus('success', 'Application submitted successfully!');
|
||||
|
||||
if (statusDiv) {
|
||||
statusDiv.className = 'status-message success';
|
||||
statusDiv.textContent = '✓ Your application has been submitted. We will contact you soon.';
|
||||
}
|
||||
} else {
|
||||
form.setStatus('error', 'Please check your IBAN');
|
||||
|
||||
if (statusDiv) {
|
||||
statusDiv.className = 'status-message error';
|
||||
statusDiv.textContent = '✗ Invalid IBAN format. Please check and try again.';
|
||||
}
|
||||
}
|
||||
|
||||
console.log('Form data logged:', data);
|
||||
});
|
||||
|
||||
// Monitor file uploads
|
||||
const fileUpload = form.querySelector('dees-input-fileupload');
|
||||
if (fileUpload) {
|
||||
fileUpload.addEventListener('change', (event: any) => {
|
||||
const files = event.detail?.files || [];
|
||||
console.log(`${files.length} file(s) selected for upload`);
|
||||
});
|
||||
}
|
||||
}
|
||||
}}>
|
||||
<dees-panel .heading="Advanced Form Features" .description="Form with specialized input types and complex validation">
|
||||
<dees-form
|
||||
@formData=${async (eventArg) => {
|
||||
const form: DeesForm = eventArg.currentTarget;
|
||||
const data = eventArg.detail.data;
|
||||
console.log('Form data:', data);
|
||||
form.setStatus('success', 'Data logged to console!');
|
||||
}}
|
||||
>
|
||||
<dees-form>
|
||||
<dees-input-iban
|
||||
key="iban"
|
||||
label="IBAN"
|
||||
@ -181,7 +305,9 @@ export const demoFunc = () => html`
|
||||
|
||||
<dees-form-submit>Submit Application</dees-form-submit>
|
||||
</dees-form>
|
||||
|
||||
<div id="status-display"></div>
|
||||
</dees-panel>
|
||||
</div>
|
||||
</dees-demowrapper>
|
||||
</dees-demowrapper>
|
||||
</div>
|
||||
`;
|
@ -1,146 +1,307 @@
|
||||
import { html } from '@design.estate/dees-element';
|
||||
import { html, css } from '@design.estate/dees-element';
|
||||
import '@design.estate/dees-wcctools/demotools';
|
||||
import './dees-panel.js';
|
||||
import './dees-input-datepicker.js';
|
||||
import type { DeesInputDatepicker } from './dees-input-datepicker.js';
|
||||
|
||||
export const demoFunc = () => html`
|
||||
<style>
|
||||
.demo-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 32px;
|
||||
padding: 32px;
|
||||
max-width: 600px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.demo-section {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.demo-title {
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.demo-description {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
${css`
|
||||
.demo-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 24px;
|
||||
padding: 24px;
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
dees-panel {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
dees-panel:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.demo-output {
|
||||
margin-top: 16px;
|
||||
padding: 12px;
|
||||
background: rgba(0, 105, 242, 0.1);
|
||||
border-radius: 4px;
|
||||
font-size: 14px;
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
.date-group {
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
`}
|
||||
</style>
|
||||
|
||||
<div class="demo-container">
|
||||
<div class="demo-section">
|
||||
<div class="demo-title">Basic Date Picker</div>
|
||||
<div class="demo-description">Simple date selection without time</div>
|
||||
<dees-input-datepicker
|
||||
label="Select Date"
|
||||
description="Choose a date from the calendar"
|
||||
placeholder="Pick a date"
|
||||
></dees-input-datepicker>
|
||||
</div>
|
||||
<dees-demowrapper .runAfterRender=${async (elementArg: HTMLElement) => {
|
||||
// Demonstrate basic date picker functionality
|
||||
const datePicker = elementArg.querySelector('dees-input-datepicker');
|
||||
|
||||
if (datePicker) {
|
||||
datePicker.addEventListener('change', (event: CustomEvent) => {
|
||||
console.log('Basic date selected:', (event.target as DeesInputDatepicker).value);
|
||||
});
|
||||
}
|
||||
}}>
|
||||
<dees-panel .title=${'Basic Date Picker'} .subtitle=${'Simple date selection without time'}>
|
||||
<dees-input-datepicker
|
||||
label="Select Date"
|
||||
description="Choose a date from the calendar"
|
||||
placeholder="Pick a date"
|
||||
></dees-input-datepicker>
|
||||
</dees-panel>
|
||||
</dees-demowrapper>
|
||||
|
||||
<div class="demo-section">
|
||||
<div class="demo-title">Date and Time Picker</div>
|
||||
<div class="demo-description">Date selection with time in 24-hour format</div>
|
||||
<dees-input-datepicker
|
||||
label="Event Date & Time"
|
||||
description="Select both date and time"
|
||||
.enableTime=${true}
|
||||
timeFormat="24h"
|
||||
></dees-input-datepicker>
|
||||
</div>
|
||||
<dees-demowrapper .runAfterRender=${async (elementArg: HTMLElement) => {
|
||||
// Demonstrate date and time picker
|
||||
const dateTimePicker = elementArg.querySelector('dees-input-datepicker[label="Event Date & Time"]');
|
||||
const appointmentPicker = elementArg.querySelector('dees-input-datepicker[label="Appointment"]');
|
||||
|
||||
if (dateTimePicker) {
|
||||
dateTimePicker.addEventListener('change', (event: CustomEvent) => {
|
||||
const value = (event.target as DeesInputDatepicker).value;
|
||||
console.log('24h format datetime:', value);
|
||||
});
|
||||
}
|
||||
|
||||
if (appointmentPicker) {
|
||||
appointmentPicker.addEventListener('change', (event: CustomEvent) => {
|
||||
const value = (event.target as DeesInputDatepicker).value;
|
||||
console.log('12h format datetime:', value);
|
||||
});
|
||||
}
|
||||
}}>
|
||||
<dees-panel .title=${'Date and Time Selection'} .subtitle=${'Date pickers with time selection in different formats'}>
|
||||
<dees-input-datepicker
|
||||
label="Event Date & Time"
|
||||
description="Select both date and time (24-hour format)"
|
||||
.enableTime=${true}
|
||||
timeFormat="24h"
|
||||
></dees-input-datepicker>
|
||||
|
||||
<dees-input-datepicker
|
||||
label="Appointment"
|
||||
description="Date and time with AM/PM selector (15-minute increments)"
|
||||
.enableTime=${true}
|
||||
timeFormat="12h"
|
||||
.minuteIncrement=${15}
|
||||
></dees-input-datepicker>
|
||||
</dees-panel>
|
||||
</dees-demowrapper>
|
||||
|
||||
<div class="demo-section">
|
||||
<div class="demo-title">12-Hour Time Format</div>
|
||||
<div class="demo-description">Date and time with AM/PM selector</div>
|
||||
<dees-input-datepicker
|
||||
label="Appointment"
|
||||
.enableTime=${true}
|
||||
timeFormat="12h"
|
||||
.minuteIncrement=${15}
|
||||
></dees-input-datepicker>
|
||||
</div>
|
||||
<dees-demowrapper .runAfterRender=${async (elementArg: HTMLElement) => {
|
||||
// Demonstrate date constraints
|
||||
const futureDatePicker = elementArg.querySelector('dees-input-datepicker');
|
||||
|
||||
if (futureDatePicker) {
|
||||
// Show the min/max constraints in action
|
||||
futureDatePicker.addEventListener('change', (event: CustomEvent) => {
|
||||
const value = (event.target as DeesInputDatepicker).value;
|
||||
if (value) {
|
||||
const selectedDate = new Date(value);
|
||||
const today = new Date();
|
||||
const daysDiff = Math.floor((selectedDate.getTime() - today.getTime()) / (1000 * 60 * 60 * 24));
|
||||
console.log(`Selected date is ${daysDiff} days from today`);
|
||||
}
|
||||
});
|
||||
}
|
||||
}}>
|
||||
<dees-panel .title=${'Date Range Constraints'} .subtitle=${'Limit selectable dates with min and max values'}>
|
||||
<dees-input-datepicker
|
||||
label="Future Date Only"
|
||||
description="Can only select dates from today to 90 days in the future"
|
||||
.minDate=${new Date().toISOString()}
|
||||
.maxDate=${new Date(Date.now() + 90 * 24 * 60 * 60 * 1000).toISOString()}
|
||||
></dees-input-datepicker>
|
||||
</dees-panel>
|
||||
</dees-demowrapper>
|
||||
|
||||
<div class="demo-section">
|
||||
<div class="demo-title">Date Range Constraints</div>
|
||||
<div class="demo-description">Limit selectable dates with min and max</div>
|
||||
<dees-input-datepicker
|
||||
label="Future Date Only"
|
||||
description="Can only select dates from today onwards"
|
||||
.minDate=${new Date().toISOString()}
|
||||
.maxDate=${new Date(Date.now() + 90 * 24 * 60 * 60 * 1000).toISOString()}
|
||||
></dees-input-datepicker>
|
||||
</div>
|
||||
<dees-demowrapper .runAfterRender=${async (elementArg: HTMLElement) => {
|
||||
// Demonstrate different date formats
|
||||
const formatters = {
|
||||
'DD/MM/YYYY': 'European',
|
||||
'MM/DD/YYYY': 'US',
|
||||
'YYYY-MM-DD': 'ISO'
|
||||
};
|
||||
|
||||
const datePickers = elementArg.querySelectorAll('dees-input-datepicker');
|
||||
datePickers.forEach((picker) => {
|
||||
picker.addEventListener('change', (event: CustomEvent) => {
|
||||
const target = event.target as DeesInputDatepicker;
|
||||
// Log the formatted value that's displayed in the input
|
||||
const input = target.shadowRoot?.querySelector('.date-input') as HTMLInputElement;
|
||||
if (input) {
|
||||
console.log(`${target.label} format:`, input.value);
|
||||
}
|
||||
});
|
||||
});
|
||||
}}>
|
||||
<dees-panel .title=${'Date Formats'} .subtitle=${'Different date display formats for various regions'}>
|
||||
<div class="date-group">
|
||||
<dees-input-datepicker
|
||||
label="European Format"
|
||||
dateFormat="DD/MM/YYYY"
|
||||
.value=${new Date().toISOString()}
|
||||
></dees-input-datepicker>
|
||||
|
||||
<dees-input-datepicker
|
||||
label="US Format"
|
||||
dateFormat="MM/DD/YYYY"
|
||||
.value=${new Date().toISOString()}
|
||||
></dees-input-datepicker>
|
||||
|
||||
<dees-input-datepicker
|
||||
label="ISO Format"
|
||||
dateFormat="YYYY-MM-DD"
|
||||
.value=${new Date().toISOString()}
|
||||
></dees-input-datepicker>
|
||||
</div>
|
||||
</dees-panel>
|
||||
</dees-demowrapper>
|
||||
|
||||
<div class="demo-section">
|
||||
<div class="demo-title">Custom Date Format</div>
|
||||
<div class="demo-description">Different date display format</div>
|
||||
<dees-input-datepicker
|
||||
label="European Format"
|
||||
dateFormat="DD/MM/YYYY"
|
||||
.value=${new Date().toISOString()}
|
||||
></dees-input-datepicker>
|
||||
</div>
|
||||
<dees-demowrapper .runAfterRender=${async (elementArg: HTMLElement) => {
|
||||
// Demonstrate required field validation
|
||||
const requiredPicker = elementArg.querySelector('dees-input-datepicker[required]');
|
||||
|
||||
if (requiredPicker) {
|
||||
// Monitor blur events for validation
|
||||
requiredPicker.addEventListener('blur', () => {
|
||||
const picker = requiredPicker as DeesInputDatepicker;
|
||||
const value = picker.getValue();
|
||||
if (!value) {
|
||||
console.log('Required date field is empty');
|
||||
}
|
||||
});
|
||||
}
|
||||
}}>
|
||||
<dees-panel .title=${'Form States'} .subtitle=${'Required and disabled states'}>
|
||||
<dees-input-datepicker
|
||||
label="Birth Date"
|
||||
description="This field is required"
|
||||
.required=${true}
|
||||
placeholder="Select your birth date"
|
||||
></dees-input-datepicker>
|
||||
|
||||
<dees-input-datepicker
|
||||
label="Disabled Date"
|
||||
description="This field cannot be edited"
|
||||
.disabled=${true}
|
||||
.value=${new Date().toISOString()}
|
||||
></dees-input-datepicker>
|
||||
</dees-panel>
|
||||
</dees-demowrapper>
|
||||
|
||||
<div class="demo-section">
|
||||
<div class="demo-title">Required Field</div>
|
||||
<div class="demo-description">Date picker as a required form field</div>
|
||||
<dees-input-datepicker
|
||||
label="Birth Date"
|
||||
description="This field is required"
|
||||
.required=${true}
|
||||
placeholder="Select your birth date"
|
||||
></dees-input-datepicker>
|
||||
</div>
|
||||
<dees-demowrapper .runAfterRender=${async (elementArg: HTMLElement) => {
|
||||
// Demonstrate week start customization
|
||||
const usPicker = elementArg.querySelector('dees-input-datepicker[label="US Calendar"]');
|
||||
const euPicker = elementArg.querySelector('dees-input-datepicker[label="EU Calendar"]');
|
||||
|
||||
if (usPicker) {
|
||||
console.log('US Calendar starts on Sunday (0)');
|
||||
}
|
||||
if (euPicker) {
|
||||
console.log('EU Calendar starts on Monday (1)');
|
||||
}
|
||||
}}>
|
||||
<dees-panel .title=${'Calendar Customization'} .subtitle=${'Different week start days for various regions'}>
|
||||
<div class="date-group">
|
||||
<dees-input-datepicker
|
||||
label="US Calendar"
|
||||
description="Week starts on Sunday"
|
||||
.weekStartsOn=${0}
|
||||
></dees-input-datepicker>
|
||||
|
||||
<dees-input-datepicker
|
||||
label="EU Calendar"
|
||||
description="Week starts on Monday"
|
||||
.weekStartsOn=${1}
|
||||
></dees-input-datepicker>
|
||||
</div>
|
||||
</dees-panel>
|
||||
</dees-demowrapper>
|
||||
|
||||
<div class="demo-section">
|
||||
<div class="demo-title">Disabled State</div>
|
||||
<div class="demo-description">Date picker in disabled state</div>
|
||||
<dees-input-datepicker
|
||||
label="Disabled Date"
|
||||
.disabled=${true}
|
||||
.value=${new Date().toISOString()}
|
||||
></dees-input-datepicker>
|
||||
</div>
|
||||
<dees-demowrapper .runAfterRender=${async (elementArg: HTMLElement) => {
|
||||
// Generate weekend dates for the current month
|
||||
const generateWeekends = () => {
|
||||
const weekends = [];
|
||||
const now = new Date();
|
||||
const year = now.getFullYear();
|
||||
const month = now.getMonth();
|
||||
|
||||
// Get all weekends for current month
|
||||
const date = new Date(year, month, 1);
|
||||
while (date.getMonth() === month) {
|
||||
if (date.getDay() === 0 || date.getDay() === 6) {
|
||||
weekends.push(new Date(date).toISOString());
|
||||
}
|
||||
date.setDate(date.getDate() + 1);
|
||||
}
|
||||
return weekends;
|
||||
};
|
||||
|
||||
const picker = elementArg.querySelector('dees-input-datepicker');
|
||||
if (picker) {
|
||||
picker.disabledDates = generateWeekends();
|
||||
console.log('Disabled weekend dates for current month');
|
||||
}
|
||||
}}>
|
||||
<dees-panel .title=${'Disabled Dates'} .subtitle=${'Calendar with specific dates disabled (weekends in current month)'}>
|
||||
<dees-input-datepicker
|
||||
label="Availability Calendar"
|
||||
description="Weekends are disabled for the current month"
|
||||
></dees-input-datepicker>
|
||||
</dees-panel>
|
||||
</dees-demowrapper>
|
||||
|
||||
<div class="demo-section">
|
||||
<div class="demo-title">Week Starts on Sunday</div>
|
||||
<div class="demo-description">Calendar with Sunday as first day of week</div>
|
||||
<dees-input-datepicker
|
||||
label="US Calendar"
|
||||
.weekStartsOn=${0}
|
||||
></dees-input-datepicker>
|
||||
</div>
|
||||
|
||||
<div class="demo-section">
|
||||
<div class="demo-title">With Disabled Dates</div>
|
||||
<div class="demo-description">Some dates are disabled and cannot be selected</div>
|
||||
<dees-input-datepicker
|
||||
label="Availability Calendar"
|
||||
description="Weekends are disabled"
|
||||
.disabledDates=${[
|
||||
new Date(2024, 0, 6).toISOString(), // Saturday
|
||||
new Date(2024, 0, 7).toISOString(), // Sunday
|
||||
new Date(2024, 0, 13).toISOString(), // Saturday
|
||||
new Date(2024, 0, 14).toISOString(), // Sunday
|
||||
new Date(2024, 0, 20).toISOString(), // Saturday
|
||||
new Date(2024, 0, 21).toISOString(), // Sunday
|
||||
new Date(2024, 0, 27).toISOString(), // Saturday
|
||||
new Date(2024, 0, 28).toISOString(), // Sunday
|
||||
]}
|
||||
></dees-input-datepicker>
|
||||
</div>
|
||||
|
||||
<div class="demo-section">
|
||||
<div class="demo-title">Event Listeners</div>
|
||||
<div class="demo-description">Check console for change events</div>
|
||||
<dees-input-datepicker
|
||||
label="Event Demo"
|
||||
@change="${(e: CustomEvent) => console.log('Date changed:', (e.target as any).value)}"
|
||||
></dees-input-datepicker>
|
||||
</div>
|
||||
<dees-demowrapper .runAfterRender=${async (elementArg: HTMLElement) => {
|
||||
// Interactive event demonstration
|
||||
const picker = elementArg.querySelector('dees-input-datepicker');
|
||||
const output = elementArg.querySelector('#event-output');
|
||||
|
||||
if (picker && output) {
|
||||
picker.addEventListener('change', (event: CustomEvent) => {
|
||||
const target = event.target as DeesInputDatepicker;
|
||||
const value = target.value;
|
||||
if (value) {
|
||||
const date = new Date(value);
|
||||
// Get the formatted value from the input element
|
||||
const input = target.shadowRoot?.querySelector('.date-input') as HTMLInputElement;
|
||||
const formattedValue = input?.value || 'N/A';
|
||||
output.innerHTML = `
|
||||
<strong>Event triggered!</strong><br>
|
||||
ISO Value: ${value}<br>
|
||||
Formatted: ${formattedValue}<br>
|
||||
Date object: ${date.toLocaleString()}
|
||||
`;
|
||||
} else {
|
||||
output.innerHTML = '<em>Date cleared</em>';
|
||||
}
|
||||
});
|
||||
|
||||
picker.addEventListener('blur', () => {
|
||||
console.log('Datepicker lost focus');
|
||||
});
|
||||
}
|
||||
}}>
|
||||
<dees-panel .title=${'Event Handling'} .subtitle=${'Interactive demonstration of change events'}>
|
||||
<dees-input-datepicker
|
||||
label="Event Demo"
|
||||
description="Select a date to see the event details"
|
||||
></dees-input-datepicker>
|
||||
|
||||
<div id="event-output" class="demo-output">
|
||||
<em>Select a date to see event details...</em>
|
||||
</div>
|
||||
</dees-panel>
|
||||
</dees-demowrapper>
|
||||
</div>
|
||||
`;
|
@ -627,7 +627,7 @@ export class DeesInputDatepicker extends DeesInputBase<DeesInputDatepicker> {
|
||||
}
|
||||
}
|
||||
|
||||
private formatDate(isoString: string): string {
|
||||
public formatDate(isoString: string): string {
|
||||
if (!isoString) return '';
|
||||
|
||||
try {
|
||||
|
@ -5,45 +5,63 @@ import './dees-form.js';
|
||||
import './dees-form-submit.js';
|
||||
|
||||
export const demoFunc = () => html`
|
||||
<dees-demowrapper>
|
||||
<style>
|
||||
${css`
|
||||
.demo-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 24px;
|
||||
padding: 24px;
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
dees-panel {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
dees-panel:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.horizontal-group {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.spacer {
|
||||
height: 200px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #999;
|
||||
font-size: 14px;
|
||||
}
|
||||
`}
|
||||
</style>
|
||||
|
||||
<div class="demo-container">
|
||||
<style>
|
||||
${css`
|
||||
.demo-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 24px;
|
||||
padding: 24px;
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
dees-panel {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
dees-panel:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.horizontal-group {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.spacer {
|
||||
height: 200px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #999;
|
||||
font-size: 14px;
|
||||
}
|
||||
`}
|
||||
</style>
|
||||
|
||||
<div class="demo-container">
|
||||
<dees-demowrapper .runAfterRender=${async (elementArg: HTMLElement) => {
|
||||
// Demonstrate programmatic interaction with basic dropdowns
|
||||
const countryDropdown = elementArg.querySelector('dees-input-dropdown[label="Select Country"]');
|
||||
const roleDropdown = elementArg.querySelector('dees-input-dropdown[label="Select Role"]');
|
||||
|
||||
// Log when country changes
|
||||
if (countryDropdown) {
|
||||
countryDropdown.addEventListener('selectedOption', (event: CustomEvent) => {
|
||||
console.log('Country selected:', event.detail);
|
||||
});
|
||||
}
|
||||
|
||||
// Log when role changes
|
||||
if (roleDropdown) {
|
||||
roleDropdown.addEventListener('selectedOption', (event: CustomEvent) => {
|
||||
console.log('Role selected:', event.detail);
|
||||
});
|
||||
}
|
||||
}}>
|
||||
<dees-panel .title=${'1. Basic Dropdowns'} .subtitle=${'Standard dropdown with search functionality and various options'}>
|
||||
<dees-input-dropdown
|
||||
.label=${'Select Country'}
|
||||
@ -70,7 +88,18 @@ export const demoFunc = () => html`
|
||||
]}
|
||||
></dees-input-dropdown>
|
||||
</dees-panel>
|
||||
</dees-demowrapper>
|
||||
|
||||
<dees-demowrapper .runAfterRender=${async (elementArg: HTMLElement) => {
|
||||
// Demonstrate simpler dropdown without search
|
||||
const priorityDropdown = elementArg.querySelector('dees-input-dropdown');
|
||||
|
||||
if (priorityDropdown) {
|
||||
priorityDropdown.addEventListener('selectedOption', (event: CustomEvent) => {
|
||||
console.log(`Priority changed to: ${event.detail.option}`);
|
||||
});
|
||||
}
|
||||
}}>
|
||||
<dees-panel .title=${'2. Without Search'} .subtitle=${'Dropdown with search functionality disabled for simpler selection'}>
|
||||
<dees-input-dropdown
|
||||
.label=${'Priority Level'}
|
||||
@ -83,7 +112,20 @@ export const demoFunc = () => html`
|
||||
.selectedOption=${{ option: 'Medium', key: 'medium' }}
|
||||
></dees-input-dropdown>
|
||||
</dees-panel>
|
||||
</dees-demowrapper>
|
||||
|
||||
<dees-demowrapper .runAfterRender=${async (elementArg: HTMLElement) => {
|
||||
// Demonstrate horizontal layout with multiple dropdowns
|
||||
const dropdowns = elementArg.querySelectorAll('dees-input-dropdown');
|
||||
|
||||
// Log all changes from horizontal dropdowns
|
||||
dropdowns.forEach((dropdown) => {
|
||||
dropdown.addEventListener('selectedOption', (event: CustomEvent) => {
|
||||
const label = dropdown.getAttribute('label');
|
||||
console.log(`${label}: ${event.detail.option}`);
|
||||
});
|
||||
});
|
||||
}}>
|
||||
<dees-panel .title=${'3. Horizontal Layout'} .subtitle=${'Multiple dropdowns in a horizontal layout for compact forms'}>
|
||||
<div class="horizontal-group">
|
||||
<dees-input-dropdown
|
||||
@ -120,7 +162,19 @@ export const demoFunc = () => html`
|
||||
></dees-input-dropdown>
|
||||
</div>
|
||||
</dees-panel>
|
||||
</dees-demowrapper>
|
||||
|
||||
<dees-demowrapper .runAfterRender=${async (elementArg: HTMLElement) => {
|
||||
// Demonstrate state handling
|
||||
const requiredDropdown = elementArg.querySelector('dees-input-dropdown[required]');
|
||||
|
||||
if (requiredDropdown) {
|
||||
// Show validation state changes
|
||||
requiredDropdown.addEventListener('blur', () => {
|
||||
console.log('Required dropdown lost focus');
|
||||
});
|
||||
}
|
||||
}}>
|
||||
<dees-panel .title=${'4. States'} .subtitle=${'Different states and configurations'}>
|
||||
<dees-input-dropdown
|
||||
.label=${'Required Field'}
|
||||
@ -141,11 +195,25 @@ export const demoFunc = () => html`
|
||||
.selectedOption=${{ option: 'Cannot Select', key: 'disabled' }}
|
||||
></dees-input-dropdown>
|
||||
</dees-panel>
|
||||
</dees-demowrapper>
|
||||
|
||||
<div class="spacer">
|
||||
(Spacer to test dropdown positioning)
|
||||
</div>
|
||||
|
||||
<dees-demowrapper .runAfterRender=${async (elementArg: HTMLElement) => {
|
||||
// This dropdown demonstrates automatic positioning
|
||||
const dropdown = elementArg.querySelector('dees-input-dropdown');
|
||||
|
||||
<div class="spacer">
|
||||
(Spacer to test dropdown positioning)
|
||||
</div>
|
||||
|
||||
if (dropdown) {
|
||||
dropdown.addEventListener('selectedOption', (event: CustomEvent) => {
|
||||
console.log('Bottom dropdown selected:', event.detail);
|
||||
});
|
||||
|
||||
// Note: The dropdown automatically detects available space
|
||||
// and opens upward when near the bottom of the viewport
|
||||
}
|
||||
}}>
|
||||
<dees-panel .title=${'5. Bottom Positioning'} .subtitle=${'Dropdown that opens upward when near bottom of viewport'}>
|
||||
<dees-input-dropdown
|
||||
.label=${'Opens Upward'}
|
||||
@ -158,7 +226,30 @@ export const demoFunc = () => html`
|
||||
]}
|
||||
></dees-input-dropdown>
|
||||
</dees-panel>
|
||||
</dees-demowrapper>
|
||||
|
||||
<dees-demowrapper .runAfterRender=${async (elementArg: HTMLElement) => {
|
||||
// Setup the interactive payload display
|
||||
const dropdown = elementArg.querySelector('dees-input-dropdown');
|
||||
const output = elementArg.querySelector('#selection-output');
|
||||
|
||||
if (dropdown && output) {
|
||||
// Initialize output
|
||||
output.innerHTML = '<em>Select a product to see details...</em>';
|
||||
|
||||
// Handle dropdown changes
|
||||
dropdown.addEventListener('change', (event: CustomEvent) => {
|
||||
if (event.detail.value) {
|
||||
output.innerHTML = `
|
||||
<strong>Selected:</strong> ${event.detail.value.option}<br>
|
||||
<strong>Key:</strong> ${event.detail.value.key}<br>
|
||||
<strong>Price:</strong> $${event.detail.value.payload?.price || 'N/A'}<br>
|
||||
<strong>Features:</strong> ${event.detail.value.payload?.features?.join(', ') || 'N/A'}
|
||||
`;
|
||||
}
|
||||
});
|
||||
}
|
||||
}}>
|
||||
<dees-panel .title=${'6. Event Handling & Payload'} .subtitle=${'Dropdown with payload data and change event handling'}>
|
||||
<dees-input-dropdown
|
||||
.label=${'Select Product'}
|
||||
@ -167,24 +258,35 @@ export const demoFunc = () => html`
|
||||
{ option: 'Pro Plan', key: 'pro', payload: { price: 19.99, features: ['Feature A', 'Feature B'] } },
|
||||
{ option: 'Enterprise Plan', key: 'enterprise', payload: { price: 49.99, features: ['Feature A', 'Feature B', 'Feature C'] } }
|
||||
]}
|
||||
@change=${(e: CustomEvent) => {
|
||||
const output = document.querySelector('#selection-output');
|
||||
if (output && e.detail.value) {
|
||||
output.innerHTML = `
|
||||
<strong>Selected:</strong> ${e.detail.value.option}<br>
|
||||
<strong>Key:</strong> ${e.detail.value.key}<br>
|
||||
<strong>Price:</strong> $${e.detail.value.payload?.price || 'N/A'}<br>
|
||||
<strong>Features:</strong> ${e.detail.value.payload?.features?.join(', ') || 'N/A'}
|
||||
`;
|
||||
}
|
||||
}}
|
||||
></dees-input-dropdown>
|
||||
|
||||
<div id="selection-output" style="margin-top: 16px; padding: 12px; background: rgba(0, 105, 242, 0.1); border-radius: 4px; font-size: 14px;">
|
||||
<em>Select a product to see details...</em>
|
||||
</div>
|
||||
<div id="selection-output" style="margin-top: 16px; padding: 12px; background: rgba(0, 105, 242, 0.1); border-radius: 4px; font-size: 14px;"></div>
|
||||
</dees-panel>
|
||||
</dees-demowrapper>
|
||||
|
||||
<dees-demowrapper .runAfterRender=${async (elementArg: HTMLElement) => {
|
||||
// Demonstrate form integration and validation
|
||||
const form = elementArg.querySelector('dees-form');
|
||||
const projectTypeDropdown = elementArg.querySelector('dees-input-dropdown[key="projectType"]');
|
||||
const frameworkDropdown = elementArg.querySelector('dees-input-dropdown[key="framework"]');
|
||||
|
||||
if (form) {
|
||||
form.addEventListener('formData', (event: CustomEvent) => {
|
||||
console.log('Form submitted with data:', event.detail.data);
|
||||
});
|
||||
}
|
||||
|
||||
if (projectTypeDropdown && frameworkDropdown) {
|
||||
// Filter frameworks based on project type
|
||||
projectTypeDropdown.addEventListener('selectedOption', (event: CustomEvent) => {
|
||||
const selectedType = event.detail.key;
|
||||
console.log(`Project type changed to: ${selectedType}`);
|
||||
|
||||
// In a real app, you could filter the framework options based on project type
|
||||
// For demo purposes, we just log the change
|
||||
});
|
||||
}
|
||||
}}>
|
||||
<dees-panel .title=${'7. Form Integration'} .subtitle=${'Dropdown working within a form with validation'}>
|
||||
<dees-form>
|
||||
<dees-input-dropdown
|
||||
@ -216,6 +318,6 @@ export const demoFunc = () => html`
|
||||
<dees-form-submit .text=${'Create Project'}></dees-form-submit>
|
||||
</dees-form>
|
||||
</dees-panel>
|
||||
</div>
|
||||
</dees-demowrapper>
|
||||
</dees-demowrapper>
|
||||
</div>
|
||||
`
|
@ -1,67 +1,87 @@
|
||||
import { html, css, cssManager } from '@design.estate/dees-element';
|
||||
import '@design.estate/dees-wcctools/demotools';
|
||||
import './dees-panel.js';
|
||||
import type { DeesInputText } from './dees-input-text.js';
|
||||
|
||||
export const demoFunc = () => html`
|
||||
<dees-demowrapper>
|
||||
<style>
|
||||
${css`
|
||||
.demo-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 24px;
|
||||
padding: 24px;
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
dees-panel {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
dees-panel:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.horizontal-group {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
<style>
|
||||
${css`
|
||||
.demo-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 24px;
|
||||
padding: 24px;
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
dees-panel {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
dees-panel:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.horizontal-group {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.grid-layout {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.grid-layout {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 16px;
|
||||
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">
|
||||
<dees-demowrapper .runAfterRender=${async (elementArg: HTMLElement) => {
|
||||
// Demonstrate basic text input functionality
|
||||
const inputs = elementArg.querySelectorAll('dees-input-text');
|
||||
|
||||
inputs.forEach((input: DeesInputText) => {
|
||||
input.addEventListener('changeSubject', (event: CustomEvent) => {
|
||||
console.log(`Input "${input.label}" changed to:`, input.getValue());
|
||||
});
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.grid-layout {
|
||||
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">
|
||||
input.addEventListener('blur', () => {
|
||||
console.log(`Input "${input.label}" lost focus`);
|
||||
});
|
||||
});
|
||||
|
||||
// Show password visibility toggle
|
||||
const passwordInput = elementArg.querySelector('dees-input-text[key="password"]') as DeesInputText;
|
||||
if (passwordInput) {
|
||||
console.log('Password input includes visibility toggle');
|
||||
}
|
||||
}}>
|
||||
<dees-panel .title=${'Basic Text Inputs'} .subtitle=${'Standard text inputs with labels and descriptions'}>
|
||||
<dees-input-text
|
||||
.label=${'Username'}
|
||||
@ -83,7 +103,33 @@ export const demoFunc = () => html`
|
||||
.key=${'password'}
|
||||
></dees-input-text>
|
||||
</dees-panel>
|
||||
</dees-demowrapper>
|
||||
|
||||
<dees-demowrapper .runAfterRender=${async (elementArg: HTMLElement) => {
|
||||
// Demonstrate horizontal layout behavior
|
||||
const horizontalInputs = elementArg.querySelectorAll('dees-input-text');
|
||||
|
||||
// Check that inputs are properly spaced horizontally
|
||||
horizontalInputs.forEach((input: DeesInputText) => {
|
||||
const computedStyle = window.getComputedStyle(input);
|
||||
console.log(`Horizontal input "${input.label}" display:`, computedStyle.display);
|
||||
});
|
||||
|
||||
// Track value changes
|
||||
const firstNameInput = elementArg.querySelector('dees-input-text[key="firstName"]');
|
||||
const lastNameInput = elementArg.querySelector('dees-input-text[key="lastName"]');
|
||||
|
||||
if (firstNameInput && lastNameInput) {
|
||||
const updateFullName = () => {
|
||||
const firstName = (firstNameInput as DeesInputText).getValue();
|
||||
const lastName = (lastNameInput as DeesInputText).getValue();
|
||||
console.log(`Full name: ${firstName} ${lastName}`);
|
||||
};
|
||||
|
||||
firstNameInput.addEventListener('changeSubject', updateFullName);
|
||||
lastNameInput.addEventListener('changeSubject', updateFullName);
|
||||
}
|
||||
}}>
|
||||
<dees-panel .title=${'Horizontal Layout'} .subtitle=${'Multiple inputs arranged horizontally for compact forms'}>
|
||||
<div class="horizontal-group">
|
||||
<dees-input-text
|
||||
@ -108,7 +154,23 @@ export const demoFunc = () => html`
|
||||
></dees-input-text>
|
||||
</div>
|
||||
</dees-panel>
|
||||
</dees-demowrapper>
|
||||
|
||||
<dees-demowrapper .runAfterRender=${async (elementArg: HTMLElement) => {
|
||||
// Demonstrate different label positions
|
||||
const inputs = elementArg.querySelectorAll('dees-input-text');
|
||||
|
||||
inputs.forEach((input: DeesInputText) => {
|
||||
const position = input.labelPosition;
|
||||
console.log(`Input "${input.label}" has label position: ${position}`);
|
||||
});
|
||||
|
||||
// Show how label position affects layout
|
||||
const leftLabelInputs = elementArg.querySelectorAll('dees-input-text[labelPosition="left"]');
|
||||
if (leftLabelInputs.length > 0) {
|
||||
console.log(`${leftLabelInputs.length} inputs have left-aligned labels for inline layout`);
|
||||
}
|
||||
}}>
|
||||
<dees-panel .title=${'Label Positions'} .subtitle=${'Different label positioning options for various layouts'}>
|
||||
<dees-input-text
|
||||
.label=${'Label on Top (Default)'}
|
||||
@ -136,7 +198,41 @@ export const demoFunc = () => html`
|
||||
></dees-input-text>
|
||||
</div>
|
||||
</dees-panel>
|
||||
</dees-demowrapper>
|
||||
|
||||
<dees-demowrapper .runAfterRender=${async (elementArg: HTMLElement) => {
|
||||
// Demonstrate validation states
|
||||
const requiredInput = elementArg.querySelector('dees-input-text[required]') as DeesInputText;
|
||||
const disabledInput = elementArg.querySelector('dees-input-text[disabled]') as DeesInputText;
|
||||
const errorInput = elementArg.querySelector('dees-input-text[validationState="invalid"]') as DeesInputText;
|
||||
|
||||
if (requiredInput) {
|
||||
// Show validation on blur for empty required field
|
||||
requiredInput.addEventListener('blur', () => {
|
||||
if (!requiredInput.getValue()) {
|
||||
console.log('Required field is empty!');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (disabledInput) {
|
||||
console.log('Disabled input cannot be edited');
|
||||
}
|
||||
|
||||
if (errorInput) {
|
||||
console.log('Error input shows validation message:', errorInput.validationText);
|
||||
|
||||
// Simulate fixing the error
|
||||
errorInput.addEventListener('changeSubject', () => {
|
||||
const value = errorInput.getValue();
|
||||
if (value.includes('@') && value.includes('.')) {
|
||||
errorInput.validationState = 'valid';
|
||||
errorInput.validationText = '';
|
||||
console.log('Email validation passed!');
|
||||
}
|
||||
});
|
||||
}
|
||||
}}>
|
||||
<dees-panel .title=${'Validation & States'} .subtitle=${'Different validation states and input configurations'}>
|
||||
<dees-input-text
|
||||
.label=${'Required Field'}
|
||||
@ -157,7 +253,31 @@ export const demoFunc = () => html`
|
||||
.validationState=${'invalid'}
|
||||
></dees-input-text>
|
||||
</dees-panel>
|
||||
</dees-demowrapper>
|
||||
|
||||
<dees-demowrapper .runAfterRender=${async (elementArg: HTMLElement) => {
|
||||
// Track password visibility toggles
|
||||
const passwordInputs = elementArg.querySelectorAll('dees-input-text[isPasswordBool]');
|
||||
|
||||
passwordInputs.forEach((input: DeesInputText) => {
|
||||
// Monitor for toggle button clicks within shadow DOM
|
||||
const checkToggle = () => {
|
||||
const inputEl = input.shadowRoot?.querySelector('input');
|
||||
if (inputEl) {
|
||||
console.log(`Password field "${input.label}" type:`, inputEl.type);
|
||||
}
|
||||
};
|
||||
|
||||
// Use MutationObserver to detect changes
|
||||
if (input.shadowRoot) {
|
||||
const observer = new MutationObserver(checkToggle);
|
||||
const inputEl = input.shadowRoot.querySelector('input');
|
||||
if (inputEl) {
|
||||
observer.observe(inputEl, { attributes: true, attributeFilter: ['type'] });
|
||||
}
|
||||
}
|
||||
});
|
||||
}}>
|
||||
<dees-panel .title=${'Advanced Features'} .subtitle=${'Password visibility toggle and other advanced features'}>
|
||||
<dees-input-text
|
||||
.label=${'Password with Toggle'}
|
||||
@ -173,23 +293,47 @@ export const demoFunc = () => html`
|
||||
.description=${'Keep this key secure and never share it'}
|
||||
></dees-input-text>
|
||||
</dees-panel>
|
||||
</dees-demowrapper>
|
||||
|
||||
<dees-demowrapper .runAfterRender=${async (elementArg: HTMLElement) => {
|
||||
// Set up interactive example
|
||||
const dynamicInput = elementArg.querySelector('dees-input-text');
|
||||
const output = elementArg.querySelector('#text-input-output');
|
||||
|
||||
if (dynamicInput && output) {
|
||||
// Update output on every change
|
||||
dynamicInput.addEventListener('changeSubject', (event: CustomEvent) => {
|
||||
const value = (event.detail as DeesInputText).getValue();
|
||||
output.textContent = `Current value: "${value}"`;
|
||||
});
|
||||
|
||||
// Also track focus/blur events
|
||||
dynamicInput.addEventListener('focus', () => {
|
||||
console.log('Input focused');
|
||||
});
|
||||
|
||||
dynamicInput.addEventListener('blur', () => {
|
||||
console.log('Input blurred');
|
||||
});
|
||||
|
||||
// Track keypress events
|
||||
let keypressCount = 0;
|
||||
dynamicInput.addEventListener('keydown', () => {
|
||||
keypressCount++;
|
||||
console.log(`Keypress count: ${keypressCount}`);
|
||||
});
|
||||
}
|
||||
}}>
|
||||
<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>
|
||||
</dees-demowrapper>
|
||||
</div>
|
||||
`;
|
Reference in New Issue
Block a user