Skip to content

Commit

Permalink
feat: added DatePicker (#58)
Browse files Browse the repository at this point in the history
* chore: wip datepicker

* chore: wip style fixes

* feat: wip added datepicker

* chore: focus on current date on datepicker toggle

* chore: minor refactors

* fix: datepicker disclosure focus restore not working

* refactor: refactored duplicate calendar component

* feat: added Tab behaviour in datepicker spinbuttons composite

* fix: ensure tabIndex 0

* feat: alt arrowdown to open dropdown

* refactor: reorganized & refactored code

* fix: datepicker on open focus on selected date

* chore: fixed calendar types & dateSegment composite spread

* feat: datepicker v3 (#70)

* refactor(datepicker): ♻️  organize imports and improve code flow

* feat(datepicker): ✨  add controllable date picker

* refactor(date-picker): ♻️  bring popover close focus back

* fix(date-picker): 🐛  fix focus spin button on focus

* fix(date-picker): 🐛  fix outside click moving focus to button

* refactor(date-picker): ♻️  arrange imports

* refactor(date-picker): 🏷️  update types for Date Segment

* fix(date-picker): 🐛  fix focus movements

* fix(date-picker): 🐛  fix focus & date values

* fix: calendar day value lag & few css improvements

Co-authored-by: Anurag <hazru.anurag@gmail.com>

* fix: range calendar start date iso timing lag

* chore: datepicker stories improvements (#72)

* refactor(date-picker): ♻️  added more stories

* refactor(date-picker): ♻️  add disabled styles

* feat: added segment component (#71)

* feat: added Segment component

* refactor: review updates & segment aria label fix

* chore: event listener rename

* feat: added Segment component to DatePicker

* fix: datepicker propagation

* refactor: unified DateValue type import & removed extra composite in DatePickerState

* chore: fieldvalue fix

* chore: removed DOMProps

* test: css ignore tests

Co-authored-by: Navin Moorthy <navin007.a@gmail.com>
  • Loading branch information
anuraghazra and navin-moorthy authored Oct 7, 2020
1 parent 4dc06ef commit 2698ddf
Show file tree
Hide file tree
Showing 29 changed files with 1,823 additions and 131 deletions.
3 changes: 3 additions & 0 deletions jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,7 @@ module.exports = {
testMatch: [join(__dirname, "src/**/*.test.{js,ts,tsx}")],
setupFilesAfterEnv: ["<rootDir>/jest.setup.js"],
preset: "ts-jest",
moduleNameMapper: {
"\\.(css|less|sass|scss)$": "<rootDir>/src/__mocks__/styleMock.js",
},
};
1 change: 1 addition & 0 deletions src/__mocks__/styleMock.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = {};
7 changes: 4 additions & 3 deletions src/calendar/CalendarState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,13 @@ import {
import { CalendarProps } from "./index.d";
import { useWeekStart } from "./useWeekStart";
import { announce } from "../utils/LiveAnnouncer";
import { generateDaysInMonthArray, isInvalid, useWeekDays } from "./__utils";
import { isInvalid, useWeekDays, generateDaysInMonthArray } from "./__utils";

export interface IUseCalendarProps extends CalendarProps {
export interface CalendarStateInitialProps extends Partial<CalendarProps> {
id?: string;
}

export function useCalendarState(props: IUseCalendarProps = {}) {
export function useCalendarState(props: CalendarStateInitialProps = {}) {
const {
minValue: initialMinValue,
maxValue: initialMaxValue,
Expand Down Expand Up @@ -142,6 +142,7 @@ export function useCalendarState(props: IUseCalendarProps = {}) {
currentMonth,
setCurrentMonth,
focusedDate,
focusCell,
setFocusedDate,
focusNextDay() {
focusCell(addDays(focusedDate, 1));
Expand Down
1 change: 1 addition & 0 deletions src/calendar/__keys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ const CALENDAR_STATE_KEYS = [
"currentMonth",
"setCurrentMonth",
"focusedDate",
"focusCell",
"setFocusedDate",
"focusNextDay",
"focusPreviousDay",
Expand Down
9 changes: 5 additions & 4 deletions src/calendar/__utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@
* All credit goes to [React Spectrum](https://github.com/adobe/react-spectrum)
* for these utils inspiration
*/
import { DateValue } from "./index.d";
import { endOfDay, setDay } from "date-fns";
import { RangeValue } from "@react-types/shared";
import { useDateFormatter } from "@react-aria/i18n";
import { endOfDay, setDay, startOfDay } from "date-fns";

import { DateValue } from "../calendar/index.d";

export function isInvalid(
date: Date,
Expand Down Expand Up @@ -40,7 +41,7 @@ export function generateDaysInMonthArray(
const daysInWeek = [...new Array(7).keys()].reduce(
(days: Date[], dayIndex) => {
const day = weekIndex * 7 + dayIndex - monthStartsAt + 1;
const cellDate = new Date(year, month, day);
const cellDate = new Date(year, month, day, new Date().getHours());

return [...days, cellDate];
},
Expand All @@ -58,7 +59,7 @@ export function makeRange(start: Date, end: Date): RangeValue<Date> {
[start, end] = [end, start];
}

return { start: startOfDay(start), end: endOfDay(end) };
return { start: start, end: endOfDay(end) };
}

export function convertRange(range: RangeValue<DateValue>): RangeValue<Date> {
Expand Down
133 changes: 10 additions & 123 deletions src/calendar/stories/Calendar.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,129 +3,16 @@ import { Meta } from "@storybook/react";
import { addDays, addWeeks, subWeeks } from "date-fns";

import "./index.css";
import {
Calendar,
DateValue,
CalendarCell,
CalendarGrid,
CalendarHeader,
CalendarButton,
IUseCalendarProps,
useCalendarState,
CalendarCellButton,
CalendarWeekTitle,
} from "../index";
import { DateValue } from "../index.d";
import { CalendarComponent } from "./CalendarComponent";

export default {
title: "Component/Calendar",
} as Meta;

const CalendarComp: React.FC<IUseCalendarProps> = props => {
const state = useCalendarState(props);

return (
<Calendar {...state} className="calendar">
<div className="header">
<CalendarButton {...state} goto="previousYear" className="prev-year">
<svg
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
d="M11 19l-7-7 7-7m8 14l-7-7 7-7"
></path>
</svg>
</CalendarButton>
<CalendarButton {...state} goto="previousMonth" className="prev-month">
<svg
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
d="M15 19l-7-7 7-7"
></path>
</svg>
</CalendarButton>
<CalendarHeader {...state} />
<CalendarButton {...state} goto="nextMonth" className="next-month">
<svg
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
d="M9 5l7 7-7 7"
></path>
</svg>
</CalendarButton>
<CalendarButton {...state} goto="nextYear" className="next-year">
<svg
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
d="M13 5l7 7-7 7M5 5l7 7-7 7"
></path>
</svg>
</CalendarButton>
</div>

<CalendarGrid {...state} as="table" className="dates">
<thead>
<tr>
{state.weekDays.map((day, dayIndex) => {
return (
<CalendarWeekTitle
{...state}
as="th"
scope="col"
key={dayIndex}
dayIndex={dayIndex}
>
<abbr title={day.title}>{day.abbr}</abbr>
</CalendarWeekTitle>
);
})}
</tr>
</thead>
<tbody>
{state.daysInMonth.map((week, weekIndex) => (
<tr key={weekIndex}>
{week.map((day, dayIndex) => (
<CalendarCell {...state} as="td" key={dayIndex} date={day}>
<CalendarCellButton {...state} date={day} />
</CalendarCell>
))}
</tr>
))}
</tbody>
</CalendarGrid>
</Calendar>
);
};

export const Default = () => <CalendarComp />;
export const Default = () => <CalendarComponent />;
export const DefaultValue = () => (
<CalendarComp defaultValue={addDays(new Date(), 1)} />
<CalendarComponent defaultValue={new Date(2001, 0, 1)} />
);
export const ControlledValue = () => {
const [value, setValue] = React.useState<DateValue>(addDays(new Date(), 1));
Expand All @@ -137,27 +24,27 @@ export const ControlledValue = () => {
onChange={e => setValue(new Date(e.target.value))}
value={(value as Date).toISOString().slice(0, 10)}
/>
<CalendarComp value={value} onChange={setValue} />
<CalendarComponent value={value} onChange={setValue} />
</div>
);
};
export const MinMaxDate = () => (
<CalendarComp minValue={new Date()} maxValue={addWeeks(new Date(), 1)} />
<CalendarComponent minValue={new Date()} maxValue={addWeeks(new Date(), 1)} />
);
export const MinMaxDefaultDate = () => (
<CalendarComp
<CalendarComponent
defaultValue={new Date()}
minValue={subWeeks(new Date(), 1)}
maxValue={addWeeks(new Date(), 1)}
/>
);
export const isDisabled = () => (
<CalendarComp defaultValue={addDays(new Date(), 1)} isDisabled />
<CalendarComponent defaultValue={addDays(new Date(), 1)} isDisabled />
);
export const isReadOnly = () => (
<CalendarComp defaultValue={addDays(new Date(), 1)} isReadOnly />
<CalendarComponent defaultValue={addDays(new Date(), 1)} isReadOnly />
);
export const autoFocus = () => (
// eslint-disable-next-line jsx-a11y/no-autofocus
<CalendarComp defaultValue={addDays(new Date(), 1)} autoFocus />
<CalendarComponent defaultValue={addDays(new Date(), 1)} autoFocus />
);
122 changes: 122 additions & 0 deletions src/calendar/stories/CalendarComponent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import React from "react";

import "./index.css";
import {
Calendar as CalendarWrapper,
CalendarButton,
CalendarCell,
CalendarCellButton,
CalendarGrid,
CalendarHeader,
CalendarWeekTitle,
CalendarStateInitialProps,
useCalendarState,
} from "../index";
import { CalendarStateReturn } from "../CalendarState";

export const CalendarComp: React.FC<CalendarStateReturn> = state => {
return (
<CalendarWrapper {...state} className="calendar">
<div className="header">
<CalendarButton {...state} goto="previousYear" className="prev-year">
<svg
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
d="M11 19l-7-7 7-7m8 14l-7-7 7-7"
></path>
</svg>
</CalendarButton>
<CalendarButton {...state} goto="previousMonth" className="prev-month">
<svg
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
d="M15 19l-7-7 7-7"
></path>
</svg>
</CalendarButton>
<CalendarHeader {...state} />
<CalendarButton {...state} goto="nextMonth" className="next-month">
<svg
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
d="M9 5l7 7-7 7"
></path>
</svg>
</CalendarButton>
<CalendarButton {...state} goto="nextYear" className="next-year">
<svg
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
d="M13 5l7 7-7 7M5 5l7 7-7 7"
></path>
</svg>
</CalendarButton>
</div>

<CalendarGrid {...state} as="table" className="dates">
<thead>
<tr>
{state.weekDays.map((day, dayIndex) => {
return (
<CalendarWeekTitle
{...state}
as="th"
scope="col"
key={dayIndex}
dayIndex={dayIndex}
>
<abbr title={day.title}>{day.abbr}</abbr>
</CalendarWeekTitle>
);
})}
</tr>
</thead>
<tbody>
{state.daysInMonth.map((week, weekIndex) => (
<tr key={weekIndex}>
{week.map((day, dayIndex) => (
<CalendarCell {...state} as="td" key={dayIndex} date={day}>
<CalendarCellButton {...state} date={day} />
</CalendarCell>
))}
</tr>
))}
</tbody>
</CalendarGrid>
</CalendarWrapper>
);
};

export const CalendarComponent: React.FC<CalendarStateInitialProps> = props => {
const state = useCalendarState(props);

return <CalendarComp {...state} />;
};
1 change: 1 addition & 0 deletions src/calendar/stories/RangeCalendar.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ export const DefaultValue = () => (
export const ControlledValue = () => {
const [start, setStart] = React.useState<DateValue>(subDays(new Date(), 1));
const [end, setEnd] = React.useState<DateValue>(addDays(new Date(), 1));

return (
<div>
<input
Expand Down
1 change: 0 additions & 1 deletion src/calendar/stories/index.css
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
.calendar {
margin-top: 1em;
max-width: 320px;
position: relative;
}
Expand Down
Loading

0 comments on commit 2698ddf

Please sign in to comment.