Skip to content

Commit

Permalink
Merge dedb21b into 27788f5
Browse files Browse the repository at this point in the history
  • Loading branch information
franmc01 authored Oct 7, 2023
2 parents 27788f5 + dedb21b commit 318be85
Show file tree
Hide file tree
Showing 9 changed files with 172 additions and 10 deletions.
3 changes: 3 additions & 0 deletions docs-site/public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
<meta name="keywords" content="React, HTML, CSS, JavaScript, JSX, date, datepicker">
<title>React Datepicker crafted by HackerOne</title>
<link href="https://fonts.googleapis.com/css?family=Open+Sans&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.2/css/all.min.css"
integrity="sha512-z3gLpd7yknf1YoNbCzqRKc4qyor8gaKU1qmn+CShxbuBusANI9QpRohGBreCFkKxLhei6S9CQXFEbbKuqLg0DA=="
crossorigin="anonymous" referrerpolicy="no-referrer" />
</head>

<body>
Expand Down
10 changes: 10 additions & 0 deletions docs-site/src/components/Examples/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,8 @@ import selectsRangeWithDisabledDates from "../../examples/selectsRangeWithDisabl
import CalendarStartDay from "../../examples/calendarStartDay";
import ExternalForm from "../../examples/externalForm";
import CalendarIcon from "../../examples/calendarIcon";
import CalendarIconExternal from "../../examples/calendarIconExternal";
import CalendarIconSvgIcon from "../../examples/calendarIconSvgIcon";

import "./style.scss";
import "react-datepicker/dist/react-datepicker.css";
Expand All @@ -118,6 +120,14 @@ export default class exampleComponents extends React.Component {
title: "Calendar Icon",
component: CalendarIcon,
},
{
title: "Calendar Icon using React Svg Component",
component: CalendarIconSvgIcon,
},
{
title: "Calendar Icon using External Lib",
component: CalendarIconExternal,
},
{
title: "Calendar container",
component: CalendarContainer,
Expand Down
11 changes: 11 additions & 0 deletions docs-site/src/examples/calendarIconExternal.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
() => {
const [startDate, setStartDate] = useState(new Date());
return (
<DatePicker
showIcon
selected={startDate}
onChange={(date) => setStartDate(date)}
icon="fa fa-calendar"
/>
);
};
33 changes: 33 additions & 0 deletions docs-site/src/examples/calendarIconSvgIcon.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
() => {
const [startDate, setStartDate] = useState(new Date());
return (
<DatePicker
showIcon
selected={startDate}
onChange={(date) => setStartDate(date)}
icon={
<svg
xmlns="http://www.w3.org/2000/svg"
width="1em"
height="1em"
viewBox="0 0 48 48"
>
<mask id="ipSApplication0">
<g fill="none" stroke="#fff" strokeLinejoin="round" strokeWidth="4">
<path strokeLinecap="round" d="M40.04 22v20h-32V22"></path>
<path
fill="#fff"
d="M5.842 13.777C4.312 17.737 7.263 22 11.51 22c3.314 0 6.019-2.686 6.019-6a6 6 0 0 0 6 6h1.018a6 6 0 0 0 6-6c0 3.314 2.706 6 6.02 6c4.248 0 7.201-4.265 5.67-8.228L39.234 6H8.845l-3.003 7.777Z"
></path>
</g>
</mask>
<path
fill="currentColor"
d="M0 0h48v48H0z"
mask="url(#ipSApplication0)"
></path>
</svg>
}
/>
);
};
7 changes: 5 additions & 2 deletions docs/datepicker.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ General datepicker component.
| `injectTimes` | `array` | | |
| `inline` | `bool` | | |
| `isClearable` | `bool` | | |
| `showIcon` | `bool` | | |
| `locale` | `string` | | |
| `maxDate` | `instanceOf(Date)` | | |
| `maxTime` | `instanceOf(Date)` | | |
Expand All @@ -69,7 +68,8 @@ General datepicker component.
| `peekNextMonth` | `bool` | | |
| `placeholderText` | `string` | | |
| `popperClassName` | `string` | | |
| `popperContainer` | `func` | | |
| `popperContainer` | `func` | |
| |
| `popperModifiers` | `object` | | |
| `popperPlacement` | `enumpopperPlacementPositions` | | |
| `preventOpenOnFocus` | `bool` | false | When this is true, the datepicker will not automatically open when the date field is focussed |
Expand Down Expand Up @@ -103,3 +103,6 @@ General datepicker component.
| |
| `yearItemNumber` | `number` | `12` | |
| `yearDropdownItemNumber` | `number` | | |
| `icon` | `string` or `element` | | Allows using a custom calendar icon. Accepts a string (icon class name) or a React component (e.g., custom SVG). If a string is passed, an `<i>` element is rendered with that string as its class name. If a React component is passed, it is rendered as-is. |
| `calendarIconClassName` | `string` | | Accepts a string that will be added as an additional CSS class to the calendar icon, allowing further styling customization. |
| `showIcon` | `bool` | `true` | Determines whether the calendar icon is displayed. Set to `true` to display the icon, and `false` to hide it. If `icon` prop is also provided, the custom icon will be displayed when `showIcon` is `true`. |
43 changes: 43 additions & 0 deletions src/calendar_icon.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import React from "react";
import PropTypes from "prop-types";

const CalendarIcon = ({ icon, className }) => {
const defaultClass = "react-datepicker__calendar-icon";

if (React.isValidElement(icon)) {
return React.cloneElement(icon, {
className: `${icon.props.className || ""} ${defaultClass} ${className}`,
});
}

if (typeof icon === "string") {
return (
<i
className={`${defaultClass} ${icon} ${className}`}
aria-hidden="true"
/>
);
}

// Default SVG Icon
return (
<svg
className="react-datepicker__calendar-icon"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 448 512"
>
<path d="M96 32V64H48C21.5 64 0 85.5 0 112v48H448V112c0-26.5-21.5-48-48-48H352V32c0-17.7-14.3-32-32-32s-32 14.3-32 32V64H160V32c0-17.7-14.3-32-32-32S96 14.3 96 32zM448 192H0V464c0 26.5 21.5 48 48 48H400c26.5 0 48-21.5 48-48V192z" />
</svg>
);
};

CalendarIcon.propTypes = {
icon: PropTypes.oneOfType([PropTypes.string, PropTypes.node]),
className: PropTypes.string,
};

CalendarIcon.defaultProps = {
className: "",
};

export default CalendarIcon;
13 changes: 5 additions & 8 deletions src/index.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React from "react";
import PropTypes from "prop-types";
import Calendar from "./calendar";
import CalendarIcon from "./calendar_icon";
import Portal from "./portal";
import PopperComponent, { popperPlacementPositions } from "./popper_component";
import classnames from "classnames";
Expand Down Expand Up @@ -181,6 +182,8 @@ export default class DatePicker extends React.Component {
inline: PropTypes.bool,
isClearable: PropTypes.bool,
showIcon: PropTypes.bool,
icon: PropTypes.oneOfType([PropTypes.string, PropTypes.node]),
calendarIconClassname: PropTypes.string,
locale: PropTypes.oneOfType([
PropTypes.string,
PropTypes.shape({ locale: PropTypes.object }),
Expand Down Expand Up @@ -1212,21 +1215,15 @@ export default class DatePicker extends React.Component {
};

renderInputContainer() {
const { showIcon } = this.props;
const { showIcon, icon, calendarIconClassname } = this.props;
return (
<div
className={`react-datepicker__input-container${
showIcon ? " react-datepicker__view-calendar-icon" : ""
}`}
>
{showIcon && (
<svg
className="react-datepicker__calendar-icon"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 448 512"
>
<path d="M96 32V64H48C21.5 64 0 85.5 0 112v48H448V112c0-26.5-21.5-48-48-48H352V32c0-17.7-14.3-32-32-32s-32 14.3-32 32V64H160V32c0-17.7-14.3-32-32-32S96 14.3 96 32zM448 192H0V464c0 26.5 21.5 48 48 48H400c26.5 0 48-21.5 48-48V192z" />
</svg>
<CalendarIcon icon={icon} className={calendarIconClassname} />
)}
{this.state.isRenderAriaLiveMessage && this.renderAriaLiveRegion()}
{this.renderDateInput()}
Expand Down
33 changes: 33 additions & 0 deletions test/calendar_icon.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import React from "react";
import { mount } from "enzyme";
import CalendarIcon from "../src/calendar_icon";
import { IconParkSolidApplication } from "./helper_components/calendar_icon";

beforeAll(() => {
jest.spyOn(console, "error").mockImplementation(() => {});
});

afterAll(() => {
console.error.mockRestore();
});

describe("CalendarIcon", () => {
it("renders a custom SVG icon when provided", () => {
const wrapper = mount(
<CalendarIcon showIcon icon={<IconParkSolidApplication />} />,
);
expect(
wrapper.find('[data-testid="icon-park-solid-application"]'),
).toHaveLength(1);
});

it("renders a FontAwesome icon when provided", () => {
const wrapper = mount(<CalendarIcon showIcon icon="fa-example-icon" />);
expect(wrapper.find("i.fa-example-icon")).toHaveLength(1);
});

it("does not render an icon when none is provided", () => {
const wrapper = mount(<CalendarIcon showIcon />);
expect(wrapper.find("svg.react-datepicker__calendar-icon")).toHaveLength(1);
});
});
29 changes: 29 additions & 0 deletions test/helper_components/calendar_icon.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import React from "react";

export function IconParkSolidApplication(props) {
return (
<svg
data-testid="icon-park-solid-application"
xmlns="http://www.w3.org/2000/svg"
width="1em"
height="1em"
viewBox="0 0 48 48"
{...props}
>
<mask id="ipSApplication0">
<g fill="none" stroke="#fff" strokeLinejoin="round" strokeWidth="4">
<path strokeLinecap="round" d="M40.04 22v20h-32V22" />
<path
fill="#fff"
d="M5.842 13.777C4.312 17.737 7.263 22 11.51 22c3.314 0 6.019-2.686 6.019-6a6 6 0 0 0 6 6h1.018a6 6 0 0 0 6-6c0 3.314 2.706 6 6.02 6c4.248 0 7.201-4.265 5.67-8.228L39.234 6H8.845l-3.003 7.777Z"
/>
</g>
</mask>
<path
fill="currentColor"
d="M0 0h48v48H0z"
mask="url(#ipSApplication0)"
/>
</svg>
);
}

0 comments on commit 318be85

Please sign in to comment.