diff --git a/common/changes/office-ui-fabric-react/jolore-CalendarUpdates_2018-05-03-18-20.json b/common/changes/office-ui-fabric-react/jolore-CalendarUpdates_2018-05-03-18-20.json new file mode 100644 index 0000000000000..91defcb3abe80 --- /dev/null +++ b/common/changes/office-ui-fabric-react/jolore-CalendarUpdates_2018-05-03-18-20.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "packageName": "office-ui-fabric-react", + "comment": "Finishing the rest of the Calendar style updates", + "type": "patch" + } + ], + "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 cf5b50601cdbb..c9e13357ef790 100644 --- a/packages/office-ui-fabric-react/src/components/Calendar/Calendar.scss +++ b/packages/office-ui-fabric-react/src/components/Calendar/Calendar.scss @@ -4,10 +4,18 @@ // Office UI Fabric // -------------------------------------------------- // Calendar styles -$Calendar-day:40px; +$Calendar-day:28px; $Calendar-dayPicker-margin: 10px; .root { @include ms-normalize; + + * { + @include focus-border($color: $ms-color-neutralSecondary); + + @include high-contrast { + @include focus-border(0, WindowText, 2px, false); + } + } } // Base wrapper for the date picker. @@ -28,7 +36,7 @@ $Calendar-dayPicker-margin: 10px; // When the picker opens, reveal the content. .picker.pickerIsOpened .holder { @include ms-borderBox; - display: block; + display: inline-block; } // When a picker opens, always open it in front of other closed pickers @@ -39,13 +47,15 @@ $Calendar-dayPicker-margin: 10px; // The frame and wrap work together to ensure that // clicks within the picker don’t reach the holder. .frame { - padding: 1px; position: relative; } .wrap { - margin: -1px; - padding: 9px; + &.goTodaySpacing { + min-height: 228px; + } + min-height: 212px; + padding: 12px; display: flex; } @@ -63,6 +73,13 @@ $Calendar-dayPicker-margin: 10px; width: 100%; } +.divider { + top: 0; + margin-top: -12px; + margin-bottom: -12px; + @include border-right(1px, solid, $ms-color-neutralLight); +} + // The month and year labels. .monthAndYear, .year { @@ -70,11 +87,14 @@ $Calendar-dayPicker-margin: 10px; flex-grow: 1; @include ms-font-m; color: $ms-color-neutralPrimary; - margin-top: -1px; font-weight: $ms-font-weight-semibold; padding: 0 5px; } +.monthAndYear:hover, .currentYear:hover { + color: $ms-color-black; +} + // The calendar table of dates. .table { text-align: center; @@ -82,7 +102,8 @@ $Calendar-dayPicker-margin: 10px; border-spacing: 0; table-layout: fixed; font-size: inherit; - margin-top: 10px; + margin-top: 4px; + width: 197px; td { margin: 0; padding: 0; @@ -93,19 +114,40 @@ $Calendar-dayPicker-margin: 10px; } // The days on the calendar. -.day, +.dayWrapper, .weekday { width: $Calendar-day; height: $Calendar-day; padding: 0; line-height: $Calendar-day; + font-size: $ms-font-size-s; @include ms-font-m-plus; color: $ms-color-neutralPrimary; - box-sizing: border-box; // border-radius: 2px; + box-sizing: border-box; + display: inline-flex; + justify-content: center; + align-items: center; + + * { + @include focus-border(-2px, $color: $ms-color-neutralSecondary); + + @include high-contrast { + @include focus-border(-2px, WindowText, 2px, false); + } + } +} + +.day { + width: 24px; + height: 24px; + border-radius: 2px; + display: inline-flex; + align-items: center; + justify-content: center; } // Today. -.dayIsToday { +.dayIsToday, .dayIsToday:hover { position: relative; background-color: $ms-color-themeLight; @include high-contrast { @@ -121,7 +163,7 @@ $Calendar-dayPicker-margin: 10px; // Out of focus days. .dayIsUnfocused, .dayIsDisabled { - color: $ms-color-neutralTertiary; + color: $ms-color-neutralSecondary; font-weight: $ms-font-weight-regular; } @@ -130,28 +172,7 @@ $Calendar-dayPicker-margin: 10px; .dayIsUnfocused:hover { cursor: pointer; 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 { - @include focus-border(1px, $ms-color-white); - @include high-contrast { - @include focus-border(1px, WindowText); - } + color: $ms-color-neutralDark; } // Highlighted and hovered/focused dates. @@ -163,7 +184,6 @@ $Calendar-dayPicker-margin: 10px; } } -.dayIsUnfocused:active, .dayIsFocused:active, .dayIsHighlighted { background: $ms-color-themeLight; @@ -172,9 +192,8 @@ $Calendar-dayPicker-margin: 10px; .dayIsFocused:active, .dayIsHighlighted { &.day { - color: $ms-color-black; + color: $ms-color-neutralPrimary; font-weight: $ms-font-weight-semibold; - background: $ms-color-themeLight; } } @@ -185,15 +204,35 @@ $Calendar-dayPicker-margin: 10px; } // Highlighted date squares -.dayBackground, -.weekBackground, -.monthBackground { - .day { - font-weight: $ms-font-weight-semibold; - background: $ms-color-themeLight; +.dayBackground, .dayBackground:hover, .dayBackground:active { + border-radius: 2px; +} + +.dayHover, .dayHover:hover { + cursor: pointer; + background: $ms-color-neutralLight; + color: $ms-color-neutralDark; +} + +.dayPress, .dayPress:hover { + cursor: pointer; + font-weight: $ms-font-weight-semibold; + background: $ms-color-themeLight; + color: $ms-color-neutralPrimary; + .dayIsToday { + background: $ms-color-themePrimary; } } +.dayIsUnfocused:active, +.dayIsFocused:active, +.dayIsHighlighted, .dayIsHighlighted:hover, .dayIsHighlighted:active, +.weekBackground, .weekBackground:hover, .weekBackground:active { + background: $ms-color-themeLight; + color: $ms-color-neutralPrimary; + font-weight: $ms-font-weight-semibold; +} + // Today. .dayIsToday, .dayIsToday, .pickerIsFocused .dayIsToday, .dayIsToday.day:active { @@ -207,18 +246,21 @@ $Calendar-dayPicker-margin: 10px; .weekNumbers { border-right: 1px solid $ms-color-neutralLight; box-sizing: border-box; - .day { + width: 28x; + padding: 0; + .dayWrapper { color: $ms-color-neutralSecondary; &.weekIsHighlighted { - color: $ms-color-black; + color: $ms-color-neutralPrimary; } } } .table { - .day, + .dayWrapper, .weekday { width: 30px; } + width: 225px; } } @@ -227,10 +269,10 @@ $Calendar-dayPicker-margin: 10px; .weekNumbers { border-left: 1px solid $ms-color-neutralLight; box-sizing: border-box; - .day { + .dayWrapper { color: $ms-color-neutralSecondary; &.weekIsHighlighted { - color: $ms-color-black; + color: $ms-color-neutralPrimary; } } } @@ -238,7 +280,7 @@ $Calendar-dayPicker-margin: 10px; &:not(.weekNumbers) { margin-right: 30px; } - .day, + .dayWrapper, .weekday { width: 30px; } @@ -253,10 +295,6 @@ $Calendar-dayPicker-margin: 10px; align-self: flex-end; } -.yearComponents { - @include margin-right(20px); -} - .prevMonth, .nextMonth, .prevYear, @@ -269,10 +307,10 @@ $Calendar-dayPicker-margin: 10px; text-align: center; line-height: $Calendar-day; text-align: center; - font-size: $ms-icon-size-m; - color: $ms-color-neutralDark; + font-size: $ms-icon-size-s; + color: $ms-color-neutralPrimary; + border-radius: 2px; position: relative; - top: 2px; background-color: transparent; border: none; padding: 0; @@ -289,13 +327,20 @@ $Calendar-dayPicker-margin: 10px; .nextYearIsDisabled, .prevDecadeIsDisabled, .nextDecadeIsDisabled { - visibility: hidden; + color: $ms-color-neutralTertiaryAlt; + pointer-events: none; } // Without modifying the Pickadate JS, this transparent // button is necessary to toggle the month view. +.headerToggleView { + display: flex; + align-items: center; + padding: 4px 8px; +} + .headerToggleView:hover { - color: $ms-color-neutralSecondary; + color: $ms-color-black; cursor: pointer; } @@ -318,8 +363,8 @@ $Calendar-dayPicker-margin: 10px; .optionGrid { position: relative; height: 210px; - width: 280px; - @include margin(12px, 0, 0, 0); + width: 196px; + @include margin(4px, 0, 0, 0); } // Button to select a different month. @@ -333,12 +378,13 @@ $Calendar-dayPicker-margin: 10px; @include margin(0, 10px, 10px, 0); @include ms-font-s-plus; color: $ms-color-neutralPrimary; - text-align: center; // border-radius: 2px; + text-align: center; border: none; padding: 0; background-color: transparent; + border-radius: 2px; &:hover { - color: $ms-color-black; + color: $ms-color-neutralDark; background-color: $ms-color-neutralLight; outline: 1px solid transparent; } @@ -348,16 +394,16 @@ $Calendar-dayPicker-margin: 10px; } } +.dayIsDisabled, .monthOptionIsDisabled, .yearOptionIsDisabled { - background-color: $ms-color-neutralLighter; color: $ms-color-neutralTertiaryAlt; pointer-events: none; } // Button to navigate to the current date. .goToday { - bottom: 9px; + bottom: 0; color: $ms-color-themePrimary; cursor: pointer; @include ms-font-s; @@ -368,6 +414,7 @@ $Calendar-dayPicker-margin: 10px; background-color: transparent; border: none; position: absolute !important; + box-sizing: content-box; @include ms-right(13px); &:hover { color: $ms-color-themePrimary; @@ -378,9 +425,13 @@ $Calendar-dayPicker-margin: 10px; } } -// Additional 30px margin needed when "Go to today" button is visible +.goTodayInlineMonth { + top: 212px; +} + +// Additional 28px padding needed when "Go to today" button is visible .wrap.goTodaySpacing { - margin-bottom: 30px; + padding-bottom: 28px; } // State: The picker is showing the year components. @@ -405,18 +456,18 @@ $Calendar-dayPicker-margin: 10px; $Calendar-day: 28px; $Calendar-month: 40px; .wrap { - padding: 9px 8px; + padding: 12px; } // Update the spacing and text for the day and month pickers .dayPicker, .monthPicker { - min-height: 214px; + min-height: 200px; } .header { height: $Calendar-day; line-height: $Calendar-day; width: 100%; } // Calendar day cells are smaller. - .day, + .dayWrapper, .weekday { width: $Calendar-day; height: $Calendar-day; @@ -429,18 +480,18 @@ $Calendar-dayPicker-margin: 10px; .nextYear, .prevDecade, .nextDecade { - font-size: 14px; - width: 24px; - height: 24px; - line-height: 24px; + font-size: $ms-font-size-s; + width: 28px; + height: 28px; + line-height: 28px; } .holder { - width: 212px; + display: inline-block; height: auto; } .monthAndYear, .year { - font-size: 17px; + font-size: $ms-font-size-m; color: $ms-color-neutralPrimary; } .yearComponents { @@ -448,26 +499,27 @@ $Calendar-dayPicker-margin: 10px; } .goToday { padding: 0 3px; + @include ms-right(20px); } .showWeekNumbers { .table { - .day, + .dayWrapper, .weekday { - width: 26px; + width: 28px; } } } // week numbers style in right-to-left view .showWeekNumbersRTL { .table { - .day, + .dayWrapper, .weekday { - width: 26px; + width: 28px; } } } // Show month picker, if enabled .monthPickerVisible { .wrap { - padding: 10px; + padding: 12px; } // Swap margin for padding so that the border extends the full height. .dayPicker { margin: -$Calendar-dayPicker-margin 0; @@ -475,26 +527,25 @@ $Calendar-dayPicker-margin: 10px; } // Contains the calendar view for picking a day. .dayPicker { @include ms-borderBox; - @include border-right(1px, solid, $ms-color-neutralLight); width: 212px; - min-height: 214px; + min-height: 200px; } // Show the month picker. .monthPicker { display: block; } .optionGrid { height: 150px; - width: 212px; + width: 196px; } // This component is only used on small displays. .toggleMonthView { display: none; } // Position the current year and decade labels. .currentYear, .currentDecade { - font-size: 17px; + font-size: $ms-font-size-m; margin: 0; height: $Calendar-day; - line-height: 26px; + line-height: $Calendar-day; display: inline-block; } // Reduce the size of the month buttons. .monthOption, @@ -502,28 +553,24 @@ $Calendar-dayPicker-margin: 10px; width: $Calendar-month; height: $Calendar-month; line-height: $Calendar-month; - font-size: 12px; - @include margin(0, 11px, 11px, 0); + font-size: $ms-font-size-s; + @include margin(0, 12px, 16px, 0); &:hover { outline: 1px solid transparent; } &:nth-child(4n+4) { - @include margin(0, 0px, 11px, 0); + @include margin(0, 0px, 16px, 0); } } // Position the "Go to today" button below the month picker. .goToday { - @include ms-borderBox; - font-size: 12px; + font-size: $ms-font-size-s; height: $Calendar-day; line-height: $Calendar-day; padding: 0 10px; @include ms-right(8px); @include text-align(right); - top: 199px; } // When date and month picker are side-by-side and "Go to today" button is visible no additional margin is needed - .wrap.goTodaySpacing { - margin-bottom: 0px; - } // State: The picker is showing the year components. + // State: The picker is showing the year components. // On larger screens the calendar will remain and the years // will replace the months. .root.isPickingYears { @@ -543,10 +590,9 @@ $Calendar-dayPicker-margin: 10px; } .calendarsInline { .wrap { - padding: 9px 12px; + padding: 12px; } .holder { - width: 440px; height: auto; } .table { @@ -556,27 +602,25 @@ $Calendar-dayPicker-margin: 10px; width: auto; } .monthPicker { - @include margin-left(13px); + @include margin-left(12px); } .goToday { - @include ms-right(13px); + @include ms-right(14px); padding: 0 10px; } - .monthComponents, - .yearComponents, - .decadeComponents { + .monthComponents { @include margin-right(12px); } } //when month picker is only visible .monthPickerOnly { .wrap { - padding: 10px; + padding: 12px; } } .monthPickerAsOverlay { .wrap { - padding-top: 4px; - padding-bottom: 4px; + padding-bottom: 28px; + margin-bottom: 6px; } .holder { height: 240px; @@ -592,10 +636,6 @@ $Calendar-dayPicker-margin: 10px; // On smaller screens the month button toggles to the picking months state. @media (max-device-width: 459px) { - // Stop elements from going off screen - .holder { - width: 300px; - } .calendarsInline { // Month and year pickers, hidden on small screens by default. .monthPicker, @@ -608,12 +648,6 @@ $Calendar-dayPicker-margin: 10px; } } -// Custom CSS for fabric-React -.wrap span:focus, -.wrap div:focus { - @include focus-border(1px, $ms-color-neutralSecondary); -} - .goToday { width: auto; } @@ -623,23 +657,20 @@ $Calendar-dayPicker-margin: 10px; .nextYear, .prevYear { display: inline-block; + &:hover { background-color: $ms-color-neutralLight; + color: $ms-color-neutralDark; } &: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; + color: $ms-color-neutralPrimary; &.monthOption:hover { background-color: $ms-color-themeLight; } @@ -658,30 +689,22 @@ $Calendar-dayPicker-margin: 10px; .monthOption:active { background-color: $ms-color-themeLight; + color: $ms-color-neutralDark; } // Highlighted Month date styling. -// Border-radius to be updated once rolled out across fabric .topLeftCornerDate { - border-radius: 0; + border-top-left-radius: 2px; } .topRightCornerDate { - border-radius: 0; + border-top-right-radius: 2px; } .bottomLeftCornerDate { - border-radius: 0; + border-bottom-left-radius: 2px; } .bottomRightCornerDate { - border-radius: 0; -} - -.singleTopDate { - border-radius: 0; -} - -.singleBottomDate { - border-radius: 0; + border-bottom-right-radius: 2px; } \ No newline at end of file diff --git a/packages/office-ui-fabric-react/src/components/Calendar/Calendar.test.tsx b/packages/office-ui-fabric-react/src/components/Calendar/Calendar.test.tsx index cf50e4755bc67..bab24cf00884b 100644 --- a/packages/office-ui-fabric-react/src/components/Calendar/Calendar.test.tsx +++ b/packages/office-ui-fabric-react/src/components/Calendar/Calendar.test.tsx @@ -136,10 +136,10 @@ describe('Calendar', () => { expect(renderedComponent.state.selectedDate!.getDate()).toEqual(today.getDate()); expect(renderedComponent.state.selectedDate!.getMonth()).toEqual(today.getMonth()); expect(renderedComponent.state.selectedDate!.getFullYear()).toEqual(today.getFullYear()); - expect(renderedComponent.state.navigatedDate).not.toBeNull(); - expect(renderedComponent.state.navigatedDate!.getDate()).toEqual(today.getDate()); - expect(renderedComponent.state.navigatedDate!.getMonth()).toEqual(today.getMonth()); - expect(renderedComponent.state.navigatedDate!.getFullYear()).toEqual(today.getFullYear()); + expect(renderedComponent.state.navigatedDayDate).not.toBeNull(); + expect(renderedComponent.state.navigatedDayDate!.getDate()).toEqual(today.getDate()); + expect(renderedComponent.state.navigatedDayDate!.getMonth()).toEqual(today.getMonth()); + expect(renderedComponent.state.navigatedDayDate!.getFullYear()).toEqual(today.getFullYear()); }); it('Verify go to today', () => { @@ -196,7 +196,7 @@ describe('Calendar', () => { it('Verify day picker selected date & navigated date', () => { expect(renderedComponent.state.selectedDate).toEqual(defaultDate); - expect(renderedComponent.state.navigatedDate).toEqual(defaultDate); + expect(renderedComponent.state.navigatedDayDate).toEqual(defaultDate); }); it('Verify month picker seen', () => { 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 a79e89f50895c..832a7bd02f179 100644 --- a/packages/office-ui-fabric-react/src/components/Calendar/Calendar.tsx +++ b/packages/office-ui-fabric-react/src/components/Calendar/Calendar.tsx @@ -35,8 +35,11 @@ const dateTimeFormatterCallbacks: ICalendarFormatDateCallbacks = { }; export interface ICalendarState { - /** The currently focused date in the calendar, but not necessarily selected */ - navigatedDate?: Date; + /** The currently focused date in the day picker, but not necessarily selected */ + navigatedDayDate?: Date; + + /** The currently focused date in the month picker, but not necessarily selected */ + navigatedMonthDate?: Date; /** The currently selected date in the calendar */ selectedDate?: Date; @@ -83,7 +86,8 @@ export class Calendar extends BaseComponent impl this.state = { selectedDate: currentDate, - navigatedDate: currentDate, + navigatedDayDate: currentDate, + navigatedMonthDate: currentDate, /** When showMonthPickerAsOverlay is active it overrides isMonthPickerVisible/isDayPickerVisible props (These props permanently set the visibility of their respective calendars). */ isMonthPickerVisible: this.props.showMonthPickerAsOverlay ? false : this.props.isMonthPickerVisible, @@ -101,7 +105,8 @@ export class Calendar extends BaseComponent impl const overrideNavigatedDate = (autoNavigateOnSelection && !compareDates(value!, this.props.value!)); if (overrideNavigatedDate) { this.setState({ - navigatedDate: value + navigatedMonthDate: value, + navigatedDayDate: value }); } @@ -112,12 +117,7 @@ export class Calendar extends BaseComponent impl public componentDidUpdate(): void { if (this._focusOnUpdate) { - // if the day picker is shown, focus on it - if (this._dayPicker.current) { - this._dayPicker.current.focus(); - } else if (this._monthPicker.current) { - this._monthPicker.current.focus(); - } + this.focus(); this._focusOnUpdate = false; } } @@ -125,7 +125,7 @@ export class Calendar extends BaseComponent impl public render(): JSX.Element { const rootClass = 'ms-DatePicker'; const { firstDayOfWeek, dateRangeType, strings, showMonthPickerAsOverlay, autoNavigateOnSelection, showGoToToday, highlightCurrentMonth, highlightSelectedMonth, navigationIcons, minDate, maxDate, className } = this.props; - const { selectedDate, navigatedDate, isMonthPickerVisible, isDayPickerVisible } = this.state; + const { selectedDate, navigatedDayDate, navigatedMonthDate, isMonthPickerVisible, isDayPickerVisible } = this.state; const onHeaderSelect = showMonthPickerAsOverlay ? this._onHeaderSelect : undefined; const monthPickerOnly = !showMonthPickerAsOverlay && !isDayPickerVisible; const overlayedWithButton = showMonthPickerAsOverlay && showGoToToday; @@ -149,10 +149,10 @@ export class Calendar extends BaseComponent impl
{ isDayPickerVisible && impl componentRef={ this._dayPicker } /> } - - { isMonthPickerVisible && } + { isDayPickerVisible && isMonthPickerVisible &&
} + { isMonthPickerVisible && + } { showGoToToday && @@ -170,12 +166,12 @@ export class CalendarDay extends BaseComponent @@ -192,7 +188,7 @@ export class CalendarDay extends BaseComponent - { showWeekNumbers && } + { showWeekNumbers && } { strings.shortDays.map((val, index) => { weeks!.map((week, weekIndex) => { showWeekNumbers && weekNumbers && this._setDayCellRef(element, day, isNavigatedDate) } + onClick={ day.isInBounds ? day.onSelected : undefined } + onMouseOver={ dateRangeType !== DateRangeType.Day ? this._onDayMouseOver(day.originalDate, weekIndex, dayIndex, dateRangeType) : undefined } + onMouseLeave={ dateRangeType !== DateRangeType.Day ? this._onDayMouseLeave(day.originalDate, weekIndex, dayIndex, dateRangeType) : undefined } + onMouseDown={ dateRangeType !== DateRangeType.Day ? this._onDayMouseDown(day.originalDate, weekIndex, dayIndex, dateRangeType) : undefined } + onMouseUp={ dateRangeType !== DateRangeType.Day ? this._onDayMouseUp(day.originalDate, weekIndex, dayIndex, dateRangeType) : undefined } >
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 } >
@@ -297,99 +294,78 @@ export class CalendarDay extends BaseComponent 2) { - cornerIndexes.splice(1, cornerIndexes.length - 2); - } - - return cornerIndexes; + private _setDayCellRef(element: HTMLElement | null, day: IDayInfo, isNavigatedDate: boolean): void { + this.days[day.key] = element; } - private _populateCornerStyles( - weekCornersStyled: any, - weekIndex: number, - cornerIndexes: number[], - singleCornerStyle: string, - leftCornerStyle: string, - rightCornerStyle: string): void { - - const cornersLength = cornerIndexes.length; - if (cornersLength > 0) { - - if (cornersLength === 1) { - - weekCornersStyled[weekIndex + '_' + cornerIndexes[0]] = singleCornerStyle; - - } else if (cornersLength === 2) { - - weekCornersStyled[weekIndex + '_' + cornerIndexes[0]] = leftCornerStyle; - weekCornersStyled[weekIndex + '_' + cornerIndexes[1]] = rightCornerStyle; - } - - if (weekIndex === 0) { - - // check if second week needs corner styles - if (cornerIndexes[0] !== 0) { - weekCornersStyled['1_0'] = leftCornerStyle; - } + private _getWeekCornerStyles(weeks: IDayInfo[][], dateRangeType: DateRangeType): IWeekCorners { + const weekCornersStyled: any = {}; - } else { + switch (dateRangeType) { + case DateRangeType.Month: + /* need to handle setting all of the corners on arbitrarily shaped blobs + __ + __|A | + |B |C |__ + |D |E |F | + + in this case, A needs top left rounded, top right rounded + B needs top left rounded + C doesn't need any rounding + D needs bottom left rounded + E doesn't need any rounding + F needs top right rounding + */ + + // if there's an item above, lose both top corners. Item below, lose both bottom corners, etc. + weeks.forEach((week: IDayInfo[], weekIndex: number) => { + week.forEach((day: IDayInfo, dayIndex: number) => { + const above = weeks[weekIndex - 1] && weeks[weekIndex - 1][dayIndex] && weeks[weekIndex - 1][dayIndex].originalDate.getMonth() === weeks[weekIndex][dayIndex].originalDate.getMonth(); + const below = weeks[weekIndex + 1] && weeks[weekIndex + 1][dayIndex] && weeks[weekIndex + 1][dayIndex].originalDate.getMonth() === weeks[weekIndex][dayIndex].originalDate.getMonth(); + const left = weeks[weekIndex][dayIndex - 1] && weeks[weekIndex][dayIndex - 1].originalDate.getMonth() === weeks[weekIndex][dayIndex].originalDate.getMonth(); + const right = weeks[weekIndex][dayIndex + 1] && weeks[weekIndex][dayIndex + 1].originalDate.getMonth() === weeks[weekIndex][dayIndex].originalDate.getMonth(); + + const roundedTopLeft = !above && !left; + const roundedTopRight = !above && !right; + const roundedBottomLeft = !below && !left; + const roundedBottomRight = !below && !right; + + let style = ''; + if (roundedTopLeft) { + style = getRTL() ? style.concat(styles.topRightCornerDate + ' ') : style.concat(styles.topLeftCornerDate + ' '); + } + if (roundedTopRight) { + style = getRTL() ? style.concat(styles.topLeftCornerDate + ' ') : style.concat(styles.topRightCornerDate + ' '); + } + if (roundedBottomLeft) { + style = getRTL() ? style.concat(styles.bottomRightCornerDate + ' ') : style.concat(styles.bottomLeftCornerDate + ' '); + } + if (roundedBottomRight) { + style = getRTL() ? style.concat(styles.bottomLeftCornerDate + ' ') : style.concat(styles.bottomRightCornerDate + ' '); + } - // Assume we are on the last week. Check if second-to-last week needs corner styles - const lastDayIndex = DAYS_IN_WEEK - 1; - if (cornerIndexes[cornersLength - 1] !== lastDayIndex) { - weekCornersStyled[(weekIndex - 1) + '_' + lastDayIndex] = rightCornerStyle; - } - } + weekCornersStyled[weekIndex + '_' + dayIndex] = style; + }); + }); + break; + case DateRangeType.Week: + case DateRangeType.WorkWeek: + weeks.forEach((week: IDayInfo[], weekIndex: number) => { + const leftStyle = styles.topLeftCornerDate + ' ' + styles.bottomLeftCornerDate; + const rightStyle = styles.topRightCornerDate + ' ' + styles.bottomRightCornerDate; + weekCornersStyled[weekIndex + '_' + 0] = getRTL() ? rightStyle : leftStyle; + weekCornersStyled[weekIndex + '_' + (DAYS_IN_WEEK - 1)] = getRTL() ? leftStyle : rightStyle; + }); + break; } - } - - private _getWeekCornerStyles(weeks: IDayInfo[][]): IWeekCorners { - - const weekCornersStyled: any = {}; - const numberOfWeeks = weeks.length; - const indexesFirstWeek = this._findCornerIndexes(weeks[0]); - const indexesLastWeek = this._findCornerIndexes(weeks[numberOfWeeks - 1]); - - this._populateCornerStyles( - weekCornersStyled, - 0 /* week index */, - indexesFirstWeek, - 'ms-DatePicker-singleTopDate ' + styles.singleTopDate, - 'ms-DatePicker-topLeftCornerDate ' + styles.topLeftCornerDate, - 'ms-DatePicker-topRightCornerDate ' + styles.topRightCornerDate - ); - - this._populateCornerStyles( - weekCornersStyled, - weeks.length - 1 /* week index */, - indexesLastWeek, - 'ms-DatePicker-singleBottomDate ' + styles.singleBottomDate, - 'ms-DatePicker-bottomLeftCornerDate ' + styles.bottomLeftCornerDate, - 'ms-DatePicker-bottomRightCornerDate ' + styles.bottomRightCornerDate - ); return weekCornersStyled; } private _getHighlightedCornerStyle(weekCorners: IWeekCorners, dayIndex: number, weekIndex: number): string { const cornerStyle = weekCorners[weekIndex + '_' + dayIndex] ? weekCorners[weekIndex + '_' + dayIndex] : ''; - return cornerStyle; } @@ -427,85 +403,124 @@ 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); - } - }); + if (dateRangeType === DateRangeType.Month) { + this._applyFunctionToDayRefs((ref, day) => { + if (ref && day.originalDate.getMonth() === originalDate.getMonth()) { + ref.classList.add(styles.dayPress); + } + }); + } else { + // week or work week view + this._applyFunctionToDayRefs((ref, day, dayWeekIndex) => { + if (ref && dayWeekIndex === weekIndex) { + ref.classList.add(styles.dayPress); + ref.classList.add(styles.dayIsHighlighted); + } else if (ref) { + ref.classList.remove(styles.dayIsHighlighted); + } + }); + } }; } - private _onDayMouseUp = (originalDate: Date, weekIndex: number, dayIndex: number) + private _onDayMouseUp = (originalDate: Date, weekIndex: number, dayIndex: number, dateRangeType: DateRangeType) : (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); - } - }); + if (dateRangeType === DateRangeType.Month) { + this._applyFunctionToDayRefs((ref, day) => { + if (ref && day.originalDate.getMonth() === originalDate.getMonth()) { + ref.classList.remove(styles.dayPress); + } + }); + } else { + // week or work week view + this._applyFunctionToDayRefs((ref, day, dayWeekIndex) => { + if (ref && dayWeekIndex === weekIndex) { + ref.classList.remove(styles.dayPress); + } + }); + } }; } - private _onDayMouseOver = (originalDate: Date, weekIndex: number, dayIndex: number) + private _onDayMouseOver = (originalDate: Date, weekIndex: number, dayIndex: number, dateRangeType: DateRangeType) : (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); - } - }); + if (dateRangeType === DateRangeType.Month) { + this._applyFunctionToDayRefs((ref, day) => { + if (ref && day.originalDate.getMonth() === originalDate.getMonth()) { + ref.classList.add(styles.dayHover); + } + }); + } else { + // week or work week view + this._applyFunctionToDayRefs((ref, day, dayWeekIndex) => { + if (ref && dayWeekIndex === weekIndex) { + ref.classList.add(styles.dayHover); + } + }); + } }; } - private _onDayMouseLeave = (originalDate: Date, weekIndex: number, dayIndex: number) + private _onDayMouseLeave = (originalDate: Date, weekIndex: number, dayIndex: number, dateRangeType: DateRangeType) : (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); - } - }); + if (dateRangeType === DateRangeType.Month) { + this._applyFunctionToDayRefs((ref, day) => { + if (ref && day.originalDate.getMonth() === originalDate.getMonth()) { + ref.classList.remove(styles.dayHover); + } + }); + } else { + // week or work week view + this._applyFunctionToDayRefs((ref, day, dayWeekIndex) => { + if (ref && dayWeekIndex === weekIndex) { + ref.classList.remove(styles.dayHover); + } + }); + } }; } private _onTableMouseLeave = (ev: React.MouseEvent): void => { - if ((ev.target as HTMLElement).contains && (ev.target as HTMLElement).contains(ev.relatedTarget as HTMLElement)) { + if ((ev.target as HTMLElement).contains && ev.relatedTarget && (ev.relatedTarget 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); + ref.classList.remove(styles.dayHover); + ref.classList.remove(styles.dayPress); } }); } private _onTableMouseUp = (ev: React.MouseEvent): void => { - if ((ev.target as HTMLElement).contains && (ev.target as HTMLElement).contains(ev.relatedTarget as HTMLElement)) { + if ((ev.target as HTMLElement).contains && ev.relatedTarget && (ev.relatedTarget as HTMLElement).contains && (ev.target as HTMLElement).contains(ev.relatedTarget as HTMLElement)) { return; } this._applyFunctionToDayRefs((ref, day) => { if (ref) { - ref.classList.remove(styles.monthPress); + ref.classList.remove(styles.dayPress); } }); } - private _applyFunctionToDayRefs(func: (ref: HTMLElement | null, day: IDayInfo) => void) { - if (this.state.weeks && this.props.dateRangeType === DateRangeType.Month) { - this.state.weeks.map(week => { + private _applyFunctionToDayRefs(func: (ref: HTMLElement | null, day: IDayInfo, weekIndex?: number) => void) { + if (this.state.weeks) { + this.state.weeks.map((week: IDayInfo[], weekIndex: number) => { week.map(day => { const ref = this.days[day.key]; - func(ref, day); + func(ref, day, weekIndex); }); }); } diff --git a/packages/office-ui-fabric-react/src/components/Calendar/CalendarMonth.tsx b/packages/office-ui-fabric-react/src/components/Calendar/CalendarMonth.tsx index 24997e311c92f..eb5540417ffda 100644 --- a/packages/office-ui-fabric-react/src/components/Calendar/CalendarMonth.tsx +++ b/packages/office-ui-fabric-react/src/components/Calendar/CalendarMonth.tsx @@ -89,11 +89,11 @@ export class CalendarMonth extends BaseComponent { className={ css('ms-DatePicker-prevYear js-prevYear', styles.prevYear, { ['ms-DatePicker-prevYear--disabled ' + styles.prevYearIsDisabled]: !isPrevYearInBounds }) } - onClick={ this._onSelectPrevYear } - onKeyDown={ this._onSelectPrevYearKeyDown } + disabled={ !isPrevYearInBounds } + onClick={ isPrevYearInBounds ? this._onSelectPrevYear : undefined } + onKeyDown={ isPrevYearInBounds ? this._onSelectPrevYearKeyDown : undefined } aria-label={ strings.prevYearAriaLabel ? strings.prevYearAriaLabel + ' ' + dateTimeFormatter.formatYear(addYears(navigatedDate, -1)) : undefined } role='button' - tabIndex={ 0 } > @@ -101,11 +101,11 @@ export class CalendarMonth extends BaseComponent { className={ css('ms-DatePicker-nextYear js-nextYear', styles.nextYear, { ['ms-DatePicker-nextYear--disabled ' + styles.nextYearIsDisabled]: !isNextYearInBounds }) } - onClick={ this._onSelectNextYear } - onKeyDown={ this._onSelectNextYearKeyDown } + disabled={ !isNextYearInBounds } + onClick={ isNextYearInBounds ? this._onSelectNextYear : undefined } + onKeyDown={ isNextYearInBounds ? this._onSelectNextYearKeyDown : undefined } aria-label={ strings.nextYearAriaLabel ? strings.nextYearAriaLabel + ' ' + dateTimeFormatter.formatYear(addYears(navigatedDate, 1)) : undefined } role='button' - tabIndex={ 0 } > @@ -133,13 +133,15 @@ 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) || - (highlightSelectedMonth && isSelectedMonth && isSelectedYear), + ['ms-DatePicker-day--highlighted ' + styles.monthIsHighlighted]: (highlightCurrentMonth || highlightSelectedMonth) && + isSelectedMonth && isSelectedYear, ['ms-DatePicker-monthOption--disabled ' + styles.monthOptionIsDisabled]: !isInBounds }) } + disabled={ !isInBounds } key={ index } onClick={ isInBounds ? this._selectMonthCallbacks[index] : undefined } + onKeyDown={ isInBounds ? this._onSelectMonthKeyDown(index) : undefined } aria-label={ dateTimeFormatter.formatMonthYear(indexedMonth, strings) } aria-selected={ isCurrentMonth || isNavigatedMonth } data-is-focusable={ isInBounds ? true : undefined } @@ -167,7 +169,7 @@ export class CalendarMonth extends BaseComponent { } private _onKeyDown = (callback: () => void, ev: React.KeyboardEvent): void => { - if (ev.which === KeyCodes.enter || ev.which === KeyCodes.space) { + if (ev.which === KeyCodes.enter) { callback(); } } @@ -194,6 +196,10 @@ export class CalendarMonth extends BaseComponent { } } + private _onSelectMonthKeyDown = (index: number): (ev: React.KeyboardEvent) => void => { + return (ev: React.KeyboardEvent) => this._onKeyDown(() => this._onSelectMonth(index), ev); + } + private _onSelectMonth = (newMonth: number): void => { const { navigatedDate, onNavigateDate, onHeaderSelect } = this.props; 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 485a312fa0e01..ae1f8eff4e693 100644 --- a/packages/office-ui-fabric-react/src/components/Calendar/CalendarPage.tsx +++ b/packages/office-ui-fabric-react/src/components/Calendar/CalendarPage.tsx @@ -31,7 +31,7 @@ export class CalendarPage extends React.Component isMonthPickerVisible={ false } dateRangeType={ DateRangeType.Day } autoNavigateOnSelection={ false } - showGoToToday={ false } + showGoToToday={ true } /> isMonthPickerVisible={ false } dateRangeType={ DateRangeType.Day } autoNavigateOnSelection={ false } - showGoToToday={ false } + showGoToToday={ true } showWeekNumbers={ true } /> @@ -99,7 +99,7 @@ export class CalendarPage extends React.Component isMonthPickerVisible={ false } dateRangeType={ DateRangeType.Day } autoNavigateOnSelection={ false } - showGoToToday={ false } + showGoToToday={ true } showSixWeeksByDefault={ true } /> @@ -146,6 +146,7 @@ export class CalendarPage extends React.Component code={ CalendarButtonExampleCode } >
+
@@ -1080,10 +1078,10 @@ exports[`Calendar Test rendering simplest calendar Renders simple calendar corre
@@ -300,7 +303,7 @@ export class DatePicker extends BaseComponent { - if (this._calendar.current) { + if (this._calendar.current && !this.props.disableAutoFocus) { this._calendar.current.focus(); } } @@ -406,10 +409,7 @@ export class DatePicker extends BaseComponent { this._preventFocusOpeningPicker = true; this._dismissDatePickerPopup(); - - if (this._textField.current) { - this._textField.current.focus(); - } + // don't need to focus the text box, if necessary the focusTrapZone will do it } private _handleEscKey = (ev: React.KeyboardEvent): void => { diff --git a/packages/office-ui-fabric-react/src/components/FocusTrapZone/FocusTrapZone.tsx b/packages/office-ui-fabric-react/src/components/FocusTrapZone/FocusTrapZone.tsx index 1c3317f5dd9e0..debd0e6ae5088 100644 --- a/packages/office-ui-fabric-react/src/components/FocusTrapZone/FocusTrapZone.tsx +++ b/packages/office-ui-fabric-react/src/components/FocusTrapZone/FocusTrapZone.tsx @@ -79,7 +79,7 @@ export class FocusTrapZone extends BaseComponent implem if (!ignoreExternalFocusing && this._previouslyFocusedElement && typeof this._previouslyFocusedElement.focus === 'function' && - elementContains(this._root.value, activeElement)) { + (elementContains(this._root.value, activeElement) || activeElement === document.body)) { focusAsync(this._previouslyFocusedElement); } }