From 14212d0e5da2afe6af08371f92e54c165baa59c6 Mon Sep 17 00:00:00 2001 From: Anveshreddy mekala Date: Wed, 9 Jul 2025 17:27:53 -0500 Subject: [PATCH 01/22] feat(date-picker): add one month view in range --- .../date-picker-month-header.tsx | 11 ++++++- .../date-picker-month/date-picker-month.tsx | 18 ++++++++--- .../components/date-picker/date-picker.scss | 11 ++++--- .../components/date-picker/date-picker.tsx | 14 +++++++-- .../src/components/date-picker/utils.ts | 7 +++++ .../input-date-picker/input-date-picker.tsx | 30 +++++++++++++------ 6 files changed, 70 insertions(+), 21 deletions(-) diff --git a/packages/calcite-components/src/components/date-picker-month-header/date-picker-month-header.tsx b/packages/calcite-components/src/components/date-picker-month-header/date-picker-month-header.tsx index c5c3308989a..b5c31ef5650 100644 --- a/packages/calcite-components/src/components/date-picker-month-header/date-picker-month-header.tsx +++ b/packages/calcite-components/src/components/date-picker-month-header/date-picker-month-header.tsx @@ -103,6 +103,15 @@ export class DatePickerMonthHeader extends LitElement { */ @property() position: Extract<"start" | "end", Position>; + /** When `true`, activates the component's range mode. */ + @property({ + reflect: true, + // converter: { + // fromAttribute: rangeFromAttribute, + // }, + }) + range: boolean | "single" = false; + /** Specifies the size of the component. */ @property({ reflect: true }) scale: Scale; @@ -434,7 +443,7 @@ export class DatePickerMonthHeader extends LitElement {
{this.renderChevron("left")}
)}
- {this.position !== "start" && this.renderChevron("right")} + {(this.position !== "start" || this.range === "single") && this.renderChevron("right")}
); diff --git a/packages/calcite-components/src/components/date-picker-month/date-picker-month.tsx b/packages/calcite-components/src/components/date-picker-month/date-picker-month.tsx index 20e3882b4ad..76588390c8f 100644 --- a/packages/calcite-components/src/components/date-picker-month/date-picker-month.tsx +++ b/packages/calcite-components/src/components/date-picker-month/date-picker-month.tsx @@ -16,6 +16,7 @@ import { HeadingLevel } from "../functional/Heading"; import type { DatePickerMonthHeader } from "../date-picker-month-header/date-picker-month-header"; import type { DatePickerDay } from "../date-picker-day/date-picker-day"; import type { DatePicker } from "../date-picker/date-picker"; +// import { rangeFromAttribute } from "../date-picker/utils"; import { CSS } from "./resources"; import { styles } from "./date-picker-month.scss"; @@ -110,7 +111,13 @@ export class DatePickerMonth extends LitElement { @property() monthStyle: "abbreviated" | "wide"; /** When `true`, activates the component's range mode which renders two calendars for selecting ranges of dates. */ - @property({ reflect: true }) range: boolean = false; + @property({ + reflect: true, + // converter: { + // fromAttribute: rangeFromAttribute, + // }, + }) + range: boolean | "single" = false; /** Specifies the size of the component. */ @property({ reflect: true }) scale: Scale; @@ -555,7 +562,7 @@ export class DatePickerMonth extends LitElement { private updateFocusableDate(date: Date): void { if (!this.selectedDate || !this.range) { this.focusedDate = this.getFirstValidDateOfMonth(date); - } else if (this.selectedDate && this.range) { + } else if (this.selectedDate && !!this.range) { if (!hasSameMonthAndYear(this.startDate, date) || !hasSameMonthAndYear(this.endDate, date)) { this.focusedDate = this.getFirstValidDateOfMonth(date); } @@ -605,7 +612,9 @@ export class DatePickerMonth extends LitElement { return (
{this.renderCalendar(adjustedWeekDays, days)} - {this.range && this.renderCalendar(adjustedWeekDays, nextMonthDays, true)} + {this.range && + this.range !== "single" && + this.renderCalendar(adjustedWeekDays, nextMonthDays, true)}
); } @@ -642,7 +651,7 @@ export class DatePickerMonth extends LitElement { [CSS.currentDay]: currentDay, [CSS.insideRangeHover]: this.isHoverInRange(), [CSS.outsideRangeHover]: !this.isHoverInRange(), - [CSS.noncurrent]: this.range && !currentMonth, + [CSS.noncurrent]: !!this.range && !currentMonth, }} currentMonth={currentMonth} dateTimeFormat={this.dateTimeFormat} @@ -689,6 +698,7 @@ export class DatePickerMonth extends LitElement { monthStyle={this.monthStyle} oncalciteInternalDatePickerMonthHeaderSelectChange={this.monthHeaderSelectChange} position={isEndCalendar ? "end" : this.range ? "start" : null} + range={this.range} scale={this.scale} selectedDate={this.selectedDate} /> diff --git a/packages/calcite-components/src/components/date-picker/date-picker.scss b/packages/calcite-components/src/components/date-picker/date-picker.scss index 1df52ecfc05..5b963f06baa 100644 --- a/packages/calcite-components/src/components/date-picker/date-picker.scss +++ b/packages/calcite-components/src/components/date-picker/date-picker.scss @@ -38,7 +38,8 @@ border-radius: var(--calcite-date-picker-corner-radius, 0); } -:host([scale="s"]) { +:host([scale="s"]), +:host([scale="s"][range="single"]) { inline-size: 236px; min-inline-size: 216px; max-inline-size: 380px; @@ -50,19 +51,21 @@ max-inline-size: 772px; } -:host([scale="m"]) { +:host([scale="m"]), +:host([scale="m"][range="single"]) { inline-size: 298px; min-inline-size: 272px; max-inline-size: 480px; } -:host([scale="m"][range][layout="horizontal"]) { +:host([scale="m"][range][layout="horizontal"]:not([range="single"])) { inline-size: 608px; min-inline-size: 544px; max-inline-size: 972px; } -:host([scale="l"]) { +:host([scale="l"]), +:host([scale="l"][range="single"]) { inline-size: 334px; min-inline-size: 320px; max-inline-size: 600px; diff --git a/packages/calcite-components/src/components/date-picker/date-picker.tsx b/packages/calcite-components/src/components/date-picker/date-picker.tsx index bf39aed48da..a2885fba092 100644 --- a/packages/calcite-components/src/components/date-picker/date-picker.tsx +++ b/packages/calcite-components/src/components/date-picker/date-picker.tsx @@ -9,6 +9,8 @@ import { method, state, JsxNode, + stringOrBoolean, + // stringOrBoolean, } from "@arcgis/lumina"; import { dateFromISO, @@ -29,7 +31,7 @@ import { focusFirstTabbable } from "../../utils/dom"; import { useT9n } from "../../controllers/useT9n"; import T9nStrings from "./assets/t9n/messages.en.json"; import { DATE_PICKER_FORMAT_OPTIONS, HEADING_LEVEL, CSS } from "./resources"; -import { DateLocaleData, getLocaleData, getValueAsDateRange } from "./utils"; +import { DateLocaleData, getLocaleData, getValueAsDateRange, rangeFromAttribute } from "./utils"; import { styles } from "./date-picker.scss"; declare global { @@ -128,7 +130,14 @@ export class DatePicker extends LitElement { @property({ reflect: true }) proximitySelectionDisabled = false; /** When `true`, activates the component's range mode to allow a start and end date. */ - @property({ reflect: true }) range = false; + @property({ + reflect: true, + converter: { + fromAttribute: rangeFromAttribute, + toAttribute: stringOrBoolean.toAttribute, + }, + }) + range: boolean | "single" = false; /** Specifies the size of the component. */ @property({ reflect: true }) scale: "s" | "m" | "l" = "m"; @@ -622,7 +631,6 @@ export class DatePicker extends LitElement { : this.minAsDate; const startCalendarActiveDate = this.range ? this.activeStartDate : activeDate; - return ( <>
diff --git a/packages/calcite-components/src/components/date-picker/utils.ts b/packages/calcite-components/src/components/date-picker/utils.ts index 8fa6ffdc41c..5285f9d748a 100644 --- a/packages/calcite-components/src/components/date-picker/utils.ts +++ b/packages/calcite-components/src/components/date-picker/utils.ts @@ -82,3 +82,10 @@ export async function getLocaleData(lang: string): Promise { export function getValueAsDateRange(value: string[]): Date[] { return value.map((v, index) => dateFromISO(v, index === 1)); } + +export function rangeFromAttribute(value: string | boolean): boolean | "single" { + if (value === "single") { + return value; + } + return value === "" || value === "true"; +} diff --git a/packages/calcite-components/src/components/input-date-picker/input-date-picker.tsx b/packages/calcite-components/src/components/input-date-picker/input-date-picker.tsx index 170a378112f..1c3c07bfd6d 100644 --- a/packages/calcite-components/src/components/input-date-picker/input-date-picker.tsx +++ b/packages/calcite-components/src/components/input-date-picker/input-date-picker.tsx @@ -58,7 +58,12 @@ import { numberStringFormatter, } from "../../utils/locale"; import { toggleOpenClose, OpenCloseComponent } from "../../utils/openCloseComponent"; -import { DateLocaleData, getLocaleData, getValueAsDateRange } from "../date-picker/utils"; +import { + DateLocaleData, + getLocaleData, + getValueAsDateRange, + rangeFromAttribute, +} from "../date-picker/utils"; import { HeadingLevel } from "../functional/Heading"; import { guid } from "../../utils/guid"; import { Status } from "../interfaces"; @@ -272,7 +277,14 @@ export class InputDatePicker @property() proximitySelectionDisabled = false; /** When `true`, activates a range for the component. */ - @property({ reflect: true }) range = false; + @property({ + reflect: true, + converter: { + fromAttribute: rangeFromAttribute, + toAttribute: stringOrBoolean.toAttribute, + }, + }) + range: boolean | "single" = false; /** * When `true`, the component's value can be read, but controls are not accessible and the value cannot be modified. @@ -1097,8 +1109,8 @@ export class InputDatePicker ariaInvalid={this.status === "invalid"} class={{ [CSS.input]: true, - [CSS.inputNoBottomBorder]: this.layout === "vertical" && this.range, - [CSS.inputNoRightBorder]: this.range, + [CSS.inputNoBottomBorder]: this.layout === "vertical" && !!this.range, + [CSS.inputNoRightBorder]: !!this.range, }} disabled={disabled} icon={ICONS.calendar} @@ -1161,12 +1173,12 @@ export class InputDatePicker />
- {this.range && ( + {!!this.range && (
)} - {this.range && ( + {!!this.range && (
Date: Fri, 11 Jul 2025 10:17:31 -0500 Subject: [PATCH 02/22] refactor --- .../src/components/date-picker/date-picker.tsx | 9 +++++++-- .../src/components/date-picker/utils.ts | 7 +++---- .../components/input-date-picker/input-date-picker.tsx | 4 ++-- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/packages/calcite-components/src/components/date-picker/date-picker.tsx b/packages/calcite-components/src/components/date-picker/date-picker.tsx index a2885fba092..186e8c6179d 100644 --- a/packages/calcite-components/src/components/date-picker/date-picker.tsx +++ b/packages/calcite-components/src/components/date-picker/date-picker.tsx @@ -31,7 +31,12 @@ import { focusFirstTabbable } from "../../utils/dom"; import { useT9n } from "../../controllers/useT9n"; import T9nStrings from "./assets/t9n/messages.en.json"; import { DATE_PICKER_FORMAT_OPTIONS, HEADING_LEVEL, CSS } from "./resources"; -import { DateLocaleData, getLocaleData, getValueAsDateRange, rangeFromAttribute } from "./utils"; +import { + DateLocaleData, + getLocaleData, + getValueAsDateRange, + stringOrBooleanFromAttribute, +} from "./utils"; import { styles } from "./date-picker.scss"; declare global { @@ -133,7 +138,7 @@ export class DatePicker extends LitElement { @property({ reflect: true, converter: { - fromAttribute: rangeFromAttribute, + fromAttribute: stringOrBooleanFromAttribute, toAttribute: stringOrBoolean.toAttribute, }, }) diff --git a/packages/calcite-components/src/components/date-picker/utils.ts b/packages/calcite-components/src/components/date-picker/utils.ts index 5285f9d748a..20207cd29f0 100644 --- a/packages/calcite-components/src/components/date-picker/utils.ts +++ b/packages/calcite-components/src/components/date-picker/utils.ts @@ -83,9 +83,8 @@ export function getValueAsDateRange(value: string[]): Date[] { return value.map((v, index) => dateFromISO(v, index === 1)); } -export function rangeFromAttribute(value: string | boolean): boolean | "single" { - if (value === "single") { - return value; +export function stringOrBooleanFromAttribute(value: string | boolean): string | boolean { + if (typeof value === "string") { + return value === "" ? true : value; } - return value === "" || value === "true"; } diff --git a/packages/calcite-components/src/components/input-date-picker/input-date-picker.tsx b/packages/calcite-components/src/components/input-date-picker/input-date-picker.tsx index 1c3c07bfd6d..6a79243a4cb 100644 --- a/packages/calcite-components/src/components/input-date-picker/input-date-picker.tsx +++ b/packages/calcite-components/src/components/input-date-picker/input-date-picker.tsx @@ -62,7 +62,7 @@ import { DateLocaleData, getLocaleData, getValueAsDateRange, - rangeFromAttribute, + stringOrBooleanFromAttribute, } from "../date-picker/utils"; import { HeadingLevel } from "../functional/Heading"; import { guid } from "../../utils/guid"; @@ -280,7 +280,7 @@ export class InputDatePicker @property({ reflect: true, converter: { - fromAttribute: rangeFromAttribute, + fromAttribute: stringOrBooleanFromAttribute, toAttribute: stringOrBoolean.toAttribute, }, }) From 1a98dec03a73d86c596f36cae8805b75f264383e Mon Sep 17 00:00:00 2001 From: Anveshreddy mekala Date: Fri, 11 Jul 2025 10:58:20 -0500 Subject: [PATCH 03/22] remove commented code --- .../date-picker-month-header/date-picker-month-header.tsx | 3 --- .../src/components/date-picker-month/date-picker-month.tsx | 4 ---- 2 files changed, 7 deletions(-) diff --git a/packages/calcite-components/src/components/date-picker-month-header/date-picker-month-header.tsx b/packages/calcite-components/src/components/date-picker-month-header/date-picker-month-header.tsx index b5c31ef5650..5f58a583463 100644 --- a/packages/calcite-components/src/components/date-picker-month-header/date-picker-month-header.tsx +++ b/packages/calcite-components/src/components/date-picker-month-header/date-picker-month-header.tsx @@ -106,9 +106,6 @@ export class DatePickerMonthHeader extends LitElement { /** When `true`, activates the component's range mode. */ @property({ reflect: true, - // converter: { - // fromAttribute: rangeFromAttribute, - // }, }) range: boolean | "single" = false; diff --git a/packages/calcite-components/src/components/date-picker-month/date-picker-month.tsx b/packages/calcite-components/src/components/date-picker-month/date-picker-month.tsx index 76588390c8f..3dc8d918e02 100644 --- a/packages/calcite-components/src/components/date-picker-month/date-picker-month.tsx +++ b/packages/calcite-components/src/components/date-picker-month/date-picker-month.tsx @@ -16,7 +16,6 @@ import { HeadingLevel } from "../functional/Heading"; import type { DatePickerMonthHeader } from "../date-picker-month-header/date-picker-month-header"; import type { DatePickerDay } from "../date-picker-day/date-picker-day"; import type { DatePicker } from "../date-picker/date-picker"; -// import { rangeFromAttribute } from "../date-picker/utils"; import { CSS } from "./resources"; import { styles } from "./date-picker-month.scss"; @@ -113,9 +112,6 @@ export class DatePickerMonth extends LitElement { /** When `true`, activates the component's range mode which renders two calendars for selecting ranges of dates. */ @property({ reflect: true, - // converter: { - // fromAttribute: rangeFromAttribute, - // }, }) range: boolean | "single" = false; From a3b311399943930be4bd24e6d032016c7cbdeb91 Mon Sep 17 00:00:00 2001 From: Anveshreddy mekala Date: Thu, 24 Jul 2025 12:18:47 -0500 Subject: [PATCH 04/22] add calendars property --- .../date-picker-month-header.tsx | 4 ++-- .../date-picker-month/date-picker-month.scss | 4 ++-- .../date-picker-month/date-picker-month.tsx | 13 ++++++----- .../components/date-picker/date-picker.scss | 12 +++++----- .../components/date-picker/date-picker.tsx | 22 +++++-------------- .../input-date-picker/input-date-picker.tsx | 17 +++++--------- 6 files changed, 30 insertions(+), 42 deletions(-) diff --git a/packages/calcite-components/src/components/date-picker-month-header/date-picker-month-header.tsx b/packages/calcite-components/src/components/date-picker-month-header/date-picker-month-header.tsx index 5f58a583463..a7632046a91 100644 --- a/packages/calcite-components/src/components/date-picker-month-header/date-picker-month-header.tsx +++ b/packages/calcite-components/src/components/date-picker-month-header/date-picker-month-header.tsx @@ -107,7 +107,7 @@ export class DatePickerMonthHeader extends LitElement { @property({ reflect: true, }) - range: boolean | "single" = false; + range = false; /** Specifies the size of the component. */ @property({ reflect: true }) scale: Scale; @@ -440,7 +440,7 @@ export class DatePickerMonthHeader extends LitElement {
{this.renderChevron("left")}
)}
- {(this.position !== "start" || this.range === "single") && this.renderChevron("right")} + {this.position !== "start" && this.renderChevron("right")}
); diff --git a/packages/calcite-components/src/components/date-picker-month/date-picker-month.scss b/packages/calcite-components/src/components/date-picker-month/date-picker-month.scss index 5c3112f38cf..4c547317ec0 100644 --- a/packages/calcite-components/src/components/date-picker-month/date-picker-month.scss +++ b/packages/calcite-components/src/components/date-picker-month/date-picker-month.scss @@ -96,11 +96,11 @@ border-color: var(--calcite-date-picker-range-calendar-divider-color, var(--calcite-color-border-1)); } -:host([range][layout="horizontal"]) .calendar--start { +:host([range][layout="horizontal"][calendars="two"]) .calendar--start { border-inline-end-width: var(--calcite-border-width-sm); } -:host([range][layout="vertical"]) .calendar--start { +:host([range][layout="vertical"][calendars="two"]) .calendar--start { border-block-end-width: var(--calcite-border-width-sm); } diff --git a/packages/calcite-components/src/components/date-picker-month/date-picker-month.tsx b/packages/calcite-components/src/components/date-picker-month/date-picker-month.tsx index 3dc8d918e02..5fedd015159 100644 --- a/packages/calcite-components/src/components/date-picker-month/date-picker-month.tsx +++ b/packages/calcite-components/src/components/date-picker-month/date-picker-month.tsx @@ -63,6 +63,9 @@ export class DatePickerMonth extends LitElement { /** The currently active Date. */ @property() activeDate: Date = new Date(); + /** Specifies the number of calendars displayed when `range` is `true`. */ + @property({ reflect: true }) calendars: "one" | "two" = "two"; + /** * The DateTimeFormat used to provide screen reader labels. * @@ -113,7 +116,7 @@ export class DatePickerMonth extends LitElement { @property({ reflect: true, }) - range: boolean | "single" = false; + range = false; /** Specifies the size of the component. */ @property({ reflect: true }) scale: Scale; @@ -558,7 +561,7 @@ export class DatePickerMonth extends LitElement { private updateFocusableDate(date: Date): void { if (!this.selectedDate || !this.range) { this.focusedDate = this.getFirstValidDateOfMonth(date); - } else if (this.selectedDate && !!this.range) { + } else if (this.selectedDate && this.range) { if (!hasSameMonthAndYear(this.startDate, date) || !hasSameMonthAndYear(this.endDate, date)) { this.focusedDate = this.getFirstValidDateOfMonth(date); } @@ -609,7 +612,7 @@ export class DatePickerMonth extends LitElement {
{this.renderCalendar(adjustedWeekDays, days)} {this.range && - this.range !== "single" && + this.calendars === "two" && this.renderCalendar(adjustedWeekDays, nextMonthDays, true)}
); @@ -647,7 +650,7 @@ export class DatePickerMonth extends LitElement { [CSS.currentDay]: currentDay, [CSS.insideRangeHover]: this.isHoverInRange(), [CSS.outsideRangeHover]: !this.isHoverInRange(), - [CSS.noncurrent]: !!this.range && !currentMonth, + [CSS.noncurrent]: this.range && !currentMonth, }} currentMonth={currentMonth} dateTimeFormat={this.dateTimeFormat} @@ -693,7 +696,7 @@ export class DatePickerMonth extends LitElement { min={this.min} monthStyle={this.monthStyle} oncalciteInternalDatePickerMonthHeaderSelectChange={this.monthHeaderSelectChange} - position={isEndCalendar ? "end" : this.range ? "start" : null} + position={isEndCalendar ? "end" : this.range && this.calendars === "two" ? "start" : null} range={this.range} scale={this.scale} selectedDate={this.selectedDate} diff --git a/packages/calcite-components/src/components/date-picker/date-picker.scss b/packages/calcite-components/src/components/date-picker/date-picker.scss index 5b963f06baa..1e227d946af 100644 --- a/packages/calcite-components/src/components/date-picker/date-picker.scss +++ b/packages/calcite-components/src/components/date-picker/date-picker.scss @@ -39,39 +39,39 @@ } :host([scale="s"]), -:host([scale="s"][range="single"]) { +:host([scale="s"][range][calendars="one"]) { inline-size: 236px; min-inline-size: 216px; max-inline-size: 380px; } -:host([scale="s"][range][layout="horizontal"]) { +:host([scale="s"][range][layout="horizontal"][calendars="two"]) { inline-size: 480px; min-inline-size: 432px; max-inline-size: 772px; } :host([scale="m"]), -:host([scale="m"][range="single"]) { +:host([scale="m"][range][calendars="one"]) { inline-size: 298px; min-inline-size: 272px; max-inline-size: 480px; } -:host([scale="m"][range][layout="horizontal"]:not([range="single"])) { +:host([scale="m"][layout="horizontal"][range][calendars="two"]) { inline-size: 608px; min-inline-size: 544px; max-inline-size: 972px; } :host([scale="l"]), -:host([scale="l"][range="single"]) { +:host([scale="l"][range][calendars="one"]) { inline-size: 334px; min-inline-size: 320px; max-inline-size: 600px; } -:host([scale="l"][range][layout="horizontal"]) { +:host([scale="l"][layout="horizontal"][range][calendars="two"]) { inline-size: 684px; min-inline-size: 640px; max-inline-size: 1212px; diff --git a/packages/calcite-components/src/components/date-picker/date-picker.tsx b/packages/calcite-components/src/components/date-picker/date-picker.tsx index 446da6c3924..c00ed569fcd 100644 --- a/packages/calcite-components/src/components/date-picker/date-picker.tsx +++ b/packages/calcite-components/src/components/date-picker/date-picker.tsx @@ -9,8 +9,6 @@ import { method, state, JsxNode, - stringOrBoolean, - // stringOrBoolean, } from "@arcgis/lumina"; import { dateFromISO, @@ -30,12 +28,7 @@ import { useT9n } from "../../controllers/useT9n"; import { useSetFocus } from "../../controllers/useSetFocus"; import T9nStrings from "./assets/t9n/messages.en.json"; import { DATE_PICKER_FORMAT_OPTIONS, HEADING_LEVEL, CSS } from "./resources"; -import { - DateLocaleData, - getLocaleData, - getValueAsDateRange, - stringOrBooleanFromAttribute, -} from "./utils"; +import { DateLocaleData, getLocaleData, getValueAsDateRange } from "./utils"; import { styles } from "./date-picker.scss"; declare global { @@ -99,6 +92,9 @@ export class DatePicker extends LitElement { /** When `range` is true, specifies the active `range`. Where `"start"` specifies the starting range date and `"end"` the ending range date. */ @property({ reflect: true }) activeRange: "start" | "end"; + /** Specifies the number of calendars displayed when `range` is `true`. */ + @property({ reflect: true }) calendars: "one" | "two" = "two"; + /** Specifies the heading level of the component's `heading` for proper document structure, without affecting visual styling. */ @property({ type: Number, reflect: true }) headingLevel: HeadingLevel; @@ -136,14 +132,7 @@ export class DatePicker extends LitElement { @property({ reflect: true }) proximitySelectionDisabled = false; /** When `true`, activates the component's range mode to allow a start and end date. */ - @property({ - reflect: true, - converter: { - fromAttribute: stringOrBooleanFromAttribute, - toAttribute: stringOrBoolean.toAttribute, - }, - }) - range: boolean | "single" = false; + @property({ reflect: true }) range = false; /** Specifies the size of the component. */ @property({ reflect: true }) scale: "s" | "m" | "l" = "m"; @@ -672,6 +661,7 @@ export class DatePicker extends LitElement { return ( Date: Thu, 24 Jul 2025 12:51:04 -0500 Subject: [PATCH 05/22] refactor --- .../date-picker-month-header.tsx | 5 +---- .../date-picker-month/date-picker-month.tsx | 5 +---- .../input-date-picker/input-date-picker.tsx | 19 ++++++++----------- 3 files changed, 10 insertions(+), 19 deletions(-) diff --git a/packages/calcite-components/src/components/date-picker-month-header/date-picker-month-header.tsx b/packages/calcite-components/src/components/date-picker-month-header/date-picker-month-header.tsx index a7632046a91..3f92001157e 100644 --- a/packages/calcite-components/src/components/date-picker-month-header/date-picker-month-header.tsx +++ b/packages/calcite-components/src/components/date-picker-month-header/date-picker-month-header.tsx @@ -104,10 +104,7 @@ export class DatePickerMonthHeader extends LitElement { @property() position: Extract<"start" | "end", Position>; /** When `true`, activates the component's range mode. */ - @property({ - reflect: true, - }) - range = false; + @property({ reflect: true }) range = false; /** Specifies the size of the component. */ @property({ reflect: true }) scale: Scale; diff --git a/packages/calcite-components/src/components/date-picker-month/date-picker-month.tsx b/packages/calcite-components/src/components/date-picker-month/date-picker-month.tsx index 5fedd015159..daa25faa8aa 100644 --- a/packages/calcite-components/src/components/date-picker-month/date-picker-month.tsx +++ b/packages/calcite-components/src/components/date-picker-month/date-picker-month.tsx @@ -113,10 +113,7 @@ export class DatePickerMonth extends LitElement { @property() monthStyle: "abbreviated" | "wide"; /** When `true`, activates the component's range mode which renders two calendars for selecting ranges of dates. */ - @property({ - reflect: true, - }) - range = false; + @property({ reflect: true }) range = false; /** Specifies the size of the component. */ @property({ reflect: true }) scale: Scale; diff --git a/packages/calcite-components/src/components/input-date-picker/input-date-picker.tsx b/packages/calcite-components/src/components/input-date-picker/input-date-picker.tsx index 6e8d3fd74fd..5ee56972291 100644 --- a/packages/calcite-components/src/components/input-date-picker/input-date-picker.tsx +++ b/packages/calcite-components/src/components/input-date-picker/input-date-picker.tsx @@ -277,10 +277,7 @@ export class InputDatePicker @property() proximitySelectionDisabled = false; /** When `true`, activates a range for the component. */ - @property({ - reflect: true, - }) - range = false; + @property({ reflect: true }) range = false; /** * When `true`, the component's value can be read, but controls are not accessible and the value cannot be modified. @@ -1112,8 +1109,8 @@ export class InputDatePicker ariaInvalid={this.status === "invalid"} class={{ [CSS.input]: true, - [CSS.inputNoBottomBorder]: this.layout === "vertical" && !!this.range, - [CSS.inputNoRightBorder]: !!this.range, + [CSS.inputNoBottomBorder]: this.layout === "vertical" && this.range, + [CSS.inputNoRightBorder]: this.range, }} disabled={disabled} icon={ICONS.calendar} @@ -1177,12 +1174,12 @@ export class InputDatePicker />
- {!!this.range && ( + {this.range && (
)} - {!!this.range && ( + {this.range && (
Date: Thu, 24 Jul 2025 12:53:04 -0500 Subject: [PATCH 06/22] remove unused props --- .../date-picker-month-header/date-picker-month-header.tsx | 3 --- .../src/components/date-picker-month/date-picker-month.tsx | 3 +-- .../src/components/date-picker/date-picker.tsx | 1 + 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/packages/calcite-components/src/components/date-picker-month-header/date-picker-month-header.tsx b/packages/calcite-components/src/components/date-picker-month-header/date-picker-month-header.tsx index 3f92001157e..c5c3308989a 100644 --- a/packages/calcite-components/src/components/date-picker-month-header/date-picker-month-header.tsx +++ b/packages/calcite-components/src/components/date-picker-month-header/date-picker-month-header.tsx @@ -103,9 +103,6 @@ export class DatePickerMonthHeader extends LitElement { */ @property() position: Extract<"start" | "end", Position>; - /** When `true`, activates the component's range mode. */ - @property({ reflect: true }) range = false; - /** Specifies the size of the component. */ @property({ reflect: true }) scale: Scale; diff --git a/packages/calcite-components/src/components/date-picker-month/date-picker-month.tsx b/packages/calcite-components/src/components/date-picker-month/date-picker-month.tsx index daa25faa8aa..88f51c6e4e7 100644 --- a/packages/calcite-components/src/components/date-picker-month/date-picker-month.tsx +++ b/packages/calcite-components/src/components/date-picker-month/date-picker-month.tsx @@ -113,7 +113,7 @@ export class DatePickerMonth extends LitElement { @property() monthStyle: "abbreviated" | "wide"; /** When `true`, activates the component's range mode which renders two calendars for selecting ranges of dates. */ - @property({ reflect: true }) range = false; + @property({ reflect: true }) range: boolean = false; /** Specifies the size of the component. */ @property({ reflect: true }) scale: Scale; @@ -694,7 +694,6 @@ export class DatePickerMonth extends LitElement { monthStyle={this.monthStyle} oncalciteInternalDatePickerMonthHeaderSelectChange={this.monthHeaderSelectChange} position={isEndCalendar ? "end" : this.range && this.calendars === "two" ? "start" : null} - range={this.range} scale={this.scale} selectedDate={this.selectedDate} /> diff --git a/packages/calcite-components/src/components/date-picker/date-picker.tsx b/packages/calcite-components/src/components/date-picker/date-picker.tsx index c00ed569fcd..a3eaeeb89a9 100644 --- a/packages/calcite-components/src/components/date-picker/date-picker.tsx +++ b/packages/calcite-components/src/components/date-picker/date-picker.tsx @@ -633,6 +633,7 @@ export class DatePicker extends LitElement { : this.minAsDate; const startCalendarActiveDate = this.range ? this.activeStartDate : activeDate; + return ( <>
From aec851cbcde0b5e9f44dae64c057b869b595e663 Mon Sep 17 00:00:00 2001 From: Anveshreddy mekala Date: Mon, 28 Jul 2025 18:07:50 -0500 Subject: [PATCH 07/22] add tests --- .../components/date-picker/date-picker.e2e.ts | 168 +++++++++++++++++- .../components/date-picker/date-picker.tsx | 3 +- 2 files changed, 169 insertions(+), 2 deletions(-) diff --git a/packages/calcite-components/src/components/date-picker/date-picker.e2e.ts b/packages/calcite-components/src/components/date-picker/date-picker.e2e.ts index 8e216ecf033..b5866f141b3 100644 --- a/packages/calcite-components/src/components/date-picker/date-picker.e2e.ts +++ b/packages/calcite-components/src/components/date-picker/date-picker.e2e.ts @@ -26,6 +26,14 @@ describe("calcite-date-picker", () => { propertyName: "scale", defaultValue: "m", }, + { + propertyName: "calendars", + defaultValue: "two", + }, + { + propertyName: "monthStyle", + defaultValue: "wide", + }, ]); }); @@ -102,7 +110,33 @@ describe("calcite-date-picker", () => { expect(eventSpy).toHaveReceivedEventTimes(2); }); - it("Emits calciteDatePickerRangeChange event and updates value property when start and end dates are selected from end calendar", async () => { + it("emits calciteDatePickerRangeChange event and updates value property when start & end dates are selected from same month in range with one calendar", async () => { + const page = await newE2EPage(); + await page.setContent(``); + const datePicker = await page.find("calcite-date-picker"); + const eventSpy = await page.spyOnEvent("calciteDatePickerRangeChange"); + + await page.waitForTimeout(animationDurationInMs); + + const now = new Date(); + const currentYear = now.getUTCFullYear(); + const currentMonth = now.getUTCMonth() + 1; + const startDate = `${currentYear}-${formatTimePart(currentMonth)}-01`; + const endDate = `${currentYear}-${formatTimePart(currentMonth)}-15`; + + await selectDayInMonthById(startDate.replaceAll("-", ""), page); + await page.waitForChanges(); + + expect(await datePicker.getProperty("value")).toEqual([startDate, ""]); + + await selectDayInMonthById(endDate.replaceAll("-", ""), page); + await page.waitForChanges(); + + expect(await datePicker.getProperty("value")).toEqual([startDate, endDate]); + expect(eventSpy).toHaveReceivedEventTimes(2); + }); + + it("emits calciteDatePickerRangeChange event and updates value property when start and end dates are selected from end calendar", async () => { const page = await newE2EPage(); await page.setContent(""); const datePicker = await page.find("calcite-date-picker"); @@ -426,6 +460,53 @@ describe("calcite-date-picker", () => { expect(await datePicker.getProperty("value")).toEqual(["2023-11-25", "2024-02-01"]); }); + it("should be able to navigate between months and select date using arrow keys & page keys when calendars is to set to one in range", async () => { + const page = await newE2EPage(); + await page.setContent(html``); + await page.waitForChanges(); + + const datePicker = await page.find("calcite-date-picker"); + await setActiveDate(page, "01-01-2024"); + + await page.keyboard.press("Tab"); + await page.waitForChanges(); + await page.keyboard.press("Tab"); + await page.waitForChanges(); + await page.keyboard.press("Tab"); + await page.waitForChanges(); + await page.keyboard.press("Tab"); + await page.waitForChanges(); + await page.keyboard.press("Tab"); + await page.waitForChanges(); + await page.keyboard.press("ArrowUp"); + await page.waitForChanges(); + await page.keyboard.press("Enter"); + await page.waitForChanges(); + + expect(await datePicker.getProperty("value")).toEqual(["2023-12-25", ""]); + + await page.keyboard.press("PageUp"); + await page.waitForChanges(); + await page.keyboard.press("Enter"); + await page.waitForChanges(); + expect(await datePicker.getProperty("value")).toEqual(["2023-11-25", "2023-12-25"]); + + await page.keyboard.press("PageDown"); + await page.waitForChanges(); + await page.keyboard.press("PageDown"); + await page.waitForChanges(); + await page.keyboard.press("Enter"); + await page.waitForChanges(); + expect(await datePicker.getProperty("value")).toEqual(["2023-11-25", "2024-01-25"]); + + await page.keyboard.press("ArrowDown"); + await page.waitForChanges(); + await page.keyboard.press("Enter"); + await page.waitForChanges(); + + expect(await datePicker.getProperty("value")).toEqual(["2023-11-25", "2024-02-01"]); + }); + it("should be able to navigate between months and select date using arrow keys and page keys in range when value is parsed", async () => { const page = await newE2EPage(); await page.setContent(html``); @@ -470,6 +551,53 @@ describe("calcite-date-picker", () => { expect(await datePicker.getProperty("value")).toEqual(["2023-12-08", "2024-02-08"]); }); + + it("should be able to navigate between months and select date using arrow keys & page keys in range when value is parsed in range with one calendar", async () => { + const page = await newE2EPage(); + await page.setContent(html``); + const datePicker = await page.find("calcite-date-picker"); + datePicker.setProperty("value", ["2024-01-01", "2024-02-10"]); + + await page.keyboard.press("Tab"); + await page.waitForChanges(); + await page.keyboard.press("Tab"); + await page.waitForChanges(); + await page.keyboard.press("Tab"); + await page.waitForChanges(); + await page.keyboard.press("Tab"); + await page.waitForChanges(); + await page.keyboard.press("Tab"); + await page.waitForChanges(); + await page.keyboard.press("ArrowUp"); + await page.waitForChanges(); + await page.keyboard.press("Enter"); + await page.waitForChanges(); + + expect(await datePicker.getProperty("value")).toEqual(["2023-12-25", "2024-02-10"]); + + await page.keyboard.press("ArrowDown"); + await page.waitForChanges(); + await page.keyboard.press("ArrowDown"); + await page.waitForChanges(); + await page.keyboard.press("Enter"); + await page.waitForChanges(); + expect(await datePicker.getProperty("value")).toEqual(["2023-12-25", "2024-01-08"]); + + await page.keyboard.press("PageUp"); + await page.waitForChanges(); + await page.keyboard.press("Enter"); + await page.waitForChanges(); + expect(await datePicker.getProperty("value")).toEqual(["2023-12-08", "2024-01-08"]); + + await page.keyboard.press("PageDown"); + await page.waitForChanges(); + await page.keyboard.press("PageDown"); + await page.waitForChanges(); + await page.keyboard.press("Enter"); + await page.waitForChanges(); + + expect(await datePicker.getProperty("value")).toEqual(["2023-12-08", "2024-02-08"]); + }); }); describe("hover range", () => { @@ -602,6 +730,44 @@ describe("calcite-date-picker", () => { }); describe("month & year selection", () => { + it("should allow selecting first and last valid month from select menu when calendars is set to one in range", async () => { + const page = await newE2EPage(); + await page.setContent( + html``, + ); + + await setActiveDate(page, "07-01-2024"); + await page.waitForChanges(); + + const monthSelect = await page.find( + `calcite-date-picker >>> calcite-date-picker-month-header >>> calcite-select.${MONTH_HEADER_CSS.monthPicker}`, + ); + const yearInput = await page.find("calcite-date-picker >>> calcite-date-picker-month-header >>> input"); + expect(await yearInput.getProperty("value")).toBe("2024"); + expect(await monthSelect.getProperty("value")).toBe("July"); + + await monthSelect.click(); + await page.waitForChanges(); + + await page.select( + `calcite-date-picker >>> calcite-date-picker-month-header >>> calcite-select.${MONTH_HEADER_CSS.monthPicker} >>> select`, + "January", + ); + await page.waitForChanges(); + + expect(await monthSelect.getProperty("value")).toBe("January"); + expect(await yearInput.getProperty("value")).toBe("2024"); + + await page.select( + `calcite-date-picker >>> calcite-date-picker-month-header >>> calcite-select.${MONTH_HEADER_CSS.monthPicker} >>> select`, + "October", + ); + await page.waitForChanges(); + + expect(await monthSelect.getProperty("value")).toBe("October"); + expect(await yearInput.getProperty("value")).toBe("2024"); + }); + it("should allow selecting last valid month from month select menu in start calendar", async () => { const page = await newE2EPage(); await page.setContent(html``); diff --git a/packages/calcite-components/src/components/date-picker/date-picker.tsx b/packages/calcite-components/src/components/date-picker/date-picker.tsx index a3eaeeb89a9..b982c7e93f6 100644 --- a/packages/calcite-components/src/components/date-picker/date-picker.tsx +++ b/packages/calcite-components/src/components/date-picker/date-picker.tsx @@ -338,7 +338,8 @@ export class DatePicker extends LitElement { const month = date.getMonth(); const isDateOutOfCurrentRange = month !== this.activeStartDate.getMonth() && - month !== nextMonth(this.activeStartDate).getMonth(); + (this.calendars === "one" || month !== nextMonth(this.activeStartDate).getMonth()); + if (this.activeRange === "end") { if (!this.activeEndDate || (this.activeStartDate && isDateOutOfCurrentRange)) { this.activeEndDate = date; From 416d42f3e9f325f28c8159001ce4dc7a453e1e26 Mon Sep 17 00:00:00 2001 From: Anveshreddy mekala Date: Tue, 29 Jul 2025 12:41:44 -0500 Subject: [PATCH 08/22] Add stories --- .../date-picker/date-picker.stories.ts | 40 +++++++++++++++---- 1 file changed, 33 insertions(+), 7 deletions(-) diff --git a/packages/calcite-components/src/components/date-picker/date-picker.stories.ts b/packages/calcite-components/src/components/date-picker/date-picker.stories.ts index 6bfe0e83cb9..4c38d006811 100644 --- a/packages/calcite-components/src/components/date-picker/date-picker.stories.ts +++ b/packages/calcite-components/src/components/date-picker/date-picker.stories.ts @@ -61,13 +61,13 @@ export const simple = (args: DatePickerStoryArgs): string => html` export const range = (): string => html`
- + +
+`; + +export const rangeOneCalendar = (): string => html` +
+
`; @@ -84,6 +84,19 @@ export const rangeHighlighted_TestOnly = (): string => html` `; +export const rangeOneCalendarWithValue = (): string => html` +
+ +
+ +`; + export const rangeValuesNotInSameMonthAndYear_TestOnly = (): string => html`
@@ -97,6 +110,19 @@ export const rangeValuesNotInSameMonthAndYear_TestOnly = (): string => html` `; +export const rangeOneCalendarValuesNotInSameMonthAndYear = (): string => html` +
+ +
+ +`; + export const Focus = (): string => html`
From fb17cec882fed560685c79253ef5b1933c60f2a1 Mon Sep 17 00:00:00 2001 From: Anveshreddy mekala Date: Wed, 6 Aug 2025 09:36:35 -0500 Subject: [PATCH 09/22] change calendars type to number --- .../date-picker-month/date-picker-month.scss | 4 ++-- .../date-picker-month/date-picker-month.tsx | 6 +++--- .../src/components/date-picker/date-picker.e2e.ts | 10 +++++----- .../src/components/date-picker/date-picker.scss | 12 ++++++------ .../components/date-picker/date-picker.stories.ts | 6 +++--- .../src/components/date-picker/date-picker.tsx | 4 ++-- .../input-date-picker/input-date-picker.e2e.ts | 4 ++++ .../input-date-picker/input-date-picker.tsx | 2 +- .../calcite-components/src/demos/date-picker.html | 10 +++++----- 9 files changed, 31 insertions(+), 27 deletions(-) diff --git a/packages/calcite-components/src/components/date-picker-month/date-picker-month.scss b/packages/calcite-components/src/components/date-picker-month/date-picker-month.scss index 4c547317ec0..70a616b1661 100644 --- a/packages/calcite-components/src/components/date-picker-month/date-picker-month.scss +++ b/packages/calcite-components/src/components/date-picker-month/date-picker-month.scss @@ -96,11 +96,11 @@ border-color: var(--calcite-date-picker-range-calendar-divider-color, var(--calcite-color-border-1)); } -:host([range][layout="horizontal"][calendars="two"]) .calendar--start { +:host([range][layout="horizontal"][calendars="2"]) .calendar--start { border-inline-end-width: var(--calcite-border-width-sm); } -:host([range][layout="vertical"][calendars="two"]) .calendar--start { +:host([range][layout="vertical"][calendars="2"]) .calendar--start { border-block-end-width: var(--calcite-border-width-sm); } diff --git a/packages/calcite-components/src/components/date-picker-month/date-picker-month.tsx b/packages/calcite-components/src/components/date-picker-month/date-picker-month.tsx index 88f51c6e4e7..9a9894d6024 100644 --- a/packages/calcite-components/src/components/date-picker-month/date-picker-month.tsx +++ b/packages/calcite-components/src/components/date-picker-month/date-picker-month.tsx @@ -64,7 +64,7 @@ export class DatePickerMonth extends LitElement { @property() activeDate: Date = new Date(); /** Specifies the number of calendars displayed when `range` is `true`. */ - @property({ reflect: true }) calendars: "one" | "two" = "two"; + @property({ type: Number, reflect: true }) calendars: 1 | 2 = 2; /** * The DateTimeFormat used to provide screen reader labels. @@ -609,7 +609,7 @@ export class DatePickerMonth extends LitElement {
{this.renderCalendar(adjustedWeekDays, days)} {this.range && - this.calendars === "two" && + this.calendars === 2 && this.renderCalendar(adjustedWeekDays, nextMonthDays, true)}
); @@ -693,7 +693,7 @@ export class DatePickerMonth extends LitElement { min={this.min} monthStyle={this.monthStyle} oncalciteInternalDatePickerMonthHeaderSelectChange={this.monthHeaderSelectChange} - position={isEndCalendar ? "end" : this.range && this.calendars === "two" ? "start" : null} + position={isEndCalendar ? "end" : this.range && this.calendars === 2 ? "start" : null} scale={this.scale} selectedDate={this.selectedDate} /> diff --git a/packages/calcite-components/src/components/date-picker/date-picker.e2e.ts b/packages/calcite-components/src/components/date-picker/date-picker.e2e.ts index b5866f141b3..0a86e560236 100644 --- a/packages/calcite-components/src/components/date-picker/date-picker.e2e.ts +++ b/packages/calcite-components/src/components/date-picker/date-picker.e2e.ts @@ -28,7 +28,7 @@ describe("calcite-date-picker", () => { }, { propertyName: "calendars", - defaultValue: "two", + defaultValue: 2, }, { propertyName: "monthStyle", @@ -112,7 +112,7 @@ describe("calcite-date-picker", () => { it("emits calciteDatePickerRangeChange event and updates value property when start & end dates are selected from same month in range with one calendar", async () => { const page = await newE2EPage(); - await page.setContent(``); + await page.setContent(``); const datePicker = await page.find("calcite-date-picker"); const eventSpy = await page.spyOnEvent("calciteDatePickerRangeChange"); @@ -462,7 +462,7 @@ describe("calcite-date-picker", () => { it("should be able to navigate between months and select date using arrow keys & page keys when calendars is to set to one in range", async () => { const page = await newE2EPage(); - await page.setContent(html``); + await page.setContent(html``); await page.waitForChanges(); const datePicker = await page.find("calcite-date-picker"); @@ -554,7 +554,7 @@ describe("calcite-date-picker", () => { it("should be able to navigate between months and select date using arrow keys & page keys in range when value is parsed in range with one calendar", async () => { const page = await newE2EPage(); - await page.setContent(html``); + await page.setContent(html``); const datePicker = await page.find("calcite-date-picker"); datePicker.setProperty("value", ["2024-01-01", "2024-02-10"]); @@ -733,7 +733,7 @@ describe("calcite-date-picker", () => { it("should allow selecting first and last valid month from select menu when calendars is set to one in range", async () => { const page = await newE2EPage(); await page.setContent( - html``, + html``, ); await setActiveDate(page, "07-01-2024"); diff --git a/packages/calcite-components/src/components/date-picker/date-picker.scss b/packages/calcite-components/src/components/date-picker/date-picker.scss index 1e227d946af..a76b47daf5b 100644 --- a/packages/calcite-components/src/components/date-picker/date-picker.scss +++ b/packages/calcite-components/src/components/date-picker/date-picker.scss @@ -39,39 +39,39 @@ } :host([scale="s"]), -:host([scale="s"][range][calendars="one"]) { +:host([scale="s"][range][calendars="1"]) { inline-size: 236px; min-inline-size: 216px; max-inline-size: 380px; } -:host([scale="s"][range][layout="horizontal"][calendars="two"]) { +:host([scale="s"][range][layout="horizontal"][calendars="2"]) { inline-size: 480px; min-inline-size: 432px; max-inline-size: 772px; } :host([scale="m"]), -:host([scale="m"][range][calendars="one"]) { +:host([scale="m"][range][calendars="1"]) { inline-size: 298px; min-inline-size: 272px; max-inline-size: 480px; } -:host([scale="m"][layout="horizontal"][range][calendars="two"]) { +:host([scale="m"][layout="horizontal"][range][calendars="2"]) { inline-size: 608px; min-inline-size: 544px; max-inline-size: 972px; } :host([scale="l"]), -:host([scale="l"][range][calendars="one"]) { +:host([scale="l"][range][calendars="1"]) { inline-size: 334px; min-inline-size: 320px; max-inline-size: 600px; } -:host([scale="l"][layout="horizontal"][range][calendars="two"]) { +:host([scale="l"][layout="horizontal"][range][calendars="2"]) { inline-size: 684px; min-inline-size: 640px; max-inline-size: 1212px; diff --git a/packages/calcite-components/src/components/date-picker/date-picker.stories.ts b/packages/calcite-components/src/components/date-picker/date-picker.stories.ts index 4c38d006811..c65e4af6dcf 100644 --- a/packages/calcite-components/src/components/date-picker/date-picker.stories.ts +++ b/packages/calcite-components/src/components/date-picker/date-picker.stories.ts @@ -67,7 +67,7 @@ export const range = (): string => html` export const rangeOneCalendar = (): string => html`
- +
`; @@ -86,7 +86,7 @@ export const rangeHighlighted_TestOnly = (): string => html` export const rangeOneCalendarWithValue = (): string => html`
- +