Skip to content

Commit

Permalink
feat(datetime): isDateEnabled to enable/disable specific days (#24898)
Browse files Browse the repository at this point in the history
Resolves #24209
  • Loading branch information
sean-perkins committed Mar 11, 2022
1 parent dda2b9f commit e932a04
Show file tree
Hide file tree
Showing 16 changed files with 616 additions and 46 deletions.
4 changes: 2 additions & 2 deletions angular/src/directives/proxies.ts
Original file line number Diff line number Diff line change
Expand Up @@ -522,14 +522,14 @@ export declare interface IonDatetime extends Components.IonDatetime {

@ProxyCmp({
defineCustomElementFn: undefined,
inputs: ['cancelText', 'clearText', 'color', 'dayValues', 'disabled', 'doneText', 'firstDayOfWeek', 'hourCycle', 'hourValues', 'locale', 'max', 'min', 'minuteValues', 'mode', 'monthValues', 'name', 'presentation', 'readonly', 'showClearButton', 'showDefaultButtons', 'showDefaultTimeLabel', 'showDefaultTitle', 'size', 'value', 'yearValues'],
inputs: ['cancelText', 'clearText', 'color', 'dayValues', 'disabled', 'doneText', 'firstDayOfWeek', 'hourCycle', 'hourValues', 'isDateEnabled', 'locale', 'max', 'min', 'minuteValues', 'mode', 'monthValues', 'name', 'presentation', 'readonly', 'showClearButton', 'showDefaultButtons', 'showDefaultTimeLabel', 'showDefaultTitle', 'size', 'value', 'yearValues'],
methods: ['confirm', 'reset', 'cancel']
})
@Component({
selector: 'ion-datetime',
changeDetection: ChangeDetectionStrategy.OnPush,
template: '<ng-content></ng-content>',
inputs: ['cancelText', 'clearText', 'color', 'dayValues', 'disabled', 'doneText', 'firstDayOfWeek', 'hourCycle', 'hourValues', 'locale', 'max', 'min', 'minuteValues', 'mode', 'monthValues', 'name', 'presentation', 'readonly', 'showClearButton', 'showDefaultButtons', 'showDefaultTimeLabel', 'showDefaultTitle', 'size', 'value', 'yearValues']
inputs: ['cancelText', 'clearText', 'color', 'dayValues', 'disabled', 'doneText', 'firstDayOfWeek', 'hourCycle', 'hourValues', 'isDateEnabled', 'locale', 'max', 'min', 'minuteValues', 'mode', 'monthValues', 'name', 'presentation', 'readonly', 'showClearButton', 'showDefaultButtons', 'showDefaultTimeLabel', 'showDefaultTitle', 'size', 'value', 'yearValues']
})
export class IonDatetime {
protected el: HTMLElement;
Expand Down
1 change: 1 addition & 0 deletions core/api.txt
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,7 @@ ion-datetime,prop,doneText,string,'Done',false,false
ion-datetime,prop,firstDayOfWeek,number,0,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
ion-datetime,prop,locale,string,'default',false,false
ion-datetime,prop,max,string | undefined,undefined,false,false
ion-datetime,prop,min,string | undefined,undefined,false,false
Expand Down
8 changes: 8 additions & 0 deletions core/src/components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -756,6 +756,10 @@ export namespace Components {
* Values used to create the list of selectable hours. By default the hour values range from `0` to `23` for 24-hour, or `1` to `12` for 12-hour. However, to control exactly which hours to display, the `hourValues` input can take a number, an array of numbers, or a string of comma separated numbers.
*/
"hourValues"?: number[] | number | string;
/**
* Returns if an individual date (calendar day) is enabled or disabled. If `true`, the day will be enabled/interactive. If `false`, the day will be disabled/non-interactive. The function accepts an ISO 8601 date string of a given day. By default, all days are enabled. Developers can use this function to write custom logic to disable certain days. Custom implementations should be optimized for performance. This function is called often, so any extra logic should be avoided to reduce and prevent jank.
*/
"isDateEnabled"?: (dateIsoString: string) => boolean;
/**
* The locale to use for `ion-datetime`. This impacts month and day name formatting. The `'default'` value refers to the default locale set by your device.
*/
Expand Down Expand Up @@ -4441,6 +4445,10 @@ declare namespace LocalJSX {
* Values used to create the list of selectable hours. By default the hour values range from `0` to `23` for 24-hour, or `1` to `12` for 12-hour. However, to control exactly which hours to display, the `hourValues` input can take a number, an array of numbers, or a string of comma separated numbers.
*/
"hourValues"?: number[] | number | string;
/**
* Returns if an individual date (calendar day) is enabled or disabled. If `true`, the day will be enabled/interactive. If `false`, the day will be disabled/non-interactive. The function accepts an ISO 8601 date string of a given day. By default, all days are enabled. Developers can use this function to write custom logic to disable certain days. Custom implementations should be optimized for performance. This function is called often, so any extra logic should be avoided to reduce and prevent jank.
*/
"isDateEnabled"?: (dateIsoString: string) => boolean;
/**
* The locale to use for `ion-datetime`. This impacts month and day name formatting. The `'default'` value refers to the default locale set by your device.
*/
Expand Down
34 changes: 33 additions & 1 deletion core/src/components/datetime/datetime.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Component, ComponentInterface, Element, Event, EventEmitter, Host, Method, Prop, State, Watch, h, writeTask } from '@stencil/core';
import { printIonError } from '@utils/logging';
import {
caretDownSharp,
caretUpSharp,
Expand Down Expand Up @@ -153,6 +154,21 @@ export class Datetime implements ComponentInterface {
*/
@Prop() readonly = false;

/**
* Returns if an individual date (calendar day) is enabled or disabled.
*
* If `true`, the day will be enabled/interactive.
* If `false`, the day will be disabled/non-interactive.
*
* The function accepts an ISO 8601 date string of a given day.
* By default, all days are enabled. Developers can use this function
* to write custom logic to disable certain days.
*
* The function is called for each rendered calendar day, for the previous, current and next month.
* Custom implementations should be optimized for performance to avoid jank.
*/
@Prop() isDateEnabled?: (dateIsoString: string) => boolean;

@Watch('disabled')
protected disabledChanged() {
this.emitStyle();
Expand Down Expand Up @@ -1275,9 +1291,25 @@ export class Datetime implements ComponentInterface {
<div class="calendar-month-grid">
{getDaysOfMonth(month, year, this.firstDayOfWeek % 7).map((dateObject, index) => {
const { day, dayOfWeek } = dateObject;
const { isDateEnabled } = this;
const referenceParts = { month, day, year };
const { isActive, isToday, ariaLabel, ariaSelected, disabled } = getCalendarDayState(this.locale, referenceParts, this.activePartsClone, this.todayParts, this.minParts, this.maxParts, this.parsedDayValues);

let isCalDayDisabled = isCalMonthDisabled || disabled;

if (!isCalDayDisabled && isDateEnabled !== undefined) {
try {
/**
* The `isDateEnabled` implementation is try-catch wrapped
* to prevent exceptions in the user's function from
* interrupting the calendar rendering.
*/
isCalDayDisabled = !isDateEnabled(convertDataToISO(referenceParts));
} catch (e) {
printIonError('Exception thrown from provided `isDateEnabled` function. Please check your function and try again.', e);
}
}

return (
<button
tabindex="-1"
Expand All @@ -1286,7 +1318,7 @@ export class Datetime implements ComponentInterface {
data-year={year}
data-index={index}
data-day-of-week={dayOfWeek}
disabled={isCalMonthDisabled || disabled}
disabled={isCalDayDisabled}
class={{
'calendar-day-padding': day === null,
'calendar-day': true,
Expand Down

0 comments on commit e932a04

Please sign in to comment.