update
This commit is contained in:
@ -97,6 +97,43 @@ export const demoFunc = () => html`
|
|||||||
</dees-panel>
|
</dees-panel>
|
||||||
</dees-demowrapper>
|
</dees-demowrapper>
|
||||||
|
|
||||||
|
<dees-demowrapper .runAfterRender=${async (elementArg: HTMLElement) => {
|
||||||
|
// Demonstrate timezone functionality
|
||||||
|
const timezonePickers = elementArg.querySelectorAll('dees-input-datepicker');
|
||||||
|
|
||||||
|
timezonePickers.forEach((picker) => {
|
||||||
|
picker.addEventListener('change', (event: CustomEvent) => {
|
||||||
|
const target = event.target as DeesInputDatepicker;
|
||||||
|
console.log(`${target.label} value:`, target.value);
|
||||||
|
const input = target.shadowRoot?.querySelector('.date-input') as HTMLInputElement;
|
||||||
|
if (input) {
|
||||||
|
console.log(`${target.label} formatted:`, input.value);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}}>
|
||||||
|
<dees-panel .title=${'Timezone Support'} .subtitle=${'Date and time selection with timezone awareness'}>
|
||||||
|
<dees-input-datepicker
|
||||||
|
label="Meeting Time (with Timezone)"
|
||||||
|
description="Select a date/time and timezone for the meeting"
|
||||||
|
.enableTime=${true}
|
||||||
|
.enableTimezone=${true}
|
||||||
|
timeFormat="24h"
|
||||||
|
timezone="America/New_York"
|
||||||
|
></dees-input-datepicker>
|
||||||
|
|
||||||
|
<dees-input-datepicker
|
||||||
|
label="Global Event Schedule"
|
||||||
|
description="Schedule an event across different timezones"
|
||||||
|
.enableTime=${true}
|
||||||
|
.enableTimezone=${true}
|
||||||
|
timeFormat="12h"
|
||||||
|
timezone="Europe/London"
|
||||||
|
.minuteIncrement=${30}
|
||||||
|
></dees-input-datepicker>
|
||||||
|
</dees-panel>
|
||||||
|
</dees-demowrapper>
|
||||||
|
|
||||||
<dees-demowrapper .runAfterRender=${async (elementArg: HTMLElement) => {
|
<dees-demowrapper .runAfterRender=${async (elementArg: HTMLElement) => {
|
||||||
// Demonstrate date constraints
|
// Demonstrate date constraints
|
||||||
const futureDatePicker = elementArg.querySelector('dees-input-datepicker');
|
const futureDatePicker = elementArg.querySelector('dees-input-datepicker');
|
||||||
|
@ -52,6 +52,12 @@ export class DeesInputDatepicker extends DeesInputBase<DeesInputDatepicker> {
|
|||||||
@property({ type: String })
|
@property({ type: String })
|
||||||
public placeholder: string = 'YYYY-MM-DD';
|
public placeholder: string = 'YYYY-MM-DD';
|
||||||
|
|
||||||
|
@property({ type: Boolean })
|
||||||
|
public enableTimezone: boolean = false;
|
||||||
|
|
||||||
|
@property({ type: String })
|
||||||
|
public timezone: string = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
||||||
|
|
||||||
@state()
|
@state()
|
||||||
private isOpened: boolean = false;
|
private isOpened: boolean = false;
|
||||||
|
|
||||||
@ -114,7 +120,8 @@ export class DeesInputDatepicker extends DeesInputBase<DeesInputDatepicker> {
|
|||||||
border-color: ${cssManager.bdTheme('hsl(222.2 47.4% 11.2%)', 'hsl(210 20% 98%)')};
|
border-color: ${cssManager.bdTheme('hsl(222.2 47.4% 11.2%)', 'hsl(210 20% 98%)')};
|
||||||
outline: 2px solid transparent;
|
outline: 2px solid transparent;
|
||||||
outline-offset: 2px;
|
outline-offset: 2px;
|
||||||
box-shadow: 0 0 0 2px ${cssManager.bdTheme('hsl(0 0% 100%)', 'hsl(224 71.4% 4.1%)')}, 0 0 0 4px ${cssManager.bdTheme('hsl(222.2 47.4% 11.2% / 0.1)', 'hsl(210 20% 98% / 0.1)')};
|
box-shadow: 0 0 0 2px ${cssManager.bdTheme('hsl(0 0% 100%)', 'hsl(224 71.4% 4.1%)')},
|
||||||
|
0 0 0 4px ${cssManager.bdTheme('hsl(222.2 47.4% 11.2% / 0.1)', 'hsl(210 20% 98% / 0.1)')};
|
||||||
}
|
}
|
||||||
|
|
||||||
.date-input:disabled {
|
.date-input:disabled {
|
||||||
@ -451,9 +458,71 @@ export class DeesInputDatepicker extends DeesInputBase<DeesInputDatepicker> {
|
|||||||
.clear-button:active {
|
.clear-button:active {
|
||||||
background: ${cssManager.bdTheme('hsl(0 72.2% 50.6% / 0.2)', 'hsl(0 62.8% 30.6% / 0.2)')};
|
background: ${cssManager.bdTheme('hsl(0 72.2% 50.6% / 0.2)', 'hsl(0 62.8% 30.6% / 0.2)')};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Timezone selector */
|
||||||
|
.timezone-selector {
|
||||||
|
margin-top: 12px;
|
||||||
|
padding-top: 12px;
|
||||||
|
border-top: 1px solid ${cssManager.bdTheme('hsl(214.3 31.8% 91.4%)', 'hsl(217.2 32.6% 17.5%)')};
|
||||||
|
}
|
||||||
|
|
||||||
|
.timezone-selector-title {
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 500;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
color: ${cssManager.bdTheme('hsl(220 8.9% 46.1%)', 'hsl(215 20.2% 65.1%)')};
|
||||||
|
}
|
||||||
|
|
||||||
|
.timezone-select {
|
||||||
|
width: 100%;
|
||||||
|
height: 36px;
|
||||||
|
border: 1px solid ${cssManager.bdTheme('hsl(214.3 31.8% 91.4%)', 'hsl(217.2 32.6% 17.5%)')};
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 0 12px;
|
||||||
|
font-size: 14px;
|
||||||
|
background: ${cssManager.bdTheme('hsl(0 0% 100%)', 'hsl(224 71.4% 4.1%)')};
|
||||||
|
color: ${cssManager.bdTheme('hsl(224 71.4% 4.1%)', 'hsl(210 20% 98%)')};
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.timezone-select:hover {
|
||||||
|
border-color: ${cssManager.bdTheme('hsl(214.3 31.8% 91.4%)', 'hsl(217.2 32.6% 17.5%)')};
|
||||||
|
background: ${cssManager.bdTheme('hsl(210 20% 98%)', 'hsl(215 27.9% 16.9%)')};
|
||||||
|
}
|
||||||
|
|
||||||
|
.timezone-select:focus {
|
||||||
|
outline: none;
|
||||||
|
border-color: ${cssManager.bdTheme('hsl(222.2 47.4% 11.2%)', 'hsl(210 20% 98%)')};
|
||||||
|
box-shadow: 0 0 0 2px ${cssManager.bdTheme('hsl(222.2 47.4% 11.2% / 0.1)', 'hsl(210 20% 98% / 0.1)')};
|
||||||
|
}
|
||||||
`,
|
`,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
private getTimezones(): { value: string; label: string }[] {
|
||||||
|
// Common timezones with their display names
|
||||||
|
return [
|
||||||
|
{ value: 'UTC', label: 'UTC (Coordinated Universal Time)' },
|
||||||
|
{ value: 'America/New_York', label: 'Eastern Time (US & Canada)' },
|
||||||
|
{ value: 'America/Chicago', label: 'Central Time (US & Canada)' },
|
||||||
|
{ value: 'America/Denver', label: 'Mountain Time (US & Canada)' },
|
||||||
|
{ value: 'America/Los_Angeles', label: 'Pacific Time (US & Canada)' },
|
||||||
|
{ value: 'America/Phoenix', label: 'Arizona' },
|
||||||
|
{ value: 'America/Anchorage', label: 'Alaska' },
|
||||||
|
{ value: 'Pacific/Honolulu', label: 'Hawaii' },
|
||||||
|
{ value: 'Europe/London', label: 'London' },
|
||||||
|
{ value: 'Europe/Paris', label: 'Paris' },
|
||||||
|
{ value: 'Europe/Berlin', label: 'Berlin' },
|
||||||
|
{ value: 'Europe/Moscow', label: 'Moscow' },
|
||||||
|
{ value: 'Asia/Dubai', label: 'Dubai' },
|
||||||
|
{ value: 'Asia/Kolkata', label: 'India Standard Time' },
|
||||||
|
{ value: 'Asia/Shanghai', label: 'China Standard Time' },
|
||||||
|
{ value: 'Asia/Tokyo', label: 'Tokyo' },
|
||||||
|
{ value: 'Australia/Sydney', label: 'Sydney' },
|
||||||
|
{ value: 'Pacific/Auckland', label: 'Auckland' },
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
render(): TemplateResult {
|
render(): TemplateResult {
|
||||||
const monthNames = [
|
const monthNames = [
|
||||||
'January', 'February', 'March', 'April', 'May', 'June',
|
'January', 'February', 'March', 'April', 'May', 'June',
|
||||||
@ -466,6 +535,7 @@ export class DeesInputDatepicker extends DeesInputBase<DeesInputDatepicker> {
|
|||||||
|
|
||||||
const days = this.getDaysInMonth();
|
const days = this.getDaysInMonth();
|
||||||
const isAM = this.selectedHour < 12;
|
const isAM = this.selectedHour < 12;
|
||||||
|
const timezones = this.getTimezones();
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<div class="input-wrapper">
|
<div class="input-wrapper">
|
||||||
@ -576,6 +646,24 @@ export class DeesInputDatepicker extends DeesInputBase<DeesInputDatepicker> {
|
|||||||
</div>
|
</div>
|
||||||
` : ''}
|
` : ''}
|
||||||
|
|
||||||
|
<!-- Timezone Selector -->
|
||||||
|
${this.enableTimezone ? html`
|
||||||
|
<div class="timezone-selector">
|
||||||
|
<div class="timezone-selector-title">Timezone</div>
|
||||||
|
<select
|
||||||
|
class="timezone-select"
|
||||||
|
.value="${this.timezone}"
|
||||||
|
@change="${(e: Event) => this.handleTimezoneChange(e)}"
|
||||||
|
>
|
||||||
|
${timezones.map(tz => html`
|
||||||
|
<option value="${tz.value}" ?selected="${tz.value === this.timezone}">
|
||||||
|
${tz.label}
|
||||||
|
</option>
|
||||||
|
`)}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
` : ''}
|
||||||
|
|
||||||
<!-- Action Buttons -->
|
<!-- Action Buttons -->
|
||||||
<div class="calendar-actions">
|
<div class="calendar-actions">
|
||||||
<button class="action-button today-button" @click="${this.selectToday}">
|
<button class="action-button today-button" @click="${this.selectToday}">
|
||||||
@ -662,6 +750,19 @@ export class DeesInputDatepicker extends DeesInputBase<DeesInputDatepicker> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Timezone formatting if enabled
|
||||||
|
if (this.enableTimezone) {
|
||||||
|
const formatter = new Intl.DateTimeFormat('en-US', {
|
||||||
|
timeZoneName: 'short',
|
||||||
|
timeZone: this.timezone
|
||||||
|
});
|
||||||
|
const parts = formatter.formatToParts(date);
|
||||||
|
const tzPart = parts.find(part => part.type === 'timeZoneName');
|
||||||
|
if (tzPart) {
|
||||||
|
formatted += ` ${tzPart.value}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return formatted;
|
return formatted;
|
||||||
} catch {
|
} catch {
|
||||||
return '';
|
return '';
|
||||||
@ -784,7 +885,7 @@ export class DeesInputDatepicker extends DeesInputBase<DeesInputDatepicker> {
|
|||||||
this.selectedMinute
|
this.selectedMinute
|
||||||
);
|
);
|
||||||
|
|
||||||
this.value = this.selectedDate.toISOString();
|
this.value = this.formatValueWithTimezone(this.selectedDate);
|
||||||
this.changeSubject.next(this);
|
this.changeSubject.next(this);
|
||||||
|
|
||||||
if (!this.enableTime) {
|
if (!this.enableTime) {
|
||||||
@ -799,7 +900,7 @@ export class DeesInputDatepicker extends DeesInputBase<DeesInputDatepicker> {
|
|||||||
this.selectedHour = today.getHours();
|
this.selectedHour = today.getHours();
|
||||||
this.selectedMinute = today.getMinutes();
|
this.selectedMinute = today.getMinutes();
|
||||||
|
|
||||||
this.value = this.selectedDate.toISOString();
|
this.value = this.formatValueWithTimezone(this.selectedDate);
|
||||||
this.changeSubject.next(this);
|
this.changeSubject.next(this);
|
||||||
|
|
||||||
if (!this.enableTime) {
|
if (!this.enableTime) {
|
||||||
@ -874,11 +975,62 @@ export class DeesInputDatepicker extends DeesInputBase<DeesInputDatepicker> {
|
|||||||
this.selectedHour,
|
this.selectedHour,
|
||||||
this.selectedMinute
|
this.selectedMinute
|
||||||
);
|
);
|
||||||
this.value = this.selectedDate.toISOString();
|
this.value = this.formatValueWithTimezone(this.selectedDate);
|
||||||
this.changeSubject.next(this);
|
this.changeSubject.next(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private handleTimezoneChange(e: Event): void {
|
||||||
|
const select = e.target as HTMLSelectElement;
|
||||||
|
this.timezone = select.value;
|
||||||
|
this.updateSelectedDateTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
private formatValueWithTimezone(date: Date): string {
|
||||||
|
if (!this.enableTimezone) {
|
||||||
|
return date.toISOString();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Format the date with timezone offset
|
||||||
|
const formatter = new Intl.DateTimeFormat('en-US', {
|
||||||
|
year: 'numeric',
|
||||||
|
month: '2-digit',
|
||||||
|
day: '2-digit',
|
||||||
|
hour: '2-digit',
|
||||||
|
minute: '2-digit',
|
||||||
|
second: '2-digit',
|
||||||
|
hour12: false,
|
||||||
|
timeZone: this.timezone,
|
||||||
|
timeZoneName: 'short'
|
||||||
|
});
|
||||||
|
|
||||||
|
const parts = formatter.formatToParts(date);
|
||||||
|
const dateParts: any = {};
|
||||||
|
parts.forEach(part => {
|
||||||
|
dateParts[part.type] = part.value;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Create ISO-like format with timezone
|
||||||
|
const isoString = `${dateParts.year}-${dateParts.month}-${dateParts.day}T${dateParts.hour}:${dateParts.minute}:${dateParts.second}`;
|
||||||
|
|
||||||
|
// Get timezone offset
|
||||||
|
const tzOffset = this.getTimezoneOffset(date, this.timezone);
|
||||||
|
return `${isoString}${tzOffset}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
private getTimezoneOffset(date: Date, timezone: string): string {
|
||||||
|
// Create a date in the target timezone
|
||||||
|
const tzDate = new Date(date.toLocaleString('en-US', { timeZone: timezone }));
|
||||||
|
const utcDate = new Date(date.toLocaleString('en-US', { timeZone: 'UTC' }));
|
||||||
|
|
||||||
|
const offsetMinutes = (tzDate.getTime() - utcDate.getTime()) / (1000 * 60);
|
||||||
|
const hours = Math.floor(Math.abs(offsetMinutes) / 60);
|
||||||
|
const minutes = Math.abs(offsetMinutes) % 60;
|
||||||
|
const sign = offsetMinutes >= 0 ? '+' : '-';
|
||||||
|
|
||||||
|
return `${sign}${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}`;
|
||||||
|
}
|
||||||
|
|
||||||
private handleKeydown(e: KeyboardEvent): void {
|
private handleKeydown(e: KeyboardEvent): void {
|
||||||
if (e.key === 'Enter' || e.key === ' ') {
|
if (e.key === 'Enter' || e.key === ' ') {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
Reference in New Issue
Block a user