Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions UNRELEASED.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ Use [the changelog guidelines](https://git.io/polaris-changelog-guidelines) to f

### Enhancements

- Added `locale` prop to `DatePicker` to support date format localization

### Bug fixes

- Removed a duplicate `activatorWrapper` in `Popover` when destructuring props ([#916](https://github.com/Shopify/polaris-react/pull/916))
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
"lint": "sewing-kit lint",
"format": "sewing-kit format",
"ts": "tsc --noEmit",
"test": "sewing-kit test",
"test": "env NODE_ICU_DATA=$(node-full-icu-path) sewing-kit test",
Copy link
Contributor Author

@joshuajay joshuajay Jan 15, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This new dependency is to enable Intl to be tested with different locales in jest, where prior it would just default to english no matter what locale you specify in the test..

"test:coverage": "yarn test --coverage",
"test:ci": "yarn test --coverage",
"check": "npm-run-all lint ts test",
Expand Down Expand Up @@ -121,6 +121,7 @@
"enzyme": "^3.7.0",
"enzyme-adapter-react-16": "^1.6.0",
"fs-extra": "^4.0.2",
"full-icu": "^1.2.1",
"generic-names": "^1.0.2",
"glob": "^7.1.2",
"gray-matter": "^4.0.1",
Expand Down
6 changes: 1 addition & 5 deletions src/components/DatePicker/DatePicker.scss
Original file line number Diff line number Diff line change
Expand Up @@ -129,15 +129,11 @@ $in-range-border-color: #9ca6de;
.Weekday {
display: block;
flex: 1 0 0%;
padding: spacing(tight);
margin: spacing(tight) auto;
background: transparent;
font-size: $font-size;
color: color('ink', 'lighter');
text-align: center;

+ .Weekday {
margin-left: -1px;
}
}

.Weekday-current {
Expand Down
63 changes: 25 additions & 38 deletions src/components/DatePicker/DatePicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,6 @@ import {
Year,
isDateAfter,
isDateBefore,
getNextDisplayYear,
getNextDisplayMonth,
getPreviousDisplayYear,
getPreviousDisplayMonth,
Weekdays,
isSameDay,
} from '@shopify/javascript-utilities/dates';
Expand Down Expand Up @@ -42,6 +38,8 @@ export interface BaseProps {
multiMonth?: boolean;
/** First day of week. Sunday by default */
weekStartsOn?: Weekdays;
/** Locale for date formatting. 'en' by default */
locale?: string;
/** Callback when date is selected. */
onChange?(date: Range): void;
/** Callback when month is changed. */
Expand Down Expand Up @@ -84,32 +82,22 @@ export class DatePicker extends React.PureComponent<CombinedProps, State> {
disableDatesBefore,
disableDatesAfter,
weekStartsOn = Weekdays.Sunday,
polaris: {intl},
locale = 'en',
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't we get the locale at the provider level or something like that? Or maybe not?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, this is more for the Polaris team to answer, but is this a pattern they want to have in their library for their components?

} = this.props;

const {hoverDate, focusDate} = this.state;

const showNextYear = getNextDisplayYear(month, year);
const showNextMonth = getNextDisplayMonth(month);

const showNextToNextYear = getNextDisplayYear(showNextMonth, showNextYear);
const showNextToNextMonth = getNextDisplayMonth(showNextMonth);

const showPreviousYear = getPreviousDisplayYear(month, year);
const showPreviousMonth = getPreviousDisplayMonth(month);

const previousMonthName = Months[showPreviousMonth];
const nextMonth = multiMonth
? Months[showNextToNextMonth]
: Months[showNextMonth];
const nextYear = multiMonth ? showNextToNextYear : showNextYear;
const visibleMonth = new Date(year, month);
const previousVisibleMonth = new Date(year, month - 1);
const nextVisibleMonth = new Date(year, month + 1);
const nextToNextVisibleMonth = new Date(year, month + 2);

const secondDatePicker = multiMonth ? (
<Month
onFocus={this.handleFocus}
focusedDate={focusDate}
month={showNextMonth}
year={showNextYear}
month={nextVisibleMonth.getMonth()}
year={nextVisibleMonth.getFullYear()}
selected={deriveRange(selected)}
hoverDate={hoverDate}
onChange={this.handleDateSelection}
Expand All @@ -118,6 +106,7 @@ export class DatePicker extends React.PureComponent<CombinedProps, State> {
disableDatesAfter={disableDatesAfter}
allowRange={allowRange}
weekStartsOn={weekStartsOn}
locale={locale}
/>
) : null;

Expand All @@ -132,41 +121,39 @@ export class DatePicker extends React.PureComponent<CombinedProps, State> {
<Button
plain
icon="arrowLeft"
accessibilityLabel={intl.translate(
'Polaris.DatePicker.previousMonth',
{
previousMonthName,
showPreviousYear,
},
)}
accessibilityLabel={Intl.DateTimeFormat(locale, {
month: 'long',
year: 'numeric',
}).format(previousVisibleMonth)}
// eslint-disable-next-line react/jsx-no-bind
onClick={this.handleMonthChangeClick.bind(
null,
showPreviousMonth,
showPreviousYear,
previousVisibleMonth.getMonth(),
previousVisibleMonth.getFullYear(),
)}
/>
<Button
plain
icon="arrowRight"
accessibilityLabel={intl.translate('Polaris.DatePicker.nextMonth', {
nextMonth,
nextYear,
})}
accessibilityLabel={Intl.DateTimeFormat(locale, {
month: 'long',
year: 'numeric',
}).format(multiMonth ? nextToNextVisibleMonth : nextVisibleMonth)}
// eslint-disable-next-line react/jsx-no-bind
onClick={this.handleMonthChangeClick.bind(
null,
showNextMonth,
showNextYear,
nextVisibleMonth.getMonth(),
nextVisibleMonth.getFullYear(),
)}
/>
</div>
<div className={styles.MonthContainer}>
<Month
locale={locale}
onFocus={this.handleFocus}
focusedDate={focusDate}
month={month}
year={year}
month={visibleMonth.getMonth()}
year={visibleMonth.getFullYear()}
selected={deriveRange(selected)}
hoverDate={hoverDate}
onChange={this.handleDateSelection}
Expand Down
20 changes: 12 additions & 8 deletions src/components/DatePicker/components/Day/Day.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@ import * as React from 'react';
import {classNames} from '@shopify/react-utilities/styles';
import {noop} from '@shopify/javascript-utilities/other';
import {autobind} from '@shopify/javascript-utilities/decorators';
import {Months, isSameDay} from '@shopify/javascript-utilities/dates';
import {isSameDay} from '@shopify/javascript-utilities/dates';
import {withAppProvider, WithAppProviderProps} from '../../../AppProvider';

import * as styles from '../../DatePicker.scss';

export interface Props {
locale?: string;
focused?: boolean;
day?: Date;
selected?: boolean;
Expand Down Expand Up @@ -42,6 +43,7 @@ export class Day extends React.PureComponent<CombinedProps, never> {
inHoveringRange,
disabled,
polaris: {intl},
locale = 'en',
} = this.props;

const handleHover = onHover.bind(null, day);
Expand All @@ -57,14 +59,16 @@ export class Day extends React.PureComponent<CombinedProps, never> {
today && styles['Day-today'],
(inRange || inHoveringRange) && !disabled && styles['Day-inRange'],
);
const date = day.getDate();
const firstDay = day.getDate() === 1;
const tabIndex =
(focused || selected || today || date === 1) && !disabled ? 0 : -1;
(focused || selected || today || firstDay) && !disabled ? 0 : -1;
const ariaLabel = [
`${today ? intl.translate('Polaris.DatePicker.today') : ''}`,
`${Months[day.getMonth()]} `,
`${date} `,
`${day.getFullYear()}`,
today ? intl.translate('Polaris.DatePicker.today') : '',
Intl.DateTimeFormat(locale, {
year: 'numeric',
month: 'long',
day: 'numeric',
}).format(day),
].join('');

return (
Expand All @@ -83,7 +87,7 @@ export class Day extends React.PureComponent<CombinedProps, never> {
aria-disabled={disabled}
role="gridcell"
>
{date}
{Intl.DateTimeFormat(locale, {day: 'numeric'}).format(day)}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Based on this Slack convo:
image

We should keep date for now.

</button>
);
}
Expand Down
16 changes: 16 additions & 0 deletions src/components/DatePicker/components/Day/tests/Day.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -68,4 +68,20 @@ describe('<Day />', () => {
expect(spy).toHaveBeenCalledTimes(1);
});
});

describe('locale', () => {
it('defaults to en locale if no locale is set', () => {
const day = mountWithAppProvider(<Day day={new Date(2019, 0, 14)} />);

expect(day.text()).toEqual('14');
});

it('day is formatted to specified locale', () => {
const day = mountWithAppProvider(
<Day locale="ja" day={new Date(2019, 0, 14)} />,
);

expect(day.text()).toEqual('14日');
});
});
});
45 changes: 30 additions & 15 deletions src/components/DatePicker/components/Month/Month.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import {
dateIsInRange,
dateIsSelected,
getNewRange,
abbreviationForWeekday,
} from '@shopify/javascript-utilities/dates';
import {noop} from '@shopify/javascript-utilities/other';
import {classNames} from '@shopify/react-utilities/styles';
Expand All @@ -20,6 +19,7 @@ import Day from '../Day';
import Weekday from '../Weekday';

export interface Props {
locale?: string;
focusedDate?: Date;
selected?: Range;
hoverDate?: Date;
Expand All @@ -32,8 +32,6 @@ export interface Props {
onChange?(date: Range): void;
onHover?(hoverEnd: Date): void;
onFocus?(date: Date): void;
monthName?(month: Months): string;
weekdayName?(weekday: Weekdays): string;
}

const WEEKDAYS = [
Expand All @@ -47,6 +45,7 @@ const WEEKDAYS = [
];

export default function Month({
locale = 'en',
focusedDate,
selected,
hoverDate,
Expand All @@ -67,26 +66,39 @@ export default function Month({
styles.Title,
current && styles['Month-current'],
);

const weeks = getWeeksForMonth(month, year, weekStartsOn);
const weekdays = getWeekdaysOrdered(weekStartsOn).map((weekday) => (
<Weekday
key={weekday}
title={abbreviationForWeekday(weekday)}
current={current && new Date().getDay() === weekday}
label={weekday}
/>
));

const weekdayFormat = Intl.DateTimeFormat(locale, {weekday: 'short'});

const weekdays = getWeekdaysOrdered(weekStartsOn).map((weekday) => {
// October 1, 2017 is a Sunday
const arbitraryWeekdayDate = new Date(2017, 9, weekday + 1);

return (
<Weekday
key={weekday}
title={weekdayFormat.format(arbitraryWeekdayDate)}
current={current && new Date().getDay() === weekday}
label={weekday}
/>
);
});

function handleDateClick(selectedDate: Date) {
onChange(getNewRange(allowRange && selected, selectedDate));
}

function renderWeek(day: Date, dayIndex: number) {
if (day == null) {
const lastDayOfMonth = new Date(year, (month as number) + 1, 0);
const lastDayOfMonth = new Date(year, month + 1, 0);
return (
// eslint-disable-next-line react/jsx-no-bind
<Day key={dayIndex} onHover={onHover.bind(null, lastDayOfMonth)} />
<Day
key={dayIndex}
// eslint-disable-next-line react/jsx-no-bind
onHover={onHover.bind(null, lastDayOfMonth)}
Copy link
Contributor Author

@joshuajay joshuajay Jan 15, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if we still need these .bind()'s since we're using @autobind below..
..didn't want to change too much unrelated in this PR though

locale={locale}
/>
);
}

Expand All @@ -96,6 +108,7 @@ export default function Month({

return (
<Day
locale={locale}
focused={focusedDate != null && isSameDay(day, focusedDate)}
day={day}
key={dayIndex}
Expand Down Expand Up @@ -123,7 +136,9 @@ export default function Month({
return (
<div role="grid" className={styles.Month}>
<div className={className}>
{Months[month]} {year}
{Intl.DateTimeFormat(locale, {month: 'long', year: 'numeric'}).format(
new Date(year, month),
)}
</div>
<div role="rowheader" className={styles.WeekHeadings}>
{weekdays}
Expand Down
Loading