Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add overlayComponent prop #563

Merged
merged 7 commits into from
Nov 24, 2017
Merged
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
703 changes: 492 additions & 211 deletions CHANGELOG.md

Large diffs are not rendered by default.

33 changes: 33 additions & 0 deletions docs/src/code-samples/examples/input-custom-overlay.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import React from 'react';
import { formatMonthTitle } from '../../../../src/LocaleUtils';
import DayPickerInput from '../../../../src/DayPickerInput';
import '../../../../src/style.css';
// import 'react-day-picker/lib/style.css';

function CustomOverlay({ classNames, selectedDay, month, children }) {
return (
<div className={classNames.overlayWrapper} style={{ marginLeft: -100 }}>
<div className={classNames.overlay}>
<h3>{formatMonthTitle(month)}</h3>
<p>
{selectedDay
? `You picked: ${selectedDay.toLocaleDateString()}`
: 'Please pick a day'}
</p>
{children}
</div>
</div>
);
}

export default function Example() {
return (
<div>
<p>Please type a day:</p>
<DayPickerInput
placeholder="MM/DD/YYYY"
overlayComponent={CustomOverlay}
/>
</div>
);
}
7 changes: 5 additions & 2 deletions docs/src/containers/ExamplePage.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,11 @@ export default function ExamplePage({ children, title }) {
</Menu.Item>
</Menu>
<Menu subtitle="Input field">
<Menu.Item to="/examples/input-advanced">
Advanced input
<Menu.Item to="/examples/input-state">
Using input with state
</Menu.Item>
<Menu.Item to="/examples/input-custom-overlay">
Customize the overlay
</Menu.Item>
</Menu>
<Menu subtitle="Matching days">
Expand Down
14 changes: 5 additions & 9 deletions docs/src/pages/api/DayPicker.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,8 @@ export default () => (

<h4>Event handlers</h4>
<p>
<a href="#onBlur">onBlur</a>, <a href="#onCaptionClick">
onCaptionClick
</a>, <a href="#onDayClick">onDayClick</a>,{' '}
<a href="#onDayFocus">onDayFocus</a>,{' '}
<a href="#onBlur">onBlur</a>, <a href="#onCaptionClick">onCaptionClick</a>,{' '}
<a href="#onDayClick">onDayClick</a>, <a href="#onDayFocus">onDayFocus</a>,{' '}
<a href="#onDayKeyDown">onDayKeyDown</a>,{' '}
<a href="#onDayMouseDown">onDayMouseDown</a>,{' '}
<a href="#onDayMouseEnter">onDayMouseEnter</a>,{' '}
Expand Down Expand Up @@ -121,9 +119,7 @@ export default () => (
passed to the component.
</li>
<li>
<code>onClick</code> The <a href="#onCaptionClick">
onCaptionClick
</a>{' '}
<code>onClick</code> The <a href="#onCaptionClick">onCaptionClick</a>{' '}
function, if specified.
</li>
</ul>
Expand Down Expand Up @@ -277,7 +273,7 @@ export default () => (
locale <code>String = &quot;en&quot;</code>
</h3>
<p>
The calendar’s locale. See {' '}
The calendar’s locale. See{' '}
<Link to="/docs/localization">Localization</Link>.
</p>
<h3>
Expand All @@ -289,7 +285,7 @@ export default () => (
</h3>
<p>
Object of functions to format dates and to get the first day of the
week. You can pass your own object for advanced localization. See {' '}
week. You can pass your own object for advanced localization. See{' '}
<Link to="/docs/localization">Localization</Link>.
</p>
<h3>
Expand Down
26 changes: 25 additions & 1 deletion docs/src/pages/api/DayPickerInput.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ export default () => (
<a href="#clickUnselectsDay">clickUnselectsDay</a>,{' '}
<a href="#component">component</a>,{' '}
<a href="#dayPickerProps">dayPickerProps</a>, <a href="#format">format</a>,{' '}
<a href="#hideOnDayClick">hideOnDayClick</a>
<a href="#hideOnDayClick">hideOnDayClick</a>,{' '}
<a href="#overlayComponent">overlayComponent</a>
</p>
<h4>Event handlers</h4>
<p>
Expand Down Expand Up @@ -124,6 +125,29 @@ function MyDayPickerInput(props) {
</h3>
<p>Hide the overlay when the user clicks on a day cell.</p>

<h3>
<Anchor id="overlayComponent" />
overlayComponent <code>React.Component</code>
</h3>
<p>
A React element or constructor to use as overlay. The element will
receive the following props:
</p>
<ul>
<li>
<code>selectedDay: ?Date</code> The currently selected day
</li>
<li>
<code>month: Date</code> The month displayed in the calendar
</li>
<li>
<code>input: DOM Element</code> The input field
</li>
</ul>
<p>
See also <Link to="/examples/input-custom-overlay">this example</Link>.
</p>

<hr />
<h2>Event handlers</h2>

Expand Down
2 changes: 1 addition & 1 deletion docs/src/pages/examples/input-advanced.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@ import CodeSample from '../../ui/CodeSample';

export default () => (
<ExamplePage title="Advanced input field">
<CodeSample name="examples/input-advanced" />
<CodeSample name="examples/input-state" />
</ExamplePage>
);
14 changes: 14 additions & 0 deletions docs/src/pages/examples/input-custom-overlay.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import React from 'react';

import ExamplePage from '../../containers/ExamplePage';
import CodeSample from '../../ui/CodeSample';

export default () => (
<ExamplePage title="Customize the DayPickerInput overlay">
<p>
Use the <code>overlayComponent</code> prop to use another component for
rendering the overlay.
</p>
<CodeSample name="examples/input-custom-overlay" />
</ExamplePage>
);
15 changes: 15 additions & 0 deletions docs/src/pages/examples/input-state.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import React from 'react';

import ExamplePage from '../../containers/ExamplePage';
import CodeSample from '../../ui/CodeSample';

export default () => (
<ExamplePage title="Using input field with state">
<p>
This example shows how to handle the state in the parent component. Note
that disabled days cannot be picked from the overlay, but they may be set
in the input field.
</p>
<CodeSample name="examples/input-state" />
</ExamplePage>
);
8 changes: 7 additions & 1 deletion docs/src/pages/examples/input.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
import React from 'react';

import Link from 'gatsby-link';
import ExamplePage from '../../containers/ExamplePage';
import CodeSample from '../../ui/CodeSample';

export default () => (
<ExamplePage title="Input field">
<p>
<Link to="/api/DayPickerInput">DayPickerInput</Link> binds the DayPicker
with an input field. See also how to{' '}
<Link to="/examples/input-state">use it with state</Link> and how to{' '}
<Link to="/examples/input-custom-overlay">customize the overlay</Link>.
</p>
<CodeSample name="examples/input" />
</ExamplePage>
);
86 changes: 51 additions & 35 deletions src/DayPickerInput.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export default class DayPickerInput extends React.Component {
hideOnDayClick: PropTypes.bool,
clickUnselectsDay: PropTypes.bool,
component: PropTypes.any,
overlayComponent: PropTypes.any,

classNames: PropTypes.shape({
container: PropTypes.string,
Expand All @@ -45,6 +46,11 @@ export default class DayPickerInput extends React.Component {
hideOnDayClick: true,
clickUnselectsDay: false,
component: 'input',
overlayComponent: ({ children, classNames }) => (
<div className={classNames.overlayWrapper}>
<div className={classNames.overlay}>{children}</div>
</div>
),
classNames: {
container: 'DayPickerInput',
overlayWrapper: 'DayPickerInput-OverlayWrapper',
Expand All @@ -54,15 +60,17 @@ export default class DayPickerInput extends React.Component {

constructor(props) {
super(props);

this.state = this.getStateFromProps(props);
this.state.showOverlay = false;

this.hideAfterDayClick = this.hideAfterDayClick.bind(this);
this.handleContainerMouseDown = this.handleContainerMouseDown.bind(this);
this.handleInputClick = this.handleInputClick.bind(this);
this.handleInputFocus = this.handleInputFocus.bind(this);
this.handleInputBlur = this.handleInputBlur.bind(this);
this.handleInputChange = this.handleInputChange.bind(this);
this.handleInputOnKeyUp = this.handleInputOnKeyUp.bind(this);
this.handleInputKeyUp = this.handleInputKeyUp.bind(this);
this.handleDayClick = this.handleDayClick.bind(this);
}

Expand Down Expand Up @@ -239,7 +247,7 @@ export default class DayPickerInput extends React.Component {
this.updateState(day, value);
}

handleInputOnKeyUp(e) {
handleInputKeyUp(e) {
// Hide the overlay if the ESC key is pressed
this.setState({ showOverlay: e.keyCode !== ESC });
if (this.props.onKeyUp) {
Expand Down Expand Up @@ -311,49 +319,57 @@ export default class DayPickerInput extends React.Component {
onTodayButtonClick = () =>
this.updateState(new Date(), moment().format(this.props.format));
}

const Overlay = this.props.overlayComponent;
return (
<div className={classNames.overlayWrapper}>
<div className={classNames.overlay}>
<DayPicker
ref={el => (this.daypicker = el)}
localeUtils={MomentLocaleUtils}
fixedWeeks
onTodayButtonClick={onTodayButtonClick}
{...dayPickerProps}
month={this.state.month}
selectedDays={selectedDay}
onDayClick={this.handleDayClick}
/>
</div>
</div>
<Overlay
classNames={classNames}
month={this.state.month}
selectedDay={selectedDay}
input={this.input}
>
<DayPicker
ref={el => (this.daypicker = el)}
localeUtils={MomentLocaleUtils}
fixedWeeks
onTodayButtonClick={onTodayButtonClick}
{...dayPickerProps}
month={this.state.month}
selectedDays={selectedDay}
onDayClick={this.handleDayClick}
onMonthChange={month => this.setState({ month })}
/>
</Overlay>
);
}

render() {
const inputProps = { ...this.props };
delete inputProps.component;
delete inputProps.dayPickerProps;
delete inputProps.format;
delete inputProps.clickUnselectsDay;
delete inputProps.hideOnDayClick;
delete inputProps.onDayChange;
delete inputProps.classNames;
const {
component,
overlayComponent,
dayPickerProps,
format,
clickUnselectsDay,
hideOnDayClick,
onDayChange,
classNames,
...inputProps
} = this.props;
const Input = this.props.component;
return (
<div
className={this.props.classNames.container}
onMouseDown={this.handleContainerMouseDown}
>
{React.createElement(this.props.component, {
ref: el => (this.input = el),
...inputProps,
value: this.state.value,
onChange: this.handleInputChange,
onFocus: this.handleInputFocus,
onBlur: this.handleInputBlur,
onKeyUp: this.handleInputOnKeyUp,
onClick: this.handleInputClick,
})}
<Input
ref={el => (this.input = el)}
{...inputProps}
value={this.state.value}
onChange={this.handleInputChange}
onFocus={this.handleInputFocus}
onBlur={this.handleInputBlur}
onKeyUp={this.handleInputKeyUp}
onClick={this.handleInputClick}
/>
{this.state.showOverlay && this.renderOverlay()}
</div>
);
Expand Down
13 changes: 9 additions & 4 deletions types/props.d.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// TypeScript Version: 2.2

import * as React from "react";
import { ClassNames, Modifier, Modifiers, DayModifiers } from "./common";
import { LocaleUtils } from "./utils";
import * as React from 'react';
import { ClassNames, Modifier, Modifiers, DayModifiers } from './common';
import { LocaleUtils } from './utils';

export interface CaptionElementProps {
date: Date;
Expand Down Expand Up @@ -43,7 +43,10 @@ export interface DayPickerProps {
| React.SFC<CaptionElementProps>;
className?: string;
classNames?: ClassNames;
containerProps?: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>;
containerProps?: React.DetailedHTMLProps<
React.HTMLAttributes<HTMLDivElement>,
HTMLDivElement
>;
disabledDays?: Modifier | Modifier[];
enableOutsideDays?: boolean;
firstDayOfWeek?: number;
Expand Down Expand Up @@ -147,8 +150,10 @@ export interface DayPickerInputProps {
dayPickerProps?: DayPickerProps;
hideOnDayClick?: boolean;
clickUnselectsDay?: boolean;

// Not sure React.ComponentClass<any> is the right type for _propTypes2.default.any
component?: any;
overlayComponent?: any;

classNames?: ClassNames;

Expand Down