Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 2a761af

Browse files
feat(datetime): add ability to specify custom colors for specific dates (#26775)
1 parent fc5fcc0 commit 2a761af

File tree

30 files changed

+363
-43
lines changed

30 files changed

+363
-43
lines changed

‎angular/src/directives/proxies.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -524,14 +524,14 @@ export declare interface IonDatetime extends Components.IonDatetime {
524524

525525
@ProxyCmp({
526526
defineCustomElementFn: undefined,
527-
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'],
527+
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'],
528528
methods: ['confirm', 'reset', 'cancel']
529529
})
530530
@Component({
531531
selector: 'ion-datetime',
532532
changeDetection: ChangeDetectionStrategy.OnPush,
533533
template: '<ng-content></ng-content>',
534-
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']
534+
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']
535535
})
536536
export class IonDatetime {
537537
protected el: HTMLElement;

‎core/api.txt‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,7 @@ ion-datetime,prop,dayValues,number | number[] | string | undefined,undefined,fal
377377
ion-datetime,prop,disabled,boolean,false,false,false
378378
ion-datetime,prop,doneText,string,'Done',false,false
379379
ion-datetime,prop,firstDayOfWeek,number,0,false,false
380+
ion-datetime,prop,highlightedDates,((dateIsoString: string) => DatetimeHighlightStyle | undefined) | DatetimeHighlight[] | undefined,undefined,false,false
380381
ion-datetime,prop,hourCycle,"h12" | "h23" | undefined,undefined,false,false
381382
ion-datetime,prop,hourValues,number | number[] | string | undefined,undefined,false,false
382383
ion-datetime,prop,isDateEnabled,((dateIsoString: string) => boolean) | undefined,undefined,false,false

‎core/src/components.d.ts‎

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,10 @@
55
* It contains typing information for all components that exist in this project.
66
*/
77
import { HTMLStencilElement, JSXBase } from "@stencil/core/internal";
8-
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";
8+
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";
99
import { IonicSafeString } from "./utils/sanitization";
1010
import { AlertAttributes } from "./components/alert/alert-interface";
11+
import { DatetimeChangeEventDetail, DatetimeHighlight, DatetimeHighlightCallback, DatetimePresentation, TitleSelectedDatesFormatter } from "./components/datetime/datetime-interface";
1112
import { CounterFormatter } from "./components/item/item-interface";
1213
import { PickerColumnItem } from "./components/picker-column-internal/picker-column-internal-interfaces";
1314
import { PickerInternalChangeEventDetail } from "./components/picker-internal/picker-internal-interfaces";
@@ -757,6 +758,10 @@ export namespace Components {
757758
* The first day of the week to use for `ion-datetime`. The default value is `0` and represents Sunday.
758759
*/
759760
"firstDayOfWeek": number;
761+
/**
762+
* 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"`.
763+
*/
764+
"highlightedDates"?: DatetimeHighlight[] | DatetimeHighlightCallback;
760765
/**
761766
* The hour cycle of the `ion-datetime`. If no value is set, this is specified by the current locale.
762767
*/
@@ -4727,6 +4732,10 @@ declare namespace LocalJSX {
47274732
* The first day of the week to use for `ion-datetime`. The default value is `0` and represents Sunday.
47284733
*/
47294734
"firstDayOfWeek"?: number;
4735+
/**
4736+
* 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"`.
4737+
*/
4738+
"highlightedDates"?: DatetimeHighlight[] | DatetimeHighlightCallback;
47304739
/**
47314740
* The hour cycle of the `ion-datetime`. If no value is set, this is specified by the current locale.
47324741
*/

‎core/src/components/datetime/datetime-interface.ts‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,17 @@ export interface DatetimeParts {
2525
export type DatetimePresentation = 'date-time' | 'time-date' | 'date' | 'time' | 'month' | 'year' | 'month-year';
2626

2727
export type TitleSelectedDatesFormatter = (selectedDates: string[]) => string;
28+
29+
export type DatetimeHighlightStyle =
30+
| {
31+
textColor: string;
32+
backgroundColor?: string;
33+
}
34+
| {
35+
textColor?: string;
36+
backgroundColor: string;
37+
};
38+
39+
export type DatetimeHighlight = { date: string } & DatetimeHighlightStyle;
40+
41+
export type DatetimeHighlightCallback = (dateIsoString: string) => DatetimeHighlightStyle | undefined;

‎core/src/components/datetime/datetime.ios.scss‎

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -92,14 +92,22 @@
9292
font-size: 20px;
9393
}
9494

95-
:host .calendar-day:after {
95+
.calendar-day:focus .calendar-day-highlight,
96+
.calendar-day.calendar-day-active .calendar-day-highlight {
9697
opacity: 0.2;
9798
}
9899

99-
:host .calendar-day:focus:after {
100+
.calendar-day.calendar-day-active .calendar-day-highlight {
100101
background: current-color(base);
101102
}
102103

104+
// !important is needed here to overwrite custom highlight background, which is inline.
105+
// Does not apply to the active state because highlights aren't applied at all there.
106+
.calendar-day:focus .calendar-day-highlight {
107+
/* stylelint-disable-next-line declaration-no-important */
108+
background: current-color(base) !important;
109+
}
110+
103111
/**
104112
* Day that today but not selected
105113
* should have ion-color for text color.
@@ -119,10 +127,6 @@
119127
font-weight: 600;
120128
}
121129

122-
:host .calendar-day.calendar-day-active:after {
123-
background: current-color(base);
124-
}
125-
126130
/**
127131
* Day that is selected and is today
128132
* should have white color.
@@ -131,7 +135,7 @@
131135
color: current-color(contrast);
132136
}
133137

134-
:host.calendar-day.calendar-day-today.calendar-day-active:after {
138+
.calendar-day.calendar-day-today.calendar-day-active.calendar-day-highlight {
135139
background: current-color(base);
136140

137141
opacity: 1;

‎core/src/components/datetime/datetime.md.scss‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@
7474
font-size: $datetime-md-calendar-item-font-size;
7575
}
7676

77-
:host.calendar-day:focus:after {
77+
.calendar-day:focus.calendar-day-highlight {
7878
background: current-color(base, 0.2);
7979

8080
box-shadow: 0px 0px 0px 4px current-color(base, 0.2);
@@ -88,7 +88,7 @@
8888
color: current-color(base);
8989
}
9090

91-
:host.calendar-day.calendar-day-today:after {
91+
.calendar-day.calendar-day-today.calendar-day-highlight {
9292
border: 1px solid current-color(base);
9393
}
9494

@@ -101,7 +101,7 @@
101101
color: current-color(contrast);
102102
}
103103

104-
:host.calendar-day.calendar-day-active:after {
104+
.calendar-day.calendar-day-active.calendar-day-highlight {
105105
border: 1px solid current-color(base);
106106

107107
background: current-color(base);

‎core/src/components/datetime/datetime.scss‎

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -356,31 +356,15 @@ ion-picker-column-internal {
356356
opacity: 0.4;
357357
}
358358

359-
:host.calendar-day:after {
359+
.calendar-day-highlight {
360360
@include border-radius(32px, 32px, 32px, 32px);
361361
@include padding(4px, 4px, 4px, 4px);
362362

363363
position: absolute;
364364

365-
/**
366-
* Explicit position values are required here
367-
* as pseudo element positioning is incorrect
368-
* in older implementations of css grid.
369-
*
370-
* TODO: FW-1720: Remove top/left styles when deprecating iOS 13 support
371-
*/
372-
/* stylelint-disable-next-line property-disallowed-list */
373-
top: 50%;
374-
/* stylelint-disable-next-line property-disallowed-list */
375-
left: 50%;
376-
377365
width: 32px;
378366
height: 32px;
379367

380-
transform: translate(-50%, -50%);
381-
382-
content: " ";
383-
384368
z-index: -1;
385369
}
386370

‎core/src/components/datetime/datetime.tsx‎

Lines changed: 61 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,22 +3,23 @@ import { Component, Element, Event, Host, Method, Prop, State, Watch, h, writeTa
33
import { caretDownSharp, caretUpSharp, chevronBack, chevronDown, chevronForward } from 'ionicons/icons';
44

55
import { getIonMode } from '../../global/ionic-global';
6-
import type {
7-
Color,
8-
DatetimePresentation,
9-
DatetimeChangeEventDetail,
10-
DatetimeParts,
11-
Mode,
12-
StyleEventDetail,
13-
TitleSelectedDatesFormatter,
14-
} from '../../interface';
6+
import type { Color, Mode, StyleEventDetail } from '../../interface';
157
import { startFocusVisible } from '../../utils/focus-visible';
168
import { getElementRoot, raf, renderHiddenInput } from '../../utils/helpers';
179
import { printIonError, printIonWarning } from '../../utils/logging';
1810
import { isRTL } from '../../utils/rtl';
1911
import { createColorClasses } from '../../utils/theme';
2012
import type { PickerColumnItem } from '../picker-column-internal/picker-column-internal-interfaces';
2113

14+
import type {
15+
DatetimePresentation,
16+
DatetimeChangeEventDetail,
17+
DatetimeParts,
18+
TitleSelectedDatesFormatter,
19+
DatetimeHighlight,
20+
DatetimeHighlightStyle,
21+
DatetimeHighlightCallback,
22+
} from './datetime-interface';
2223
import { isSameDay, warnIfValueOutOfBounds, isBefore, isAfter } from './utils/comparison';
2324
import {
2425
generateMonths,
@@ -60,6 +61,7 @@ import {
6061
} from './utils/parse';
6162
import {
6263
getCalendarDayState,
64+
getHighlightStyles,
6365
isDayDisabled,
6466
isMonthDisabled,
6567
isNextMonthDisabled,
@@ -322,6 +324,17 @@ export class Datetime implements ComponentInterface {
322324
*/
323325
@Prop() multiple = false;
324326

327+
/**
328+
* Used to apply custom text and background colors to specific dates.
329+
*
330+
* Can be either an array of objects containing ISO strings and colors,
331+
* or a callback that receives an ISO string and returns the colors.
332+
*
333+
* Only applies to the `date`, `date-time`, and `time-date` presentations,
334+
* with `preferWheel="false"`.
335+
*/
336+
@Prop() highlightedDates?: DatetimeHighlight[] | DatetimeHighlightCallback;
337+
325338
/**
326339
* The value of the datetime as a valid ISO 8601 datetime string.
327340
* Should be an array of strings if `multiple="true"`.
@@ -1235,7 +1248,7 @@ export class Datetime implements ComponentInterface {
12351248
};
12361249

12371250
componentWillLoad() {
1238-
const { el, multiple, presentation, preferWheel } = this;
1251+
const { el, highlightedDates,multiple, presentation, preferWheel } = this;
12391252

12401253
if (multiple) {
12411254
if (presentation !== 'date') {
@@ -1247,6 +1260,19 @@ export class Datetime implements ComponentInterface {
12471260
}
12481261
}
12491262

1263+
if (highlightedDates !== undefined) {
1264+
if (presentation !== 'date' && presentation !== 'date-time' && presentation !== 'time-date') {
1265+
printIonWarning(
1266+
'The highlightedDates property is only supported with the date, date-time, and time-date presentations.',
1267+
el
1268+
);
1269+
}
1270+
1271+
if (preferWheel) {
1272+
printIonWarning('The highlightedDates property is not supported with preferWheel="true".', el);
1273+
}
1274+
}
1275+
12501276
this.processMinParts();
12511277
this.processMaxParts();
12521278
const hourValues = (this.parsedHourValues = convertToArrayOfNumbers(this.hourValues));
@@ -1971,7 +1997,7 @@ export class Datetime implements ComponentInterface {
19711997
<div class="calendar-month-grid">
19721998
{getDaysOfMonth(month, year, this.firstDayOfWeek % 7).map((dateObject, index) => {
19731999
const { day, dayOfWeek } = dateObject;
1974-
const { isDateEnabled, multiple } = this;
2000+
const { el, highlightedDates,isDateEnabled, multiple } = this;
19752001
const referenceParts = { month, day, year };
19762002
const { isActive, isToday, ariaLabel, ariaSelected, disabled, text } = getCalendarDayState(
19772003
this.locale,
@@ -1983,6 +2009,7 @@ export class Datetime implements ComponentInterface {
19832009
this.parsedDayValues
19842010
);
19852011

2012+
const dateIsoString = convertDataToISO(referenceParts);
19862013
let isCalDayDisabled = isCalMonthDisabled || disabled;
19872014

19882015
if (!isCalDayDisabled && isDateEnabled !== undefined) {
@@ -1992,15 +2019,26 @@ export class Datetime implements ComponentInterface {
19922019
* to prevent exceptions in the user's function from
19932020
* interrupting the calendar rendering.
19942021
*/
1995-
isCalDayDisabled = !isDateEnabled(convertDataToISO(referenceParts));
2022+
isCalDayDisabled = !isDateEnabled(dateIsoString);
19962023
} catch (e) {
19972024
printIonError(
19982025
'Exception thrown from provided `isDateEnabled` function. Please check your function and try again.',
2026+
el,
19992027
e
20002028
);
20012029
}
20022030
}
20032031

2032+
let dateStyle: DatetimeHighlightStyle | undefined = undefined;
2033+
2034+
/**
2035+
* Custom highlight styles should not override the style for selected dates,
2036+
* nor apply to "filler days" at the start of the grid.
2037+
*/
2038+
if (highlightedDates !== undefined && !isActive && day !== null) {
2039+
dateStyle = getHighlightStyles(highlightedDates, dateIsoString, el);
2040+
}
2041+
20042042
return (
20052043
<button
20062044
tabindex="-1"
@@ -2016,6 +2054,11 @@ export class Datetime implements ComponentInterface {
20162054
'calendar-day-active': isActive,
20172055
'calendar-day-today': isToday,
20182056
}}
2057+
style={
2058+
dateStyle && {
2059+
color: dateStyle.textColor,
2060+
}
2061+
}
20192062
aria-selected={ariaSelected}
20202063
aria-label={ariaLabel}
20212064
onClick={() => {
@@ -2050,6 +2093,12 @@ export class Datetime implements ComponentInterface {
20502093
}
20512094
}}
20522095
>
2096+
<div
2097+
class="calendar-day-highlight"
2098+
style={{
2099+
backgroundColor: dateStyle?.backgroundColor,
2100+
}}
2101+
></div>
20532102
{text}
20542103
</button>
20552104
);

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /