diff --git a/angular/src/directives/proxies.ts b/angular/src/directives/proxies.ts index e0a36eb59a9..32d31f9414b 100644 --- a/angular/src/directives/proxies.ts +++ b/angular/src/directives/proxies.ts @@ -524,14 +524,14 @@ export declare interface IonDatetime extends Components.IonDatetime { @ProxyCmp({ defineCustomElementFn: undefined, - inputs: ['cancelText', 'clearText', 'color', 'dayValues', 'disabled', 'doneText', 'firstDayOfWeek', 'hourCycle', 'hourValues', 'isDateEnabled', 'locale', 'max', 'min', 'minuteValues', 'mode', 'monthValues', 'multiple', 'name', 'preferWheel', 'presentation', 'readonly', 'showClearButton', 'showDefaultButtons', 'showDefaultTimeLabel', 'showDefaultTitle', 'size', 'titleSelectedDatesFormatter', 'value', 'yearValues'], + inputs: ['cancelText', 'clearText', 'color', 'dayValues', 'disabled', 'doneText', 'firstDayOfWeek', 'highlightedDates', 'hourCycle', 'hourValues', 'isDateEnabled', 'locale', 'max', 'min', 'minuteValues', 'mode', 'monthValues', 'multiple', 'name', 'preferWheel', 'presentation', 'readonly', 'showClearButton', 'showDefaultButtons', 'showDefaultTimeLabel', 'showDefaultTitle', 'size', 'titleSelectedDatesFormatter', 'value', 'yearValues'], methods: ['confirm', 'reset', 'cancel'] }) @Component({ selector: 'ion-datetime', changeDetection: ChangeDetectionStrategy.OnPush, template: '', - inputs: ['cancelText', 'clearText', 'color', 'dayValues', 'disabled', 'doneText', 'firstDayOfWeek', 'hourCycle', 'hourValues', 'isDateEnabled', 'locale', 'max', 'min', 'minuteValues', 'mode', 'monthValues', 'multiple', 'name', 'preferWheel', 'presentation', 'readonly', 'showClearButton', 'showDefaultButtons', 'showDefaultTimeLabel', 'showDefaultTitle', 'size', 'titleSelectedDatesFormatter', 'value', 'yearValues'] + inputs: ['cancelText', 'clearText', 'color', 'dayValues', 'disabled', 'doneText', 'firstDayOfWeek', 'highlightedDates', 'hourCycle', 'hourValues', 'isDateEnabled', 'locale', 'max', 'min', 'minuteValues', 'mode', 'monthValues', 'multiple', 'name', 'preferWheel', 'presentation', 'readonly', 'showClearButton', 'showDefaultButtons', 'showDefaultTimeLabel', 'showDefaultTitle', 'size', 'titleSelectedDatesFormatter', 'value', 'yearValues'] }) export class IonDatetime { protected el: HTMLElement; diff --git a/core/api.txt b/core/api.txt index 8eb31c06047..9783b904b80 100644 --- a/core/api.txt +++ b/core/api.txt @@ -377,6 +377,7 @@ ion-datetime,prop,dayValues,number | number[] | string | undefined,undefined,fal ion-datetime,prop,disabled,boolean,false,false,false ion-datetime,prop,doneText,string,'Done',false,false ion-datetime,prop,firstDayOfWeek,number,0,false,false +ion-datetime,prop,highlightedDates,((dateIsoString: string) => DatetimeHighlightStyle | undefined) | DatetimeHighlight[] | undefined,undefined,false,false ion-datetime,prop,hourCycle,"h12" | "h23" | undefined,undefined,false,false ion-datetime,prop,hourValues,number | number[] | string | undefined,undefined,false,false ion-datetime,prop,isDateEnabled,((dateIsoString: string) => boolean) | undefined,undefined,false,false diff --git a/core/src/components.d.ts b/core/src/components.d.ts index 1164b07ad0a..844887bb26d 100644 --- a/core/src/components.d.ts +++ b/core/src/components.d.ts @@ -5,9 +5,10 @@ * It contains typing information for all components that exist in this project. */ import { HTMLStencilElement, JSXBase } from "@stencil/core/internal"; -import { AccordionGroupChangeEventDetail, ActionSheetAttributes, ActionSheetButton, AlertButton, AlertInput, AnimationBuilder, AutocompleteTypes, BreadcrumbCollapsedClickEventDetail, CheckboxChangeEventDetail, Color, ComponentProps, ComponentRef, DatetimeChangeEventDetail, DatetimePresentation, DomRenderFn, FooterHeightFn, FrameworkDelegate, HeaderFn, HeaderHeightFn, InputChangeEventDetail, ItemHeightFn, ItemRenderFn, ItemReorderEventDetail, LoadingAttributes, MenuChangeEventDetail, ModalAttributes, ModalBreakpointChangeEventDetail, ModalHandleBehavior, NavComponent, NavComponentWithProps, NavOptions, OverlayEventDetail, PickerAttributes, PickerButton, PickerColumn, PopoverAttributes, PopoverSize, PositionAlign, PositionReference, PositionSide, RadioGroupChangeEventDetail, RangeChangeEventDetail, RangeKnobMoveEndEventDetail, RangeKnobMoveStartEventDetail, RangeValue, RefresherEventDetail, RouteID, RouterDirection, RouterEventDetail, RouterOutletOptions, RouteWrite, ScrollBaseDetail, ScrollDetail, SearchbarChangeEventDetail, SegmentButtonLayout, SegmentChangeEventDetail, SelectChangeEventDetail, SelectInterface, SelectPopoverOption, Side, SpinnerTypes, StyleEventDetail, SwipeGestureHandler, TabBarChangedEventDetail, TabButtonClickEventDetail, TabButtonLayout, TextareaChangeEventDetail, TextFieldTypes, TitleSelectedDatesFormatter, ToastButton, ToggleChangeEventDetail, TransitionDoneFn, TransitionInstruction, TriggerAction, ViewController } from "./interface"; +import { AccordionGroupChangeEventDetail, ActionSheetAttributes, ActionSheetButton, AlertButton, AlertInput, AnimationBuilder, AutocompleteTypes, BreadcrumbCollapsedClickEventDetail, CheckboxChangeEventDetail, Color, ComponentProps, ComponentRef, DomRenderFn, FooterHeightFn, FrameworkDelegate, HeaderFn, HeaderHeightFn, InputChangeEventDetail, ItemHeightFn, ItemRenderFn, ItemReorderEventDetail, LoadingAttributes, MenuChangeEventDetail, ModalAttributes, ModalBreakpointChangeEventDetail, ModalHandleBehavior, NavComponent, NavComponentWithProps, NavOptions, OverlayEventDetail, PickerAttributes, PickerButton, PickerColumn, PopoverAttributes, PopoverSize, PositionAlign, PositionReference, PositionSide, RadioGroupChangeEventDetail, RangeChangeEventDetail, RangeKnobMoveEndEventDetail, RangeKnobMoveStartEventDetail, RangeValue, RefresherEventDetail, RouteID, RouterDirection, RouterEventDetail, RouterOutletOptions, RouteWrite, ScrollBaseDetail, ScrollDetail, SearchbarChangeEventDetail, SegmentButtonLayout, SegmentChangeEventDetail, SelectChangeEventDetail, SelectInterface, SelectPopoverOption, Side, SpinnerTypes, StyleEventDetail, SwipeGestureHandler, TabBarChangedEventDetail, TabButtonClickEventDetail, TabButtonLayout, TextareaChangeEventDetail, TextFieldTypes, ToastButton, ToggleChangeEventDetail, TransitionDoneFn, TransitionInstruction, TriggerAction, ViewController } from "./interface"; import { IonicSafeString } from "./utils/sanitization"; import { AlertAttributes } from "./components/alert/alert-interface"; +import { DatetimeChangeEventDetail, DatetimeHighlight, DatetimeHighlightCallback, DatetimePresentation, TitleSelectedDatesFormatter } from "./components/datetime/datetime-interface"; import { CounterFormatter } from "./components/item/item-interface"; import { PickerColumnItem } from "./components/picker-column-internal/picker-column-internal-interfaces"; import { PickerInternalChangeEventDetail } from "./components/picker-internal/picker-internal-interfaces"; @@ -757,6 +758,10 @@ export namespace Components { * The first day of the week to use for `ion-datetime`. The default value is `0` and represents Sunday. */ "firstDayOfWeek": number; + /** + * Used to apply custom text and background colors to specific dates. Can be either an array of objects containing ISO strings and colors, or a callback that receives an ISO string and returns the colors. Only applies to the `date`, `date-time`, and `time-date` presentations, with `preferWheel="false"`. + */ + "highlightedDates"?: DatetimeHighlight[] | DatetimeHighlightCallback; /** * The hour cycle of the `ion-datetime`. If no value is set, this is specified by the current locale. */ @@ -4727,6 +4732,10 @@ declare namespace LocalJSX { * The first day of the week to use for `ion-datetime`. The default value is `0` and represents Sunday. */ "firstDayOfWeek"?: number; + /** + * Used to apply custom text and background colors to specific dates. Can be either an array of objects containing ISO strings and colors, or a callback that receives an ISO string and returns the colors. Only applies to the `date`, `date-time`, and `time-date` presentations, with `preferWheel="false"`. + */ + "highlightedDates"?: DatetimeHighlight[] | DatetimeHighlightCallback; /** * The hour cycle of the `ion-datetime`. If no value is set, this is specified by the current locale. */ diff --git a/core/src/components/datetime/datetime-interface.ts b/core/src/components/datetime/datetime-interface.ts index 83aa501af82..4fea1af5663 100644 --- a/core/src/components/datetime/datetime-interface.ts +++ b/core/src/components/datetime/datetime-interface.ts @@ -25,3 +25,17 @@ export interface DatetimeParts { export type DatetimePresentation = 'date-time' | 'time-date' | 'date' | 'time' | 'month' | 'year' | 'month-year'; export type TitleSelectedDatesFormatter = (selectedDates: string[]) => string; + +export type DatetimeHighlightStyle = + | { + textColor: string; + backgroundColor?: string; + } + | { + textColor?: string; + backgroundColor: string; + }; + +export type DatetimeHighlight = { date: string } & DatetimeHighlightStyle; + +export type DatetimeHighlightCallback = (dateIsoString: string) => DatetimeHighlightStyle | undefined; diff --git a/core/src/components/datetime/datetime.ios.scss b/core/src/components/datetime/datetime.ios.scss index 1ce28a13506..155ab6d5f77 100644 --- a/core/src/components/datetime/datetime.ios.scss +++ b/core/src/components/datetime/datetime.ios.scss @@ -92,14 +92,22 @@ font-size: 20px; } -:host .calendar-day:after { +.calendar-day:focus .calendar-day-highlight, +.calendar-day.calendar-day-active .calendar-day-highlight { opacity: 0.2; } -:host .calendar-day:focus:after { +.calendar-day.calendar-day-active .calendar-day-highlight { background: current-color(base); } +// !important is needed here to overwrite custom highlight background, which is inline. +// Does not apply to the active state because highlights aren't applied at all there. +.calendar-day:focus .calendar-day-highlight { + /* stylelint-disable-next-line declaration-no-important */ + background: current-color(base) !important; +} + /** * Day that today but not selected * should have ion-color for text color. @@ -119,10 +127,6 @@ font-weight: 600; } -:host .calendar-day.calendar-day-active:after { - background: current-color(base); -} - /** * Day that is selected and is today * should have white color. @@ -131,7 +135,7 @@ color: current-color(contrast); } -:host .calendar-day.calendar-day-today.calendar-day-active:after { +.calendar-day.calendar-day-today.calendar-day-active .calendar-day-highlight { background: current-color(base); opacity: 1; diff --git a/core/src/components/datetime/datetime.md.scss b/core/src/components/datetime/datetime.md.scss index 5d74dd563d6..832b61fec83 100644 --- a/core/src/components/datetime/datetime.md.scss +++ b/core/src/components/datetime/datetime.md.scss @@ -74,7 +74,7 @@ font-size: $datetime-md-calendar-item-font-size; } -:host .calendar-day:focus:after { +.calendar-day:focus .calendar-day-highlight { background: current-color(base, 0.2); box-shadow: 0px 0px 0px 4px current-color(base, 0.2); @@ -88,7 +88,7 @@ color: current-color(base); } -:host .calendar-day.calendar-day-today:after { +.calendar-day.calendar-day-today .calendar-day-highlight { border: 1px solid current-color(base); } @@ -101,7 +101,7 @@ color: current-color(contrast); } -:host .calendar-day.calendar-day-active:after { +.calendar-day.calendar-day-active .calendar-day-highlight { border: 1px solid current-color(base); background: current-color(base); diff --git a/core/src/components/datetime/datetime.scss b/core/src/components/datetime/datetime.scss index 71c997ef661..3bd90f3bb29 100644 --- a/core/src/components/datetime/datetime.scss +++ b/core/src/components/datetime/datetime.scss @@ -356,31 +356,15 @@ ion-picker-column-internal { opacity: 0.4; } -:host .calendar-day:after { +.calendar-day-highlight { @include border-radius(32px, 32px, 32px, 32px); @include padding(4px, 4px, 4px, 4px); position: absolute; - /** - * Explicit position values are required here - * as pseudo element positioning is incorrect - * in older implementations of css grid. - * - * TODO: FW-1720: Remove top/left styles when deprecating iOS 13 support - */ - /* stylelint-disable-next-line property-disallowed-list */ - top: 50%; - /* stylelint-disable-next-line property-disallowed-list */ - left: 50%; - width: 32px; height: 32px; - transform: translate(-50%, -50%); - - content: " "; - z-index: -1; } diff --git a/core/src/components/datetime/datetime.tsx b/core/src/components/datetime/datetime.tsx index 63cf10adf3a..f92c2abbc4e 100644 --- a/core/src/components/datetime/datetime.tsx +++ b/core/src/components/datetime/datetime.tsx @@ -3,15 +3,7 @@ import { Component, Element, Event, Host, Method, Prop, State, Watch, h, writeTa import { caretDownSharp, caretUpSharp, chevronBack, chevronDown, chevronForward } from 'ionicons/icons'; import { getIonMode } from '../../global/ionic-global'; -import type { - Color, - DatetimePresentation, - DatetimeChangeEventDetail, - DatetimeParts, - Mode, - StyleEventDetail, - TitleSelectedDatesFormatter, -} from '../../interface'; +import type { Color, Mode, StyleEventDetail } from '../../interface'; import { startFocusVisible } from '../../utils/focus-visible'; import { getElementRoot, raf, renderHiddenInput } from '../../utils/helpers'; import { printIonError, printIonWarning } from '../../utils/logging'; @@ -19,6 +11,15 @@ import { isRTL } from '../../utils/rtl'; import { createColorClasses } from '../../utils/theme'; import type { PickerColumnItem } from '../picker-column-internal/picker-column-internal-interfaces'; +import type { + DatetimePresentation, + DatetimeChangeEventDetail, + DatetimeParts, + TitleSelectedDatesFormatter, + DatetimeHighlight, + DatetimeHighlightStyle, + DatetimeHighlightCallback, +} from './datetime-interface'; import { isSameDay, warnIfValueOutOfBounds, isBefore, isAfter } from './utils/comparison'; import { generateMonths, @@ -60,6 +61,7 @@ import { } from './utils/parse'; import { getCalendarDayState, + getHighlightStyles, isDayDisabled, isMonthDisabled, isNextMonthDisabled, @@ -322,6 +324,17 @@ export class Datetime implements ComponentInterface { */ @Prop() multiple = false; + /** + * Used to apply custom text and background colors to specific dates. + * + * Can be either an array of objects containing ISO strings and colors, + * or a callback that receives an ISO string and returns the colors. + * + * Only applies to the `date`, `date-time`, and `time-date` presentations, + * with `preferWheel="false"`. + */ + @Prop() highlightedDates?: DatetimeHighlight[] | DatetimeHighlightCallback; + /** * The value of the datetime as a valid ISO 8601 datetime string. * Should be an array of strings if `multiple="true"`. @@ -1235,7 +1248,7 @@ export class Datetime implements ComponentInterface { }; componentWillLoad() { - const { el, multiple, presentation, preferWheel } = this; + const { el, highlightedDates, multiple, presentation, preferWheel } = this; if (multiple) { if (presentation !== 'date') { @@ -1247,6 +1260,19 @@ export class Datetime implements ComponentInterface { } } + if (highlightedDates !== undefined) { + if (presentation !== 'date' && presentation !== 'date-time' && presentation !== 'time-date') { + printIonWarning( + 'The highlightedDates property is only supported with the date, date-time, and time-date presentations.', + el + ); + } + + if (preferWheel) { + printIonWarning('The highlightedDates property is not supported with preferWheel="true".', el); + } + } + this.processMinParts(); this.processMaxParts(); const hourValues = (this.parsedHourValues = convertToArrayOfNumbers(this.hourValues)); @@ -1971,7 +1997,7 @@ export class Datetime implements ComponentInterface {
{getDaysOfMonth(month, year, this.firstDayOfWeek % 7).map((dateObject, index) => { const { day, dayOfWeek } = dateObject; - const { isDateEnabled, multiple } = this; + const { el, highlightedDates, isDateEnabled, multiple } = this; const referenceParts = { month, day, year }; const { isActive, isToday, ariaLabel, ariaSelected, disabled, text } = getCalendarDayState( this.locale, @@ -1983,6 +2009,7 @@ export class Datetime implements ComponentInterface { this.parsedDayValues ); + const dateIsoString = convertDataToISO(referenceParts); let isCalDayDisabled = isCalMonthDisabled || disabled; if (!isCalDayDisabled && isDateEnabled !== undefined) { @@ -1992,15 +2019,26 @@ export class Datetime implements ComponentInterface { * to prevent exceptions in the user's function from * interrupting the calendar rendering. */ - isCalDayDisabled = !isDateEnabled(convertDataToISO(referenceParts)); + isCalDayDisabled = !isDateEnabled(dateIsoString); } catch (e) { printIonError( 'Exception thrown from provided `isDateEnabled` function. Please check your function and try again.', + el, e ); } } + let dateStyle: DatetimeHighlightStyle | undefined = undefined; + + /** + * Custom highlight styles should not override the style for selected dates, + * nor apply to "filler days" at the start of the grid. + */ + if (highlightedDates !== undefined && !isActive && day !== null) { + dateStyle = getHighlightStyles(highlightedDates, dateIsoString, el); + } + return ( ); diff --git a/core/src/components/datetime/test/highlightedDates/datetime.e2e.ts b/core/src/components/datetime/test/highlightedDates/datetime.e2e.ts new file mode 100644 index 00000000000..2edebb7cffa --- /dev/null +++ b/core/src/components/datetime/test/highlightedDates/datetime.e2e.ts @@ -0,0 +1,103 @@ +import { expect } from '@playwright/test'; +import { test } from '@utils/test/playwright'; + +test.describe('datetime: highlightedDates', () => { + test.beforeEach(async ({ page, skip }) => { + skip.rtl(); + + await page.setContent(` + + `); + }); + + test('should render highlights correctly when using an array', async ({ page }) => { + const datetime = page.locator('ion-datetime'); + + await datetime.evaluate((el: HTMLIonDatetimeElement) => { + el.highlightedDates = [ + { + date: '2023-01-01', // ensure selected date style overrides highlight + textColor: '#800080', + backgroundColor: '#ffc0cb', + }, + { + date: '2023-01-02', + textColor: '#b22222', + backgroundColor: '#fa8072', + }, + { + date: '2023-01-03', + textColor: '#0000ff', + backgroundColor: '#add8e6', + }, + ]; + }); + + await page.waitForChanges(); + expect(await datetime.screenshot()).toMatchSnapshot( + `datetime-highlightedDates-array-${page.getSnapshotSettings()}.png` + ); + }); + + test('should render highlights correctly when using a callback', async ({ page }) => { + const datetime = page.locator('ion-datetime'); + + await datetime.evaluate((el: HTMLIonDatetimeElement) => { + el.highlightedDates = (isoString) => { + const date = new Date(isoString); + const utcDay = date.getUTCDate(); + + // ensure selected date style overrides highlight + if (utcDay === 1) { + return { + textColor: '#b22222', + backgroundColor: '#fa8072', + }; + } + + if (utcDay % 5 === 0) { + return { + textColor: '#800080', + backgroundColor: '#ffc0cb', + }; + } + + if (utcDay % 3 === 0) { + return { + textColor: '#0000ff', + backgroundColor: '#add8e6', + }; + } + + return undefined; + }; + }); + + await page.waitForChanges(); + expect(await datetime.screenshot()).toMatchSnapshot( + `datetime-highlightedDates-callback-${page.getSnapshotSettings()}.png` + ); + }); + + test('should render highlights correctly when only using one color or the other', async ({ page }) => { + const datetime = page.locator('ion-datetime'); + + await datetime.evaluate((el: HTMLIonDatetimeElement) => { + el.highlightedDates = [ + { + date: '2023-01-02', + backgroundColor: '#fa8072', + }, + { + date: '2023-01-03', + textColor: '#0000ff', + }, + ]; + }); + + await page.waitForChanges(); + expect(await datetime.screenshot()).toMatchSnapshot( + `datetime-highlightedDates-single-color-${page.getSnapshotSettings()}.png` + ); + }); +}); diff --git a/core/src/components/datetime/test/highlightedDates/datetime.e2e.ts-snapshots/datetime-highlightedDates-array-ios-ltr-Mobile-Chrome-linux.png b/core/src/components/datetime/test/highlightedDates/datetime.e2e.ts-snapshots/datetime-highlightedDates-array-ios-ltr-Mobile-Chrome-linux.png new file mode 100644 index 00000000000..86a3447122c Binary files /dev/null and b/core/src/components/datetime/test/highlightedDates/datetime.e2e.ts-snapshots/datetime-highlightedDates-array-ios-ltr-Mobile-Chrome-linux.png differ diff --git a/core/src/components/datetime/test/highlightedDates/datetime.e2e.ts-snapshots/datetime-highlightedDates-array-ios-ltr-Mobile-Firefox-linux.png b/core/src/components/datetime/test/highlightedDates/datetime.e2e.ts-snapshots/datetime-highlightedDates-array-ios-ltr-Mobile-Firefox-linux.png new file mode 100644 index 00000000000..c751dd3858a Binary files /dev/null and b/core/src/components/datetime/test/highlightedDates/datetime.e2e.ts-snapshots/datetime-highlightedDates-array-ios-ltr-Mobile-Firefox-linux.png differ diff --git a/core/src/components/datetime/test/highlightedDates/datetime.e2e.ts-snapshots/datetime-highlightedDates-array-ios-ltr-Mobile-Safari-linux.png b/core/src/components/datetime/test/highlightedDates/datetime.e2e.ts-snapshots/datetime-highlightedDates-array-ios-ltr-Mobile-Safari-linux.png new file mode 100644 index 00000000000..d58794cf180 Binary files /dev/null and b/core/src/components/datetime/test/highlightedDates/datetime.e2e.ts-snapshots/datetime-highlightedDates-array-ios-ltr-Mobile-Safari-linux.png differ diff --git a/core/src/components/datetime/test/highlightedDates/datetime.e2e.ts-snapshots/datetime-highlightedDates-array-md-ltr-Mobile-Chrome-linux.png b/core/src/components/datetime/test/highlightedDates/datetime.e2e.ts-snapshots/datetime-highlightedDates-array-md-ltr-Mobile-Chrome-linux.png new file mode 100644 index 00000000000..c5084a62304 Binary files /dev/null and b/core/src/components/datetime/test/highlightedDates/datetime.e2e.ts-snapshots/datetime-highlightedDates-array-md-ltr-Mobile-Chrome-linux.png differ diff --git a/core/src/components/datetime/test/highlightedDates/datetime.e2e.ts-snapshots/datetime-highlightedDates-array-md-ltr-Mobile-Firefox-linux.png b/core/src/components/datetime/test/highlightedDates/datetime.e2e.ts-snapshots/datetime-highlightedDates-array-md-ltr-Mobile-Firefox-linux.png new file mode 100644 index 00000000000..7d98d74a71e Binary files /dev/null and b/core/src/components/datetime/test/highlightedDates/datetime.e2e.ts-snapshots/datetime-highlightedDates-array-md-ltr-Mobile-Firefox-linux.png differ diff --git a/core/src/components/datetime/test/highlightedDates/datetime.e2e.ts-snapshots/datetime-highlightedDates-array-md-ltr-Mobile-Safari-linux.png b/core/src/components/datetime/test/highlightedDates/datetime.e2e.ts-snapshots/datetime-highlightedDates-array-md-ltr-Mobile-Safari-linux.png new file mode 100644 index 00000000000..b138075ff54 Binary files /dev/null and b/core/src/components/datetime/test/highlightedDates/datetime.e2e.ts-snapshots/datetime-highlightedDates-array-md-ltr-Mobile-Safari-linux.png differ diff --git a/core/src/components/datetime/test/highlightedDates/datetime.e2e.ts-snapshots/datetime-highlightedDates-callback-ios-ltr-Mobile-Chrome-linux.png b/core/src/components/datetime/test/highlightedDates/datetime.e2e.ts-snapshots/datetime-highlightedDates-callback-ios-ltr-Mobile-Chrome-linux.png new file mode 100644 index 00000000000..e566c190d98 Binary files /dev/null and b/core/src/components/datetime/test/highlightedDates/datetime.e2e.ts-snapshots/datetime-highlightedDates-callback-ios-ltr-Mobile-Chrome-linux.png differ diff --git a/core/src/components/datetime/test/highlightedDates/datetime.e2e.ts-snapshots/datetime-highlightedDates-callback-ios-ltr-Mobile-Firefox-linux.png b/core/src/components/datetime/test/highlightedDates/datetime.e2e.ts-snapshots/datetime-highlightedDates-callback-ios-ltr-Mobile-Firefox-linux.png new file mode 100644 index 00000000000..bd77a99038c Binary files /dev/null and b/core/src/components/datetime/test/highlightedDates/datetime.e2e.ts-snapshots/datetime-highlightedDates-callback-ios-ltr-Mobile-Firefox-linux.png differ diff --git a/core/src/components/datetime/test/highlightedDates/datetime.e2e.ts-snapshots/datetime-highlightedDates-callback-ios-ltr-Mobile-Safari-linux.png b/core/src/components/datetime/test/highlightedDates/datetime.e2e.ts-snapshots/datetime-highlightedDates-callback-ios-ltr-Mobile-Safari-linux.png new file mode 100644 index 00000000000..58c1376934f Binary files /dev/null and b/core/src/components/datetime/test/highlightedDates/datetime.e2e.ts-snapshots/datetime-highlightedDates-callback-ios-ltr-Mobile-Safari-linux.png differ diff --git a/core/src/components/datetime/test/highlightedDates/datetime.e2e.ts-snapshots/datetime-highlightedDates-callback-md-ltr-Mobile-Chrome-linux.png b/core/src/components/datetime/test/highlightedDates/datetime.e2e.ts-snapshots/datetime-highlightedDates-callback-md-ltr-Mobile-Chrome-linux.png new file mode 100644 index 00000000000..75685f791a4 Binary files /dev/null and b/core/src/components/datetime/test/highlightedDates/datetime.e2e.ts-snapshots/datetime-highlightedDates-callback-md-ltr-Mobile-Chrome-linux.png differ diff --git a/core/src/components/datetime/test/highlightedDates/datetime.e2e.ts-snapshots/datetime-highlightedDates-callback-md-ltr-Mobile-Firefox-linux.png b/core/src/components/datetime/test/highlightedDates/datetime.e2e.ts-snapshots/datetime-highlightedDates-callback-md-ltr-Mobile-Firefox-linux.png new file mode 100644 index 00000000000..b8646fde35b Binary files /dev/null and b/core/src/components/datetime/test/highlightedDates/datetime.e2e.ts-snapshots/datetime-highlightedDates-callback-md-ltr-Mobile-Firefox-linux.png differ diff --git a/core/src/components/datetime/test/highlightedDates/datetime.e2e.ts-snapshots/datetime-highlightedDates-callback-md-ltr-Mobile-Safari-linux.png b/core/src/components/datetime/test/highlightedDates/datetime.e2e.ts-snapshots/datetime-highlightedDates-callback-md-ltr-Mobile-Safari-linux.png new file mode 100644 index 00000000000..da31daf14a5 Binary files /dev/null and b/core/src/components/datetime/test/highlightedDates/datetime.e2e.ts-snapshots/datetime-highlightedDates-callback-md-ltr-Mobile-Safari-linux.png differ diff --git a/core/src/components/datetime/test/highlightedDates/datetime.e2e.ts-snapshots/datetime-highlightedDates-single-color-ios-ltr-Mobile-Chrome-linux.png b/core/src/components/datetime/test/highlightedDates/datetime.e2e.ts-snapshots/datetime-highlightedDates-single-color-ios-ltr-Mobile-Chrome-linux.png new file mode 100644 index 00000000000..c18944f97dc Binary files /dev/null and b/core/src/components/datetime/test/highlightedDates/datetime.e2e.ts-snapshots/datetime-highlightedDates-single-color-ios-ltr-Mobile-Chrome-linux.png differ diff --git a/core/src/components/datetime/test/highlightedDates/datetime.e2e.ts-snapshots/datetime-highlightedDates-single-color-ios-ltr-Mobile-Firefox-linux.png b/core/src/components/datetime/test/highlightedDates/datetime.e2e.ts-snapshots/datetime-highlightedDates-single-color-ios-ltr-Mobile-Firefox-linux.png new file mode 100644 index 00000000000..457b3540834 Binary files /dev/null and b/core/src/components/datetime/test/highlightedDates/datetime.e2e.ts-snapshots/datetime-highlightedDates-single-color-ios-ltr-Mobile-Firefox-linux.png differ diff --git a/core/src/components/datetime/test/highlightedDates/datetime.e2e.ts-snapshots/datetime-highlightedDates-single-color-ios-ltr-Mobile-Safari-linux.png b/core/src/components/datetime/test/highlightedDates/datetime.e2e.ts-snapshots/datetime-highlightedDates-single-color-ios-ltr-Mobile-Safari-linux.png new file mode 100644 index 00000000000..2e9ff91ece0 Binary files /dev/null and b/core/src/components/datetime/test/highlightedDates/datetime.e2e.ts-snapshots/datetime-highlightedDates-single-color-ios-ltr-Mobile-Safari-linux.png differ diff --git a/core/src/components/datetime/test/highlightedDates/datetime.e2e.ts-snapshots/datetime-highlightedDates-single-color-md-ltr-Mobile-Chrome-linux.png b/core/src/components/datetime/test/highlightedDates/datetime.e2e.ts-snapshots/datetime-highlightedDates-single-color-md-ltr-Mobile-Chrome-linux.png new file mode 100644 index 00000000000..d71aad7f7b8 Binary files /dev/null and b/core/src/components/datetime/test/highlightedDates/datetime.e2e.ts-snapshots/datetime-highlightedDates-single-color-md-ltr-Mobile-Chrome-linux.png differ diff --git a/core/src/components/datetime/test/highlightedDates/datetime.e2e.ts-snapshots/datetime-highlightedDates-single-color-md-ltr-Mobile-Firefox-linux.png b/core/src/components/datetime/test/highlightedDates/datetime.e2e.ts-snapshots/datetime-highlightedDates-single-color-md-ltr-Mobile-Firefox-linux.png new file mode 100644 index 00000000000..c32b0135b73 Binary files /dev/null and b/core/src/components/datetime/test/highlightedDates/datetime.e2e.ts-snapshots/datetime-highlightedDates-single-color-md-ltr-Mobile-Firefox-linux.png differ diff --git a/core/src/components/datetime/test/highlightedDates/datetime.e2e.ts-snapshots/datetime-highlightedDates-single-color-md-ltr-Mobile-Safari-linux.png b/core/src/components/datetime/test/highlightedDates/datetime.e2e.ts-snapshots/datetime-highlightedDates-single-color-md-ltr-Mobile-Safari-linux.png new file mode 100644 index 00000000000..af652b53a90 Binary files /dev/null and b/core/src/components/datetime/test/highlightedDates/datetime.e2e.ts-snapshots/datetime-highlightedDates-single-color-md-ltr-Mobile-Safari-linux.png differ diff --git a/core/src/components/datetime/test/highlightedDates/index.html b/core/src/components/datetime/test/highlightedDates/index.html new file mode 100644 index 00000000000..965865b7b0f --- /dev/null +++ b/core/src/components/datetime/test/highlightedDates/index.html @@ -0,0 +1,110 @@ + + + + + Datetime - highlightedDates + + + + + + + + + + + + + Datetime - highlightedDates + + + +
+
+

With Array

+ +
+
+

With Callback

+ +
+
+

Highlight Today

+ +
+
+
+
+ + + + diff --git a/core/src/components/datetime/utils/state.ts b/core/src/components/datetime/utils/state.ts index 0d9200ffeb8..f709d7289a1 100644 --- a/core/src/components/datetime/utils/state.ts +++ b/core/src/components/datetime/utils/state.ts @@ -1,4 +1,11 @@ -import type { DatetimeParts } from '../datetime-interface'; +import { printIonError } from '@utils/logging'; + +import type { + DatetimeHighlight, + DatetimeHighlightCallback, + DatetimeHighlightStyle, + DatetimeParts, +} from '../datetime-interface'; import { isAfter, isBefore, isSameDay } from './comparison'; import { generateDayAriaLabel, getDay } from './format'; @@ -182,3 +189,41 @@ export const isNextMonthDisabled = (refParts: DatetimeParts, maxParts?: Datetime maxParts, }); }; + +/** + * Given the value of the highlightedDates property + * and an ISO string, return the styles to use for + * that date, or undefined if none are found. + */ +export const getHighlightStyles = ( + highlightedDates: DatetimeHighlight[] | DatetimeHighlightCallback, + dateIsoString: string, + el: HTMLIonDatetimeElement +): DatetimeHighlightStyle | undefined => { + if (Array.isArray(highlightedDates)) { + const dateStringWithoutTime = dateIsoString.split('T')[0]; + const matchingHighlight = highlightedDates.find((hd) => hd.date === dateStringWithoutTime); + if (matchingHighlight) { + return { + textColor: matchingHighlight.textColor, + backgroundColor: matchingHighlight.backgroundColor, + } as DatetimeHighlightStyle; + } + } else { + /** + * Wrap in a try-catch to prevent exceptions in the user's function + * from interrupting the calendar's rendering. + */ + try { + return highlightedDates(dateIsoString); + } catch (e) { + printIonError( + 'Exception thrown from provided `highlightedDates` callback. Please check your function and try again.', + el, + e + ); + } + } + + return undefined; +}; diff --git a/packages/vue/src/proxies.ts b/packages/vue/src/proxies.ts index efd8d274f42..9479c895deb 100644 --- a/packages/vue/src/proxies.ts +++ b/packages/vue/src/proxies.ts @@ -289,6 +289,7 @@ export const IonDatetime = /*@__PURE__*/ defineContainer('ion-d 'firstDayOfWeek', 'titleSelectedDatesFormatter', 'multiple', + 'highlightedDates', 'value', 'showDefaultTitle', 'showDefaultButtons',