diff --git a/common/changes/office-ui-fabric-react/jolore-CalendarUpdates_2018-04-19-23-57.json b/common/changes/office-ui-fabric-react/jolore-CalendarUpdates_2018-04-19-23-57.json new file mode 100644 index 00000000000000..7f476d75b2e1bf --- /dev/null +++ b/common/changes/office-ui-fabric-react/jolore-CalendarUpdates_2018-04-19-23-57.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "packageName": "office-ui-fabric-react", + "comment": "fixing selection bugs in Calendar component, updating styling for new designs", + "type": "minor" + } + ], + "packageName": "office-ui-fabric-react", + "email": "jolore@microsoft.com" +} \ No newline at end of file diff --git a/packages/office-ui-fabric-react/src/components/Calendar/Calendar.scss b/packages/office-ui-fabric-react/src/components/Calendar/Calendar.scss index 5dea7e3f5b3378..cf5b50601cdbbb 100644 --- a/packages/office-ui-fabric-react/src/components/Calendar/Calendar.scss +++ b/packages/office-ui-fabric-react/src/components/Calendar/Calendar.scss @@ -60,27 +60,21 @@ $Calendar-dayPicker-margin: 10px; display: inline-flex; height: $Calendar-day; line-height: 44px; + width: 100%; } // The month and year labels. .monthAndYear, .year { - display: inline-block; - @include ms-font-xl; + display: inline-flex; + flex-grow: 1; + @include ms-font-m; color: $ms-color-neutralPrimary; margin-top: -1px; - font-weight: $ms-font-weight-semilight; + font-weight: $ms-font-weight-semibold; padding: 0 5px; } -.monthAndYear { - @include margin-left(5px); -} - -.year { - @include margin-left(5px); -} - // The calendar table of dates. .table { text-align: center; @@ -135,7 +129,22 @@ $Calendar-dayPicker-margin: 10px; .dayIsFocused:hover, .dayIsUnfocused:hover { cursor: pointer; - background: $ms-color-neutralTertiaryAlt; + background: $ms-color-neutralLight; +} + +.weekHover:hover, .monthHover, .monthHover:hover { + cursor: pointer; + background: $ms-color-neutralLight; +} + +.weekHover:active, .weekHover:active .day, .monthPress, .monthPress:hover { + cursor: pointer; + font-weight: $ms-font-weight-semibold; + background: $ms-color-themeLight; + + .dayIsToday { + background: $ms-color-themePrimary; + } } .day.dayIsHighlighted.dayIsFocused { @@ -155,10 +164,16 @@ $Calendar-dayPicker-margin: 10px; } .dayIsUnfocused:active, +.dayIsFocused:active, +.dayIsHighlighted { + background: $ms-color-themeLight; +} + .dayIsFocused:active, .dayIsHighlighted { &.day { color: $ms-color-black; + font-weight: $ms-font-weight-semibold; background: $ms-color-themeLight; } } @@ -169,42 +184,29 @@ $Calendar-dayPicker-margin: 10px; background: $ms-color-neutralTertiary; } -// Today. -.dayIsToday, -.pickerIsFocused .dayIsToday { - position: relative; - color: $ms-color-white; - background-color: $ms-color-themePrimary; - font-weight: 600; -} - // Highlighted date squares .dayBackground, .weekBackground, .monthBackground { - background: $ms-color-neutralLight; -} - -.dayBackground { - // border-radius: 2px; + .day { + font-weight: $ms-font-weight-semibold; + background: $ms-color-themeLight; + } } -.weekBackground { - &:first-child { - // border-radius: 2px 0px 0px 2px; - } - &:last-child { - // border-radius: 0px 2px 2px 0px; - } +// Today. +.dayIsToday, .dayIsToday, +.pickerIsFocused .dayIsToday, .dayIsToday.day:active { + position: relative; + color: $ms-color-white; + font-weight: $ms-font-weight-semibold; + background: $ms-color-themePrimary; } .showWeekNumbers { .weekNumbers { - position: absolute; - margin-top: $Calendar-day; border-right: 1px solid $ms-color-neutralLight; box-sizing: border-box; - width: 30px; .day { color: $ms-color-neutralSecondary; &.weekIsHighlighted { @@ -213,9 +215,6 @@ $Calendar-dayPicker-margin: 10px; } } .table { - &:not(.weekNumbers) { - margin-left: 30px; - } .day, .weekday { width: 30px; @@ -226,11 +225,8 @@ $Calendar-dayPicker-margin: 10px; // week numbers style in right-to-left view .showWeekNumbersRTL { .weekNumbers { - position: absolute; - margin-top: $Calendar-day; border-left: 1px solid $ms-color-neutralLight; box-sizing: border-box; - width: 30px; .day { color: $ms-color-neutralSecondary; &.weekIsHighlighted { @@ -254,11 +250,11 @@ $Calendar-dayPicker-margin: 10px; .yearComponents, .decadeComponents { display: inline-flex; - margin-left: 3px; + align-self: flex-end; } .yearComponents { - margin-left: 3px; + @include margin-right(20px); } .prevMonth, @@ -306,14 +302,15 @@ $Calendar-dayPicker-margin: 10px; // Text showing the currently-selected year. .currentYear, .currentDecade { - display: block; + display: inline-flex; + flex-grow: 1; padding: 0 5px; - @include ms-font-xl; + @include ms-font-m; color: $ms-color-neutralPrimary; height: $Calendar-day; line-height: $Calendar-day; @include margin-left(5px); - font-weight: $ms-font-weight-semilight; + font-weight: $ms-font-weight-semibold; } // A grid of month or year options, which pushes them over @@ -342,7 +339,7 @@ $Calendar-dayPicker-margin: 10px; background-color: transparent; &:hover { color: $ms-color-black; - background-color: $ms-color-neutralTertiaryAlt; + background-color: $ms-color-neutralLight; outline: 1px solid transparent; } &.isHighlighted { @@ -417,6 +414,7 @@ $Calendar-dayPicker-margin: 10px; .header { height: $Calendar-day; line-height: $Calendar-day; + width: 100%; } // Calendar day cells are smaller. .day, .weekday { @@ -452,15 +450,7 @@ $Calendar-dayPicker-margin: 10px; padding: 0 3px; } .showWeekNumbers { - .weekNumbers { - margin-top: $Calendar-day; - width: 26px; - margin-left: -7px - } .table { - &:not(.weekNumbers) { - margin-left: 19px; - } .day, .weekday { width: 26px; @@ -468,15 +458,7 @@ $Calendar-dayPicker-margin: 10px; } } // week numbers style in right-to-left view .showWeekNumbersRTL { - .weekNumbers { - margin-top: $Calendar-day; - width: 26px; - margin-right: -7px; - } .table { - &:not(.weekNumbers) { - margin-right: 19px; - } .day, .weekday { width: 26px; @@ -568,18 +550,23 @@ $Calendar-dayPicker-margin: 10px; height: auto; } .table { - margin-right: 12px + @include margin-right(12px); } .dayPicker { width: auto; } .monthPicker { - margin-left: 13px; + @include margin-left(13px); } .goToday { @include ms-right(13px); padding: 0 10px; } + .monthComponents, + .yearComponents, + .decadeComponents { + @include margin-right(12px); + } } //when month picker is only visible .monthPickerOnly { .wrap { @@ -637,16 +624,21 @@ $Calendar-dayPicker-margin: 10px; .prevYear { display: inline-block; &:hover { - background-color: $ms-color-neutralTertiaryAlt; + background-color: $ms-color-neutralLight; + } + &:active { + background-color: $ms-color-themeLight; } } .nextMonth, .nextYear { margin-left: 3px; + margin-right: 2px; } .monthIsHighlighted { + font-weight: $ms-font-weight-semibold; background-color: $ms-color-themeLight; &.monthOption:hover { background-color: $ms-color-themeLight; @@ -654,11 +646,11 @@ $Calendar-dayPicker-margin: 10px; } .monthIsCurrentMonth { - font-weight: 600; + font-weight: $ms-font-weight-semibold; color: $ms-color-white; background-color: $ms-color-themePrimary; &.monthOption:hover { - font-weight: 600; + font-weight: $ms-font-weight-semibold; color: $ms-color-white; background-color: $ms-color-themePrimary; } diff --git a/packages/office-ui-fabric-react/src/components/Calendar/Calendar.tsx b/packages/office-ui-fabric-react/src/components/Calendar/Calendar.tsx index c7f0ddb44012ec..138bf8b85ccd72 100644 --- a/packages/office-ui-fabric-react/src/components/Calendar/Calendar.tsx +++ b/packages/office-ui-fabric-react/src/components/Calendar/Calendar.tsx @@ -63,6 +63,7 @@ export class Calendar extends BaseComponent impl showGoToToday: true, strings: null, highlightCurrentMonth: false, + highlightSelectedMonth: false, navigationIcons: iconStrings, showWeekNumbers: false, firstWeekOfYear: FirstWeekOfYear.FirstDay, @@ -123,7 +124,7 @@ export class Calendar extends BaseComponent impl public render(): JSX.Element { const rootClass = 'ms-DatePicker'; - const { firstDayOfWeek, dateRangeType, strings, showMonthPickerAsOverlay, autoNavigateOnSelection, showGoToToday, highlightCurrentMonth, navigationIcons, minDate, maxDate } = this.props; + const { firstDayOfWeek, dateRangeType, strings, showMonthPickerAsOverlay, autoNavigateOnSelection, showGoToToday, highlightCurrentMonth, highlightSelectedMonth, navigationIcons, minDate, maxDate } = this.props; const { selectedDate, navigatedDate, isMonthPickerVisible, isDayPickerVisible } = this.state; const onHeaderSelect = showMonthPickerAsOverlay ? this._onHeaderSelect : undefined; const monthPickerOnly = !showMonthPickerAsOverlay && !isDayPickerVisible; @@ -172,10 +173,12 @@ export class Calendar extends BaseComponent impl { isMonthPickerVisible && { */ highlightCurrentMonth?: boolean; + /** + * Whether the month picker should highlight the selected month + * @defaultvalue false + */ + highlightSelectedMonth?: boolean; + /** * Customize navigation icons using ICalendarIconStrings */ @@ -196,6 +202,11 @@ export interface ICalendarStrings { */ nextYearAriaLabel?: string; + /** + * Aria-label format string for the week number header. Should have 1 string param e.g. "week number {0}" + */ + weekNumberFormatString?: string; + } export interface ICalendarIconStrings { diff --git a/packages/office-ui-fabric-react/src/components/Calendar/CalendarDay.tsx b/packages/office-ui-fabric-react/src/components/Calendar/CalendarDay.tsx index 60cafbab4a897f..a443b150e0fddc 100644 --- a/packages/office-ui-fabric-react/src/components/Calendar/CalendarDay.tsx +++ b/packages/office-ui-fabric-react/src/components/Calendar/CalendarDay.tsx @@ -5,7 +5,8 @@ import { css, getId, getRTL, - getRTLSafeKeyCode + getRTLSafeKeyCode, + format } from '../../Utilities'; import { ICalendarStrings, ICalendarIconStrings, ICalendarFormatDateCallbacks } from './Calendar.types'; import { DayOfWeek, FirstWeekOfYear, DateRangeType } from '../../utilities/dateValues/DateValues'; @@ -78,10 +79,8 @@ interface IWeekCorners { } export class CalendarDay extends BaseComponent { - public refs: { - [key: string]: React.ReactInstance; - navigatedDay: HTMLElement; - }; + private navigatedDay: HTMLElement | null; + private days: { [key: string]: HTMLElement | null } = {}; public constructor(props: ICalendarDayProps) { super(props); @@ -130,44 +129,11 @@ export class CalendarDay extends BaseComponent -
-
- - -
-
-
+
{ this.props.onHeaderSelect ?
}
+
+
+ + +
+
- { - showWeekNumbers ? - - - { weekNumbers!.map((weekNumber, index) => - - - - ) } - -
-
- { weekNumber } -
-
- : null - } + { showWeekNumbers && - + { weeks!.map((week, weekIndex) => - + + { showWeekNumbers && weekNumbers && + + } { week.map((day, dayIndex) => { const isNavigatedDate = compareDates(navigatedDate, day.originalDate); return - +
} { strings.shortDays.map((val, index) => ) }
+
+ { weekNumbers[weekIndex] } +
+
this._setDayRef(element, day, isNavigatedDate) } + onMouseOver={ dateRangeType === DateRangeType.Month ? this._onDayMouseOver(day.originalDate, weekIndex, dayIndex) : undefined } + onMouseLeave={ dateRangeType === DateRangeType.Month ? this._onDayMouseLeave(day.originalDate, weekIndex, dayIndex) : undefined } + onMouseDown={ dateRangeType === DateRangeType.Month ? this._onDayMouseDown(day.originalDate, weekIndex, dayIndex) : undefined } + onMouseUp={ dateRangeType === DateRangeType.Month ? this._onDayMouseUp(day.originalDate, weekIndex, dayIndex) : undefined } >
@@ -282,14 +287,21 @@ export class CalendarDay extends BaseComponent) => void => { + return (ev: React.MouseEvent): void => { + // set the press styling + this._applyFunctionToDayRefs((ref, day) => { + if (ref && day.originalDate.getMonth() === originalDate.getMonth()) { + ref.classList.add(styles.monthPress); + } + }); + }; + } + + private _onDayMouseUp = (originalDate: Date, weekIndex: number, dayIndex: number) + : (ev: React.MouseEvent) => void => { + return (ev: React.MouseEvent): void => { + // remove press styling + this._applyFunctionToDayRefs((ref, day) => { + if (ref && day.originalDate.getMonth() === originalDate.getMonth()) { + ref.classList.remove(styles.monthPress); + } + }); + }; + } + + private _onDayMouseOver = (originalDate: Date, weekIndex: number, dayIndex: number) + : (ev: React.MouseEvent) => void => { + return (ev: React.MouseEvent): void => { + // set the hover styling on every day in the same month + this._applyFunctionToDayRefs((ref, day) => { + if (ref && day.originalDate.getMonth() === originalDate.getMonth()) { + ref.classList.add(styles.monthHover); + } + }); + }; + } + + private _onDayMouseLeave = (originalDate: Date, weekIndex: number, dayIndex: number) + : (ev: React.MouseEvent) => void => { + return (ev: React.MouseEvent): void => { + // remove the hover and pressed styling + this._applyFunctionToDayRefs((ref, day) => { + if (ref && day.originalDate.getMonth() === originalDate.getMonth()) { + ref.classList.remove(styles.monthHover); + } + }); + }; + } + + private _onTableMouseLeave = (ev: React.MouseEvent): void => { + if ((ev.target as HTMLElement).contains && (ev.target as HTMLElement).contains(ev.relatedTarget as HTMLElement)) { + return; + } + + this._applyFunctionToDayRefs((ref, day) => { + if (ref) { + ref.classList.remove(styles.monthHover); + ref.classList.remove(styles.monthPress); + } + }); + } + + private _onTableMouseUp = (ev: React.MouseEvent): void => { + if ((ev.target as HTMLElement).contains && (ev.target as HTMLElement).contains(ev.relatedTarget as HTMLElement)) { + return; + } + + this._applyFunctionToDayRefs((ref, day) => { + if (ref) { + ref.classList.remove(styles.monthPress); + } + }); + } + + private _applyFunctionToDayRefs(func: (ref: HTMLElement | null, day: IDayInfo) => void) { + if (this.state.weeks && this.props.dateRangeType === DateRangeType.Month) { + this.state.weeks.map(week => { + week.map(day => { + const ref = this.days[day.key]; + func(ref, day); + }); + }); + } + } + private _onSelectDate = (selectedDate: Date): void => { const { onSelectDate, @@ -501,7 +597,9 @@ export class CalendarDay extends BaseComponent { componentRef?: (c: ICalendarMonth) => void; navigatedDate: Date; + selectedDate: Date; strings: ICalendarStrings; onNavigateDate: (date: Date, focusOnNavigatedDay: boolean) => void; today?: Date; highlightCurrentMonth: boolean; + highlightSelectedMonth: boolean; onHeaderSelect?: (focus: boolean) => void; navigationIcons: ICalendarIconStrings; dateTimeFormatter: ICalendarFormatDateCallbacks; @@ -54,7 +56,7 @@ export class CalendarMonth extends BaseComponent { public render(): JSX.Element { - const { navigatedDate, strings, today, highlightCurrentMonth, navigationIcons, dateTimeFormatter, minDate, maxDate } = this.props; + const { navigatedDate, selectedDate, strings, today, highlightCurrentMonth, highlightSelectedMonth, navigationIcons, dateTimeFormatter, minDate, maxDate } = this.props; const leftNavigationIcon = navigationIcons.leftNavigation; const rightNavigationIcon = navigationIcons.rightNavigation; @@ -64,34 +66,6 @@ export class CalendarMonth extends BaseComponent { return (
-
-
- - -
-
{ this.props.onHeaderSelect ?
{ { dateTimeFormatter.formatYear(navigatedDate) }
} +
+
+ + +
+
{ const indexedMonth = setMonth(navigatedDate, index); const isCurrentMonth = this._isCurrentMonth(index, navigatedDate.getFullYear(), today!); const isNavigatedMonth = navigatedDate.getMonth() === index; + const isSelectedMonth = selectedDate.getMonth() === index; + const isSelectedYear = selectedDate.getFullYear() === navigatedDate.getFullYear(); const isInBounds = (minDate ? compareDatePart(minDate, getMonthEnd(indexedMonth)) < 1 : true) && (maxDate ? compareDatePart(getMonthStart(indexedMonth), maxDate) < 1 : true); @@ -129,7 +133,8 @@ export class CalendarMonth extends BaseComponent { css('ms-DatePicker-monthOption', styles.monthOption, { ['ms-DatePicker-day--today ' + styles.monthIsCurrentMonth]: highlightCurrentMonth && isCurrentMonth!, - ['ms-DatePicker-day--highlighted ' + styles.monthIsHighlighted]: highlightCurrentMonth && isNavigatedMonth, + ['ms-DatePicker-day--highlighted ' + styles.monthIsHighlighted]: (highlightCurrentMonth && isNavigatedMonth) || + (highlightSelectedMonth && isSelectedMonth && isSelectedYear), ['ms-DatePicker-monthOption--disabled ' + styles.monthOptionIsDisabled]: !isInBounds }) } diff --git a/packages/office-ui-fabric-react/src/components/Calendar/CalendarPage.tsx b/packages/office-ui-fabric-react/src/components/Calendar/CalendarPage.tsx index 3beb5f7fc49148..485a312fa0e01b 100644 --- a/packages/office-ui-fabric-react/src/components/Calendar/CalendarPage.tsx +++ b/packages/office-ui-fabric-react/src/components/Calendar/CalendarPage.tsx @@ -40,7 +40,8 @@ export class CalendarPage extends React.Component > @@ -64,6 +66,8 @@ export class CalendarPage extends React.Component @@ -75,6 +79,8 @@ export class CalendarPage extends React.Component @@ -102,7 +108,8 @@ export class CalendarPage extends React.Component dateRangeType={ DateRangeType.Month } autoNavigateOnSelection={ false } showGoToToday={ true } - highlightCurrentMonth={ true } + highlightCurrentMonth={ false } + highlightSelectedMonth={ true } isDayPickerVisible={ false } /> @@ -113,7 +120,8 @@ export class CalendarPage extends React.Component dateRangeType={ DateRangeType.WorkWeek } firstDayOfWeek={ DayOfWeek.Monday } autoNavigateOnSelection={ true } - highlightCurrentMonth={ true } + highlightCurrentMonth={ false } + highlightSelectedMonth={ true } showGoToToday={ true } workWeekDays={ [DayOfWeek.Tuesday, DayOfWeek.Saturday, DayOfWeek.Wednesday, DayOfWeek.Friday] } /> @@ -145,7 +154,8 @@ export class CalendarPage extends React.Component > @@ -155,7 +165,8 @@ export class CalendarPage extends React.Component > diff --git a/packages/office-ui-fabric-react/src/components/Calendar/__snapshots__/Calendar.test.tsx.snap b/packages/office-ui-fabric-react/src/components/Calendar/__snapshots__/Calendar.test.tsx.snap index 507065a96d6f5d..7d08d9ef31f465 100644 --- a/packages/office-ui-fabric-react/src/components/Calendar/__snapshots__/Calendar.test.tsx.snap +++ b/packages/office-ui-fabric-react/src/components/Calendar/__snapshots__/Calendar.test.tsx.snap @@ -22,54 +22,6 @@ exports[`Calendar Test rendering simplest calendar Renders simple calendar corre className="ms-DatePicker-dayPicker" id="DatePickerDay-dayPicker10" > -
-
- - -
-
@@ -77,6 +29,7 @@ exports[`Calendar Test rendering simplest calendar Renders simple calendar corre aria-atomic="true" aria-live="polite" aria-relevant="text" + className={undefined} id="DatePickerDay-monthAndYear11" >
+
+
+ + +
+
-
-
- - -
-
@@ -952,6 +1055,52 @@ exports[`Calendar Test rendering simplest calendar Renders simple calendar corre > 2000
+
+
+ + +
+
diff --git a/packages/office-ui-fabric-react/src/components/Calendar/examples/Calendar.Inline.Example.tsx b/packages/office-ui-fabric-react/src/components/Calendar/examples/Calendar.Inline.Example.tsx index ab0091063ea14e..59b966a8142add 100644 --- a/packages/office-ui-fabric-react/src/components/Calendar/examples/Calendar.Inline.Example.tsx +++ b/packages/office-ui-fabric-react/src/components/Calendar/examples/Calendar.Inline.Example.tsx @@ -58,7 +58,8 @@ const DayPickerStrings = { 'S' ], - goToToday: 'Go to today' + goToToday: 'Go to today', + weekNumberFormatString: 'Week number {0}', }; export interface ICalendarInlineExampleState { @@ -73,6 +74,7 @@ export interface ICalendarInlineExampleProps { showGoToToday: boolean; showNavigateButtons?: boolean; highlightCurrentMonth?: boolean; + highlightSelectedMonth?: boolean; isDayPickerVisible?: boolean; showMonthPickerAsOverlay?: boolean; showWeekNumbers?: boolean; @@ -140,6 +142,7 @@ export class CalendarInlineExample extends React.Component
{ isDatePickerShown && ( @@ -261,6 +262,7 @@ export class DatePicker extends BaseComponent { */ highlightCurrentMonth?: boolean; + /** + * Whether the month picker should highlight the selected month + * @defaultvalue false + */ + highlightSelectedMonth?: boolean; + /** * Whether the calendar should show the week number (weeks 1 to 53) before each week row * @defaultvalue false diff --git a/packages/office-ui-fabric-react/src/components/DatePicker/__snapshots__/DatePicker.test.tsx.snap b/packages/office-ui-fabric-react/src/components/DatePicker/__snapshots__/DatePicker.test.tsx.snap index 889c76539f9c30..7e99f740e15d86 100644 --- a/packages/office-ui-fabric-react/src/components/DatePicker/__snapshots__/DatePicker.test.tsx.snap +++ b/packages/office-ui-fabric-react/src/components/DatePicker/__snapshots__/DatePicker.test.tsx.snap @@ -32,7 +32,7 @@ exports[`DatePicker renders default DatePicker correctly 1`] = ` placeholder={undefined} readOnly={true} required={false} - role="menu" + role="button" type="text" value="" />