├── .babelrc ├── .coveralls.yml ├── .editorconfig ├── .eslintignore ├── .eslintrc.json ├── .github ├── ISSUE_TEMPLATE │ └── bug_report.md └── workflows │ ├── publish.yml │ └── run-tests.yaml ├── .gitignore ├── .nvmrc ├── .storybook ├── addons.js ├── config.js ├── preview-head.html └── webpack.config.js ├── .travis.yml ├── .yarnclean ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── config ├── jest.client.js ├── jest.common.js ├── jest.lint.js ├── rollup.config.js ├── setupTest.ts └── tsconfig.base.json ├── docs ├── THEME_PROPS.md ├── datepicker.gif ├── logo.jpg └── migrating.md ├── jest.config.js ├── lerna.json ├── package.json ├── packages ├── hooks │ ├── CHANGELOG.md │ ├── README.md │ ├── lib │ │ ├── index.cjs.js │ │ ├── index.d.ts │ │ ├── index.esm.js │ │ ├── useDatepicker │ │ │ ├── index.d.ts │ │ │ ├── useDatepicker.d.ts │ │ │ ├── useDatepicker.test.d.ts │ │ │ └── useDatepicker.utils.d.ts │ │ ├── useDay │ │ │ ├── index.d.ts │ │ │ ├── useDay.d.ts │ │ │ └── useDay.test.d.ts │ │ └── useMonth │ │ │ ├── index.d.ts │ │ │ ├── useMonth.d.ts │ │ │ ├── useMonth.test.d.ts │ │ │ └── useMonth.utils.d.ts │ ├── package.json │ ├── rollup.config.js │ ├── src │ │ ├── index.ts │ │ ├── useDatepicker │ │ │ ├── index.ts │ │ │ ├── useDatepicker.test.ts │ │ │ ├── useDatepicker.ts │ │ │ └── useDatepicker.utils.ts │ │ ├── useDay │ │ │ ├── index.ts │ │ │ ├── useDay.test.ts │ │ │ └── useDay.ts │ │ └── useMonth │ │ │ ├── index.ts │ │ │ ├── useMonth.test.ts │ │ │ ├── useMonth.ts │ │ │ └── useMonth.utils.ts │ ├── tsconfig.json │ └── yarn.lock └── styled │ ├── CHANGELOG.md │ ├── README.md │ ├── lib │ ├── components │ │ ├── Box │ │ │ ├── Box.d.ts │ │ │ ├── Box.test.d.ts │ │ │ └── index.d.ts │ │ ├── Close │ │ │ ├── Close.d.ts │ │ │ ├── Close.test.d.ts │ │ │ └── index.d.ts │ │ ├── DateRangeInput │ │ │ ├── DateRangeInput.d.ts │ │ │ ├── DateRangeInput.stories.d.ts │ │ │ ├── DateRangeInput.test.d.ts │ │ │ └── index.d.ts │ │ ├── DateSingleInput │ │ │ ├── DateSingleInput.d.ts │ │ │ ├── DateSingleInput.stories.d.ts │ │ │ ├── DateSingleInput.test.d.ts │ │ │ └── index.d.ts │ │ ├── Datepicker │ │ │ ├── Datepicker.d.ts │ │ │ ├── Datepicker.stories.d.ts │ │ │ ├── Datepicker.test.d.ts │ │ │ └── index.d.ts │ │ ├── Day │ │ │ ├── Day.d.ts │ │ │ ├── Day.test.d.ts │ │ │ └── index.d.ts │ │ ├── DayLabel │ │ │ ├── DayLabel.d.ts │ │ │ ├── DayLabel.test.d.ts │ │ │ └── index.d.ts │ │ ├── Flex │ │ │ ├── Flex.d.ts │ │ │ ├── Flex.test.d.ts │ │ │ └── index.d.ts │ │ ├── Grid │ │ │ ├── Grid.d.ts │ │ │ ├── Grid.test.d.ts │ │ │ └── index.d.ts │ │ ├── Input │ │ │ ├── Input.d.ts │ │ │ ├── Input.test.d.ts │ │ │ └── index.d.ts │ │ ├── Month │ │ │ ├── Month.d.ts │ │ │ ├── Month.test.d.ts │ │ │ └── index.d.ts │ │ ├── MonthLabel │ │ │ ├── MonthLabel.d.ts │ │ │ ├── MonthLabel.test.d.ts │ │ │ └── index.d.ts │ │ ├── NavButton │ │ │ ├── NavButton.d.ts │ │ │ ├── NavButton.test.d.ts │ │ │ └── index.d.ts │ │ ├── ResetDates │ │ │ ├── ResetDates.d.ts │ │ │ ├── ResetDates.test.d.ts │ │ │ └── index.d.ts │ │ ├── SelectedDate │ │ │ ├── SelectedDate.d.ts │ │ │ ├── SelectedDate.test.d.ts │ │ │ └── index.d.ts │ │ └── Text │ │ │ ├── Test.test.d.ts │ │ │ ├── Text.d.ts │ │ │ └── index.d.ts │ ├── context │ │ └── datepickerContext.d.ts │ ├── globalStyles.d.ts │ ├── hooks │ │ └── useThemeProps │ │ │ ├── index.d.ts │ │ │ ├── useThemeProps.d.ts │ │ │ └── useThemeProps.test.d.ts │ ├── icons │ │ ├── ArrowIcon │ │ │ ├── ArrowIcon.d.ts │ │ │ ├── ArrowIcon.test.d.ts │ │ │ └── index.d.ts │ │ ├── CalendarIcon │ │ │ ├── CalendarIcon.d.ts │ │ │ ├── CalendarIcon.test.d.ts │ │ │ └── index.d.ts │ │ ├── CaretIcon │ │ │ ├── CaretIcon.d.ts │ │ │ ├── CaretIcon.test.d.ts │ │ │ └── index.d.ts │ │ ├── CloseIcon │ │ │ ├── CloseIcon.d.ts │ │ │ ├── CloseIcon.test.d.ts │ │ │ └── index.d.ts │ │ └── RedoIcon │ │ │ ├── RedoIcon.d.ts │ │ │ ├── RedoIcon.test.d.ts │ │ │ └── index.d.ts │ ├── index.cjs.js │ ├── index.d.ts │ ├── index.esm.js │ ├── phrases.d.ts │ ├── testUtil.d.ts │ └── utils │ │ └── getThemeProp │ │ ├── getThemeProp.d.ts │ │ ├── getThemeProp.test.d.ts │ │ └── index.d.ts │ ├── package.json │ ├── rollup.config.js │ ├── src │ ├── @types │ │ ├── index.d.ts │ │ └── theme.d.ts │ ├── components │ │ ├── Box │ │ │ ├── Box.test.tsx │ │ │ ├── Box.tsx │ │ │ ├── __snapshots__ │ │ │ │ └── Box.test.tsx.snap │ │ │ └── index.ts │ │ ├── Close │ │ │ ├── Close.test.tsx │ │ │ ├── Close.tsx │ │ │ ├── __snapshots__ │ │ │ │ └── Close.test.tsx.snap │ │ │ └── index.ts │ │ ├── DateRangeInput │ │ │ ├── DateRangeInput.stories.tsx │ │ │ ├── DateRangeInput.test.tsx │ │ │ ├── DateRangeInput.tsx │ │ │ ├── __snapshots__ │ │ │ │ └── DateRangeInput.test.tsx.snap │ │ │ └── index.ts │ │ ├── DateSingleInput │ │ │ ├── DateSingleInput.stories.tsx │ │ │ ├── DateSingleInput.test.tsx │ │ │ ├── DateSingleInput.tsx │ │ │ ├── __snapshots__ │ │ │ │ └── DateSingleInput.test.tsx.snap │ │ │ └── index.ts │ │ ├── Datepicker │ │ │ ├── Datepicker.stories.tsx │ │ │ ├── Datepicker.test.tsx │ │ │ ├── Datepicker.tsx │ │ │ ├── __snapshots__ │ │ │ │ └── Datepicker.test.tsx.snap │ │ │ └── index.ts │ │ ├── Day │ │ │ ├── Day.test.tsx │ │ │ ├── Day.tsx │ │ │ ├── __snapshots__ │ │ │ │ └── Day.test.tsx.snap │ │ │ └── index.ts │ │ ├── DayLabel │ │ │ ├── DayLabel.test.tsx │ │ │ ├── DayLabel.tsx │ │ │ ├── __snapshots__ │ │ │ │ └── DayLabel.test.tsx.snap │ │ │ └── index.ts │ │ ├── Flex │ │ │ ├── Flex.test.tsx │ │ │ ├── Flex.tsx │ │ │ ├── __snapshots__ │ │ │ │ └── Flex.test.tsx.snap │ │ │ └── index.ts │ │ ├── Grid │ │ │ ├── Grid.test.tsx │ │ │ ├── Grid.tsx │ │ │ ├── __snapshots__ │ │ │ │ └── Grid.test.tsx.snap │ │ │ └── index.ts │ │ ├── Input │ │ │ ├── Input.test.tsx │ │ │ ├── Input.tsx │ │ │ ├── __snapshots__ │ │ │ │ └── Input.test.tsx.snap │ │ │ └── index.tsx │ │ ├── Month │ │ │ ├── Month.test.tsx │ │ │ ├── Month.tsx │ │ │ ├── __snapshots__ │ │ │ │ └── Month.test.tsx.snap │ │ │ └── index.ts │ │ ├── MonthLabel │ │ │ ├── MonthLabel.test.tsx │ │ │ ├── MonthLabel.tsx │ │ │ ├── __snapshots__ │ │ │ │ └── MonthLabel.test.tsx.snap │ │ │ └── index.ts │ │ ├── NavButton │ │ │ ├── NavButton.test.tsx │ │ │ ├── NavButton.tsx │ │ │ ├── __snapshots__ │ │ │ │ └── NavButton.test.tsx.snap │ │ │ └── index.ts │ │ ├── ResetDates │ │ │ ├── ResetDates.test.tsx │ │ │ ├── ResetDates.tsx │ │ │ ├── __snapshots__ │ │ │ │ └── ResetDates.test.tsx.snap │ │ │ └── index.ts │ │ ├── SelectedDate │ │ │ ├── SelectedDate.test.tsx │ │ │ ├── SelectedDate.tsx │ │ │ ├── __snapshots__ │ │ │ │ └── SelectedDate.test.tsx.snap │ │ │ └── index.ts │ │ └── Text │ │ │ ├── Test.test.tsx │ │ │ ├── Text.tsx │ │ │ ├── __snapshots__ │ │ │ └── Test.test.tsx.snap │ │ │ └── index.ts │ ├── context │ │ └── datepickerContext.ts │ ├── globalStyles.ts │ ├── hooks │ │ └── useThemeProps │ │ │ ├── index.ts │ │ │ ├── useThemeProps.test.tsx │ │ │ └── useThemeProps.ts │ ├── icons │ │ ├── ArrowIcon │ │ │ ├── ArrowIcon.test.tsx │ │ │ ├── ArrowIcon.tsx │ │ │ ├── __snapshots__ │ │ │ │ └── ArrowIcon.test.tsx.snap │ │ │ └── index.ts │ │ ├── CalendarIcon │ │ │ ├── CalendarIcon.test.tsx │ │ │ ├── CalendarIcon.tsx │ │ │ ├── __snapshots__ │ │ │ │ └── CalendarIcon.test.tsx.snap │ │ │ └── index.ts │ │ ├── CaretIcon │ │ │ ├── CaretIcon.test.tsx │ │ │ ├── CaretIcon.tsx │ │ │ ├── __snapshots__ │ │ │ │ └── CaretIcon.test.tsx.snap │ │ │ └── index.ts │ │ ├── CloseIcon │ │ │ ├── CloseIcon.test.tsx │ │ │ ├── CloseIcon.tsx │ │ │ ├── __snapshots__ │ │ │ │ └── CloseIcon.test.tsx.snap │ │ │ └── index.ts │ │ └── RedoIcon │ │ │ ├── RedoIcon.test.tsx │ │ │ ├── RedoIcon.tsx │ │ │ ├── __snapshots__ │ │ │ └── RedoIcon.test.tsx.snap │ │ │ └── index.ts │ ├── index.ts │ ├── phrases.ts │ ├── testUtil.tsx │ └── utils │ │ └── getThemeProp │ │ ├── getThemeProp.test.ts │ │ ├── getThemeProp.ts │ │ └── index.ts │ ├── tsconfig.json │ └── yarn.lock ├── prettier.config.js ├── renovate.json ├── tsconfig.json └── yarn.lock /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "@babel/env", 5 | { 6 | "modules": false, 7 | "targets": { 8 | "browsers": "> 0.25%, not IE 11, not op_mini all, not dead", 9 | "node": 10 10 | } 11 | } 12 | ], 13 | "@babel/preset-react" 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /.coveralls.yml: -------------------------------------------------------------------------------- 1 | service_name: travis-pro 2 | repo_token: z4t18Q0wgavVdvAUDo16RIumX2C160Ckc 3 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | insert_final_newline = true 6 | charset = utf-8 7 | indent_style = space 8 | indent_size = 2 9 | trim_trailing_whitespace = true 10 | max_line_length = 100 -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | lib/ 3 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["prettier", "react-app"], 3 | "parser": "@typescript-eslint/parser", 4 | "plugins": ["react", "jsx-a11y", "import", "@typescript-eslint", "react-hooks"], 5 | "rules": { 6 | "semi": 0, 7 | "no-unused-vars": "off", 8 | "react/jsx-filename-extension": [ 9 | "error", 10 | { 11 | "extensions": [".js", ".tsx", ".ts"] 12 | } 13 | ], 14 | "import/no-unresolved": ["error", {"ignore": ["^react$", "csstype"]}], 15 | "@typescript-eslint/no-angle-bracket-type-assertion": 0 16 | }, 17 | "settings": { 18 | "import/resolver": { 19 | "node": { 20 | "extensions": [".js", ".jsx", ".ts", ".tsx"] 21 | } 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **@datepicker-react/hooks or @datepicker-react/styled version** 11 | e.g. @datepicker-react/hooks@1.0.0 12 | 13 | **Describe the bug** 14 | A clear and concise description of what the bug is. 15 | 16 | **Source code (including props configuration)** 17 | Steps to reproduce the behavior: 18 | ``` 19 | dispatch({type: 'dateChange', payload: data})} 21 | onFocusChange={focusedInput => dispatch({type: 'focusChange', payload: focusedInput})} 22 | startDate={state.startDate} // Date or null 23 | endDate={state.endDate} // Date or null 24 | focusedInput={state.focusedInput} // START_DATE, END_DATE or null 25 | /> 26 | ``` 27 | If you have custom methods that you are passing into a `@datepicker-react` component / hooks, please include the source for those as well. 28 | 29 | **Screenshots/Gifs** 30 | If applicable, add screenshots or gifs to help explain your problem. 31 | 32 | **Desktop (please complete the following information):** 33 | - OS: [e.g. iOS] 34 | - Browser [e.g. chrome, safari] 35 | - Version [e.g. 22] 36 | 37 | **Smartphone (please complete the following information):** 38 | - Device: [e.g. iPhone6] 39 | - OS: [e.g. iOS8.1] 40 | - Browser [e.g. stock browser, safari] 41 | - Version [e.g. 22] 42 | 43 | **Is the issue reproducible in Storybook?** 44 | Please link to the relevant storybook example 45 | 46 | **Additional context** 47 | Add any other context about the problem here. 48 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | branches: 4 | - master 5 | 6 | jobs: 7 | publish: 8 | name: Publish 9 | runs-on: ubuntu-latest 10 | env: 11 | NODE_AUTH_TOKEN: ${{ secrets.NPM_AUTH_TOKEN }} 12 | steps: 13 | 14 | # 1. provide Personal Access Token for checkout@v2 15 | - name: Checkout 16 | uses: actions/checkout@v2 17 | with: 18 | token: ${{ secrets.GITHUB_TOKEN }} 19 | fetch-depth: 0 20 | 21 | # 2. setup .npmrc it uses NODE_AUTH_TOKEN 22 | - name: Setup .npmrc file for publish 23 | uses: actions/setup-node@v2 24 | with: 25 | node-version: '14.x' 26 | registry-url: 'https://registry.npmjs.org' 27 | 28 | # 3. configure git user used to push tag 29 | - name: Configure Git User 30 | run: | 31 | git config --global user.name 'github-actions[bot]' 32 | git config --global user.email 'github-actions[bot]@users.noreply.github.com' 33 | git remote set-url origin https://x-access-token:${GITHUB_TOKEN}@github.com/$GITHUB_REPOSITORY 34 | env: 35 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 36 | - name: Install dependencies 37 | run: yarn install 38 | 39 | - name: Publish 40 | run: | 41 | lerna publish from-git --yes -------------------------------------------------------------------------------- /.github/workflows/run-tests.yaml: -------------------------------------------------------------------------------- 1 | name: Test Package 2 | 3 | on: [push] 4 | 5 | jobs: 6 | test: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - uses: actions/checkout@v1 10 | - uses: actions/setup-node@v1 11 | with: 12 | node-version: 14 13 | - run: yarn 14 | - run: yarn test:generate-output -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | coverage/ 3 | .idea/ 4 | .vscode/ 5 | **/**/stats.html 6 | 7 | **/.env -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | 13.14 2 | -------------------------------------------------------------------------------- /.storybook/addons.js: -------------------------------------------------------------------------------- 1 | import '@storybook/addon-actions/register' 2 | import '@storybook/addon-links/register' 3 | import '@storybook/addon-knobs/register' 4 | import '@storybook/addon-viewport/register' 5 | -------------------------------------------------------------------------------- /.storybook/config.js: -------------------------------------------------------------------------------- 1 | import {configure, addDecorator} from '@storybook/react' 2 | import {withKnobs} from '@storybook/addon-knobs' 3 | 4 | // automatically import all files ending in *.stories.js 5 | const req = require.context('../packages', true, /\.stories\.tsx$/) 6 | function loadStories() { 7 | req.keys().forEach(filename => req(filename)) 8 | } 9 | 10 | addDecorator(withKnobs) 11 | 12 | configure(loadStories, module) 13 | -------------------------------------------------------------------------------- /.storybook/preview-head.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /.storybook/webpack.config.js: -------------------------------------------------------------------------------- 1 | module.exports = ({config}) => { 2 | config.module.rules.push({ 3 | test: /\.(ts|tsx)$/, 4 | loader: require.resolve('awesome-typescript-loader'), 5 | }) 6 | config.resolve.extensions.push('.ts', '.tsx') 7 | return config 8 | } 9 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: node_js 3 | node_js: 4 | - '12' 5 | branches: 6 | only: 7 | - master 8 | cache: 9 | yarn: true 10 | directories: 11 | - node_modules 12 | install: 13 | - yarn install 14 | - yarn bootstrap 15 | script: 16 | - yarn coveralls 17 | - yarn build 18 | -------------------------------------------------------------------------------- /.yarnclean: -------------------------------------------------------------------------------- 1 | @types/react-native 2 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers 6 | pledge to making participation in our project and our community a harassment-free experience for 7 | everyone, regardless of age, body size, disability, ethnicity, sex characteristics, gender identity 8 | and expression, level of experience, education, socio-economic status, nationality, personal 9 | appearance, race, religion, or sexual identity and orientation. 10 | 11 | ## Our Standards 12 | 13 | Examples of behavior that contributes to creating a positive environment include: 14 | 15 | - Using welcoming and inclusive language 16 | - Being respectful of differing viewpoints and experiences 17 | - Gracefully accepting constructive criticism 18 | - Focusing on what is best for the community 19 | - Showing empathy towards other community members 20 | 21 | Examples of unacceptable behavior by participants include: 22 | 23 | - The use of sexualized language or imagery and unwelcome sexual attention or advances 24 | - Trolling, insulting/derogatory comments, and personal or political attacks 25 | - Public or private harassment 26 | - Publishing others' private information, such as a physical or electronic address, without explicit 27 | permission 28 | - Other conduct which could reasonably be considered inappropriate in a professional setting 29 | 30 | ## Our Responsibilities 31 | 32 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are 33 | expected to take appropriate and fair corrective action in response to any instances of unacceptable 34 | behavior. 35 | 36 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, 37 | code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or 38 | to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, 39 | threatening, offensive, or harmful. 40 | 41 | ## Scope 42 | 43 | This Code of Conduct applies both within project spaces and in public spaces when an individual is 44 | representing the project or its community. Examples of representing a project or community include 45 | using an official project e-mail address, posting via an official social media account, or acting as 46 | an appointed representative at an online or offline event. Representation of a project may be 47 | further defined and clarified by project maintainers. 48 | 49 | ## Enforcement 50 | 51 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting 52 | the project team at [sedej.miha@gmail.com](mailto:sedej.miha@gmail.com). All complaints will be 53 | reviewed and investigated and will result in a response that is deemed necessary and appropriate to 54 | the circumstances. The project team is obligated to maintain confidentiality with regard to the 55 | reporter of an incident. Further details of specific enforcement policies may be posted separately. 56 | 57 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face 58 | temporary or permanent repercussions as determined by other members of the project's leadership. 59 | 60 | ## Attribution 61 | 62 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at 63 | https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 64 | 65 | [homepage]: https://www.contributor-covenant.org 66 | 67 | For answers to common questions about this code of conduct, see 68 | https://www.contributor-covenant.org/faq 69 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contribution Guidelines 2 | 3 | Styled System has a [Code of Conduct][]. Please review and help enforce this code of conduct to help 4 | us foster an open and inclusive project. 5 | 6 | [code of conduct]: ./CODE_OF_CONDUCT.MD 7 | 8 | ## How to Contribute 9 | 10 | Feel free to contribute by opening and commenting on issues, helping answer questions, updating 11 | docs, or opening a pull request. For quick bug fixes or PRs that address an open issue, feel free to 12 | open a PR. If you'd like to suggest a new feature or change to the API, please open an issue for 13 | discussion first. 14 | 15 | ## Pull Requests 16 | 17 | To submit a pull request, follow these steps 18 | 19 | 1. Fork and clone this repo 20 | 2. Create a branch for your changes 21 | 3. Install dependencies with `yarn install && bootstrap` 22 | 4. Ensure tests are passing by running `yarn test` 23 | 5. If you're fixing a bug, it's recommended to write a failing test before writing any code 24 | 6. Make changes locally and commit them 25 | 7. Try to make sure tests still pass and that there's 100% coverage 26 | 8. Push your branch to origin 27 | 9. Open a pull request in this repository with a clear title and description and link to any 28 | relevant issues 29 | 10. Wait for a maintainer to review your PR 30 | 31 | ## Documentation 32 | 33 | The documentation is in [README](./README.MD). 34 | 35 | ## Architecture 36 | 37 | @datepicker-react is intentionally divided into two libraries, `@datepicker-react/styled` 38 | (./packages/styled) and `@datepicker-react/hooks` (./packages/hooks). `@datepicker-react/hooks` 39 | library contains hooks, which allows us to control the date picker. The second library 40 | (`@datepicker-react/styled`) contains date picker components. 41 | 42 | ### Monorepo 43 | 44 | This repo is set up as a monorepo using Yarn workspaces and Lerna. 45 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Miha Sedej 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /config/jest.client.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line 2 | const path = require('path') 3 | 4 | module.exports = { 5 | // eslint-disable-next-line 6 | ...require('./jest.common'), 7 | displayName: 'dom', 8 | testEnvironment: 'jest-environment-jsdom', 9 | setupFilesAfterEnv: [require.resolve('./setupTest.ts')], 10 | testMatch: ['**/__tests__/*.+(ts|tsx|js)', '**/*.test.+(ts|tsx|js)'], 11 | testPathIgnorePatterns: ['/node_modules/', '/lib/', '/coverage/', '/config/'], 12 | } 13 | -------------------------------------------------------------------------------- /config/jest.common.js: -------------------------------------------------------------------------------- 1 | const {defaults} = require('jest-config') 2 | const path = require('path') 3 | 4 | module.exports = { 5 | rootDir: path.join(__dirname, '..'), 6 | testURL: 'http://localhost/', 7 | globals: { 8 | 'ts-jest': { 9 | extends: path.join(__dirname, '..', 'babel.config.js'), 10 | }, 11 | }, 12 | transform: { 13 | '^.+\\.(ts|tsx)$': 'ts-jest', 14 | }, 15 | moduleFileExtensions: ['ts', 'tsx', 'js'], 16 | coveragePathIgnorePatterns: [ 17 | ...defaults.coveragePathIgnorePatterns, 18 | '.stories.tsx', 19 | '.d.ts', 20 | './packages/styled/src/index.ts', 21 | './packages/hooks/src/index.ts', 22 | ], 23 | // coveragePathIgnorePatterns: ['**/**/*.d.ts', '**/**/*.test.+(ts|tsx|js)', '++/**/*.stories.+(ts|tsx)'], 24 | snapshotSerializers: ['jest-serializer-html'], 25 | watchPlugins: [ 26 | 'jest-watch-typeahead/filename', 27 | 'jest-watch-typeahead/testname', 28 | 'jest-watch-select-projects', 29 | 'jest-runner-eslint/watch-fix', 30 | ], 31 | } 32 | -------------------------------------------------------------------------------- /config/jest.lint.js: -------------------------------------------------------------------------------- 1 | const {rootDir, moduleFileExtensions} = require('./jest.common') 2 | 3 | module.exports = { 4 | rootDir, 5 | moduleFileExtensions, 6 | displayName: 'lint', 7 | runner: 'jest-runner-eslint', 8 | testMatch: ['**/*.+(ts|tsx|js)'], 9 | testPathIgnorePatterns: [ 10 | '/node_modules/', 11 | '/lib/', 12 | '/coverage/', 13 | '/config/', 14 | 'commitlint.config.js', 15 | ], 16 | } 17 | -------------------------------------------------------------------------------- /config/rollup.config.js: -------------------------------------------------------------------------------- 1 | import typescript from 'rollup-plugin-typescript2' 2 | import babel from 'rollup-plugin-babel' 3 | import resolve from 'rollup-plugin-node-resolve' 4 | import commonjs from 'rollup-plugin-commonjs' 5 | // import analyze from 'rollup-plugin-analyzer' 6 | // import visualizer from 'rollup-plugin-visualizer' 7 | import replace from 'rollup-plugin-replace' 8 | import {terser} from 'rollup-plugin-terser' 9 | 10 | export function rollup({packageJsonPath, input = './src/index.ts'}) { 11 | return { 12 | input: input, 13 | external: ['react', 'react-dom', 'styled-components'], 14 | output: [ 15 | { 16 | file: 'lib/index.cjs.js', 17 | format: 'cjs', 18 | exports: 'named', 19 | sourcemap: false, 20 | }, 21 | { 22 | file: 'lib/index.esm.js', 23 | format: 'es', 24 | exports: 'named', 25 | sourcemap: false, 26 | }, 27 | ], 28 | plugins: [ 29 | commonjs(), 30 | resolve(), 31 | replace({ 32 | 'process.env.NODE_ENV': JSON.stringify('production'), 33 | }), 34 | // analyze(), 35 | babel({ 36 | exclude: 'node_modules/**', 37 | }), 38 | typescript({ 39 | typescript: require('typescript'), 40 | rollupCommonJSResolveHack: true, 41 | clean: true, 42 | }), 43 | terser(), 44 | // visualizer(), 45 | ], 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /config/setupTest.ts: -------------------------------------------------------------------------------- 1 | import 'jest-styled-components' 2 | import '@testing-library/jest-dom/extend-expect' 3 | -------------------------------------------------------------------------------- /config/tsconfig.base.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "outDir": "lib", 4 | "module": "esnext", 5 | "target": "es5", 6 | "lib": ["es6", "dom", "es2016", "es2017"], 7 | "sourceMap": true, 8 | "allowJs": false, 9 | "jsx": "react", 10 | "declaration": true, 11 | "moduleResolution": "node", 12 | "forceConsistentCasingInFileNames": true, 13 | "noImplicitReturns": true, 14 | "noImplicitThis": true, 15 | "noImplicitAny": true, 16 | "strictNullChecks": true, 17 | "suppressImplicitAnyIndexErrors": true, 18 | "noUnusedLocals": true, 19 | "noUnusedParameters": true, 20 | "esModuleInterop": true 21 | }, 22 | "awesomeTypescriptLoaderOptions": { 23 | "useBabel": true, 24 | "babelCore": "@babel/core" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /docs/datepicker.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/t0gre/react-datepicker/ad472f6bc50a55daa662aee3e31df7486a3ac0ec/docs/datepicker.gif -------------------------------------------------------------------------------- /docs/logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/t0gre/react-datepicker/ad472f6bc50a55daa662aee3e31df7486a3ac0ec/docs/logo.jpg -------------------------------------------------------------------------------- /docs/migrating.md: -------------------------------------------------------------------------------- 1 | # Migrating to 2.0.0 2 | 3 | In version v2.0.0 we updated date-fns to 2.0.0. Therefore we need to make some breaking changes. 4 | 5 | - **Date formatting** [All formats](https://date-fns.org/v2.0.0/docs/format), 6 | [Popular mistakes](https://date-fns.org/v2.0.0/docs/Unicode-Tokens) 7 | 8 | ```js 9 | // Before v2.0.0. 10 | const dayLabelFormatFn = (date) => format(date, 'DD') 11 | const weekdayLabelFormatFn = (date) => format(date, 'dd') 12 | const monthLabelFormatFn = (date) => format(date, 'MMMM YYYY') 13 | 14 | useMonth({ 15 | ..., 16 | dayLabelFormat = dayLabelFormatFn, 17 | weekdayLabelFormat = weekdayLabelFormatFn, 18 | monthLabelFormat = monthLabelFormatFn, 19 | }) 20 | 21 | // v2.0.0. 22 | const dayLabelFormatFn = (date) => format(date, 'dd') 23 | const weekdayLabelFormatFn = (date) => format(date, 'eeeeee') 24 | const monthLabelFormatFn = (date) => format(date, 'MMMM yyyy') 25 | 26 | useMonth({ 27 | ..., 28 | dayLabelFormat = dayLabelFormatFn, 29 | weekdayLabelFormat = weekdayLabelFormatFn, 30 | monthLabelFormat = monthLabelFormatFn, 31 | }) 32 | ``` 33 | 34 | - **Hooks: parseDate function:** The function takes an additional parameter, namely a date. 35 | [Docs](https://date-fns.org/v2.0.0/docs/parse) 36 | 37 | ```js 38 | // Before v2.0.0 39 | parseDate('02/11/2014', 'MM/dd/yyyy') 40 | 41 | // v2.0.0 42 | parseDate('02/11/2014', 'MM/dd/yyyy', new Date()) 43 | ``` 44 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | // eslint-disable-next-line 3 | ...require('./config/jest.common'), 4 | projects: ['./config/jest.client.js', './config/jest.lint.js'], 5 | coverageThreshold: { 6 | global: { 7 | branches: 80, 8 | functions: 80, 9 | lines: 80, 10 | statements: 80, 11 | }, 12 | }, 13 | collectCoverageFrom: [ 14 | './packages/styled/src/**/*.+(ts|tsx)', 15 | './packages/hooks/src/**/*.+(ts|tsx)', 16 | ], 17 | } 18 | -------------------------------------------------------------------------------- /lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "packages": [ 3 | "packages/*" 4 | ], 5 | "version": "2.8.4", 6 | "npmClient": "yarn", 7 | "useWorkspaces": true 8 | } 9 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "workspaces": [ 4 | "packages/*" 5 | ], 6 | "description": "A datepicker library for the web.", 7 | "repository": { 8 | "type": "git", 9 | "url": "git+https://github.com/tomgreenwood1/react-datepicker.git" 10 | }, 11 | "keywords": [ 12 | "react", 13 | "datepicker", 14 | "styled-components", 15 | "react", 16 | "hooks" 17 | ], 18 | "scripts": { 19 | "test": "is-ci \"test:coverage\" \"test:watch\"", 20 | "test:debug": "node --inspect-brk ./node_modules/jest/bin/jest.js --runInBand", 21 | "test:generate-output": "jest --json --outputFile=jest-test-results.json", 22 | "test:watch": "jest --watch", 23 | "test:coverage": "jest --coverage", 24 | "commit": "git-cz", 25 | "format": "lerna run format", 26 | "lint:ts": "eslint ./packages/**/*.ts{,x}", 27 | "tsc": "lerna run tsc", 28 | "prebuild": "yarn run tsc && yarn run lint:ts", 29 | "build": "lerna run build", 30 | "build:watch": "lerna run build:watch", 31 | "bootstrap": "lerna bootstrap", 32 | "storybook": "start-storybook -p 6006", 33 | "build-storybook": "build-storybook -c .storybook", 34 | "lerna:publish": "lerna publish from-package", 35 | "lerna:version-prerelease": "lerna version prerelease --github-release --conventional-commits", 36 | "lerna:version-patch": "lerna version patch --github-release --conventional-commits", 37 | "lerna:version-minor": "lerna version minor --github-release --conventional-commits", 38 | "lerna:version-major": "lerna version major --github-release --conventional-commits", 39 | "coveralls": "yarn run test:coverage && cat ./coverage/lcov.info | coveralls" 40 | }, 41 | "author": "Miha Sedej", 42 | "license": "MIT", 43 | "bugs": { 44 | "url": "https://github.com/tomgreenwood1/react-datepicker/issues" 45 | }, 46 | "homepage": "https://github.com/tomgreenwood1/react-datepicker#readme", 47 | "devDependencies": { 48 | "@babel/core": "^7.10.2", 49 | "@babel/preset-env": "^7.10.2", 50 | "@babel/preset-react": "^7.10.1", 51 | "@storybook/addon-actions": "^5.3.19", 52 | "@storybook/addon-knobs": "^5.3.19", 53 | "@storybook/addon-links": "^5.3.19", 54 | "@storybook/addon-viewport": "^5.3.19", 55 | "@storybook/addons": "^5.3.19", 56 | "@storybook/react": "^5.3.19", 57 | "@testing-library/jest-dom": "^5.10.1", 58 | "@testing-library/react": "^10.2.1", 59 | "@testing-library/react-hooks": "^3.3.0", 60 | "@types/jest": "^26.0.0", 61 | "@types/node": "^13.7.4", 62 | "@types/react": "^16.9.38", 63 | "@types/react-dom": "^16.9.8", 64 | "@typescript-eslint/eslint-plugin": "^3.3.0", 65 | "@typescript-eslint/parser": "^3.3.0", 66 | "awesome-typescript-loader": "^5.2.1", 67 | "babel-eslint": "^10.1.0", 68 | "babel-loader": "^8.1.0", 69 | "commitizen": "^4.1.2", 70 | "coveralls": "^3.1.0", 71 | "cz-lerna-changelog": "^2.0.2", 72 | "date-fns": "^2.14.0", 73 | "eslint": "^7.2.0", 74 | "eslint-config-prettier": "^6.11.0", 75 | "eslint-config-react-app": "^5.2.1", 76 | "eslint-plugin-flowtype": "^5.1.3", 77 | "eslint-plugin-import": "^2.21.2", 78 | "eslint-plugin-jsx-a11y": "^6.2.3", 79 | "eslint-plugin-react": "^7.20.0", 80 | "eslint-plugin-react-hooks": "^4.0.4", 81 | "husky": "^4.2.5", 82 | "is-ci-cli": "^2.1.1", 83 | "jest": "^26.0.1", 84 | "jest-config": "^26.0.1", 85 | "jest-date-mock": "^1.0.8", 86 | "jest-environment-jsdom": "^26.0.1", 87 | "jest-environment-node": "^26.0.1", 88 | "jest-runner-eslint": "^0.10.0", 89 | "jest-serializer-html": "^7.0.0", 90 | "jest-styled-components": "^7.0.2", 91 | "jest-watch-select-projects": "^2.0.0", 92 | "jest-watch-typeahead": "^0.6.0", 93 | "lerna": "^3.22.1", 94 | "lint-staged": "^10.2.11", 95 | "npm-run-all": "^4.1.5", 96 | "prettier": "^2.0.5", 97 | "react": "^16.13.1", 98 | "react-dom": "^16.13.1", 99 | "react-test-renderer": "^16.13.1", 100 | "rimraf": "^3.0.2", 101 | "rollup": "^2.16.1", 102 | "rollup-plugin-analyzer": "^3.2.3", 103 | "rollup-plugin-babel": "^4.4.0", 104 | "rollup-plugin-commonjs": "^10.1.0", 105 | "rollup-plugin-node-resolve": "^5.2.0", 106 | "rollup-plugin-replace": "^2.2.0", 107 | "rollup-plugin-terser": "^6.1.0", 108 | "rollup-plugin-typescript2": "^0.27.1", 109 | "rollup-plugin-visualizer": "^4.0.4", 110 | "ts-jest": "^26.1.0", 111 | "tslib": "^2.0.0", 112 | "typescript": "^3.9.5" 113 | }, 114 | "config": { 115 | "commitizen": { 116 | "path": "./node_modules/cz-lerna-changelog" 117 | }, 118 | "validate-commit-msg": { 119 | "helpMessage": "Commit message violates the rules defined for this project. Please, execute `yarn commit` to generate a correct commit message with `commitizen`" 120 | } 121 | }, 122 | "husky": { 123 | "hooks": { 124 | "pre-commit": "yarn tsc && lint-staged" 125 | } 126 | }, 127 | "lint-staged": { 128 | "*.+(js|jsx|ts|tsx)": [ 129 | "prettier --write", 130 | "eslint", 131 | "git add" 132 | ] 133 | }, 134 | "resolutions": { 135 | "@types/react": "^16.9.38" 136 | }, 137 | "name": "react-datepicker" 138 | } 139 | -------------------------------------------------------------------------------- /packages/hooks/lib/index.d.ts: -------------------------------------------------------------------------------- 1 | import parseDate from 'date-fns/parse' 2 | import { 3 | useMonth, 4 | UseMonthProps, 5 | UseMonthResult, 6 | GetDaysProps, 7 | GetWeekdayLabelsProps, 8 | getWeekdayLabels, 9 | getDays, 10 | CalendarDay, 11 | dayLabelFormat, 12 | weekdayLabelFormat, 13 | monthLabelFormat, 14 | } from './useMonth' 15 | import { 16 | isDateSelected, 17 | isFirstOrLastSelectedDate, 18 | isEndDate, 19 | isStartDate, 20 | isDateBlocked, 21 | getCurrentYearMonthAndDate, 22 | getDateMonthAndYear, 23 | getInitialMonths, 24 | MonthType, 25 | useDatepicker, 26 | UseDatepickerProps, 27 | START_DATE, 28 | END_DATE, 29 | getInputValue, 30 | FormatFunction, 31 | FocusedInput, 32 | FirstDayOfWeek, 33 | OnDatesChangeProps, 34 | } from './useDatepicker' 35 | import useDay from './useDay' 36 | export { 37 | useDay, 38 | useMonth, 39 | UseMonthProps, 40 | UseMonthResult, 41 | GetDaysProps, 42 | GetWeekdayLabelsProps, 43 | getWeekdayLabels, 44 | getDays, 45 | CalendarDay, 46 | isDateSelected, 47 | isFirstOrLastSelectedDate, 48 | isStartDate, 49 | isEndDate, 50 | isDateBlocked, 51 | getCurrentYearMonthAndDate, 52 | getDateMonthAndYear, 53 | getInitialMonths, 54 | MonthType, 55 | useDatepicker, 56 | UseDatepickerProps, 57 | START_DATE, 58 | END_DATE, 59 | getInputValue, 60 | FormatFunction, 61 | FocusedInput, 62 | FirstDayOfWeek, 63 | OnDatesChangeProps, 64 | dayLabelFormat, 65 | weekdayLabelFormat, 66 | monthLabelFormat, 67 | parseDate, 68 | } 69 | -------------------------------------------------------------------------------- /packages/hooks/lib/useDatepicker/index.d.ts: -------------------------------------------------------------------------------- 1 | import { 2 | useDatepicker, 3 | UseDatepickerProps, 4 | END_DATE, 5 | START_DATE, 6 | FocusedInput, 7 | FirstDayOfWeek, 8 | OnDatesChangeProps, 9 | } from './useDatepicker' 10 | import { 11 | isDateSelected, 12 | isFirstOrLastSelectedDate, 13 | isStartDate, 14 | isEndDate, 15 | isDateBlocked, 16 | getCurrentYearMonthAndDate, 17 | getDateMonthAndYear, 18 | getInitialMonths, 19 | getInputValue, 20 | getNextActiveMonth, 21 | FormatFunction, 22 | MonthType, 23 | canSelectRange, 24 | isDateHovered, 25 | } from './useDatepicker.utils' 26 | export { 27 | useDatepicker, 28 | isDateSelected, 29 | isFirstOrLastSelectedDate, 30 | isStartDate, 31 | isEndDate, 32 | isDateBlocked, 33 | getCurrentYearMonthAndDate, 34 | getDateMonthAndYear, 35 | getInitialMonths, 36 | getInputValue, 37 | getNextActiveMonth, 38 | canSelectRange, 39 | isDateHovered, 40 | FormatFunction, 41 | MonthType, 42 | UseDatepickerProps, 43 | END_DATE, 44 | START_DATE, 45 | FocusedInput, 46 | FirstDayOfWeek, 47 | OnDatesChangeProps, 48 | } 49 | -------------------------------------------------------------------------------- /packages/hooks/lib/useDatepicker/useDatepicker.d.ts: -------------------------------------------------------------------------------- 1 | export declare const START_DATE = 'startDate' 2 | export declare const END_DATE = 'endDate' 3 | export declare type FocusedInput = 'startDate' | 'endDate' | null 4 | export interface OnDatesChangeProps { 5 | focusedInput: FocusedInput 6 | startDate: Date | null 7 | endDate: Date | null 8 | } 9 | export declare type FirstDayOfWeek = 0 | 1 | 2 | 3 | 4 | 5 | 6 10 | export interface UseDatepickerProps { 11 | onDatesChange(data: OnDatesChangeProps): void 12 | minBookingDate?: Date 13 | maxBookingDate?: Date 14 | startDate: Date | null 15 | endDate: Date | null 16 | focusedInput: FocusedInput 17 | numberOfMonths?: number 18 | minBookingDays?: number 19 | exactMinBookingDays?: boolean 20 | firstDayOfWeek?: FirstDayOfWeek 21 | initialVisibleMonth?: Date 22 | isDateBlocked?(date: Date): boolean 23 | unavailableDates?: Date[] 24 | changeActiveMonthOnSelect?: boolean 25 | } 26 | export declare function useDatepicker({ 27 | startDate, 28 | endDate, 29 | focusedInput, 30 | minBookingDate, 31 | maxBookingDate, 32 | onDatesChange, 33 | initialVisibleMonth, 34 | exactMinBookingDays, 35 | minBookingDays, 36 | numberOfMonths, 37 | firstDayOfWeek, 38 | isDateBlocked: isDateBlockedProps, 39 | unavailableDates, 40 | changeActiveMonthOnSelect, 41 | }: UseDatepickerProps): { 42 | firstDayOfWeek: FirstDayOfWeek 43 | activeMonths: import('./useDatepicker.utils').MonthType[] 44 | isDateSelected: (date: Date) => boolean 45 | isDateHovered: (date: Date) => boolean 46 | isFirstOrLastSelectedDate: (date: Date) => boolean 47 | isStartDate: (date: Date) => boolean 48 | isEndDate: (date: Date) => boolean 49 | isDateBlocked: (date: Date) => boolean 50 | numberOfMonths: number 51 | isDateFocused: (date: Date) => boolean 52 | focusedDate: Date | null 53 | hoveredDate: Date | null 54 | onResetDates: () => void 55 | onDateHover: (date: Date | null) => void 56 | onDateSelect: (date: Date) => void 57 | onDateFocus: (date: Date) => void 58 | goToPreviousMonths: () => void 59 | goToPreviousMonthsByOneMonth: () => void 60 | goToNextMonths: () => void 61 | goToNextMonthsByOneMonth: () => void 62 | goToDate: (date: Date) => void 63 | goToPreviousYear: (numYears?: number) => void 64 | goToNextYear: (numYears?: number) => void 65 | } 66 | -------------------------------------------------------------------------------- /packages/hooks/lib/useDatepicker/useDatepicker.test.d.ts: -------------------------------------------------------------------------------- 1 | export {} 2 | -------------------------------------------------------------------------------- /packages/hooks/lib/useDatepicker/useDatepicker.utils.d.ts: -------------------------------------------------------------------------------- 1 | export declare const isInUnavailableDates: ( 2 | unavailableDates: Date[] | undefined, 3 | date: Date, 4 | ) => boolean 5 | export declare function isDateSelected( 6 | date: Date, 7 | startDate: Date | null, 8 | endDate: Date | null, 9 | ): boolean 10 | export declare function isFirstOrLastSelectedDate( 11 | date: Date, 12 | startDate: Date | null, 13 | endDate: Date | null, 14 | ): boolean 15 | export declare function isStartDate(date: Date, startDate: Date | null): boolean 16 | export declare function isEndDate(date: Date, endDate: Date | null): boolean 17 | interface IsDateBlockedProps { 18 | date: Date 19 | startDate: Date | null 20 | endDate: Date | null 21 | minBookingDays?: number 22 | minBookingDate?: Date 23 | maxBookingDate?: Date 24 | isDateBlockedFn?: (date?: Date) => boolean 25 | unavailableDates?: Date[] 26 | } 27 | export declare function isDateBlocked({ 28 | date, 29 | minBookingDate, 30 | maxBookingDate, 31 | isDateBlockedFn, 32 | startDate, 33 | endDate, 34 | minBookingDays, 35 | unavailableDates, 36 | }: IsDateBlockedProps): boolean 37 | export interface MonthType { 38 | year: number 39 | month: number 40 | date: Date 41 | } 42 | export declare function getDateMonthAndYear(date: Date): MonthType 43 | export declare function getCurrentYearMonthAndDate(): MonthType 44 | export declare function getInitialMonths( 45 | numberOfMonths: number, 46 | startDate: Date | null, 47 | ): MonthType[] 48 | export declare function getNextActiveMonth( 49 | activeMonth: MonthType[], 50 | numberOfMonths: number, 51 | counter: number, 52 | step?: number, 53 | ): MonthType[] 54 | export declare type FormatFunction = (date: Date) => string 55 | export declare function getInputValue( 56 | date: Date | null, 57 | displayFormat: string | FormatFunction, 58 | defaultValue: string, 59 | ): string 60 | export interface CanSelectRangeProps { 61 | startDate: Date 62 | endDate: Date | null 63 | isDateBlocked(date: Date): boolean 64 | minBookingDays: number 65 | exactMinBookingDays?: boolean 66 | minBookingDate?: Date 67 | maxBookingDate?: Date 68 | } 69 | export declare function canSelectRange({ 70 | startDate, 71 | endDate, 72 | isDateBlocked, 73 | minBookingDays, 74 | exactMinBookingDays, 75 | minBookingDate, 76 | maxBookingDate, 77 | }: CanSelectRangeProps): boolean 78 | export interface IsDateHoveredProps { 79 | startDate: Date | null 80 | endDate: Date | null 81 | date: Date 82 | isDateBlocked(date: Date): boolean 83 | hoveredDate: Date | null 84 | minBookingDays: number 85 | exactMinBookingDays: boolean 86 | } 87 | export declare function isDateHovered({ 88 | date, 89 | startDate, 90 | endDate, 91 | isDateBlocked, 92 | hoveredDate, 93 | minBookingDays, 94 | exactMinBookingDays, 95 | }: IsDateHoveredProps): boolean 96 | export {} 97 | -------------------------------------------------------------------------------- /packages/hooks/lib/useDay/index.d.ts: -------------------------------------------------------------------------------- 1 | import useDay from './useDay'; 2 | export default useDay; 3 | -------------------------------------------------------------------------------- /packages/hooks/lib/useDay/useDay.d.ts: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | interface UseDayProps { 3 | date: Date 4 | focusedDate: Date | null 5 | isDateFocused(date: Date): boolean 6 | isDateSelected(date: Date): boolean 7 | isDateHovered(date: Date): boolean 8 | isDateBlocked(date: Date): boolean 9 | isFirstOrLastSelectedDate(date: Date): boolean 10 | onDateFocus(date: Date): void 11 | onDateSelect(date: Date): void 12 | onDateHover(date: Date): void 13 | dayRef?: React.RefObject 14 | } 15 | declare function useDay({ 16 | date, 17 | focusedDate, 18 | isDateSelected, 19 | isDateFocused, 20 | isFirstOrLastSelectedDate, 21 | isDateHovered, 22 | isDateBlocked, 23 | onDateSelect, 24 | onDateFocus, 25 | onDateHover, 26 | }: UseDayProps): { 27 | tabIndex: number 28 | isSelected: boolean 29 | isSelectedStartOrEnd: boolean 30 | isWithinHoverRange: boolean 31 | disabledDate: boolean 32 | onKeyDown: (e: React.KeyboardEvent) => void 33 | onClick: () => void 34 | onMouseEnter: () => void 35 | } 36 | export default useDay 37 | -------------------------------------------------------------------------------- /packages/hooks/lib/useDay/useDay.test.d.ts: -------------------------------------------------------------------------------- 1 | export {} 2 | -------------------------------------------------------------------------------- /packages/hooks/lib/useMonth/index.d.ts: -------------------------------------------------------------------------------- 1 | import { 2 | useMonth, 3 | UseMonthProps, 4 | UseMonthResult, 5 | dayLabelFormatFn as dayLabelFormat, 6 | monthLabelFormatFn as monthLabelFormat, 7 | weekdayLabelFormatFn as weekdayLabelFormat, 8 | } from './useMonth' 9 | import { 10 | getDays, 11 | getWeekdayLabels, 12 | GetWeekdayLabelsProps, 13 | GetDaysProps, 14 | CalendarDay, 15 | } from './useMonth.utils' 16 | export { 17 | dayLabelFormat, 18 | monthLabelFormat, 19 | weekdayLabelFormat, 20 | useMonth, 21 | getDays, 22 | getWeekdayLabels, 23 | GetWeekdayLabelsProps, 24 | GetDaysProps, 25 | UseMonthResult, 26 | UseMonthProps, 27 | CalendarDay, 28 | } 29 | -------------------------------------------------------------------------------- /packages/hooks/lib/useMonth/useMonth.d.ts: -------------------------------------------------------------------------------- 1 | import {GetDaysProps, GetWeekdayLabelsProps} from './useMonth.utils' 2 | export declare const dayLabelFormatFn: (date: Date) => string 3 | export declare const weekdayLabelFormatFn: (date: Date) => string 4 | export declare const monthLabelFormatFn: (date: Date) => string 5 | export interface UseMonthResult { 6 | weekdayLabels: string[] 7 | days: ( 8 | | number 9 | | { 10 | dayLabel: string 11 | date: Date 12 | } 13 | )[] 14 | monthLabel: string 15 | } 16 | export interface UseMonthProps extends GetWeekdayLabelsProps, GetDaysProps { 17 | monthLabelFormat?(date: Date): string 18 | } 19 | export declare function useMonth({ 20 | year, 21 | month, 22 | firstDayOfWeek, 23 | dayLabelFormat, 24 | weekdayLabelFormat, 25 | monthLabelFormat, 26 | }: UseMonthProps): UseMonthResult 27 | -------------------------------------------------------------------------------- /packages/hooks/lib/useMonth/useMonth.test.d.ts: -------------------------------------------------------------------------------- 1 | export {} 2 | -------------------------------------------------------------------------------- /packages/hooks/lib/useMonth/useMonth.utils.d.ts: -------------------------------------------------------------------------------- 1 | declare type FirstDayOfWeek = 0 | 1 | 2 | 3 | 4 | 5 | 6 2 | export interface GetWeekdayLabelsProps { 3 | firstDayOfWeek?: FirstDayOfWeek 4 | weekdayLabelFormat?(date: Date): string 5 | } 6 | export declare function getWeekdayLabels({ 7 | firstDayOfWeek, 8 | weekdayLabelFormat, 9 | }?: GetWeekdayLabelsProps): never[] 10 | export interface GetDaysProps { 11 | year: number 12 | month: number 13 | firstDayOfWeek?: FirstDayOfWeek 14 | dayLabelFormat?(date: Date): string 15 | } 16 | export declare type CalendarDay = 17 | | number 18 | | { 19 | dayLabel: string 20 | date: Date 21 | } 22 | export declare function getDays({ 23 | year, 24 | month, 25 | firstDayOfWeek, 26 | dayLabelFormat, 27 | }: GetDaysProps): CalendarDay[] 28 | export {} 29 | -------------------------------------------------------------------------------- /packages/hooks/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@datepicker-react/hooks", 3 | "version": "2.8.4", 4 | "description": "React hooks for datepicker.", 5 | "keywords": [ 6 | "react", 7 | "hooks", 8 | "datepicker" 9 | ], 10 | "author": "Miha Sedej ", 11 | "homepage": "https://github.com/tresko/react-datepicker/tree/master/packages/hooks", 12 | "license": "MIT", 13 | "main": "lib/index.cjs.js", 14 | "module": "lib/index.esm.js", 15 | "typings": "lib/index.d.ts", 16 | "directories": { 17 | "lib": "lib", 18 | "test": "__tests__" 19 | }, 20 | "files": [ 21 | "lib" 22 | ], 23 | "repository": { 24 | "type": "git", 25 | "url": "git+https://github.com/tresko/react-datepicker.git" 26 | }, 27 | "scripts": { 28 | "build": "../../node_modules/.bin/rollup -c rollup.config.js", 29 | "build:watch": "yarn build -w", 30 | "format": "../../node_modules/.bin/prettier --write \"src/**/*.+(ts|tsx)\"", 31 | "tsc": "../../node_modules/.bin/tsc --noEmit", 32 | "prebuild": "../../node_modules/.bin/rimraf lib" 33 | }, 34 | "bugs": { 35 | "url": "https://github.com/tresko/react-datepicker/issues" 36 | }, 37 | "peerDependencies": { 38 | "react": ">= 16.8.5" 39 | }, 40 | "dependencies": { 41 | "date-fns": "^2.14.0" 42 | }, 43 | "publishConfig": { 44 | "access": "public" 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /packages/hooks/rollup.config.js: -------------------------------------------------------------------------------- 1 | import {rollup} from '../../config/rollup.config' 2 | 3 | export default rollup({ 4 | input: 'src/index.ts', 5 | packageJsonPath: './package.json', 6 | }) 7 | -------------------------------------------------------------------------------- /packages/hooks/src/index.ts: -------------------------------------------------------------------------------- 1 | import parseDate from 'date-fns/parse' 2 | import { 3 | useMonth, 4 | UseMonthProps, 5 | UseMonthResult, 6 | GetDaysProps, 7 | GetWeekdayLabelsProps, 8 | getWeekdayLabels, 9 | getDays, 10 | CalendarDay, 11 | dayLabelFormat, 12 | weekdayLabelFormat, 13 | monthLabelFormat, 14 | } from './useMonth' 15 | import { 16 | isDateSelected, 17 | isFirstOrLastSelectedDate, 18 | isEndDate, 19 | isStartDate, 20 | isDateBlocked, 21 | getCurrentYearMonthAndDate, 22 | getDateMonthAndYear, 23 | getInitialMonths, 24 | MonthType, 25 | useDatepicker, 26 | UseDatepickerProps, 27 | START_DATE, 28 | END_DATE, 29 | getInputValue, 30 | FormatFunction, 31 | FocusedInput, 32 | FirstDayOfWeek, 33 | OnDatesChangeProps, 34 | } from './useDatepicker' 35 | import useDay from './useDay' 36 | 37 | export { 38 | useDay, 39 | useMonth, 40 | UseMonthProps, 41 | UseMonthResult, 42 | GetDaysProps, 43 | GetWeekdayLabelsProps, 44 | getWeekdayLabels, 45 | getDays, 46 | CalendarDay, 47 | isDateSelected, 48 | isFirstOrLastSelectedDate, 49 | isStartDate, 50 | isEndDate, 51 | isDateBlocked, 52 | getCurrentYearMonthAndDate, 53 | getDateMonthAndYear, 54 | getInitialMonths, 55 | MonthType, 56 | useDatepicker, 57 | UseDatepickerProps, 58 | START_DATE, 59 | END_DATE, 60 | getInputValue, 61 | FormatFunction, 62 | FocusedInput, 63 | FirstDayOfWeek, 64 | OnDatesChangeProps, 65 | dayLabelFormat, 66 | weekdayLabelFormat, 67 | monthLabelFormat, 68 | parseDate, 69 | } 70 | -------------------------------------------------------------------------------- /packages/hooks/src/useDatepicker/index.ts: -------------------------------------------------------------------------------- 1 | import { 2 | useDatepicker, 3 | UseDatepickerProps, 4 | END_DATE, 5 | START_DATE, 6 | FocusedInput, 7 | FirstDayOfWeek, 8 | OnDatesChangeProps, 9 | } from './useDatepicker' 10 | import { 11 | isDateSelected, 12 | isFirstOrLastSelectedDate, 13 | isStartDate, 14 | isEndDate, 15 | isDateBlocked, 16 | getCurrentYearMonthAndDate, 17 | getDateMonthAndYear, 18 | getInitialMonths, 19 | getInputValue, 20 | getNextActiveMonth, 21 | FormatFunction, 22 | MonthType, 23 | canSelectRange, 24 | isDateHovered, 25 | } from './useDatepicker.utils' 26 | 27 | export { 28 | useDatepicker, 29 | isDateSelected, 30 | isFirstOrLastSelectedDate, 31 | isStartDate, 32 | isEndDate, 33 | isDateBlocked, 34 | getCurrentYearMonthAndDate, 35 | getDateMonthAndYear, 36 | getInitialMonths, 37 | getInputValue, 38 | getNextActiveMonth, 39 | canSelectRange, 40 | isDateHovered, 41 | FormatFunction, 42 | MonthType, 43 | UseDatepickerProps, 44 | END_DATE, 45 | START_DATE, 46 | FocusedInput, 47 | FirstDayOfWeek, 48 | OnDatesChangeProps, 49 | } 50 | -------------------------------------------------------------------------------- /packages/hooks/src/useDay/index.ts: -------------------------------------------------------------------------------- 1 | import useDay from './useDay' 2 | 3 | export default useDay 4 | -------------------------------------------------------------------------------- /packages/hooks/src/useDay/useDay.test.ts: -------------------------------------------------------------------------------- 1 | import {renderHook, act} from '@testing-library/react-hooks' 2 | import useDay from '.' 3 | 4 | const date = new Date(2019, 2, 1, 0, 0, 0) 5 | const dayRef = { 6 | current: { 7 | focus: jest.fn(), 8 | }, 9 | } 10 | 11 | test('should execute onClick callback', () => { 12 | const onDateSelect = jest.fn() 13 | const {result} = renderHook(() => 14 | useDay({ 15 | date, 16 | // @ts-ignore 17 | dayRef, 18 | onDateSelect, 19 | focusedDate: null, 20 | isDateSelected: jest.fn(), 21 | isDateFocused: jest.fn(), 22 | isFirstOrLastSelectedDate: jest.fn(), 23 | isDateHovered: jest.fn(), 24 | isDateBlocked: jest.fn(), 25 | onDateFocus: jest.fn(), 26 | onDateHover: jest.fn(), 27 | unavailableDates: [], 28 | }), 29 | ) 30 | 31 | act(() => { 32 | result.current.onClick() 33 | }) 34 | 35 | expect(onDateSelect).toBeCalled() 36 | }) 37 | 38 | test('should not execute onClick callback, because day is disabled', () => { 39 | const onDateSelect = jest.fn() 40 | const {result} = renderHook(() => 41 | useDay({ 42 | date, 43 | // @ts-ignore 44 | dayRef, 45 | onDateSelect, 46 | focusedDate: null, 47 | isDateSelected: jest.fn(), 48 | isDateFocused: jest.fn(), 49 | isFirstOrLastSelectedDate: jest.fn(), 50 | isDateHovered: jest.fn(), 51 | isDateBlocked: () => true, 52 | onDateFocus: jest.fn(), 53 | onDateHover: jest.fn(), 54 | unavailableDates: [], 55 | }), 56 | ) 57 | 58 | act(() => { 59 | result.current.onClick() 60 | }) 61 | 62 | expect(result.current.disabledDate).toBe(true) 63 | expect(onDateSelect).not.toBeCalled() 64 | }) 65 | 66 | test('should not allow date to be selected when supplied as unavailable', () => { 67 | const onDateSelect = jest.fn() 68 | const {result} = renderHook(() => 69 | useDay({ 70 | date, 71 | // @ts-ignore 72 | dayRef, 73 | onDateSelect, 74 | focusedDate: null, 75 | isDateSelected: jest.fn(), 76 | isDateFocused: jest.fn(), 77 | isFirstOrLastSelectedDate: jest.fn(), 78 | isDateHovered: jest.fn(), 79 | isDateBlocked: () => true, 80 | onDateFocus: jest.fn(), 81 | onDateHover: jest.fn(), 82 | unavailableDates: [new Date()], 83 | }), 84 | ) 85 | 86 | act(() => { 87 | result.current.onClick() 88 | }) 89 | 90 | expect(result.current.disabledDate).toBe(true) 91 | expect(onDateSelect).not.toBeCalled() 92 | }) 93 | 94 | test('should be active', () => { 95 | const {result} = renderHook(() => 96 | useDay({ 97 | date, 98 | // @ts-ignore 99 | dayRef, 100 | onDateSelect: jest.fn(), 101 | focusedDate: null, 102 | isDateSelected: () => true, 103 | isDateFocused: jest.fn(), 104 | isFirstOrLastSelectedDate: jest.fn(), 105 | isDateHovered: jest.fn(), 106 | isDateBlocked: jest.fn(), 107 | onDateFocus: jest.fn(), 108 | onDateHover: jest.fn(), 109 | unavailableDates: [], 110 | }), 111 | ) 112 | 113 | expect(result.current.isSelected).toBe(true) 114 | }) 115 | 116 | test('should be active first or last day', () => { 117 | const {result} = renderHook(() => 118 | useDay({ 119 | date, 120 | // @ts-ignore 121 | dayRef, 122 | onDateSelect: jest.fn(), 123 | focusedDate: null, 124 | isDateSelected: jest.fn(), 125 | isDateFocused: jest.fn(), 126 | isFirstOrLastSelectedDate: () => true, 127 | isDateHovered: jest.fn(), 128 | isDateBlocked: jest.fn(), 129 | onDateFocus: jest.fn(), 130 | onDateHover: jest.fn(), 131 | unavailableDates: [], 132 | }), 133 | ) 134 | 135 | expect(result.current.isSelectedStartOrEnd).toBe(true) 136 | }) 137 | 138 | test('should be within range', () => { 139 | const {result} = renderHook(() => 140 | useDay({ 141 | date, 142 | // @ts-ignore 143 | dayRef, 144 | onDateSelect: jest.fn(), 145 | focusedDate: null, 146 | isDateSelected: jest.fn(), 147 | isDateFocused: jest.fn(), 148 | isFirstOrLastSelectedDate: jest.fn(), 149 | isDateHovered: () => true, 150 | isDateBlocked: jest.fn(), 151 | onDateFocus: jest.fn(), 152 | onDateHover: jest.fn(), 153 | unavailableDates: [], 154 | }), 155 | ) 156 | 157 | expect(result.current.isWithinHoverRange).toBe(true) 158 | }) 159 | 160 | test('tabIndex should be 0', () => { 161 | const {result} = renderHook(() => 162 | useDay({ 163 | date, 164 | // @ts-ignore 165 | dayRef, 166 | onDateSelect: jest.fn(), 167 | focusedDate: null, 168 | isDateSelected: jest.fn(), 169 | isDateFocused: jest.fn(), 170 | isFirstOrLastSelectedDate: jest.fn(), 171 | isDateHovered: jest.fn(), 172 | isDateBlocked: jest.fn(), 173 | onDateFocus: jest.fn(), 174 | onDateHover: jest.fn(), 175 | unavailableDates: [], 176 | }), 177 | ) 178 | 179 | expect(result.current.tabIndex).toBe(0) 180 | }) 181 | 182 | test('should be unfocused', () => { 183 | const {result} = renderHook(() => 184 | useDay({ 185 | date, 186 | // @ts-ignore 187 | dayRef, 188 | onDateSelect: jest.fn(), 189 | focusedDate: date, 190 | isDateSelected: jest.fn(), 191 | isDateFocused: jest.fn(), 192 | isFirstOrLastSelectedDate: jest.fn(), 193 | isDateHovered: jest.fn(), 194 | isDateBlocked: jest.fn(), 195 | onDateFocus: jest.fn(), 196 | onDateHover: jest.fn(), 197 | unavailableDates: [], 198 | }), 199 | ) 200 | 201 | expect(result.current.tabIndex).toBe(-1) 202 | }) 203 | 204 | test('should be focused', () => { 205 | const {result} = renderHook(() => 206 | useDay({ 207 | date, 208 | // @ts-ignore 209 | dayRef, 210 | onDateSelect: jest.fn(), 211 | focusedDate: date, 212 | isDateSelected: jest.fn(), 213 | isDateFocused: () => true, 214 | isFirstOrLastSelectedDate: jest.fn(), 215 | isDateHovered: jest.fn(), 216 | isDateBlocked: jest.fn(), 217 | onDateFocus: jest.fn(), 218 | onDateHover: jest.fn(), 219 | unavailableDates: [], 220 | }), 221 | ) 222 | 223 | expect(result.current.tabIndex).toBe(0) 224 | }) 225 | -------------------------------------------------------------------------------- /packages/hooks/src/useDay/useDay.ts: -------------------------------------------------------------------------------- 1 | import React, {useCallback} from 'react' 2 | import addDays from 'date-fns/addDays' 3 | 4 | interface UseDayProps { 5 | date: Date 6 | focusedDate: Date | null 7 | isDateFocused(date: Date): boolean 8 | isDateSelected(date: Date): boolean 9 | isDateHovered(date: Date): boolean 10 | isDateBlocked(date: Date): boolean 11 | isFirstOrLastSelectedDate(date: Date): boolean 12 | onDateFocus(date: Date): void 13 | onDateSelect(date: Date): void 14 | onDateHover(date: Date): void 15 | 16 | // Not used anymore 17 | dayRef?: React.RefObject 18 | } 19 | 20 | function useDay({ 21 | date, 22 | focusedDate, 23 | isDateSelected, 24 | isDateFocused, 25 | isFirstOrLastSelectedDate, 26 | isDateHovered, 27 | isDateBlocked, 28 | onDateSelect, 29 | onDateFocus, 30 | onDateHover, 31 | }: UseDayProps) { 32 | const onClick = useCallback(() => onDateSelect(date), [date, onDateSelect]) 33 | const onMouseEnter = useCallback(() => onDateHover(date), [date, onDateHover]) 34 | const disabled = isDateBlocked(date) && !isDateHovered(date) 35 | 36 | return { 37 | tabIndex: focusedDate === null || isDateFocused(date) ? 0 : -1, 38 | isSelected: isDateSelected(date), 39 | isSelectedStartOrEnd: isFirstOrLastSelectedDate(date), 40 | isWithinHoverRange: isDateHovered(date), 41 | disabledDate: disabled, 42 | onKeyDown: (e: React.KeyboardEvent) => { 43 | if (e.key === 'ArrowRight') { 44 | onDateFocus(addDays(date, 1)) 45 | } else if (e.key === 'ArrowLeft') { 46 | onDateFocus(addDays(date, -1)) 47 | } else if (e.key === 'ArrowUp') { 48 | onDateFocus(addDays(date, -7)) 49 | } else if (e.key === 'ArrowDown') { 50 | onDateFocus(addDays(date, 7)) 51 | } 52 | }, 53 | onClick: disabled ? () => {} : onClick, 54 | onMouseEnter, 55 | } 56 | } 57 | 58 | export default useDay 59 | -------------------------------------------------------------------------------- /packages/hooks/src/useMonth/index.ts: -------------------------------------------------------------------------------- 1 | import { 2 | useMonth, 3 | UseMonthProps, 4 | UseMonthResult, 5 | dayLabelFormatFn as dayLabelFormat, 6 | monthLabelFormatFn as monthLabelFormat, 7 | weekdayLabelFormatFn as weekdayLabelFormat, 8 | } from './useMonth' 9 | import { 10 | getDays, 11 | getWeekdayLabels, 12 | GetWeekdayLabelsProps, 13 | GetDaysProps, 14 | CalendarDay, 15 | } from './useMonth.utils' 16 | 17 | export { 18 | dayLabelFormat, 19 | monthLabelFormat, 20 | weekdayLabelFormat, 21 | useMonth, 22 | getDays, 23 | getWeekdayLabels, 24 | GetWeekdayLabelsProps, 25 | GetDaysProps, 26 | UseMonthResult, 27 | UseMonthProps, 28 | CalendarDay, 29 | } 30 | -------------------------------------------------------------------------------- /packages/hooks/src/useMonth/useMonth.ts: -------------------------------------------------------------------------------- 1 | import {useMemo} from 'react' 2 | import format from 'date-fns/format' 3 | import {getDays, GetDaysProps, getWeekdayLabels, GetWeekdayLabelsProps} from './useMonth.utils' 4 | 5 | export const dayLabelFormatFn = (date: Date) => format(date, 'dd') 6 | export const weekdayLabelFormatFn = (date: Date) => format(date, 'eeeeee') 7 | export const monthLabelFormatFn = (date: Date) => format(date, 'MMMM yyyy') 8 | 9 | export interface UseMonthResult { 10 | weekdayLabels: string[] 11 | days: (number | {dayLabel: string; date: Date})[] 12 | monthLabel: string 13 | } 14 | 15 | export interface UseMonthProps extends GetWeekdayLabelsProps, GetDaysProps { 16 | monthLabelFormat?(date: Date): string 17 | } 18 | 19 | export function useMonth({ 20 | year, 21 | month, 22 | firstDayOfWeek = 1, 23 | dayLabelFormat = dayLabelFormatFn, 24 | weekdayLabelFormat = weekdayLabelFormatFn, 25 | monthLabelFormat = monthLabelFormatFn, 26 | }: UseMonthProps): UseMonthResult { 27 | const days = useMemo(() => getDays({year, month, firstDayOfWeek, dayLabelFormat}), [ 28 | year, 29 | month, 30 | firstDayOfWeek, 31 | dayLabelFormat, 32 | ]) 33 | const weekdayLabels = useMemo(() => getWeekdayLabels({firstDayOfWeek, weekdayLabelFormat}), [ 34 | firstDayOfWeek, 35 | weekdayLabelFormat, 36 | ]) 37 | 38 | return { 39 | days, 40 | weekdayLabels, 41 | monthLabel: monthLabelFormat(new Date(year, month)), 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /packages/hooks/src/useMonth/useMonth.utils.ts: -------------------------------------------------------------------------------- 1 | import addDays from 'date-fns/addDays' 2 | import eachDay from 'date-fns/eachDayOfInterval' 3 | import endOfMonth from 'date-fns/endOfMonth' 4 | import endOfWeek from 'date-fns/endOfWeek' 5 | import format from 'date-fns/format' 6 | import getDay from 'date-fns/getDay' 7 | import startOfMonth from 'date-fns/startOfMonth' 8 | import startOfWeek from 'date-fns/startOfWeek' 9 | 10 | type FirstDayOfWeek = 0 | 1 | 2 | 3 | 4 | 5 | 6 11 | export interface GetWeekdayLabelsProps { 12 | firstDayOfWeek?: FirstDayOfWeek 13 | weekdayLabelFormat?(date: Date): string 14 | } 15 | 16 | export function getWeekdayLabels({ 17 | firstDayOfWeek = 1, 18 | weekdayLabelFormat = (date: Date) => format(date, 'iiiiii'), 19 | }: GetWeekdayLabelsProps = {}) { 20 | const now = new Date() 21 | const arr = eachDay({ 22 | start: addDays(startOfWeek(now), firstDayOfWeek), 23 | end: addDays(endOfWeek(now), firstDayOfWeek), 24 | }) 25 | return arr.reduce((array, date) => { 26 | // @ts-ignore 27 | array.push(weekdayLabelFormat(date)) 28 | return array 29 | }, []) 30 | } 31 | 32 | export interface GetDaysProps { 33 | year: number 34 | month: number 35 | firstDayOfWeek?: FirstDayOfWeek 36 | dayLabelFormat?(date: Date): string 37 | } 38 | 39 | export type CalendarDay = number | {dayLabel: string; date: Date} 40 | export function getDays({ 41 | year, 42 | month, 43 | firstDayOfWeek = 1, 44 | dayLabelFormat = (date: Date) => format(date, 'dd'), 45 | }: GetDaysProps): CalendarDay[] { 46 | const date = new Date(year, month) 47 | 48 | const monthStart = startOfMonth(date) 49 | const monthStartDay = getDay(monthStart) 50 | const monthEnd = endOfMonth(date) 51 | 52 | const prevMonthDays = Array.from( 53 | Array( 54 | monthStartDay >= firstDayOfWeek 55 | ? monthStartDay - firstDayOfWeek 56 | : 6 - firstDayOfWeek + monthStartDay + 1, 57 | ).keys(), 58 | ).fill(0) 59 | const days = eachDay({start: monthStart, end: monthEnd}).map(date => ({ 60 | date, 61 | dayLabel: dayLabelFormat(date), 62 | })) 63 | 64 | return [...prevMonthDays, ...days] 65 | } 66 | -------------------------------------------------------------------------------- /packages/hooks/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../config/tsconfig.base.json", 3 | "include": ["src"], 4 | "exclude": ["node_modules", "lib", "rollup.config.js"], 5 | "compilerOptions": { 6 | "types" : ["jest"] 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /packages/hooks/yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | date-fns@^1.30.1: 6 | version "1.30.1" 7 | resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-1.30.1.tgz#2e71bf0b119153dbb4cc4e88d9ea5acfb50dc05c" 8 | integrity sha512-hBSVCvSmWC+QypYObzwGOd9wqdDpOt+0wl0KbU+R+uuZBS1jN8VsD1ss3irQDknRj5NvxiTF6oj/nDRnN/UQNw== 9 | -------------------------------------------------------------------------------- /packages/styled/lib/components/Box/Box.d.ts: -------------------------------------------------------------------------------- 1 | import { 2 | BottomProps, 3 | GridAreaProps, 4 | HeightProps, 5 | LeftProps, 6 | PositionProps, 7 | RightProps, 8 | SpaceProps, 9 | TopProps, 10 | WidthProps, 11 | ZIndexProps, 12 | } from 'styled-system' 13 | interface BoxProps 14 | extends GridAreaProps, 15 | HeightProps, 16 | SpaceProps, 17 | PositionProps, 18 | TopProps, 19 | BottomProps, 20 | LeftProps, 21 | RightProps, 22 | ZIndexProps, 23 | WidthProps {} 24 | declare const Box: import('styled-components').StyledComponent<'div', any, BoxProps, never> 25 | export default Box 26 | -------------------------------------------------------------------------------- /packages/styled/lib/components/Box/Box.test.d.ts: -------------------------------------------------------------------------------- 1 | export {} 2 | -------------------------------------------------------------------------------- /packages/styled/lib/components/Box/index.d.ts: -------------------------------------------------------------------------------- 1 | import Box from './Box' 2 | export default Box 3 | -------------------------------------------------------------------------------- /packages/styled/lib/components/Close/Close.d.ts: -------------------------------------------------------------------------------- 1 | interface CloseProps { 2 | onClick(): void 3 | rtl: boolean 4 | closeText: string 5 | } 6 | declare function Close({onClick, rtl, closeText}: CloseProps): JSX.Element 7 | export default Close 8 | -------------------------------------------------------------------------------- /packages/styled/lib/components/Close/Close.test.d.ts: -------------------------------------------------------------------------------- 1 | export {} 2 | -------------------------------------------------------------------------------- /packages/styled/lib/components/Close/index.d.ts: -------------------------------------------------------------------------------- 1 | import Close from './Close' 2 | export default Close 3 | -------------------------------------------------------------------------------- /packages/styled/lib/components/DateRangeInput/DateRangeInput.d.ts: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import {UseDatepickerProps, FormatFunction, FocusedInput} from '@datepicker-react/hooks' 3 | import {DateRangeInputPhrases} from '../../phrases' 4 | export interface DateRangeInputProps extends UseDatepickerProps { 5 | displayFormat?: string | FormatFunction 6 | phrases?: DateRangeInputPhrases 7 | onFocusChange(focusInput: FocusedInput): void 8 | showStartDateCalendarIcon?: boolean 9 | showEndDateCalendarIcon?: boolean 10 | onClose?(): void 11 | vertical?: boolean 12 | showResetDates?: boolean 13 | showSelectedDates?: boolean 14 | showClose?: boolean 15 | rtl?: boolean 16 | placement?: 'top' | 'bottom' 17 | dayLabelFormat?(date: Date): string 18 | weekdayLabelFormat?(date: Date): string 19 | monthLabelFormat?(date: Date): string 20 | onDayRender?(date: Date): React.ReactNode 21 | startDateInputId?: string 22 | endDateInputId?: string 23 | unavailableDates?: Date[] 24 | initialVisibleMonth?: Date 25 | } 26 | declare function DateRangeInput({ 27 | startDate, 28 | endDate, 29 | minBookingDate, 30 | maxBookingDate, 31 | firstDayOfWeek, 32 | onFocusChange, 33 | numberOfMonths, 34 | focusedInput, 35 | onDatesChange, 36 | exactMinBookingDays, 37 | dayLabelFormat, 38 | weekdayLabelFormat, 39 | monthLabelFormat, 40 | onDayRender, 41 | initialVisibleMonth, 42 | showClose, 43 | showSelectedDates, 44 | showResetDates, 45 | vertical, 46 | rtl, 47 | isDateBlocked, 48 | minBookingDays, 49 | onClose, 50 | showStartDateCalendarIcon, 51 | showEndDateCalendarIcon, 52 | displayFormat, 53 | phrases, 54 | placement, 55 | startDateInputId, 56 | endDateInputId, 57 | unavailableDates, 58 | }: DateRangeInputProps): JSX.Element 59 | export default DateRangeInput 60 | -------------------------------------------------------------------------------- /packages/styled/lib/components/DateRangeInput/DateRangeInput.stories.d.ts: -------------------------------------------------------------------------------- 1 | export {} 2 | -------------------------------------------------------------------------------- /packages/styled/lib/components/DateRangeInput/DateRangeInput.test.d.ts: -------------------------------------------------------------------------------- 1 | export {} 2 | -------------------------------------------------------------------------------- /packages/styled/lib/components/DateRangeInput/index.d.ts: -------------------------------------------------------------------------------- 1 | import DateRangeInput from './DateRangeInput' 2 | export default DateRangeInput 3 | -------------------------------------------------------------------------------- /packages/styled/lib/components/DateSingleInput/DateSingleInput.d.ts: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import {FormatFunction, FirstDayOfWeek} from '@datepicker-react/hooks' 3 | import {DateSingleInputPhrases} from '../../phrases' 4 | export interface OnDateChangeProps { 5 | date: Date | null 6 | showDatepicker: boolean 7 | } 8 | export interface DateSingleInputProps { 9 | date: Date | null 10 | minBookingDate?: Date 11 | maxBookingDate?: Date 12 | showDatepicker: boolean 13 | numberOfMonths?: number 14 | firstDayOfWeek?: FirstDayOfWeek 15 | displayFormat?: string | FormatFunction 16 | phrases?: DateSingleInputPhrases 17 | showCalendarIcon?: boolean 18 | vertical?: boolean 19 | showResetDate?: boolean 20 | showClose?: boolean 21 | rtl?: boolean 22 | placement?: 'top' | 'bottom' 23 | initialVisibleMonth?: Date 24 | onDateChange(data: OnDateChangeProps): void 25 | onFocusChange(focusInput: boolean): void 26 | isDateBlocked?(date: Date): boolean 27 | onClose?(): void 28 | dayLabelFormat?(date: Date): string 29 | weekdayLabelFormat?(date: Date): string 30 | monthLabelFormat?(date: Date): string 31 | onDayRender?(date: Date): React.ReactNode 32 | inputId?: string 33 | unavailableDates?: Date[] 34 | } 35 | declare function DateSingleInput({ 36 | date, 37 | minBookingDate, 38 | maxBookingDate, 39 | firstDayOfWeek, 40 | onFocusChange, 41 | showDatepicker, 42 | onDateChange, 43 | dayLabelFormat, 44 | weekdayLabelFormat, 45 | monthLabelFormat, 46 | onDayRender, 47 | initialVisibleMonth, 48 | numberOfMonths, 49 | showClose, 50 | showResetDate, 51 | vertical, 52 | rtl, 53 | isDateBlocked, 54 | onClose, 55 | showCalendarIcon, 56 | displayFormat, 57 | phrases, 58 | placement, 59 | inputId, 60 | unavailableDates, 61 | }: DateSingleInputProps): JSX.Element 62 | export default DateSingleInput 63 | -------------------------------------------------------------------------------- /packages/styled/lib/components/DateSingleInput/DateSingleInput.stories.d.ts: -------------------------------------------------------------------------------- 1 | export {} 2 | -------------------------------------------------------------------------------- /packages/styled/lib/components/DateSingleInput/DateSingleInput.test.d.ts: -------------------------------------------------------------------------------- 1 | export {} 2 | -------------------------------------------------------------------------------- /packages/styled/lib/components/DateSingleInput/index.d.ts: -------------------------------------------------------------------------------- 1 | import DateSingleInput, {OnDateChangeProps} from './DateSingleInput' 2 | export {OnDateChangeProps} 3 | export default DateSingleInput 4 | -------------------------------------------------------------------------------- /packages/styled/lib/components/Datepicker/Datepicker.d.ts: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import {UseDatepickerProps, FormatFunction} from '@datepicker-react/hooks' 3 | import {DatepickerPhrases} from '../../phrases' 4 | export interface DatepickerProps extends UseDatepickerProps { 5 | phrases?: DatepickerPhrases 6 | displayFormat?: string | FormatFunction 7 | onClose?(): void 8 | showResetDates?: boolean 9 | showSelectedDates?: boolean 10 | showClose?: boolean 11 | vertical?: boolean 12 | rtl?: boolean 13 | initialVisibleMonth?: Date 14 | dayLabelFormat?(date: Date): string 15 | weekdayLabelFormat?(date: Date): string 16 | monthLabelFormat?(date: Date): string 17 | onDayRender?(date: Date): React.ReactNode 18 | unavailableDates?: Date[] 19 | } 20 | declare const _default: React.ForwardRefExoticComponent< 21 | DatepickerProps & React.RefAttributes 22 | > 23 | export default _default 24 | -------------------------------------------------------------------------------- /packages/styled/lib/components/Datepicker/Datepicker.stories.d.ts: -------------------------------------------------------------------------------- 1 | export {} 2 | -------------------------------------------------------------------------------- /packages/styled/lib/components/Datepicker/Datepicker.test.d.ts: -------------------------------------------------------------------------------- 1 | export {} 2 | -------------------------------------------------------------------------------- /packages/styled/lib/components/Datepicker/index.d.ts: -------------------------------------------------------------------------------- 1 | import Datepicker from './Datepicker' 2 | export default Datepicker 3 | -------------------------------------------------------------------------------- /packages/styled/lib/components/Day/Day.d.ts: -------------------------------------------------------------------------------- 1 | interface DayProps { 2 | day: string 3 | date: Date 4 | } 5 | declare function Day({day, date}: DayProps): JSX.Element 6 | export default Day 7 | -------------------------------------------------------------------------------- /packages/styled/lib/components/Day/Day.test.d.ts: -------------------------------------------------------------------------------- 1 | export {} 2 | -------------------------------------------------------------------------------- /packages/styled/lib/components/Day/index.d.ts: -------------------------------------------------------------------------------- 1 | import Day from './Day' 2 | export default Day 3 | -------------------------------------------------------------------------------- /packages/styled/lib/components/DayLabel/DayLabel.d.ts: -------------------------------------------------------------------------------- 1 | interface MonthLabelProps { 2 | label: string 3 | } 4 | declare const MonthLabel: ({label}: MonthLabelProps) => JSX.Element 5 | export default MonthLabel 6 | -------------------------------------------------------------------------------- /packages/styled/lib/components/DayLabel/DayLabel.test.d.ts: -------------------------------------------------------------------------------- 1 | export {} 2 | -------------------------------------------------------------------------------- /packages/styled/lib/components/DayLabel/index.d.ts: -------------------------------------------------------------------------------- 1 | import DayLabel from './DayLabel' 2 | export default DayLabel 3 | -------------------------------------------------------------------------------- /packages/styled/lib/components/Flex/Flex.d.ts: -------------------------------------------------------------------------------- 1 | import { 2 | AlignItemsProps, 3 | FlexProps, 4 | FlexDirectionProps, 5 | FlexWrapProps, 6 | JustifyContentProps, 7 | SpaceProps, 8 | GridAreaProps, 9 | HeightProps, 10 | WidthProps, 11 | } from 'styled-system' 12 | interface FlexComponentProps 13 | extends SpaceProps, 14 | FlexWrapProps, 15 | FlexDirectionProps, 16 | AlignItemsProps, 17 | GridAreaProps, 18 | HeightProps, 19 | WidthProps, 20 | FlexProps, 21 | JustifyContentProps {} 22 | declare const Flex: import('styled-components').StyledComponent< 23 | 'div', 24 | any, 25 | FlexComponentProps, 26 | never 27 | > 28 | export default Flex 29 | -------------------------------------------------------------------------------- /packages/styled/lib/components/Flex/Flex.test.d.ts: -------------------------------------------------------------------------------- 1 | export {} 2 | -------------------------------------------------------------------------------- /packages/styled/lib/components/Flex/index.d.ts: -------------------------------------------------------------------------------- 1 | import Flex from './Flex' 2 | export default Flex 3 | -------------------------------------------------------------------------------- /packages/styled/lib/components/Grid/Grid.d.ts: -------------------------------------------------------------------------------- 1 | import { 2 | GridAutoColumnsProps, 3 | GridAutoFlowProps, 4 | GridAutoRowsProps, 5 | AlignItemsProps, 6 | JustifyContentProps, 7 | GridColumnGapProps, 8 | GridGapProps, 9 | GridRowGapProps, 10 | GridTemplateAreasProps, 11 | GridTemplateColumnsProps, 12 | GridTemplateRowsProps, 13 | SpaceProps, 14 | } from 'styled-system' 15 | interface GridProps 16 | extends GridAutoColumnsProps, 17 | GridAutoFlowProps, 18 | GridAutoRowsProps, 19 | AlignItemsProps, 20 | JustifyContentProps, 21 | GridColumnGapProps, 22 | GridGapProps, 23 | GridRowGapProps, 24 | GridTemplateAreasProps, 25 | GridTemplateColumnsProps, 26 | SpaceProps, 27 | GridTemplateRowsProps { 28 | daySizeGridTemplateColumns?: number | (number | null)[] | undefined 29 | numberOfMonthsGridTemplateColumns?: number | (number | null)[] | undefined 30 | } 31 | declare const Grid: import('styled-components').StyledComponent<'div', any, GridProps, never> 32 | export default Grid 33 | -------------------------------------------------------------------------------- /packages/styled/lib/components/Grid/Grid.test.d.ts: -------------------------------------------------------------------------------- 1 | export {} 2 | -------------------------------------------------------------------------------- /packages/styled/lib/components/Grid/index.d.ts: -------------------------------------------------------------------------------- 1 | import Grid from './Grid' 2 | export default Grid 3 | -------------------------------------------------------------------------------- /packages/styled/lib/components/Input/Input.d.ts: -------------------------------------------------------------------------------- 1 | import {ResponsiveValue, TLengthStyledSystem} from 'styled-system' 2 | import {PaddingProperty} from 'csstype' 3 | interface InputProps { 4 | placeholder: string 5 | value: string 6 | id: string 7 | ariaLabel: string 8 | onClick(): void 9 | showCalendarIcon: boolean 10 | vertical: boolean 11 | isActive: boolean 12 | rtl: boolean 13 | disableAccessibility?: boolean 14 | padding?: ResponsiveValue> 15 | onChange?(date: Date): void 16 | dateFormat: string 17 | } 18 | declare function Input({ 19 | placeholder, 20 | id, 21 | vertical, 22 | isActive, 23 | ariaLabel, 24 | onClick, 25 | value, 26 | showCalendarIcon, 27 | padding, 28 | rtl, 29 | disableAccessibility, 30 | dateFormat, 31 | onChange, 32 | }: InputProps): JSX.Element 33 | export default Input 34 | -------------------------------------------------------------------------------- /packages/styled/lib/components/Input/Input.test.d.ts: -------------------------------------------------------------------------------- 1 | export {} 2 | -------------------------------------------------------------------------------- /packages/styled/lib/components/Input/index.d.ts: -------------------------------------------------------------------------------- 1 | import Input from './Input' 2 | export default Input 3 | -------------------------------------------------------------------------------- /packages/styled/lib/components/Month/Month.d.ts: -------------------------------------------------------------------------------- 1 | import {FirstDayOfWeek} from '@datepicker-react/hooks' 2 | interface MonthProps { 3 | year: number 4 | month: number 5 | firstDayOfWeek: FirstDayOfWeek 6 | dayLabelFormat(date: Date): string 7 | weekdayLabelFormat(date: Date): string 8 | monthLabelFormat(date: Date): string 9 | } 10 | declare const Month: ({ 11 | year, 12 | month, 13 | firstDayOfWeek, 14 | dayLabelFormat, 15 | monthLabelFormat, 16 | weekdayLabelFormat, 17 | }: MonthProps) => JSX.Element 18 | export default Month 19 | -------------------------------------------------------------------------------- /packages/styled/lib/components/Month/Month.test.d.ts: -------------------------------------------------------------------------------- 1 | export {} 2 | -------------------------------------------------------------------------------- /packages/styled/lib/components/Month/index.d.ts: -------------------------------------------------------------------------------- 1 | import Month from './Month' 2 | export default Month 3 | -------------------------------------------------------------------------------- /packages/styled/lib/components/MonthLabel/MonthLabel.d.ts: -------------------------------------------------------------------------------- 1 | interface MonthLabelProps { 2 | label: string 3 | } 4 | declare const MonthLabel: ({label}: MonthLabelProps) => JSX.Element 5 | export default MonthLabel 6 | -------------------------------------------------------------------------------- /packages/styled/lib/components/MonthLabel/MonthLabel.test.d.ts: -------------------------------------------------------------------------------- 1 | export {} 2 | -------------------------------------------------------------------------------- /packages/styled/lib/components/MonthLabel/index.d.ts: -------------------------------------------------------------------------------- 1 | import MonthLabel from './MonthLabel' 2 | export default MonthLabel 3 | -------------------------------------------------------------------------------- /packages/styled/lib/components/NavButton/NavButton.d.ts: -------------------------------------------------------------------------------- 1 | interface NavButtonProps { 2 | type: 'next' | 'prev' 3 | onClick(): void 4 | vertical: boolean 5 | rtl: boolean 6 | ariaLabel: string 7 | } 8 | declare function NavButton({type, onClick, vertical, rtl, ariaLabel}: NavButtonProps): JSX.Element 9 | export default NavButton 10 | -------------------------------------------------------------------------------- /packages/styled/lib/components/NavButton/NavButton.test.d.ts: -------------------------------------------------------------------------------- 1 | export {} 2 | -------------------------------------------------------------------------------- /packages/styled/lib/components/NavButton/index.d.ts: -------------------------------------------------------------------------------- 1 | import NavButton from './NavButton' 2 | export default NavButton 3 | -------------------------------------------------------------------------------- /packages/styled/lib/components/ResetDates/ResetDates.d.ts: -------------------------------------------------------------------------------- 1 | interface ResetDatesProps { 2 | onResetDates(): void 3 | text: string 4 | rtl: boolean 5 | } 6 | declare function ResetDates({onResetDates, text, rtl}: ResetDatesProps): JSX.Element 7 | export default ResetDates 8 | -------------------------------------------------------------------------------- /packages/styled/lib/components/ResetDates/ResetDates.test.d.ts: -------------------------------------------------------------------------------- 1 | export {} 2 | -------------------------------------------------------------------------------- /packages/styled/lib/components/ResetDates/index.d.ts: -------------------------------------------------------------------------------- 1 | import ResetDates from './ResetDates' 2 | export default ResetDates 3 | -------------------------------------------------------------------------------- /packages/styled/lib/components/SelectedDate/SelectedDate.d.ts: -------------------------------------------------------------------------------- 1 | export interface SelectDateProps { 2 | title: string 3 | date: string 4 | isActive: boolean 5 | vertical: boolean 6 | } 7 | declare function SelectDate({title, isActive, date, vertical}: SelectDateProps): JSX.Element 8 | export default SelectDate 9 | -------------------------------------------------------------------------------- /packages/styled/lib/components/SelectedDate/SelectedDate.test.d.ts: -------------------------------------------------------------------------------- 1 | export {} 2 | -------------------------------------------------------------------------------- /packages/styled/lib/components/SelectedDate/index.d.ts: -------------------------------------------------------------------------------- 1 | import SelectedDate from './SelectedDate' 2 | export default SelectedDate 3 | -------------------------------------------------------------------------------- /packages/styled/lib/components/Text/Test.test.d.ts: -------------------------------------------------------------------------------- 1 | export {} 2 | -------------------------------------------------------------------------------- /packages/styled/lib/components/Text/Text.d.ts: -------------------------------------------------------------------------------- 1 | import { 2 | FontFamilyProps, 3 | FontSizeProps, 4 | FontWeightProps, 5 | ColorProps, 6 | LineHeightProps, 7 | SpaceProps, 8 | } from 'styled-system' 9 | interface TextProps 10 | extends FontWeightProps, 11 | FontSizeProps, 12 | FontFamilyProps, 13 | ColorProps, 14 | SpaceProps, 15 | LineHeightProps {} 16 | declare const Text: import('styled-components').StyledComponent<'div', any, TextProps, never> 17 | export default Text 18 | -------------------------------------------------------------------------------- /packages/styled/lib/components/Text/index.d.ts: -------------------------------------------------------------------------------- 1 | import Text from './Text' 2 | export default Text 3 | -------------------------------------------------------------------------------- /packages/styled/lib/context/datepickerContext.d.ts: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | interface DatepickerContext { 3 | rtl: boolean 4 | focusedDate: Date | null 5 | onDateFocus(date: Date): void 6 | onDateSelect(date: Date): void 7 | onDateHover(date: Date): void 8 | isDateFocused(date: Date): boolean 9 | isDateSelected(date: Date): boolean 10 | isDateHovered(date: Date): boolean 11 | isDateBlocked(date: Date): boolean 12 | isFirstOrLastSelectedDate(date: Date): boolean 13 | onDayRender?(date: Date): React.ReactNode 14 | } 15 | export declare const datepickerContextDefaultValue: { 16 | rtl: boolean 17 | focusedDate: null 18 | isDateFocused: () => boolean 19 | isDateSelected: () => boolean 20 | isDateHovered: () => boolean 21 | isDateBlocked: () => boolean 22 | isFirstOrLastSelectedDate: () => boolean 23 | onDateFocus: () => void 24 | onDateHover: () => void 25 | onDateSelect: () => void 26 | onDayRender: undefined 27 | } 28 | declare const _default: React.Context 29 | export default _default 30 | -------------------------------------------------------------------------------- /packages/styled/lib/globalStyles.d.ts: -------------------------------------------------------------------------------- 1 | declare const _default: { 2 | fontFamily: string 3 | colors: { 4 | primaryColor: string 5 | silverCloud: string 6 | charcoal: string 7 | darcula: string 8 | mud: string 9 | greey: string 10 | graci: string 11 | white: string 12 | accessibility: string 13 | selectedDay: string 14 | selectedDayHover: string 15 | normalDayHover: string 16 | } 17 | daySize: number 18 | } 19 | export default _default 20 | -------------------------------------------------------------------------------- /packages/styled/lib/hooks/useThemeProps/index.d.ts: -------------------------------------------------------------------------------- 1 | import useThemeProps from './useThemeProps' 2 | export default useThemeProps 3 | -------------------------------------------------------------------------------- /packages/styled/lib/hooks/useThemeProps/useThemeProps.d.ts: -------------------------------------------------------------------------------- 1 | export default function useThemeProps(themeProps?: Record): Record 2 | -------------------------------------------------------------------------------- /packages/styled/lib/hooks/useThemeProps/useThemeProps.test.d.ts: -------------------------------------------------------------------------------- 1 | export {} 2 | -------------------------------------------------------------------------------- /packages/styled/lib/icons/ArrowIcon/ArrowIcon.d.ts: -------------------------------------------------------------------------------- 1 | interface Props { 2 | direction?: 'up' | 'down' | 'left' | 'right' 3 | height: string 4 | width: string 5 | iconColor?: string 6 | className?: string 7 | } 8 | declare function ArrowIcon({height, width, iconColor, direction, className}: Props): JSX.Element 9 | export default ArrowIcon 10 | -------------------------------------------------------------------------------- /packages/styled/lib/icons/ArrowIcon/ArrowIcon.test.d.ts: -------------------------------------------------------------------------------- 1 | export {} 2 | -------------------------------------------------------------------------------- /packages/styled/lib/icons/ArrowIcon/index.d.ts: -------------------------------------------------------------------------------- 1 | import ArrowIcon from './ArrowIcon' 2 | export default ArrowIcon 3 | -------------------------------------------------------------------------------- /packages/styled/lib/icons/CalendarIcon/CalendarIcon.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | declare function CalendarIcon({height, width, color, className}: IconProps): JSX.Element 3 | export default CalendarIcon 4 | -------------------------------------------------------------------------------- /packages/styled/lib/icons/CalendarIcon/CalendarIcon.test.d.ts: -------------------------------------------------------------------------------- 1 | export {} 2 | -------------------------------------------------------------------------------- /packages/styled/lib/icons/CalendarIcon/index.d.ts: -------------------------------------------------------------------------------- 1 | import CalendarIcon from './CalendarIcon' 2 | export default CalendarIcon 3 | -------------------------------------------------------------------------------- /packages/styled/lib/icons/CaretIcon/CaretIcon.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | interface Props extends IconProps { 3 | direction?: 'up' | 'down' | 'left' | 'right' 4 | } 5 | declare function CaretIcon({height, width, color, direction, className}: Props): JSX.Element 6 | export default CaretIcon 7 | -------------------------------------------------------------------------------- /packages/styled/lib/icons/CaretIcon/CaretIcon.test.d.ts: -------------------------------------------------------------------------------- 1 | export {} 2 | -------------------------------------------------------------------------------- /packages/styled/lib/icons/CaretIcon/index.d.ts: -------------------------------------------------------------------------------- 1 | import CaretIcon from './CaretIcon' 2 | export default CaretIcon 3 | -------------------------------------------------------------------------------- /packages/styled/lib/icons/CloseIcon/CloseIcon.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | declare function CloseIcon({height, width, color, className}: IconProps): JSX.Element 3 | export default CloseIcon 4 | -------------------------------------------------------------------------------- /packages/styled/lib/icons/CloseIcon/CloseIcon.test.d.ts: -------------------------------------------------------------------------------- 1 | export {} 2 | -------------------------------------------------------------------------------- /packages/styled/lib/icons/CloseIcon/index.d.ts: -------------------------------------------------------------------------------- 1 | import CloseIcon from './CloseIcon' 2 | export default CloseIcon 3 | -------------------------------------------------------------------------------- /packages/styled/lib/icons/RedoIcon/RedoIcon.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | declare function CaretIcon({height, width, color, className}: IconProps): JSX.Element 3 | export default CaretIcon 4 | -------------------------------------------------------------------------------- /packages/styled/lib/icons/RedoIcon/RedoIcon.test.d.ts: -------------------------------------------------------------------------------- 1 | export {} 2 | -------------------------------------------------------------------------------- /packages/styled/lib/icons/RedoIcon/index.d.ts: -------------------------------------------------------------------------------- 1 | import RedoIcon from './RedoIcon' 2 | export default RedoIcon 3 | -------------------------------------------------------------------------------- /packages/styled/lib/index.d.ts: -------------------------------------------------------------------------------- 1 | import { 2 | FirstDayOfWeek, 3 | FocusedInput, 4 | START_DATE, 5 | END_DATE, 6 | OnDatesChangeProps, 7 | FormatFunction, 8 | MonthType, 9 | } from '@datepicker-react/hooks' 10 | import DateRangeInput from './components/DateRangeInput' 11 | import DateSingleInput, {OnDateChangeProps} from './components/DateSingleInput' 12 | import Datepicker from './components/Datepicker' 13 | import { 14 | dateRangeInputPhrases, 15 | DateRangeInputPhrases, 16 | datepickerPhrases, 17 | DatepickerPhrases, 18 | DateSingleInputPhrases, 19 | dateSingleInputPhrases, 20 | } from './phrases' 21 | export { 22 | DateRangeInput, 23 | DateSingleInput, 24 | FirstDayOfWeek, 25 | Datepicker, 26 | dateRangeInputPhrases, 27 | DateRangeInputPhrases, 28 | datepickerPhrases, 29 | DatepickerPhrases, 30 | DateSingleInputPhrases, 31 | dateSingleInputPhrases, 32 | FocusedInput, 33 | START_DATE, 34 | END_DATE, 35 | OnDatesChangeProps, 36 | FormatFunction, 37 | MonthType, 38 | OnDateChangeProps, 39 | } 40 | -------------------------------------------------------------------------------- /packages/styled/lib/phrases.d.ts: -------------------------------------------------------------------------------- 1 | export interface DatepickerPhrases { 2 | datepickerStartDatePlaceholder: string 3 | datepickerStartDateLabel: string 4 | datepickerEndDateLabel: string 5 | datepickerEndDatePlaceholder: string 6 | resetDates: string 7 | close: string 8 | } 9 | export interface DateRangeInputPhrases extends DatepickerPhrases { 10 | startDateAriaLabel: string 11 | endDateAriaLabel: string 12 | startDatePlaceholder: string 13 | endDatePlaceholder: string 14 | } 15 | export interface DateRangeInputPhrases extends DatepickerPhrases { 16 | startDateAriaLabel: string 17 | endDateAriaLabel: string 18 | startDatePlaceholder: string 19 | endDatePlaceholder: string 20 | } 21 | export interface DateSingleInputPhrases extends DatepickerPhrases { 22 | dateAriaLabel: string 23 | datePlaceholder: string 24 | } 25 | export declare const datepickerPhrases: { 26 | datepickerStartDatePlaceholder: string 27 | datepickerStartDateLabel: string 28 | datepickerEndDatePlaceholder: string 29 | datepickerEndDateLabel: string 30 | resetDates: string 31 | close: string 32 | } 33 | export declare const dateRangeInputPhrases: { 34 | startDateAriaLabel: string 35 | endDateAriaLabel: string 36 | startDatePlaceholder: string 37 | endDatePlaceholder: string 38 | datepickerStartDatePlaceholder: string 39 | datepickerStartDateLabel: string 40 | datepickerEndDatePlaceholder: string 41 | datepickerEndDateLabel: string 42 | resetDates: string 43 | close: string 44 | } 45 | export declare const dateSingleInputPhrases: { 46 | dateAriaLabel: string 47 | datePlaceholder: string 48 | datepickerStartDatePlaceholder: string 49 | datepickerStartDateLabel: string 50 | datepickerEndDatePlaceholder: string 51 | datepickerEndDateLabel: string 52 | resetDates: string 53 | close: string 54 | } 55 | -------------------------------------------------------------------------------- /packages/styled/lib/testUtil.d.ts: -------------------------------------------------------------------------------- 1 | declare function renderWithProviders( 2 | ui: any, 3 | options?: any, 4 | contextValues?: Record, 5 | ): import('@testing-library/react').RenderResult< 6 | typeof import('@testing-library/dom/types/queries') 7 | > 8 | export * from '@testing-library/react' 9 | export {renderWithProviders as render} 10 | -------------------------------------------------------------------------------- /packages/styled/lib/utils/getThemeProp/getThemeProp.d.ts: -------------------------------------------------------------------------------- 1 | declare function getThemeProp( 2 | themeProp: string, 3 | defaultValue: any, 4 | theme?: Record, 5 | ): any 6 | export default getThemeProp 7 | -------------------------------------------------------------------------------- /packages/styled/lib/utils/getThemeProp/getThemeProp.test.d.ts: -------------------------------------------------------------------------------- 1 | export {} 2 | -------------------------------------------------------------------------------- /packages/styled/lib/utils/getThemeProp/index.d.ts: -------------------------------------------------------------------------------- 1 | import getThemeProp from './getThemeProp' 2 | export default getThemeProp 3 | -------------------------------------------------------------------------------- /packages/styled/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@datepicker-react/styled", 3 | "version": "2.8.4", 4 | "description": "A React datepicker build with styled-components.", 5 | "keywords": [ 6 | "datepicker", 7 | "react", 8 | "styled-components" 9 | ], 10 | "author": "Miha Sedej ", 11 | "homepage": "https://github.com/tresko/react-datepicker#readme", 12 | "license": "MIT", 13 | "main": "lib/index.cjs.js", 14 | "module": "lib/index.esm.js", 15 | "typings": "lib/index.d.ts", 16 | "directories": { 17 | "lib": "lib", 18 | "test": "__tests__" 19 | }, 20 | "files": [ 21 | "lib" 22 | ], 23 | "repository": { 24 | "type": "git", 25 | "url": "git+https://github.com/tresko/react-datepicker.git" 26 | }, 27 | "scripts": { 28 | "build": "../../node_modules/.bin/rollup -c rollup.config.js", 29 | "build:watch": "yarn build -w", 30 | "format": "../../node_modules/.bin/prettier --write \"src/**/*.+(ts|tsx)\"", 31 | "tsc": "../../node_modules/.bin/tsc --noEmit", 32 | "prebuild": "../../node_modules/.bin/rimraf lib" 33 | }, 34 | "bugs": { 35 | "url": "https://github.com/tresko/react-datepicker/issues" 36 | }, 37 | "peerDependencies": { 38 | "react": ">= 16.8.5", 39 | "styled-components": ">= 4.0.0" 40 | }, 41 | "devDependencies": { 42 | "@types/styled-components": "^5.1.0", 43 | "@types/styled-system": "^5.1.9", 44 | "csstype": "^2.6.10", 45 | "date-fns": "^2.14.0", 46 | "styled-components": "^5.1.1" 47 | }, 48 | "dependencies": { 49 | "@datepicker-react/hooks": "^2.8.4", 50 | "styled-system": "^5.1.5" 51 | }, 52 | "publishConfig": { 53 | "access": "public" 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /packages/styled/rollup.config.js: -------------------------------------------------------------------------------- 1 | import {rollup} from '../../config/rollup.config' 2 | 3 | export default rollup({ 4 | input: 'src/index.ts', 5 | packageJsonPath: './package.json', 6 | }) 7 | -------------------------------------------------------------------------------- /packages/styled/src/@types/index.d.ts: -------------------------------------------------------------------------------- 1 | interface IconProps { 2 | height: string 3 | width: string 4 | color: string 5 | className?: string 6 | } 7 | -------------------------------------------------------------------------------- /packages/styled/src/components/Box/Box.test.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import {render} from '../../testUtil' 3 | import Box from '.' 4 | 5 | test('should match snapshot', () => { 6 | const {container} = render( 7 | 19 |
test1
20 |
test2
21 |
test3
22 |
test4
23 |
test5
24 |
, 25 | ) 26 | expect(container).toMatchSnapshot() 27 | }) 28 | -------------------------------------------------------------------------------- /packages/styled/src/components/Box/Box.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | bottom, 3 | BottomProps, 4 | compose, 5 | gridArea, 6 | GridAreaProps, 7 | height, 8 | HeightProps, 9 | left, 10 | LeftProps, 11 | position, 12 | PositionProps, 13 | right, 14 | RightProps, 15 | space, 16 | SpaceProps, 17 | top, 18 | TopProps, 19 | width, 20 | WidthProps, 21 | zIndex, 22 | ZIndexProps, 23 | } from 'styled-system' 24 | import styled from 'styled-components' 25 | 26 | interface BoxProps 27 | extends GridAreaProps, 28 | HeightProps, 29 | SpaceProps, 30 | PositionProps, 31 | TopProps, 32 | BottomProps, 33 | LeftProps, 34 | RightProps, 35 | ZIndexProps, 36 | WidthProps {} 37 | const composeBoxStyles = compose( 38 | gridArea, 39 | height, 40 | space, 41 | width, 42 | position, 43 | top, 44 | left, 45 | right, 46 | bottom, 47 | zIndex, 48 | ) 49 | 50 | const Box = styled('div')` 51 | box-sizing: border-box; 52 | ${composeBoxStyles} 53 | ` 54 | 55 | export default Box 56 | -------------------------------------------------------------------------------- /packages/styled/src/components/Box/__snapshots__/Box.test.tsx.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`should match snapshot 1`] = ` 4 | .c0 { 5 | box-sizing: border-box; 6 | grid-area: test; 7 | height: 150px; 8 | width: 150px; 9 | padding: 10px; 10 | position: relative; 11 | top: 10px; 12 | left: 15px; 13 | right: 20px; 14 | bottom: 30px; 15 | z-index: 1; 16 | } 17 | 18 |
19 |
24 |
25 | test1 26 |
27 |
28 | test2 29 |
30 |
31 | test3 32 |
33 |
34 | test4 35 |
36 |
37 | test5 38 |
39 |
40 |
41 | `; 42 | -------------------------------------------------------------------------------- /packages/styled/src/components/Box/index.ts: -------------------------------------------------------------------------------- 1 | import Box from './Box' 2 | 3 | export default Box 4 | -------------------------------------------------------------------------------- /packages/styled/src/components/Close/Close.test.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import {render, fireEvent} from '../../testUtil' 3 | import CloseModal from '.' 4 | 5 | test('should match snapshot', () => { 6 | const {container} = render() 7 | expect(container).toMatchSnapshot() 8 | }) 9 | 10 | test('should render rtl variant', () => { 11 | const {container} = render() 12 | expect(container).toMatchSnapshot() 13 | }) 14 | 15 | test('should execute callback', () => { 16 | const onClick = jest.fn() 17 | const {container} = render() 18 | // @ts-ignore 19 | fireEvent.click(container.firstChild) 20 | expect(onClick).toHaveBeenCalled() 21 | }) 22 | -------------------------------------------------------------------------------- /packages/styled/src/components/Close/Close.tsx: -------------------------------------------------------------------------------- 1 | import React, {useContext} from 'react' 2 | import styled, {ThemeContext} from 'styled-components' 3 | import { 4 | color, 5 | ColorProps, 6 | space, 7 | SpaceProps, 8 | fontSize, 9 | FontSizeProps, 10 | fontFamily, 11 | FontFamilyProps, 12 | fontWeight, 13 | FontWeightProps, 14 | compose, 15 | } from 'styled-system' 16 | import CloseIcon from '../../icons/CloseIcon' 17 | // eslint-disable-next-line import/no-unresolved 18 | import {CloseTheme} from '../../@types/theme' 19 | import useThemeProps from '../../hooks/useThemeProps' 20 | import globalStyles from '../../globalStyles' 21 | import getThemeProp from '../../utils/getThemeProp' 22 | 23 | interface TextProps 24 | extends ColorProps, 25 | SpaceProps, 26 | FontSizeProps, 27 | FontFamilyProps, 28 | FontWeightProps {} 29 | const composeTextStyles = compose(space, color, fontSize, fontFamily, fontWeight) 30 | const Text = styled('div')` 31 | ${composeTextStyles} 32 | float: left; 33 | transition: color 0.15s; 34 | ` 35 | 36 | const Wrapper = styled('button')` 37 | display: flex; 38 | align-items: center; 39 | cursor: pointer; 40 | background: transparent; 41 | padding: 0; 42 | border: 0; 43 | 44 | svg { 45 | transition: color 0.15s; 46 | } 47 | 48 | &:hover { 49 | ${Text} { 50 | ${color} 51 | } 52 | 53 | svg { 54 | ${color} 55 | } 56 | } 57 | ` 58 | 59 | interface CloseProps { 60 | onClick(): void 61 | rtl: boolean 62 | closeText: string 63 | } 64 | 65 | function Close({onClick, rtl, closeText}: CloseProps) { 66 | const themeContext = useContext(ThemeContext) 67 | const theme: CloseTheme = useThemeProps({ 68 | fontFamily: globalStyles.fontFamily, 69 | closeMargin: rtl ? '1px 16px 0 0' : '1px 0 0 16px', 70 | closeColor: getThemeProp('silverCloud', globalStyles.colors.silverCloud, themeContext), 71 | closeHoverColor: getThemeProp('darcula', globalStyles.colors.darcula, themeContext), 72 | closeFontSize: '12px', 73 | closeFontWeight: 600, 74 | }) 75 | 76 | return ( 77 | 85 | 86 | 94 | {closeText} 95 | 96 | 97 | ) 98 | } 99 | 100 | export default Close 101 | -------------------------------------------------------------------------------- /packages/styled/src/components/Close/__snapshots__/Close.test.tsx.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`should match snapshot 1`] = ` 4 | .c2 { 5 | margin: 1px 0 0 16px; 6 | color: #929598; 7 | font-size: 12px; 8 | font-family: Montserrat,sans-serif; 9 | font-weight: 600; 10 | float: left; 11 | -webkit-transition: color 0.15s; 12 | transition: color 0.15s; 13 | } 14 | 15 | .c0 { 16 | display: -webkit-box; 17 | display: -webkit-flex; 18 | display: -ms-flexbox; 19 | display: flex; 20 | -webkit-align-items: center; 21 | -webkit-box-align: center; 22 | -ms-flex-align: center; 23 | align-items: center; 24 | cursor: pointer; 25 | background: transparent; 26 | padding: 0; 27 | border: 0; 28 | } 29 | 30 | .c0 svg { 31 | -webkit-transition: color 0.15s; 32 | transition: color 0.15s; 33 | } 34 | 35 | .c0:hover .c1 { 36 | color: #343132; 37 | } 38 | 39 | .c0:hover svg { 40 | color: #343132; 41 | } 42 | 43 |
44 | 75 |
76 | `; 77 | 78 | exports[`should render rtl variant 1`] = ` 79 | .c2 { 80 | margin: 1px 0 0 16px; 81 | color: #929598; 82 | font-size: 12px; 83 | font-family: Montserrat,sans-serif; 84 | font-weight: 600; 85 | float: left; 86 | -webkit-transition: color 0.15s; 87 | transition: color 0.15s; 88 | } 89 | 90 | .c0 { 91 | display: -webkit-box; 92 | display: -webkit-flex; 93 | display: -ms-flexbox; 94 | display: flex; 95 | -webkit-align-items: center; 96 | -webkit-box-align: center; 97 | -ms-flex-align: center; 98 | align-items: center; 99 | cursor: pointer; 100 | background: transparent; 101 | padding: 0; 102 | border: 0; 103 | } 104 | 105 | .c0 svg { 106 | -webkit-transition: color 0.15s; 107 | transition: color 0.15s; 108 | } 109 | 110 | .c0:hover .c1 { 111 | color: #343132; 112 | } 113 | 114 | .c0:hover svg { 115 | color: #343132; 116 | } 117 | 118 |
119 | 150 |
151 | `; 152 | -------------------------------------------------------------------------------- /packages/styled/src/components/Close/index.ts: -------------------------------------------------------------------------------- 1 | import Close from './Close' 2 | 3 | export default Close 4 | -------------------------------------------------------------------------------- /packages/styled/src/components/DateRangeInput/index.ts: -------------------------------------------------------------------------------- 1 | import DateRangeInput from './DateRangeInput' 2 | 3 | export default DateRangeInput 4 | -------------------------------------------------------------------------------- /packages/styled/src/components/DateSingleInput/DateSingleInput.test.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | import {advanceTo, clear} from 'jest-date-mock' 3 | import {render, fireEvent} from '../../testUtil' 4 | import Datepicker from '.' 5 | 6 | beforeEach(() => { 7 | advanceTo(new Date(2019, 2, 27, 0, 0, 0)) 8 | }) 9 | 10 | afterEach(() => { 11 | clear() 12 | }) 13 | 14 | test('should have empty empty date and opened datepicker', () => { 15 | const onDatesChange = jest.fn() 16 | const onFocusChange = jest.fn() 17 | const {container, getByText, getAllByTestId, getByTestId} = render( 18 | , 24 | ) 25 | expect(container).toMatchSnapshot() 26 | expect(getByText('March 2019')) 27 | 28 | // Click on close (fire default function 29 | fireEvent.click(getByTestId('DatepickerClose')) 30 | 31 | // Test if first day is monday 32 | // @ts-ignore 33 | expect(getAllByTestId('DayLabel')[0]).toHaveTextContent('Mo') 34 | 35 | // Click on March 16 36 | const selectedDay = getAllByTestId('Day')[15] 37 | // @ts-ignore 38 | expect(selectedDay).toHaveTextContent('16') 39 | fireEvent.click(selectedDay) 40 | expect(onDatesChange).toHaveBeenCalledWith({ 41 | date: new Date(2019, 2, 16, 0, 0, 0), 42 | showDatepicker: false, 43 | }) 44 | }) 45 | 46 | test('should render custom day', () => { 47 | const onDatesChange = jest.fn() 48 | const onFocusChange = jest.fn() 49 | const {container, getByText, getAllByTestId, getByTestId} = render( 50 |
{date.toDateString()}
} 56 | />, 57 | ) 58 | expect(container).toMatchSnapshot() 59 | expect(getByText('March 2019')) 60 | 61 | // Click on close (fire default function 62 | fireEvent.click(getByTestId('DatepickerClose')) 63 | 64 | // Test if first day is monday 65 | // @ts-ignore 66 | expect(getAllByTestId('DayLabel')[0]).toHaveTextContent('Mo') 67 | 68 | // Click on March 16 69 | const selectedDay = getAllByTestId('Day')[15] 70 | // @ts-ignore 71 | expect(selectedDay).toHaveTextContent('16') 72 | fireEvent.click(selectedDay) 73 | expect(onDatesChange).toHaveBeenCalledWith({ 74 | date: new Date(2019, 2, 16, 0, 0, 0), 75 | showDatepicker: false, 76 | }) 77 | }) 78 | 79 | test('placement top', () => { 80 | const onDatesChange = jest.fn() 81 | const onFocusChange = jest.fn() 82 | const {container} = render( 83 | , 90 | ) 91 | expect(container).toMatchSnapshot() 92 | }) 93 | 94 | test('should render vertical variant', () => { 95 | const onDatesChange = jest.fn() 96 | const onFocusChange = jest.fn() 97 | const {container} = render( 98 | , 106 | ) 107 | expect(container).toMatchSnapshot() 108 | }) 109 | 110 | test('should render vertical, rtl, variant', () => { 111 | const onDatesChange = jest.fn() 112 | const onFocusChange = jest.fn() 113 | const {container} = render( 114 | , 123 | ) 124 | expect(container).toMatchSnapshot() 125 | }) 126 | 127 | test('should render rtl, variant', () => { 128 | const onDatesChange = jest.fn() 129 | const onFocusChange = jest.fn() 130 | const {container} = render( 131 | , 139 | ) 140 | expect(container).toMatchSnapshot() 141 | }) 142 | 143 | test('should render without calendar icon, reset dates and close component', () => { 144 | const onDatesChange = jest.fn() 145 | const onFocusChange = jest.fn() 146 | const {container} = render( 147 | , 158 | ) 159 | expect(container).toMatchSnapshot() 160 | }) 161 | 162 | test('should execute onClose callback', () => { 163 | const onDatesChange = jest.fn() 164 | const onClose = jest.fn() 165 | const onFocusChange = jest.fn() 166 | const isDateBlocked = jest.fn() 167 | const {getByTestId, getAllByTestId} = render( 168 | , 190 | ) 191 | 192 | fireEvent.click(getByTestId('DatepickerClose')) 193 | expect(onClose).toHaveBeenCalled() 194 | 195 | fireEvent.focus(getAllByTestId('DatepickerInput')[0]) 196 | expect(onFocusChange).toHaveBeenCalledWith(true) 197 | fireEvent.click(getByTestId('DatepickerClose')) 198 | }) 199 | 200 | // @ts-ignore 201 | const App = ({onDateChange, onFocusChange}) => ( 202 | <> 203 | 209 |
210 | 211 | ) 212 | 213 | test('should handle click outside (close datepicker)', () => { 214 | const onDatesChange = jest.fn() 215 | const onFocusChange = jest.fn() 216 | const {getByTestId} = render() 217 | fireEvent.click(getByTestId('outside')) 218 | expect(onFocusChange).toHaveBeenCalledWith(false) 219 | }) 220 | 221 | test('should handle custom id for input field', () => { 222 | const onDatesChange = jest.fn() 223 | const onFocusChange = jest.fn() 224 | const {container, getByTestId} = render( 225 | , 232 | ) 233 | expect(container).toMatchSnapshot() 234 | expect(getByTestId('DatepickerInput').id).toEqual('customId') 235 | }) 236 | -------------------------------------------------------------------------------- /packages/styled/src/components/DateSingleInput/DateSingleInput.tsx: -------------------------------------------------------------------------------- 1 | import React, {useRef, useEffect} from 'react' 2 | import {zIndex, ZIndexProps} from 'styled-system' 3 | import styled, {css, ThemeProvider} from 'styled-components' 4 | import { 5 | START_DATE, 6 | FormatFunction, 7 | getInputValue, 8 | OnDatesChangeProps, 9 | FirstDayOfWeek, 10 | } from '@datepicker-react/hooks' 11 | import {dateSingleInputPhrases, DateSingleInputPhrases} from '../../phrases' 12 | import Box from '../Box' 13 | import Input from '../Input' 14 | import Datepicker from '../Datepicker' 15 | // eslint-disable-next-line import/no-unresolved 16 | import {DateSingleInputTheme} from '../../@types/theme' 17 | import useThemeProps from '../../hooks/useThemeProps' 18 | 19 | interface RtlProps { 20 | rtl: boolean 21 | } 22 | interface WrapperProps extends RtlProps, ZIndexProps {} 23 | const Wrapper = styled(Box)` 24 | ${zIndex} 25 | ${({rtl}) => 26 | rtl && 27 | css` 28 | direction: rtl; 29 | `} 30 | ` 31 | 32 | function getPlacement(placement: 'bottom' | 'top', rtl: boolean) { 33 | if (placement === 'top' && !rtl) { 34 | return { 35 | dateSingleDatepickerWrapperTop: 'unset', 36 | dateSingleDatepickerWrapperRight: 'unset', 37 | dateSingleDatepickerWrapperBottom: '65px', 38 | dateSingleDatepickerWrapperLeft: '0', 39 | } 40 | } else if (placement === 'top' && rtl) { 41 | return { 42 | dateSingleDatepickerWrapperTop: 'unset', 43 | dateSingleDatepickerWrapperRight: '0', 44 | dateSingleDatepickerWrapperBottom: '65px', 45 | dateSingleDatepickerWrapperLeft: 'unset', 46 | } 47 | } else if (placement === 'bottom' && rtl) { 48 | return { 49 | dateSingleDatepickerWrapperTop: 'unset', 50 | dateSingleDatepickerWrapperRight: '0', 51 | dateSingleDatepickerWrapperBottom: 'unset', 52 | dateSingleDatepickerWrapperLeft: 'unset', 53 | } 54 | } 55 | 56 | return { 57 | dateSingleDatepickerWrapperTop: 'unset', 58 | dateSingleDatepickerWrapperRight: 'unset', 59 | dateSingleDatepickerWrapperBottom: 'unset', 60 | dateSingleDatepickerWrapperLeft: '0', 61 | } 62 | } 63 | 64 | export interface OnDateChangeProps { 65 | date: Date | null 66 | showDatepicker: boolean 67 | } 68 | 69 | export interface DateSingleInputProps { 70 | date: Date | null 71 | minBookingDate?: Date 72 | maxBookingDate?: Date 73 | showDatepicker: boolean 74 | numberOfMonths?: number 75 | firstDayOfWeek?: FirstDayOfWeek 76 | displayFormat?: string | FormatFunction 77 | phrases?: DateSingleInputPhrases 78 | showCalendarIcon?: boolean 79 | vertical?: boolean 80 | showResetDate?: boolean 81 | showClose?: boolean 82 | rtl?: boolean 83 | placement?: 'top' | 'bottom' 84 | initialVisibleMonth?: Date 85 | onDateChange(data: OnDateChangeProps): void 86 | onFocusChange(focusInput: boolean): void 87 | isDateBlocked?(date: Date): boolean 88 | onClose?(): void 89 | dayLabelFormat?(date: Date): string 90 | weekdayLabelFormat?(date: Date): string 91 | monthLabelFormat?(date: Date): string 92 | onDayRender?(date: Date): React.ReactNode 93 | inputId?: string 94 | unavailableDates?: Date[] 95 | } 96 | 97 | function DateSingleInput({ 98 | date, 99 | minBookingDate, 100 | maxBookingDate, 101 | firstDayOfWeek, 102 | onFocusChange, 103 | showDatepicker, 104 | onDateChange, 105 | dayLabelFormat, 106 | weekdayLabelFormat, 107 | monthLabelFormat, 108 | onDayRender, 109 | initialVisibleMonth, 110 | numberOfMonths = 1, 111 | showClose = true, 112 | showResetDate = true, 113 | vertical = false, 114 | rtl = false, 115 | isDateBlocked = () => false, 116 | onClose = () => {}, 117 | showCalendarIcon = true, 118 | displayFormat = 'MM/dd/yyyy', 119 | phrases = dateSingleInputPhrases, 120 | placement = 'bottom', 121 | inputId = 'startDate', 122 | unavailableDates = [], 123 | }: DateSingleInputProps) { 124 | const ref = useRef(null) 125 | const datepickerWrapperRef = useRef(null) 126 | const theme: DateSingleInputTheme = useThemeProps({ 127 | dateSingleZIndex: null, 128 | dateSingleInputPadding: vertical ? (rtl ? '0 32px 0 8px' : '0 8px 0 32px') : '0 44px', 129 | dateSingleDatepickerWrapperPosition: 'absolute', 130 | ...getPlacement(placement, rtl), 131 | }) 132 | 133 | useEffect(() => { 134 | if (typeof window !== 'undefined') { 135 | window.addEventListener('click', onClickOutsideHandler) 136 | } 137 | 138 | return () => { 139 | window.removeEventListener('click', onClickOutsideHandler) 140 | } 141 | }) 142 | 143 | function onClickOutsideHandler(event: Event) { 144 | if ( 145 | showDatepicker && 146 | datepickerWrapperRef && 147 | datepickerWrapperRef.current && 148 | // @ts-ignore 149 | !datepickerWrapperRef.current.contains(event.target) 150 | ) { 151 | onFocusChange(false) 152 | } 153 | } 154 | 155 | function handleDatepickerClose() { 156 | onClose() 157 | onFocusChange(false) 158 | } 159 | 160 | function onDatesChange({focusedInput, startDate}: OnDatesChangeProps) { 161 | onDateChange({ 162 | showDatepicker: focusedInput !== null, 163 | date: startDate, 164 | }) 165 | } 166 | 167 | function handleInputChange(date: Date) { 168 | // @ts-ignore 169 | if (ref && ref.current && ref.current.onDateSelect) { 170 | // @ts-ignore 171 | ref.current.onDateSelect(date) 172 | } 173 | } 174 | 175 | return ( 176 | ) => theme || {}}> 177 | 183 | onFocusChange(true)} 189 | showCalendarIcon={showCalendarIcon} 190 | vertical={vertical} 191 | isActive={false} 192 | padding={theme.dateSingleInputPadding} 193 | rtl={rtl} 194 | onChange={handleInputChange} 195 | // @ts-ignore 196 | dateFormat={displayFormat} 197 | /> 198 | 205 | {showDatepicker && ( 206 | 234 | )} 235 | 236 | 237 | 238 | ) 239 | } 240 | 241 | export default DateSingleInput 242 | -------------------------------------------------------------------------------- /packages/styled/src/components/DateSingleInput/index.ts: -------------------------------------------------------------------------------- 1 | import DateSingleInput, {OnDateChangeProps} from './DateSingleInput' 2 | 3 | export {OnDateChangeProps} 4 | 5 | export default DateSingleInput 6 | -------------------------------------------------------------------------------- /packages/styled/src/components/Datepicker/Datepicker.test.tsx: -------------------------------------------------------------------------------- 1 | import {advanceTo, clear} from 'jest-date-mock' 2 | import * as React from 'react' 3 | import {render, fireEvent, act} from '@testing-library/react' 4 | import {END_DATE, START_DATE} from '@datepicker-react/hooks' 5 | import Datepicker from '.' 6 | 7 | beforeEach(() => { 8 | advanceTo(new Date(2019, 2, 27, 0, 0, 0)) 9 | }) 10 | 11 | afterEach(() => { 12 | clear() 13 | }) 14 | 15 | test('should have empty start and end date and focused start date', () => { 16 | const onDatesChange = jest.fn() 17 | const {container, getAllByText, getByText, getAllByTestId, getByTestId} = render( 18 | , 24 | ) 25 | expect(container).toMatchSnapshot() 26 | expect(getAllByText('Select').length).toBe(2) 27 | expect(getByText('March 2019')) 28 | expect(getByText('April 2019')) 29 | 30 | // Click on close (fire default function 31 | fireEvent.click(getByTestId('DatepickerClose')) 32 | 33 | // Test if first day is monday 34 | // @ts-ignore 35 | expect(getAllByTestId('DayLabel')[0]).toHaveTextContent('Mo') 36 | 37 | // Click on March 16 38 | const selectedDay = getAllByTestId('Day')[15] 39 | // @ts-ignore 40 | expect(selectedDay).toHaveTextContent('16') 41 | fireEvent.click(selectedDay) 42 | expect(onDatesChange).toHaveBeenCalledWith({ 43 | startDate: new Date(2019, 2, 16, 0, 0, 0), 44 | endDate: null, 45 | focusedInput: END_DATE, 46 | }) 47 | }) 48 | 49 | test('should custom render day', () => { 50 | const onDatesChange = jest.fn() 51 | const {container, getAllByText, getByText, getAllByTestId, getByTestId} = render( 52 |
{date.toDateString()}
} 58 | />, 59 | ) 60 | expect(container).toMatchSnapshot() 61 | expect(getAllByText('Select').length).toBe(2) 62 | expect(getByText('March 2019')) 63 | expect(getByText('April 2019')) 64 | 65 | // Click on close (fire default function 66 | fireEvent.click(getByTestId('DatepickerClose')) 67 | 68 | // Test if first day is monday 69 | // @ts-ignore 70 | expect(getAllByTestId('DayLabel')[0]).toHaveTextContent('Mo') 71 | 72 | // Click on March 16 73 | const selectedDay = getAllByTestId('Day')[15] 74 | // @ts-ignore 75 | expect(selectedDay).toHaveTextContent('16') 76 | fireEvent.click(selectedDay) 77 | expect(onDatesChange).toHaveBeenCalledWith({ 78 | startDate: new Date(2019, 2, 16, 0, 0, 0), 79 | endDate: null, 80 | focusedInput: END_DATE, 81 | }) 82 | }) 83 | 84 | test('should select exact range', () => { 85 | const onDatesChange = jest.fn() 86 | const {container, getAllByText, getByText, getAllByTestId, getByTestId} = render( 87 | , 95 | ) 96 | expect(container).toMatchSnapshot() 97 | expect(getAllByText('Select').length).toBe(2) 98 | expect(getByText('March 2019')) 99 | expect(getByText('April 2019')) 100 | 101 | // Click on close (fire default function 102 | fireEvent.click(getByTestId('DatepickerClose')) 103 | 104 | // Test if first day is monday 105 | // @ts-ignore 106 | expect(getAllByTestId('DayLabel')[0]).toHaveTextContent('Mo') 107 | 108 | // Click on March 16 109 | const selectedDay = getAllByTestId('Day')[15] 110 | // @ts-ignore 111 | expect(selectedDay).toHaveTextContent('16') 112 | fireEvent.click(selectedDay) 113 | expect(onDatesChange).toHaveBeenCalledWith({ 114 | startDate: new Date(2019, 2, 16, 0, 0, 0), 115 | endDate: new Date(2019, 2, 22, 0, 0, 0), 116 | focusedInput: null, 117 | }) 118 | }) 119 | 120 | test('should hover exact range and move the mouse out of the MonthGrid', () => { 121 | const {container, getAllByText, getAllByTestId, getByTestId} = render( 122 | , 130 | ) 131 | expect(container).toMatchSnapshot() 132 | expect(getAllByText('Select').length).toBe(2) 133 | 134 | // Hover the March 16 135 | const hoveredDay = getAllByTestId('Day')[15] 136 | // @ts-ignore 137 | expect(hoveredDay).toHaveTextContent('16') 138 | fireEvent.mouseEnter(hoveredDay) 139 | expect(container).toMatchSnapshot() 140 | fireEvent.mouseLeave(getByTestId('MonthGrid')) 141 | expect(container).toMatchSnapshot() 142 | }) 143 | 144 | test('should render vertical datepicker', () => { 145 | const onDatesChange = jest.fn() 146 | const {container} = render( 147 | , 154 | ) 155 | expect(container).toMatchSnapshot() 156 | }) 157 | 158 | test('should go to next and previous month - vertical variant', () => { 159 | const onDatesChange = jest.fn() 160 | const {container, getAllByTestId} = render( 161 | , 168 | ) 169 | expect(container).toMatchSnapshot() 170 | 171 | // Go to next month 172 | act(() => { 173 | fireEvent.click(getAllByTestId('DatepickerNavButton')[1]) 174 | }) 175 | expect(container).toMatchSnapshot() 176 | 177 | // Go to prev month 178 | act(() => { 179 | fireEvent.click(getAllByTestId('DatepickerNavButton')[0]) 180 | }) 181 | expect(container).toMatchSnapshot() 182 | }) 183 | 184 | test('should have empty end date and focused end date', () => { 185 | const onDatesChange = jest.fn() 186 | const {container, getAllByText, getByText, getAllByTestId} = render( 187 | , 196 | ) 197 | expect(container).toMatchSnapshot() 198 | expect(getByText('03/16/2019')) 199 | expect(getAllByText('Select').length).toBe(1) 200 | expect(getByText('March 2019')) 201 | expect(getByText('April 2019')) 202 | 203 | // Test if first day is sunday 204 | // @ts-ignore 205 | expect(getAllByTestId('DayLabel')[0]).toHaveTextContent('Su') 206 | 207 | // Click on March 19 208 | const selectedDay = getAllByTestId('Day')[18] 209 | // @ts-ignore 210 | expect(selectedDay).toHaveTextContent('19') 211 | fireEvent.click(selectedDay) 212 | expect(onDatesChange).toHaveBeenCalledWith({ 213 | startDate: new Date(2019, 2, 16, 0, 0, 0), 214 | endDate: new Date(2019, 2, 19, 0, 0, 0), 215 | focusedInput: null, 216 | }) 217 | }) 218 | 219 | test('should execute onClose callback', () => { 220 | const onDatesChange = jest.fn() 221 | const onClose = jest.fn() 222 | const {getByTestId, getByText, getAllByText} = render( 223 | , 242 | ) 243 | 244 | // Get formatted date 245 | getByText('16.03.2019') 246 | 247 | expect(getAllByText('test').length).toBe(5) 248 | 249 | fireEvent.click(getByTestId('DatepickerClose')) 250 | expect(onClose).toHaveBeenCalled() 251 | }) 252 | -------------------------------------------------------------------------------- /packages/styled/src/components/Datepicker/index.ts: -------------------------------------------------------------------------------- 1 | import Datepicker from './Datepicker' 2 | 3 | export default Datepicker 4 | -------------------------------------------------------------------------------- /packages/styled/src/components/Day/Day.test.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | import {render, fireEvent} from '../../testUtil' 3 | import Day from '.' 4 | 5 | test('should render disabled day', () => { 6 | const {container} = render( 7 | , 8 | {}, 9 | {isDateBlocked: () => true}, 10 | ) 11 | expect(container).toMatchSnapshot() 12 | }) 13 | 14 | test('should render normal day', () => { 15 | const onDateSelect = jest.fn() 16 | const {container} = render( 17 | , 18 | {}, 19 | {onDateSelect}, 20 | ) 21 | expect(container).toMatchSnapshot() 22 | // @ts-ignore 23 | fireEvent.click(container.firstChild) 24 | expect(onDateSelect).toBeCalled() 25 | }) 26 | 27 | test('should render active day', () => { 28 | const {container} = render( 29 | , 30 | {}, 31 | {isDateSelected: () => true}, 32 | ) 33 | expect(container).toMatchSnapshot() 34 | }) 35 | 36 | test('should render first or last active day', () => { 37 | const {container} = render( 38 | , 39 | {}, 40 | {isFirstOrLastSelectedDate: () => true}, 41 | ) 42 | expect(container).toMatchSnapshot() 43 | }) 44 | 45 | test('should execute onDateHover callback', () => { 46 | const onDateHover = jest.fn() 47 | const {container} = render( 48 | , 49 | {}, 50 | {onDateHover, isDateHovered: () => true}, 51 | ) 52 | // @ts-ignore 53 | fireEvent.mouseEnter(container.firstChild) 54 | expect(onDateHover).toBeCalled() 55 | }) 56 | -------------------------------------------------------------------------------- /packages/styled/src/components/Day/__snapshots__/Day.test.tsx.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`should render active day 1`] = ` 4 | .c1 { 5 | display: -webkit-box; 6 | display: -webkit-flex; 7 | display: -ms-flexbox; 8 | display: flex; 9 | -webkit-box-pack: center; 10 | -webkit-justify-content: center; 11 | -ms-flex-pack: center; 12 | justify-content: center; 13 | -webkit-align-items: center; 14 | -webkit-box-align: center; 15 | -ms-flex-align: center; 16 | align-items: center; 17 | height: 100%; 18 | width: 100%; 19 | } 20 | 21 | .c0 { 22 | height: 36px; 23 | width: 36px; 24 | background: #71c9ed; 25 | color: #ffffff; 26 | font-family: Montserrat,sans-serif; 27 | font-weight: 500; 28 | font-size: 14px; 29 | box-shadow: 1px 0 0 0 #71c9ed, 0 1px 0 0 #71c9ed, 1px 1px 0 0 #71c9ed, 1px 0 0 0 #71c9ed inset, 0 1px 0 0 #71c9ed inset; 30 | cursor: pointer; 31 | border: 0; 32 | padding: 0; 33 | outline: 0; 34 | } 35 | 36 | .c0:hover { 37 | background: #39beef; 38 | color: #ffffff; 39 | } 40 | 41 | .c0:focus { 42 | box-shadow: none; 43 | border: 2px solid #009fef; 44 | } 45 | 46 |
47 | 66 |
67 | `; 68 | 69 | exports[`should render disabled day 1`] = ` 70 | .c1 { 71 | display: -webkit-box; 72 | display: -webkit-flex; 73 | display: -ms-flexbox; 74 | display: flex; 75 | -webkit-box-pack: center; 76 | -webkit-justify-content: center; 77 | -ms-flex-pack: center; 78 | justify-content: center; 79 | -webkit-align-items: center; 80 | -webkit-box-align: center; 81 | -ms-flex-align: center; 82 | align-items: center; 83 | height: 100%; 84 | width: 100%; 85 | } 86 | 87 | .c0 { 88 | height: 36px; 89 | width: 36px; 90 | background: #ffffff; 91 | color: #58595B; 92 | font-family: Montserrat,sans-serif; 93 | font-weight: 500; 94 | font-size: 14px; 95 | box-shadow: 1px 0 0 0 #e6e7e8, 0 1px 0 0 #e6e7e8, 1px 1px 0 0 #e6e7e8, 1px 0 0 0 #e6e7e8 inset, 0 1px 0 0 #e6e7e8 inset; 96 | cursor: pointer; 97 | border: 0; 98 | padding: 0; 99 | outline: 0; 100 | cursor: initial; 101 | opacity: 0.4; 102 | } 103 | 104 | .c0:focus { 105 | box-shadow: none; 106 | border: 2px solid #009fef; 107 | } 108 | 109 |
110 | 129 |
130 | `; 131 | 132 | exports[`should render first or last active day 1`] = ` 133 | .c1 { 134 | display: -webkit-box; 135 | display: -webkit-flex; 136 | display: -ms-flexbox; 137 | display: flex; 138 | -webkit-box-pack: center; 139 | -webkit-justify-content: center; 140 | -ms-flex-pack: center; 141 | justify-content: center; 142 | -webkit-align-items: center; 143 | -webkit-box-align: center; 144 | -ms-flex-align: center; 145 | align-items: center; 146 | height: 100%; 147 | width: 100%; 148 | } 149 | 150 | .c0 { 151 | height: 36px; 152 | width: 36px; 153 | background: #00aeef; 154 | color: #ffffff; 155 | font-family: Montserrat,sans-serif; 156 | font-weight: 500; 157 | font-size: 14px; 158 | box-shadow: 1px 0 0 0 #00aeef, 0 1px 0 0 #00aeef, 1px 1px 0 0 #00aeef, 1px 0 0 0 #00aeef inset, 0 1px 0 0 #00aeef inset; 159 | cursor: pointer; 160 | border: 0; 161 | padding: 0; 162 | outline: 0; 163 | } 164 | 165 | .c0:focus { 166 | box-shadow: none; 167 | border: 2px solid #009fef; 168 | } 169 | 170 |
171 | 190 |
191 | `; 192 | 193 | exports[`should render normal day 1`] = ` 194 | .c1 { 195 | display: -webkit-box; 196 | display: -webkit-flex; 197 | display: -ms-flexbox; 198 | display: flex; 199 | -webkit-box-pack: center; 200 | -webkit-justify-content: center; 201 | -ms-flex-pack: center; 202 | justify-content: center; 203 | -webkit-align-items: center; 204 | -webkit-box-align: center; 205 | -ms-flex-align: center; 206 | align-items: center; 207 | height: 100%; 208 | width: 100%; 209 | } 210 | 211 | .c0 { 212 | height: 36px; 213 | width: 36px; 214 | background: #ffffff; 215 | color: #58595B; 216 | font-family: Montserrat,sans-serif; 217 | font-weight: 500; 218 | font-size: 14px; 219 | box-shadow: 1px 0 0 0 #e6e7e8, 0 1px 0 0 #e6e7e8, 1px 1px 0 0 #e6e7e8, 1px 0 0 0 #e6e7e8 inset, 0 1px 0 0 #e6e7e8 inset; 220 | cursor: pointer; 221 | border: 0; 222 | padding: 0; 223 | outline: 0; 224 | } 225 | 226 | .c0:hover { 227 | background: #e6e7e8; 228 | color: #58595B; 229 | } 230 | 231 | .c0:focus { 232 | box-shadow: none; 233 | border: 2px solid #009fef; 234 | } 235 | 236 |
237 | 256 |
257 | `; 258 | -------------------------------------------------------------------------------- /packages/styled/src/components/Day/index.ts: -------------------------------------------------------------------------------- 1 | import Day from './Day' 2 | 3 | export default Day 4 | -------------------------------------------------------------------------------- /packages/styled/src/components/DayLabel/DayLabel.test.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | import {render} from '../../testUtil' 3 | import DayLabel from '.' 4 | 5 | test('should match snapshot', () => { 6 | const {container} = render() 7 | expect(container).toMatchSnapshot() 8 | }) 9 | -------------------------------------------------------------------------------- /packages/styled/src/components/DayLabel/DayLabel.tsx: -------------------------------------------------------------------------------- 1 | import React, {useContext} from 'react' 2 | import {ThemeContext} from 'styled-components' 3 | import Text from '../Text' 4 | // eslint-disable-next-line import/no-unresolved 5 | import {DayLabelTheme} from '../../@types/theme' 6 | import useThemeProps from '../../hooks/useThemeProps' 7 | import globalStyles from '../../globalStyles' 8 | import getThemeProp from '../../utils/getThemeProp' 9 | 10 | interface MonthLabelProps { 11 | label: string 12 | } 13 | 14 | const MonthLabel = ({label}: MonthLabelProps) => { 15 | const themeContext = useContext(ThemeContext) 16 | 17 | const theme: DayLabelTheme = useThemeProps({ 18 | fontFamily: globalStyles.fontFamily, 19 | dayLabelColor: getThemeProp('silverCloud', globalStyles.colors.silverCloud, themeContext), 20 | dayLabelFontWeight: 500, 21 | dayLabelFontSize: '11px', 22 | }) 23 | return ( 24 | 32 | {label} 33 | 34 | ) 35 | } 36 | 37 | export default MonthLabel 38 | -------------------------------------------------------------------------------- /packages/styled/src/components/DayLabel/__snapshots__/DayLabel.test.tsx.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`should match snapshot 1`] = ` 4 | .c0 { 5 | font-family: Montserrat,sans-serif; 6 | font-size: 11px; 7 | font-weight: 500; 8 | color: #929598; 9 | } 10 | 11 |
12 |
20 | Test 21 |
22 |
23 | `; 24 | -------------------------------------------------------------------------------- /packages/styled/src/components/DayLabel/index.ts: -------------------------------------------------------------------------------- 1 | import DayLabel from './DayLabel' 2 | 3 | export default DayLabel 4 | -------------------------------------------------------------------------------- /packages/styled/src/components/Flex/Flex.test.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import {render} from '../../testUtil' 3 | import Flex from '.' 4 | 5 | test('should match snapshot', () => { 6 | const {container} = render( 7 | 17 |
test1
18 |
test2
19 |
test3
20 |
test4
21 |
test5
22 |
, 23 | ) 24 | expect(container).toMatchSnapshot() 25 | }) 26 | -------------------------------------------------------------------------------- /packages/styled/src/components/Flex/Flex.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | alignItems, 3 | AlignItemsProps, 4 | flex, 5 | FlexProps, 6 | flexDirection, 7 | FlexDirectionProps, 8 | flexWrap, 9 | FlexWrapProps, 10 | justifyContent, 11 | JustifyContentProps, 12 | space, 13 | SpaceProps, 14 | gridArea, 15 | GridAreaProps, 16 | height, 17 | HeightProps, 18 | width, 19 | WidthProps, 20 | compose, 21 | } from 'styled-system' 22 | import styled from 'styled-components' 23 | 24 | interface FlexComponentProps 25 | extends SpaceProps, 26 | FlexWrapProps, 27 | FlexDirectionProps, 28 | AlignItemsProps, 29 | GridAreaProps, 30 | HeightProps, 31 | WidthProps, 32 | FlexProps, 33 | JustifyContentProps {} 34 | 35 | const composeFlexStyles = compose( 36 | space, 37 | flex, 38 | flexWrap, 39 | flexDirection, 40 | alignItems, 41 | justifyContent, 42 | gridArea, 43 | height, 44 | width, 45 | ) 46 | 47 | const Flex = styled('div')` 48 | display: flex; 49 | ${composeFlexStyles} 50 | ` 51 | 52 | export default Flex 53 | -------------------------------------------------------------------------------- /packages/styled/src/components/Flex/__snapshots__/Flex.test.tsx.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`should match snapshot 1`] = ` 4 | .c0 { 5 | display: -webkit-box; 6 | display: -webkit-flex; 7 | display: -ms-flexbox; 8 | display: flex; 9 | height: 50px; 10 | width: 50px; 11 | grid-area: test; 12 | -webkit-box-pack: center; 13 | -webkit-justify-content: center; 14 | -ms-flex-pack: center; 15 | justify-content: center; 16 | -webkit-align-items: center; 17 | -webkit-box-align: center; 18 | -ms-flex-align: center; 19 | align-items: center; 20 | -webkit-flex-direction: column; 21 | -ms-flex-direction: column; 22 | flex-direction: column; 23 | -webkit-flex-wrap: wrap; 24 | -ms-flex-wrap: wrap; 25 | flex-wrap: wrap; 26 | margin: 30px; 27 | } 28 | 29 |
30 |
35 |
36 | test1 37 |
38 |
39 | test2 40 |
41 |
42 | test3 43 |
44 |
45 | test4 46 |
47 |
48 | test5 49 |
50 |
51 |
52 | `; 53 | -------------------------------------------------------------------------------- /packages/styled/src/components/Flex/index.ts: -------------------------------------------------------------------------------- 1 | import Flex from './Flex' 2 | 3 | export default Flex 4 | -------------------------------------------------------------------------------- /packages/styled/src/components/Grid/Grid.test.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import {render} from '../../testUtil' 3 | import Grid from '.' 4 | 5 | test('should match snapshot', () => { 6 | const {container} = render( 7 | 17 |
test1
18 |
test2
19 |
test3
20 |
test4
21 |
test5
22 |
, 23 | ) 24 | expect(container).toMatchSnapshot() 25 | }) 26 | -------------------------------------------------------------------------------- /packages/styled/src/components/Grid/Grid.tsx: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components' 2 | import { 3 | gridAutoColumns, 4 | GridAutoColumnsProps, 5 | gridAutoFlow, 6 | GridAutoFlowProps, 7 | gridAutoRows, 8 | GridAutoRowsProps, 9 | alignItems, 10 | AlignItemsProps, 11 | justifyContent, 12 | JustifyContentProps, 13 | gridColumnGap, 14 | GridColumnGapProps, 15 | gridGap, 16 | GridGapProps, 17 | gridRowGap, 18 | GridRowGapProps, 19 | gridTemplateAreas, 20 | GridTemplateAreasProps, 21 | gridTemplateColumns, 22 | GridTemplateColumnsProps, 23 | gridTemplateRows, 24 | GridTemplateRowsProps, 25 | space, 26 | SpaceProps, 27 | style, 28 | compose, 29 | } from 'styled-system' 30 | 31 | interface GridProps 32 | extends GridAutoColumnsProps, 33 | GridAutoFlowProps, 34 | GridAutoRowsProps, 35 | AlignItemsProps, 36 | JustifyContentProps, 37 | GridColumnGapProps, 38 | GridGapProps, 39 | GridRowGapProps, 40 | GridTemplateAreasProps, 41 | GridTemplateColumnsProps, 42 | SpaceProps, 43 | GridTemplateRowsProps { 44 | daySizeGridTemplateColumns?: number | (number | null)[] | undefined 45 | numberOfMonthsGridTemplateColumns?: number | (number | null)[] | undefined 46 | } 47 | 48 | const daySizeGridTemplateColumns = style({ 49 | // React prop name and CSS property 50 | prop: 'daySizeGridTemplateColumns', 51 | // CSS property (if different from prop argument) 52 | cssProperty: 'gridTemplateColumns', 53 | // key for theme values 54 | key: 'gridTemplateColumns', 55 | // accessor function for transforming the value 56 | transformValue: n => `repeat(7, ${n}px)`, 57 | // add a fallback scale object or array, if theme is not present 58 | scale: [0, 4, 8, 16, 32], 59 | }) 60 | 61 | const composeGridStyles = compose( 62 | gridAutoColumns, 63 | gridAutoFlow, 64 | gridAutoRows, 65 | gridColumnGap, 66 | gridGap, 67 | gridRowGap, 68 | gridTemplateAreas, 69 | gridTemplateColumns, 70 | gridTemplateRows, 71 | alignItems, 72 | justifyContent, 73 | space, 74 | ) 75 | 76 | const Grid = styled('div')` 77 | display: grid; 78 | ${composeGridStyles} 79 | ${daySizeGridTemplateColumns} 80 | ` 81 | 82 | export default Grid 83 | -------------------------------------------------------------------------------- /packages/styled/src/components/Grid/__snapshots__/Grid.test.tsx.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`should match snapshot 1`] = ` 4 | .c0 { 5 | display: grid; 6 | grid-template-columns: repeat(6,1fr); 7 | grid-template-rows: repeat(6,1fr); 8 | grid-template-areas: "c1 c2 c3" "c4 c5 c6"; 9 | grid-gap: 10px 10px; 10 | grid-column-gap: 10px; 11 | grid-row-gap: 10px; 12 | -webkit-box-pack: initial; 13 | -webkit-justify-content: initial; 14 | -ms-flex-pack: initial; 15 | justify-content: initial; 16 | -webkit-align-items: initial; 17 | -webkit-box-align: initial; 18 | -ms-flex-align: initial; 19 | align-items: initial; 20 | } 21 | 22 |
23 |
26 |
27 | test1 28 |
29 |
30 | test2 31 |
32 |
33 | test3 34 |
35 |
36 | test4 37 |
38 |
39 | test5 40 |
41 |
42 |
43 | `; 44 | -------------------------------------------------------------------------------- /packages/styled/src/components/Grid/index.ts: -------------------------------------------------------------------------------- 1 | import Grid from './Grid' 2 | 3 | export default Grid 4 | -------------------------------------------------------------------------------- /packages/styled/src/components/Input/Input.test.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | import {render, fireEvent} from '../../testUtil' 3 | import Input from '.' 4 | 5 | test('should render with icon', () => { 6 | const onClick = jest.fn() 7 | const {container, getByPlaceholderText} = render( 8 | , 20 | ) 21 | 22 | expect(container).toMatchSnapshot() 23 | getByPlaceholderText('Placeholder') 24 | // @ts-ignore 25 | fireEvent.focus(getByPlaceholderText('Placeholder')) 26 | expect(onClick).toHaveBeenCalled() 27 | }) 28 | 29 | test('should render rtl variant', () => { 30 | const onClick = jest.fn() 31 | const {container, getByPlaceholderText} = render( 32 | , 44 | ) 45 | 46 | expect(container).toMatchSnapshot() 47 | getByPlaceholderText('Placeholder') 48 | // @ts-ignore 49 | fireEvent.focus(getByPlaceholderText('Placeholder')) 50 | expect(onClick).toHaveBeenCalled() 51 | }) 52 | 53 | test('should render without icon', () => { 54 | const onClick = jest.fn() 55 | const {container} = render( 56 | , 68 | ) 69 | 70 | expect(container).toMatchSnapshot() 71 | }) 72 | 73 | test('should render with value', () => { 74 | const onClick = jest.fn() 75 | const {container, getByDisplayValue} = render( 76 | , 88 | ) 89 | 90 | expect(container).toMatchSnapshot() 91 | getByDisplayValue('14/11/1992') 92 | }) 93 | 94 | test('should render vertical variant', () => { 95 | const onClick = jest.fn() 96 | const {container} = render( 97 | , 109 | ) 110 | 111 | expect(container).toMatchSnapshot() 112 | }) 113 | -------------------------------------------------------------------------------- /packages/styled/src/components/Input/index.tsx: -------------------------------------------------------------------------------- 1 | import Input from './Input' 2 | 3 | export default Input 4 | -------------------------------------------------------------------------------- /packages/styled/src/components/Month/Month.test.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | import {dayLabelFormat, weekdayLabelFormat, monthLabelFormat} from '@datepicker-react/hooks' 3 | import {render} from '../../testUtil' 4 | import Month from '.' 5 | 6 | test('should match snapshot', () => { 7 | const {container, getByText, getAllByTestId} = render( 8 | , 16 | ) 17 | expect(container).toMatchSnapshot() 18 | getByText('February 2019') 19 | 20 | const days = getAllByTestId('Day') 21 | expect(days[0].textContent).toBe('01') 22 | expect(days[days.length - 1].textContent).toBe('28') 23 | 24 | const dayLabels = getAllByTestId('DayLabel') 25 | expect(dayLabels[0].textContent).toBe('Mo') 26 | expect(dayLabels[dayLabels.length - 1].textContent).toBe('Su') 27 | }) 28 | 29 | test('Sunday should be first day of the week', () => { 30 | const {container, getByText, getAllByTestId} = render( 31 | , 39 | ) 40 | expect(container).toMatchSnapshot() 41 | getByText('February 2019') 42 | 43 | const days = getAllByTestId('Day') 44 | expect(days[0].textContent).toBe('01') 45 | expect(days[days.length - 1].textContent).toBe('28') 46 | 47 | const dayLabels = getAllByTestId('DayLabel') 48 | expect(dayLabels[0].textContent).toBe('Su') 49 | expect(dayLabels[dayLabels.length - 1].textContent).toBe('Sa') 50 | }) 51 | -------------------------------------------------------------------------------- /packages/styled/src/components/Month/Month.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import {useMonth, CalendarDay, FirstDayOfWeek} from '@datepicker-react/hooks' 3 | import styled, {keyframes} from 'styled-components' 4 | import MonthLabel from '../MonthLabel' 5 | import DayLabel from '../DayLabel' 6 | import Flex from '../Flex' 7 | import Grid from '../Grid' 8 | import Day from '../Day' 9 | import useThemeProps from '../../hooks/useThemeProps' 10 | import globalStyles from '../../globalStyles' 11 | // eslint-disable-next-line import/no-unresolved 12 | import {MonthTheme} from '../../@types/theme' 13 | 14 | const opacity0To100 = keyframes` 15 | from { 16 | opacity: 0; 17 | } 18 | 19 | to { 20 | opacity: 1; 21 | } 22 | ` 23 | 24 | const MonthWrapper = styled('div')` 25 | animation-name: ${opacity0To100}; 26 | animation-duration: 0.25s; 27 | animation-timing-function: ease-in; 28 | 29 | &:last-child { 30 | padding: 0 1px 1px 0; 31 | } 32 | ` 33 | 34 | interface MonthProps { 35 | year: number 36 | month: number 37 | firstDayOfWeek: FirstDayOfWeek 38 | dayLabelFormat(date: Date): string 39 | weekdayLabelFormat(date: Date): string 40 | monthLabelFormat(date: Date): string 41 | } 42 | 43 | const Month = ({ 44 | year, 45 | month, 46 | firstDayOfWeek, 47 | dayLabelFormat, 48 | monthLabelFormat, 49 | weekdayLabelFormat, 50 | }: MonthProps) => { 51 | const {days, weekdayLabels, monthLabel} = useMonth({ 52 | dayLabelFormat, 53 | monthLabelFormat, 54 | weekdayLabelFormat, 55 | year, 56 | month, 57 | firstDayOfWeek, 58 | }) 59 | const theme: MonthTheme = useThemeProps({ 60 | daySize: globalStyles.daySize, 61 | monthLabelMargin: '0 0 28px', 62 | monthDayLabelMargin: '0 0 16px', 63 | }) 64 | 65 | return ( 66 | 67 | 68 | 69 | 70 | 71 | {weekdayLabels.map((weekdayLabel: string) => ( 72 | 73 | 74 | 75 | ))} 76 | 77 | 78 | {days.map((day: CalendarDay, index: number) => { 79 | if (typeof day === 'object') { 80 | return 81 | } 82 | return
83 | })} 84 | 85 | 86 | ) 87 | } 88 | 89 | export default Month 90 | -------------------------------------------------------------------------------- /packages/styled/src/components/Month/index.ts: -------------------------------------------------------------------------------- 1 | import Month from './Month' 2 | 3 | export default Month 4 | -------------------------------------------------------------------------------- /packages/styled/src/components/MonthLabel/MonthLabel.test.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | import {render} from '../../testUtil' 3 | import MonthLabel from '.' 4 | 5 | test('should match snapshot', () => { 6 | const {container} = render() 7 | expect(container).toMatchSnapshot() 8 | }) 9 | -------------------------------------------------------------------------------- /packages/styled/src/components/MonthLabel/MonthLabel.tsx: -------------------------------------------------------------------------------- 1 | import React, {useContext} from 'react' 2 | import {ThemeContext} from 'styled-components' 3 | import Text from '../Text' 4 | // eslint-disable-next-line import/no-unresolved 5 | import {MonthLabelTheme} from '../../@types/theme' 6 | import useThemeProps from '../../hooks/useThemeProps' 7 | import globalStyles from '../../globalStyles' 8 | import getThemeProp from '../../utils/getThemeProp' 9 | 10 | interface MonthLabelProps { 11 | label: string 12 | } 13 | 14 | const MonthLabel = ({label}: MonthLabelProps) => { 15 | const themeContext = useContext(ThemeContext) 16 | const theme: MonthLabelTheme = useThemeProps({ 17 | fontFamily: globalStyles.fontFamily, 18 | monthLabelColor: getThemeProp('darcula', globalStyles.colors.darcula, themeContext), 19 | monthLabelLineHeight: 1.57, 20 | monthLabelFontWeight: 600, 21 | monthLabelFontSize: '14px', 22 | }) 23 | 24 | return ( 25 | 34 | {label} 35 | 36 | ) 37 | } 38 | 39 | export default MonthLabel 40 | -------------------------------------------------------------------------------- /packages/styled/src/components/MonthLabel/__snapshots__/MonthLabel.test.tsx.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`should match snapshot 1`] = ` 4 | .c0 { 5 | font-family: Montserrat,sans-serif; 6 | font-size: 14px; 7 | font-weight: 600; 8 | line-height: 1.57; 9 | color: #343132; 10 | } 11 | 12 |
13 |
21 | Test 22 |
23 |
24 | `; 25 | -------------------------------------------------------------------------------- /packages/styled/src/components/MonthLabel/index.ts: -------------------------------------------------------------------------------- 1 | import MonthLabel from './MonthLabel' 2 | 3 | export default MonthLabel 4 | -------------------------------------------------------------------------------- /packages/styled/src/components/NavButton/NavButton.test.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | import {render, fireEvent} from '../../testUtil' 3 | import NavButton from '.' 4 | 5 | test('should match snapshot - prev month', () => { 6 | const {container} = render( 7 | , 8 | ) 9 | expect(container).toMatchSnapshot() 10 | }) 11 | 12 | test('should match snapshot - prev month rtl', () => { 13 | const {container} = render( 14 | , 15 | ) 16 | expect(container).toMatchSnapshot() 17 | }) 18 | 19 | test('should match snapshot - next month', () => { 20 | const {container} = render( 21 | , 22 | ) 23 | expect(container).toMatchSnapshot() 24 | }) 25 | 26 | test('should match snapshot - next month rtl', () => { 27 | const {container} = render( 28 | , 29 | ) 30 | expect(container).toMatchSnapshot() 31 | }) 32 | 33 | test('should match snapshot - prev month vertical', () => { 34 | const {container} = render( 35 | , 36 | ) 37 | expect(container).toMatchSnapshot() 38 | }) 39 | 40 | test('should match snapshot - next month vertical', () => { 41 | const {container} = render( 42 | , 43 | ) 44 | expect(container).toMatchSnapshot() 45 | }) 46 | 47 | test('should match snapshot - prev month vertical, rtl', () => { 48 | const {container} = render( 49 | , 50 | ) 51 | expect(container).toMatchSnapshot() 52 | }) 53 | 54 | test('should match snapshot - next month vertical, rtl', () => { 55 | const {container} = render( 56 | , 57 | ) 58 | expect(container).toMatchSnapshot() 59 | }) 60 | 61 | test('should execute onClick callback', () => { 62 | const onClick = jest.fn() 63 | const {container} = render( 64 | , 65 | ) 66 | // @ts-ignore 67 | fireEvent.click(container.firstChild) 68 | expect(onClick).toHaveBeenCalled() 69 | // @ts-ignore 70 | fireEvent.mouseUp(container.firstChild) 71 | expect(container).toMatchSnapshot() 72 | }) 73 | -------------------------------------------------------------------------------- /packages/styled/src/components/NavButton/NavButton.tsx: -------------------------------------------------------------------------------- 1 | import React, {useContext} from 'react' 2 | import styled, {ThemeContext} from 'styled-components' 3 | import { 4 | width, 5 | WidthProps, 6 | height, 7 | HeightProps, 8 | background, 9 | BackgroundProps, 10 | space, 11 | SpaceProps, 12 | borders, 13 | BordersProps, 14 | compose, 15 | } from 'styled-system' 16 | import CaretIcon from '../../icons/CaretIcon' 17 | // eslint-disable-next-line import/no-unresolved 18 | import {NavButtonTheme} from '../../@types/theme' 19 | import useThemeProps from '../../hooks/useThemeProps' 20 | import globalStyles from '../../globalStyles' 21 | import getThemeProp from '../../utils/getThemeProp' 22 | 23 | interface StyledNavButtonProps 24 | extends HeightProps, 25 | WidthProps, 26 | BackgroundProps, 27 | SpaceProps, 28 | BordersProps {} 29 | 30 | const composeSyles = compose(width, height, background, space, borders) 31 | 32 | const StyledNavButton = styled('button')` 33 | ${composeSyles} 34 | display: flex; 35 | justify-content: center; 36 | align-items: center; 37 | ` 38 | 39 | interface NavButtonProps { 40 | type: 'next' | 'prev' 41 | onClick(): void 42 | vertical: boolean 43 | rtl: boolean 44 | ariaLabel: string 45 | } 46 | 47 | function NavButton({type, onClick, vertical, rtl, ariaLabel}: NavButtonProps) { 48 | const themeContext = useContext(ThemeContext) 49 | const theme: NavButtonTheme = useThemeProps({ 50 | navButtonWidth: vertical ? '48px' : '30px', 51 | navButtonHeight: vertical ? '48px' : '30px', 52 | navButtonBackground: getThemeProp('white', globalStyles.colors.white, themeContext), 53 | navButtonBorder: `1px solid ${getThemeProp( 54 | 'silverCloud', 55 | globalStyles.colors.silverCloud, 56 | themeContext, 57 | )}`, 58 | navButtonPadding: '0', 59 | navButtonIconHeight: vertical ? '18px' : '11px', 60 | navButtonIconWidth: vertical ? '28px' : '18px', 61 | navButtonIconColor: getThemeProp('greey', globalStyles.colors.greey, themeContext), 62 | }) 63 | 64 | function handleMouseUp(e: React.MouseEvent) { 65 | // @ts-ignore 66 | e.currentTarget.blur() 67 | } 68 | 69 | function getDirection() { 70 | if (type === 'next' && !vertical) { 71 | return 'right' 72 | } else if (type === 'next' && vertical) { 73 | return 'down' 74 | } else if (type === 'prev' && !vertical) { 75 | return 'left' 76 | } 77 | 78 | return 'up' 79 | } 80 | 81 | return ( 82 | 96 | 105 | 106 | ) 107 | } 108 | 109 | export default NavButton 110 | -------------------------------------------------------------------------------- /packages/styled/src/components/NavButton/index.ts: -------------------------------------------------------------------------------- 1 | import NavButton from './NavButton' 2 | 3 | export default NavButton 4 | -------------------------------------------------------------------------------- /packages/styled/src/components/ResetDates/ResetDates.test.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | import {render, fireEvent} from '../../testUtil' 3 | import ResetDates from '.' 4 | 5 | test('should match snapshot', () => { 6 | const {container} = render() 7 | expect(container).toMatchSnapshot() 8 | }) 9 | 10 | test('should render rtl variant', () => { 11 | const {container} = render() 12 | expect(container).toMatchSnapshot() 13 | }) 14 | 15 | test('should execute onClick callback', () => { 16 | const onResetDates = jest.fn() 17 | const {container} = render( 18 | , 19 | ) 20 | // @ts-ignore 21 | fireEvent.click(container.firstChild) 22 | expect(onResetDates).toHaveBeenCalled() 23 | // @ts-ignore 24 | fireEvent.mouseUp(container.firstChild) 25 | }) 26 | -------------------------------------------------------------------------------- /packages/styled/src/components/ResetDates/ResetDates.tsx: -------------------------------------------------------------------------------- 1 | import React, {useContext} from 'react' 2 | import styled, {css, ThemeContext} from 'styled-components' 3 | import RedoIcon from '../../icons/RedoIcon' 4 | import Text from '../Text' 5 | // eslint-disable-next-line import/no-unresolved 6 | import {ResetDatesTheme} from '../../@types/theme' 7 | import useThemeProps from '../../hooks/useThemeProps' 8 | import globalStyles from '../../globalStyles' 9 | import getThemeProp from '../../utils/getThemeProp' 10 | 11 | const StyledReactDates = styled('button')` 12 | display: flex; 13 | align-items: center; 14 | cursor: pointer; 15 | border: 0; 16 | background: transparent; 17 | padding: 0; 18 | 19 | &:hover { 20 | text-decoration: underline; 21 | } 22 | ` 23 | 24 | interface RedoIconProps { 25 | rtl: boolean 26 | } 27 | const RedoIconStyle = styled(RedoIcon)` 28 | ${({rtl}) => 29 | rtl && 30 | css` 31 | transform: rotate(-180deg); 32 | `} 33 | ` 34 | 35 | interface ResetDatesProps { 36 | onResetDates(): void 37 | text: string 38 | rtl: boolean 39 | } 40 | 41 | function ResetDates({onResetDates, text, rtl}: ResetDatesProps) { 42 | const themeContext = useContext(ThemeContext) 43 | const theme: ResetDatesTheme = useThemeProps({ 44 | fontFamily: globalStyles.fontFamily, 45 | resetDatesIconColor: getThemeProp('mud', globalStyles.colors.mud, themeContext), 46 | resetDatesIconHeight: '14px', 47 | resetDatesIconWidth: '14px', 48 | resetDatesTextColor: getThemeProp('darcula', globalStyles.colors.darcula, themeContext), 49 | resetDatesTextMargin: rtl ? '1px 8px 0 0' : '1px 0 0 8px', 50 | resetDatesTextLineHeight: 1.18, 51 | resetDatesTextFontSize: '11px', 52 | }) 53 | 54 | function handleMouseUp(e: React.MouseEvent) { 55 | // @ts-ignore 56 | e.currentTarget.blur() 57 | } 58 | 59 | return ( 60 | 66 | 75 | 83 | {text} 84 | 85 | 86 | ) 87 | } 88 | 89 | export default ResetDates 90 | -------------------------------------------------------------------------------- /packages/styled/src/components/ResetDates/__snapshots__/ResetDates.test.tsx.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`should match snapshot 1`] = ` 4 | .c1 { 5 | margin: 1px 0 0 8px; 6 | line-height: 1.18; 7 | font-family: Montserrat,sans-serif; 8 | font-size: 11px; 9 | color: #343132; 10 | } 11 | 12 | .c0 { 13 | display: -webkit-box; 14 | display: -webkit-flex; 15 | display: -ms-flexbox; 16 | display: flex; 17 | -webkit-align-items: center; 18 | -webkit-box-align: center; 19 | -ms-flex-align: center; 20 | align-items: center; 21 | cursor: pointer; 22 | border: 0; 23 | background: transparent; 24 | padding: 0; 25 | } 26 | 27 | .c0:hover { 28 | -webkit-text-decoration: underline; 29 | text-decoration: underline; 30 | } 31 | 32 |
33 | 61 |
62 | `; 63 | 64 | exports[`should render rtl variant 1`] = ` 65 | .c2 { 66 | margin: 1px 8px 0 0; 67 | line-height: 1.18; 68 | font-family: Montserrat,sans-serif; 69 | font-size: 11px; 70 | color: #343132; 71 | } 72 | 73 | .c0 { 74 | display: -webkit-box; 75 | display: -webkit-flex; 76 | display: -ms-flexbox; 77 | display: flex; 78 | -webkit-align-items: center; 79 | -webkit-box-align: center; 80 | -ms-flex-align: center; 81 | align-items: center; 82 | cursor: pointer; 83 | border: 0; 84 | background: transparent; 85 | padding: 0; 86 | } 87 | 88 | .c0:hover { 89 | -webkit-text-decoration: underline; 90 | text-decoration: underline; 91 | } 92 | 93 | .c1 { 94 | -webkit-transform: rotate(-180deg); 95 | -ms-transform: rotate(-180deg); 96 | transform: rotate(-180deg); 97 | } 98 | 99 |
100 | 128 |
129 | `; 130 | -------------------------------------------------------------------------------- /packages/styled/src/components/ResetDates/index.ts: -------------------------------------------------------------------------------- 1 | import ResetDates from './ResetDates' 2 | 3 | export default ResetDates 4 | -------------------------------------------------------------------------------- /packages/styled/src/components/SelectedDate/SelectedDate.test.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | import {render} from '../../testUtil' 3 | import SelectedDate from '.' 4 | 5 | test('should be unactive', () => { 6 | const {container} = render( 7 | , 8 | ) 9 | expect(container).toMatchSnapshot() 10 | }) 11 | 12 | test('should be active', () => { 13 | const {container} = render( 14 | , 15 | ) 16 | expect(container).toMatchSnapshot() 17 | }) 18 | 19 | test('should render vertical variant', () => { 20 | const {container} = render() 21 | expect(container).toMatchSnapshot() 22 | }) 23 | -------------------------------------------------------------------------------- /packages/styled/src/components/SelectedDate/SelectedDate.tsx: -------------------------------------------------------------------------------- 1 | import React, {useContext} from 'react' 2 | import styled, {css, ThemeContext} from 'styled-components' 3 | import useThemeProps from '../../hooks/useThemeProps' 4 | // eslint-disable-next-line import/no-unresolved 5 | import {SelectDateTheme} from '../../@types/theme' 6 | import globalStyles from '../../globalStyles' 7 | import getThemeProp from '../../utils/getThemeProp' 8 | import Text from '../Text' 9 | import Box from '../Box' 10 | 11 | interface StyledDateProps { 12 | isActive: boolean 13 | selectDateBorderColor: string 14 | } 15 | const StyledDate = styled(Text)` 16 | position: relative; 17 | display: inline-block; 18 | 19 | &:after { 20 | content: ''; 21 | position: absolute; 22 | height: 2px; 23 | width: 100%; 24 | bottom: 0; 25 | left: 0; 26 | z-index: 1; 27 | } 28 | 29 | ${({isActive, selectDateBorderColor}) => 30 | isActive && 31 | css` 32 | &:after { 33 | background: ${selectDateBorderColor}; 34 | } 35 | `} 36 | ` 37 | 38 | export interface SelectDateProps { 39 | title: string 40 | date: string 41 | isActive: boolean 42 | vertical: boolean 43 | } 44 | 45 | function SelectDate({title, isActive, date, vertical}: SelectDateProps) { 46 | const themeContext = useContext(ThemeContext) 47 | const theme: SelectDateTheme = useThemeProps({ 48 | fontFamily: globalStyles.fontFamily, 49 | selectDateLabelFontSize: '11px', 50 | selectDateLabelColor: getThemeProp( 51 | 'silverCloud', 52 | globalStyles.colors.silverCloud, 53 | themeContext, 54 | ), 55 | selectDateLabelMargin: '0 0 8px', 56 | selectDateDateColor: getThemeProp('charcoal', globalStyles.colors.charcoal, themeContext), 57 | selectDateDateFontSize: vertical ? '16px' : '24px', 58 | selectDateDateFontWeight: 500, 59 | selectDateDatePadding: '0 0 15px', 60 | selectDateBorderColor: getThemeProp( 61 | 'primaryColor', 62 | globalStyles.colors.primaryColor, 63 | themeContext, 64 | ), 65 | selectDatePadding: '0', 66 | }) 67 | 68 | return ( 69 | 70 | 77 | {title} 78 | 79 | 91 | {date} 92 | 93 | 94 | ) 95 | } 96 | 97 | export default SelectDate 98 | -------------------------------------------------------------------------------- /packages/styled/src/components/SelectedDate/__snapshots__/SelectedDate.test.tsx.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`should be active 1`] = ` 4 | .c1 { 5 | font-family: Montserrat,sans-serif; 6 | font-size: 11px; 7 | color: #929598; 8 | margin: 0 0 8px; 9 | } 10 | 11 | .c0 { 12 | box-sizing: border-box; 13 | padding: 0; 14 | } 15 | 16 | .c2 { 17 | color: #001217; 18 | font-size: 24px; 19 | font-weight: 500; 20 | font-family: Montserrat,sans-serif; 21 | padding: 0 0 15px; 22 | position: relative; 23 | display: inline-block; 24 | } 25 | 26 | .c2:after { 27 | content: ''; 28 | position: absolute; 29 | height: 2px; 30 | width: 100%; 31 | bottom: 0; 32 | left: 0; 33 | z-index: 1; 34 | } 35 | 36 | .c2:after { 37 | background: #00aeef; 38 | } 39 | 40 |
41 |
44 |
50 | test 51 |
52 | 59 | 15.10.2018 60 | 61 |
62 |
63 | `; 64 | 65 | exports[`should be unactive 1`] = ` 66 | .c1 { 67 | font-family: Montserrat,sans-serif; 68 | font-size: 11px; 69 | color: #929598; 70 | margin: 0 0 8px; 71 | } 72 | 73 | .c0 { 74 | box-sizing: border-box; 75 | padding: 0; 76 | } 77 | 78 | .c2 { 79 | color: #001217; 80 | font-size: 24px; 81 | font-weight: 500; 82 | font-family: Montserrat,sans-serif; 83 | padding: 0 0 15px; 84 | position: relative; 85 | display: inline-block; 86 | } 87 | 88 | .c2:after { 89 | content: ''; 90 | position: absolute; 91 | height: 2px; 92 | width: 100%; 93 | bottom: 0; 94 | left: 0; 95 | z-index: 1; 96 | } 97 | 98 |
99 |
102 |
108 | test 109 |
110 | 117 | 15.10.2018 118 | 119 |
120 |
121 | `; 122 | 123 | exports[`should render vertical variant 1`] = ` 124 | .c1 { 125 | font-family: Montserrat,sans-serif; 126 | font-size: 11px; 127 | color: #929598; 128 | margin: 0 0 8px; 129 | } 130 | 131 | .c0 { 132 | box-sizing: border-box; 133 | padding: 0; 134 | } 135 | 136 | .c2 { 137 | color: #001217; 138 | font-size: 16px; 139 | font-weight: 500; 140 | font-family: Montserrat,sans-serif; 141 | padding: 0 0 15px; 142 | position: relative; 143 | display: inline-block; 144 | } 145 | 146 | .c2:after { 147 | content: ''; 148 | position: absolute; 149 | height: 2px; 150 | width: 100%; 151 | bottom: 0; 152 | left: 0; 153 | z-index: 1; 154 | } 155 | 156 | .c2:after { 157 | background: #00aeef; 158 | } 159 | 160 |
161 |
164 |
170 | test 171 |
172 | 179 | 15.10.2018 180 | 181 |
182 |
183 | `; 184 | -------------------------------------------------------------------------------- /packages/styled/src/components/SelectedDate/index.ts: -------------------------------------------------------------------------------- 1 | import SelectedDate from './SelectedDate' 2 | 3 | export default SelectedDate 4 | -------------------------------------------------------------------------------- /packages/styled/src/components/Text/Test.test.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import {render} from '../../testUtil' 3 | import Text from '.' 4 | 5 | test('should match snapshot', () => { 6 | const {container} = render( 7 | 16 | Test 17 | , 18 | ) 19 | expect(container).toMatchSnapshot() 20 | // @ts-ignore 21 | expect(container.firstChild).toHaveTextContent('Test') 22 | }) 23 | 24 | test('should match style rules', () => { 25 | const {container} = render( 26 | 35 | Test 36 | , 37 | ) 38 | // @ts-ignore 39 | expect(container.firstChild).toHaveStyleRule('font-family', 'Montserrat') 40 | // @ts-ignore 41 | expect(container.firstChild).toHaveStyleRule('font-weight', '500') 42 | // @ts-ignore 43 | expect(container.firstChild).toHaveStyleRule('font-size', '14px') 44 | // @ts-ignore 45 | expect(container.firstChild).toHaveStyleRule('color', '#000000') 46 | // @ts-ignore 47 | expect(container.firstChild).toHaveStyleRule('line-height', '1.2') 48 | // @ts-ignore 49 | expect(container.firstChild).toHaveStyleRule('margin', '10px') 50 | // @ts-ignore 51 | expect(container.firstChild).toHaveStyleRule('padding', '10px') 52 | }) 53 | -------------------------------------------------------------------------------- /packages/styled/src/components/Text/Text.tsx: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components' 2 | import { 3 | fontFamily, 4 | FontFamilyProps, 5 | fontSize, 6 | FontSizeProps, 7 | fontWeight, 8 | FontWeightProps, 9 | color, 10 | ColorProps, 11 | lineHeight, 12 | LineHeightProps, 13 | space, 14 | SpaceProps, 15 | compose, 16 | } from 'styled-system' 17 | 18 | interface TextProps 19 | extends FontWeightProps, 20 | FontSizeProps, 21 | FontFamilyProps, 22 | ColorProps, 23 | SpaceProps, 24 | LineHeightProps {} 25 | 26 | const composeStyles = compose(fontFamily, fontSize, fontWeight, color, lineHeight, space) 27 | 28 | const Text = styled('div')` 29 | ${composeStyles} 30 | ` 31 | 32 | export default Text 33 | -------------------------------------------------------------------------------- /packages/styled/src/components/Text/__snapshots__/Test.test.tsx.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`should match snapshot 1`] = ` 4 | .c0 { 5 | font-family: Montserrat; 6 | font-size: 14px; 7 | font-weight: 500; 8 | color: #000000; 9 | line-height: 1.2; 10 | padding: 10px; 11 | margin: 10px; 12 | } 13 | 14 |
15 |
22 | Test 23 |
24 |
25 | `; 26 | -------------------------------------------------------------------------------- /packages/styled/src/components/Text/index.ts: -------------------------------------------------------------------------------- 1 | import Text from './Text' 2 | 3 | export default Text 4 | -------------------------------------------------------------------------------- /packages/styled/src/context/datepickerContext.ts: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | interface DatepickerContext { 4 | rtl: boolean 5 | focusedDate: Date | null 6 | onDateFocus(date: Date): void 7 | onDateSelect(date: Date): void 8 | onDateHover(date: Date): void 9 | isDateFocused(date: Date): boolean 10 | isDateSelected(date: Date): boolean 11 | isDateHovered(date: Date): boolean 12 | isDateBlocked(date: Date): boolean 13 | isFirstOrLastSelectedDate(date: Date): boolean 14 | onDayRender?(date: Date): React.ReactNode 15 | } 16 | 17 | export const datepickerContextDefaultValue = { 18 | rtl: false, 19 | focusedDate: null, 20 | isDateFocused: () => false, 21 | isDateSelected: () => false, 22 | isDateHovered: () => false, 23 | isDateBlocked: () => false, 24 | isFirstOrLastSelectedDate: () => false, 25 | onDateFocus: () => {}, 26 | onDateHover: () => {}, 27 | onDateSelect: () => {}, 28 | onDayRender: undefined, 29 | } 30 | 31 | export default React.createContext(datepickerContextDefaultValue) 32 | -------------------------------------------------------------------------------- /packages/styled/src/globalStyles.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | fontFamily: 'Montserrat, sans-serif', 3 | colors: { 4 | primaryColor: '#00aeef', 5 | silverCloud: '#929598', 6 | charcoal: '#001217', 7 | darcula: '#343132', 8 | mud: '#58595B', 9 | greey: '#808285', 10 | graci: '#BCBEC0', 11 | white: '#ffffff', 12 | accessibility: '#009fef', 13 | selectedDay: '#71c9ed', 14 | selectedDayHover: '#39beef', 15 | normalDayHover: '#e6e7e8', 16 | }, 17 | daySize: 36, 18 | } 19 | -------------------------------------------------------------------------------- /packages/styled/src/hooks/useThemeProps/index.ts: -------------------------------------------------------------------------------- 1 | import useThemeProps from './useThemeProps' 2 | 3 | export default useThemeProps 4 | -------------------------------------------------------------------------------- /packages/styled/src/hooks/useThemeProps/useThemeProps.test.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import {renderHook} from '@testing-library/react-hooks' 3 | import {ThemeProvider} from 'styled-components' 4 | import useThemeProps from '.' 5 | 6 | test('should return empty object - no provider', () => { 7 | const {result} = renderHook(() => useThemeProps()) 8 | expect(result.current).toEqual({}) 9 | }) 10 | 11 | const emptyTheme = ({children}: {children: any}) => ( 12 | {children} 13 | ) 14 | test('should return empty object - empty theme', () => { 15 | const {result} = renderHook(() => useThemeProps(), {wrapper: emptyTheme}) 16 | expect(result.current).toEqual({}) 17 | }) 18 | 19 | const emptyDatepickerTheme = ({children}: {children: any}) => ( 20 | {children} 21 | ) 22 | test('should return empty object - empty reactDatepicker', () => { 23 | const {result} = renderHook(() => useThemeProps(), {wrapper: emptyDatepickerTheme}) 24 | expect(result.current).toEqual({}) 25 | }) 26 | 27 | const datepickerTheme = ({children}: {children: any}) => ( 28 | {children} 29 | ) 30 | test('should return theme values', () => { 31 | const {result} = renderHook(() => useThemeProps({width: '60px', height: '100px'}), { 32 | wrapper: datepickerTheme, 33 | }) 34 | expect(result.current).toEqual({width: '50px', height: '100px'}) 35 | }) 36 | -------------------------------------------------------------------------------- /packages/styled/src/hooks/useThemeProps/useThemeProps.ts: -------------------------------------------------------------------------------- 1 | import {ThemeContext} from 'styled-components' 2 | import {useContext, useMemo} from 'react' 3 | 4 | export default function useThemeProps(themeProps: Record = {}) { 5 | const context = useContext(ThemeContext) 6 | const theme = useMemo(() => { 7 | if ( 8 | context && 9 | typeof context === 'object' && 10 | context.reactDatepicker && 11 | typeof context.reactDatepicker === 'object' 12 | ) { 13 | return Object.keys(themeProps).reduce( 14 | (prevObj: Record, val: string) => ({ 15 | ...prevObj, 16 | [val]: context.reactDatepicker[val] || themeProps[val], 17 | }), 18 | {}, 19 | ) 20 | } 21 | 22 | return themeProps 23 | }, [context, themeProps]) 24 | 25 | return theme 26 | } 27 | -------------------------------------------------------------------------------- /packages/styled/src/icons/ArrowIcon/ArrowIcon.test.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import {render} from '@testing-library/react' 3 | import ArrowIcon from '.' 4 | 5 | test('should match snapshot', () => { 6 | const {container} = render() 7 | expect(container).toMatchSnapshot() 8 | }) 9 | 10 | test('should get className', () => { 11 | const {container} = render( 12 | , 13 | ) 14 | expect(container).toMatchSnapshot() 15 | }) 16 | 17 | test('should be facing to the left', () => { 18 | const {container} = render( 19 | , 20 | ) 21 | expect(container).toMatchSnapshot() 22 | }) 23 | 24 | test('should be facing to the right', () => { 25 | const {container} = render( 26 | , 27 | ) 28 | expect(container).toMatchSnapshot() 29 | }) 30 | 31 | test('should be facing to the down', () => { 32 | const {container} = render( 33 | , 34 | ) 35 | expect(container).toMatchSnapshot() 36 | }) 37 | 38 | test('should be facing to the up', () => { 39 | const {container} = render( 40 | , 41 | ) 42 | expect(container).toMatchSnapshot() 43 | }) 44 | -------------------------------------------------------------------------------- /packages/styled/src/icons/ArrowIcon/ArrowIcon.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | interface Props { 4 | direction?: 'up' | 'down' | 'left' | 'right' 5 | height: string 6 | width: string 7 | iconColor?: string 8 | className?: string 9 | } 10 | 11 | function calculateAngle(direction: Props['direction']) { 12 | switch (direction) { 13 | case 'up': 14 | return 0 15 | case 'down': 16 | return 180 17 | case 'left': 18 | return -90 19 | case 'right': 20 | default: 21 | return 90 22 | } 23 | } 24 | 25 | function ArrowIcon({height, width, iconColor, direction = 'right', className = ''}: Props) { 26 | const angle = calculateAngle(direction) 27 | return ( 28 | 37 | 41 | 42 | ) 43 | } 44 | 45 | export default ArrowIcon 46 | -------------------------------------------------------------------------------- /packages/styled/src/icons/ArrowIcon/__snapshots__/ArrowIcon.test.tsx.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`should be facing to the down 1`] = ` 4 |
5 | 14 | 18 | 19 |
20 | `; 21 | 22 | exports[`should be facing to the left 1`] = ` 23 |
24 | 33 | 37 | 38 |
39 | `; 40 | 41 | exports[`should be facing to the right 1`] = ` 42 |
43 | 52 | 56 | 57 |
58 | `; 59 | 60 | exports[`should be facing to the up 1`] = ` 61 |
62 | 71 | 75 | 76 |
77 | `; 78 | 79 | exports[`should get className 1`] = ` 80 |
81 | 90 | 94 | 95 |
96 | `; 97 | 98 | exports[`should match snapshot 1`] = ` 99 |
100 | 109 | 113 | 114 |
115 | `; 116 | -------------------------------------------------------------------------------- /packages/styled/src/icons/ArrowIcon/index.ts: -------------------------------------------------------------------------------- 1 | import ArrowIcon from './ArrowIcon' 2 | 3 | export default ArrowIcon 4 | -------------------------------------------------------------------------------- /packages/styled/src/icons/CalendarIcon/CalendarIcon.test.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import {render} from '@testing-library/react' 3 | import CalendarIcon from '.' 4 | 5 | test('should match snapshot', () => { 6 | const {container} = render() 7 | expect(container).toMatchSnapshot() 8 | }) 9 | 10 | test('should get classname', () => { 11 | const {container} = render( 12 | , 13 | ) 14 | expect(container).toMatchSnapshot() 15 | }) 16 | -------------------------------------------------------------------------------- /packages/styled/src/icons/CalendarIcon/CalendarIcon.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | function CalendarIcon({height, width, color, className = ''}: IconProps) { 4 | return ( 5 | 13 | 18 | 19 | ) 20 | } 21 | 22 | export default CalendarIcon 23 | -------------------------------------------------------------------------------- /packages/styled/src/icons/CalendarIcon/__snapshots__/CalendarIcon.test.tsx.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`should get classname 1`] = ` 4 |
5 | 13 | 18 | 19 |
20 | `; 21 | 22 | exports[`should match snapshot 1`] = ` 23 |
24 | 32 | 37 | 38 |
39 | `; 40 | -------------------------------------------------------------------------------- /packages/styled/src/icons/CalendarIcon/index.ts: -------------------------------------------------------------------------------- 1 | import CalendarIcon from './CalendarIcon' 2 | 3 | export default CalendarIcon 4 | -------------------------------------------------------------------------------- /packages/styled/src/icons/CaretIcon/CaretIcon.test.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | import {render} from '@testing-library/react' 3 | import CaretIcon from '.' 4 | 5 | test('should match snapshot', () => { 6 | const {container} = render() 7 | expect(container).toMatchSnapshot() 8 | }) 9 | 10 | test('should get classname', () => { 11 | const {container} = render() 12 | expect(container).toMatchSnapshot() 13 | }) 14 | 15 | test('should be facing to the left', () => { 16 | const {container} = render() 17 | expect(container).toMatchSnapshot() 18 | }) 19 | 20 | test('should be facing to the right', () => { 21 | const {container} = render() 22 | expect(container).toMatchSnapshot() 23 | }) 24 | 25 | test('should be facing down', () => { 26 | const {container} = render() 27 | expect(container).toMatchSnapshot() 28 | }) 29 | 30 | test('should be facing up', () => { 31 | const {container} = render() 32 | expect(container).toMatchSnapshot() 33 | }) 34 | -------------------------------------------------------------------------------- /packages/styled/src/icons/CaretIcon/CaretIcon.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import styled, {css} from 'styled-components' 3 | 4 | interface SvgProps { 5 | angle: number 6 | } 7 | const Svg = styled('svg')` 8 | ${({angle}) => 9 | css` 10 | transform: rotate(${angle}deg); 11 | `} 12 | ` 13 | 14 | interface Props extends IconProps { 15 | direction?: 'up' | 'down' | 'left' | 'right' 16 | } 17 | 18 | function calculateAngle(direction: Props['direction']) { 19 | switch (direction) { 20 | case 'up': 21 | return 180 22 | case 'down': 23 | return 0 24 | case 'left': 25 | return 90 26 | case 'right': 27 | default: 28 | return -90 29 | } 30 | } 31 | 32 | function CaretIcon({height, width, color, direction = 'right', className = ''}: Props) { 33 | const angle = calculateAngle(direction) 34 | return ( 35 | 44 | 49 | 50 | ) 51 | } 52 | 53 | export default CaretIcon 54 | -------------------------------------------------------------------------------- /packages/styled/src/icons/CaretIcon/__snapshots__/CaretIcon.test.tsx.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`should be facing down 1`] = ` 4 | .c0 { 5 | -webkit-transform: rotate(0deg); 6 | -ms-transform: rotate(0deg); 7 | transform: rotate(0deg); 8 | } 9 | 10 |
11 | 19 | 24 | 25 |
26 | `; 27 | 28 | exports[`should be facing to the left 1`] = ` 29 | .c0 { 30 | -webkit-transform: rotate(90deg); 31 | -ms-transform: rotate(90deg); 32 | transform: rotate(90deg); 33 | } 34 | 35 |
36 | 44 | 49 | 50 |
51 | `; 52 | 53 | exports[`should be facing to the right 1`] = ` 54 | .c0 { 55 | -webkit-transform: rotate(-90deg); 56 | -ms-transform: rotate(-90deg); 57 | transform: rotate(-90deg); 58 | } 59 | 60 |
61 | 69 | 74 | 75 |
76 | `; 77 | 78 | exports[`should be facing up 1`] = ` 79 | .c0 { 80 | -webkit-transform: rotate(180deg); 81 | -ms-transform: rotate(180deg); 82 | transform: rotate(180deg); 83 | } 84 | 85 |
86 | 94 | 99 | 100 |
101 | `; 102 | 103 | exports[`should get classname 1`] = ` 104 | .c0 { 105 | -webkit-transform: rotate(-90deg); 106 | -ms-transform: rotate(-90deg); 107 | transform: rotate(-90deg); 108 | } 109 | 110 |
111 | 119 | 124 | 125 |
126 | `; 127 | 128 | exports[`should match snapshot 1`] = ` 129 | .c0 { 130 | -webkit-transform: rotate(-90deg); 131 | -ms-transform: rotate(-90deg); 132 | transform: rotate(-90deg); 133 | } 134 | 135 |
136 | 144 | 149 | 150 |
151 | `; 152 | -------------------------------------------------------------------------------- /packages/styled/src/icons/CaretIcon/index.ts: -------------------------------------------------------------------------------- 1 | import CaretIcon from './CaretIcon' 2 | 3 | export default CaretIcon 4 | -------------------------------------------------------------------------------- /packages/styled/src/icons/CloseIcon/CloseIcon.test.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | import {render} from '@testing-library/react' 3 | import CloseIcon from '.' 4 | 5 | test('should match snapshot', () => { 6 | const {container} = render() 7 | expect(container).toMatchSnapshot() 8 | }) 9 | 10 | test('should get className', () => { 11 | const {container} = render() 12 | expect(container).toMatchSnapshot() 13 | }) 14 | -------------------------------------------------------------------------------- /packages/styled/src/icons/CloseIcon/CloseIcon.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | function CloseIcon({height, width, color, className = ''}: IconProps) { 4 | return ( 5 | 13 | 18 | 19 | ) 20 | } 21 | 22 | export default CloseIcon 23 | -------------------------------------------------------------------------------- /packages/styled/src/icons/CloseIcon/__snapshots__/CloseIcon.test.tsx.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`should get className 1`] = ` 4 |
5 | 13 | 18 | 19 |
20 | `; 21 | 22 | exports[`should match snapshot 1`] = ` 23 |
24 | 32 | 37 | 38 |
39 | `; 40 | -------------------------------------------------------------------------------- /packages/styled/src/icons/CloseIcon/index.ts: -------------------------------------------------------------------------------- 1 | import CloseIcon from './CloseIcon' 2 | 3 | export default CloseIcon 4 | -------------------------------------------------------------------------------- /packages/styled/src/icons/RedoIcon/RedoIcon.test.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | import {render} from '@testing-library/react' 3 | import RedoIcon from '.' 4 | 5 | test('should match snapshot', () => { 6 | const {container} = render() 7 | expect(container).toMatchSnapshot() 8 | }) 9 | 10 | test('should get className', () => { 11 | const {container} = render() 12 | expect(container).toMatchSnapshot() 13 | }) 14 | -------------------------------------------------------------------------------- /packages/styled/src/icons/RedoIcon/RedoIcon.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | function CaretIcon({height, width, color, className = ''}: IconProps) { 4 | return ( 5 | 13 | 18 | 19 | ) 20 | } 21 | 22 | export default CaretIcon 23 | -------------------------------------------------------------------------------- /packages/styled/src/icons/RedoIcon/__snapshots__/RedoIcon.test.tsx.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`should get className 1`] = ` 4 |
5 | 13 | 18 | 19 |
20 | `; 21 | 22 | exports[`should match snapshot 1`] = ` 23 |
24 | 32 | 37 | 38 |
39 | `; 40 | -------------------------------------------------------------------------------- /packages/styled/src/icons/RedoIcon/index.ts: -------------------------------------------------------------------------------- 1 | import RedoIcon from './RedoIcon' 2 | 3 | export default RedoIcon 4 | -------------------------------------------------------------------------------- /packages/styled/src/index.ts: -------------------------------------------------------------------------------- 1 | import { 2 | FirstDayOfWeek, 3 | FocusedInput, 4 | START_DATE, 5 | END_DATE, 6 | OnDatesChangeProps, 7 | FormatFunction, 8 | MonthType, 9 | } from '@datepicker-react/hooks' 10 | import DateRangeInput from './components/DateRangeInput' 11 | import DateSingleInput, {OnDateChangeProps} from './components/DateSingleInput' 12 | import Datepicker from './components/Datepicker' 13 | import { 14 | dateRangeInputPhrases, 15 | DateRangeInputPhrases, 16 | datepickerPhrases, 17 | DatepickerPhrases, 18 | DateSingleInputPhrases, 19 | dateSingleInputPhrases, 20 | } from './phrases' 21 | 22 | export { 23 | DateRangeInput, 24 | DateSingleInput, 25 | FirstDayOfWeek, 26 | Datepicker, 27 | dateRangeInputPhrases, 28 | DateRangeInputPhrases, 29 | datepickerPhrases, 30 | DatepickerPhrases, 31 | DateSingleInputPhrases, 32 | dateSingleInputPhrases, 33 | FocusedInput, 34 | START_DATE, 35 | END_DATE, 36 | OnDatesChangeProps, 37 | FormatFunction, 38 | MonthType, 39 | OnDateChangeProps, 40 | } 41 | -------------------------------------------------------------------------------- /packages/styled/src/phrases.ts: -------------------------------------------------------------------------------- 1 | export interface DatepickerPhrases { 2 | datepickerStartDatePlaceholder: string 3 | datepickerStartDateLabel: string 4 | datepickerEndDateLabel: string 5 | datepickerEndDatePlaceholder: string 6 | resetDates: string 7 | close: string 8 | } 9 | 10 | export interface DateRangeInputPhrases extends DatepickerPhrases { 11 | startDateAriaLabel: string 12 | endDateAriaLabel: string 13 | startDatePlaceholder: string 14 | endDatePlaceholder: string 15 | } 16 | 17 | export interface DateRangeInputPhrases extends DatepickerPhrases { 18 | startDateAriaLabel: string 19 | endDateAriaLabel: string 20 | startDatePlaceholder: string 21 | endDatePlaceholder: string 22 | } 23 | 24 | export interface DateSingleInputPhrases extends DatepickerPhrases { 25 | dateAriaLabel: string 26 | datePlaceholder: string 27 | } 28 | 29 | export const datepickerPhrases = { 30 | datepickerStartDatePlaceholder: 'Select', 31 | datepickerStartDateLabel: 'Start date:', 32 | datepickerEndDatePlaceholder: 'Select', 33 | datepickerEndDateLabel: 'End date:', 34 | resetDates: 'Reset dates', 35 | close: 'Close', 36 | } 37 | 38 | export const dateRangeInputPhrases = { 39 | ...datepickerPhrases, 40 | startDateAriaLabel: 'Start date', 41 | endDateAriaLabel: 'End date', 42 | startDatePlaceholder: 'Start date', 43 | endDatePlaceholder: 'End date', 44 | } 45 | 46 | export const dateSingleInputPhrases = { 47 | ...datepickerPhrases, 48 | dateAriaLabel: 'Select date', 49 | datePlaceholder: 'Select date', 50 | } 51 | -------------------------------------------------------------------------------- /packages/styled/src/testUtil.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import {render} from '@testing-library/react' 3 | import DatepickerContext, {datepickerContextDefaultValue} from './context/datepickerContext' 4 | 5 | function renderWithProviders(ui: any, options?: any, contextValues?: Record) { 6 | return render( 7 | 8 | {ui} 9 | , 10 | options, 11 | ) 12 | } 13 | 14 | export * from '@testing-library/react' 15 | export {renderWithProviders as render} 16 | -------------------------------------------------------------------------------- /packages/styled/src/utils/getThemeProp/getThemeProp.test.ts: -------------------------------------------------------------------------------- 1 | import getThemeProp from './getThemeProp' 2 | 3 | test('should return default prop', () => { 4 | expect(getThemeProp('primaryColor', 'red', undefined)).toBe('red') 5 | expect(getThemeProp('primaryColor', 'red', {})).toBe('red') 6 | expect(getThemeProp('primaryColor', 'red', {reactDatepicker: {}})).toBe('red') 7 | expect(getThemeProp('primaryColor', 'red', {reactDatepicker: {primaryColor: 'blue'}})).toBe('red') 8 | }) 9 | 10 | test('should return theme prop', () => { 11 | expect( 12 | getThemeProp('primaryColor', 'red', {reactDatepicker: {colors: {primaryColor: 'blue'}}}), 13 | ).toBe('blue') 14 | }) 15 | -------------------------------------------------------------------------------- /packages/styled/src/utils/getThemeProp/getThemeProp.ts: -------------------------------------------------------------------------------- 1 | function getThemeProp(themeProp: string, defaultValue: any, theme?: Record) { 2 | if ( 3 | theme && 4 | typeof theme === 'object' && 5 | theme.reactDatepicker && 6 | typeof theme.reactDatepicker === 'object' && 7 | theme.reactDatepicker.colors && 8 | typeof theme.reactDatepicker.colors === 'object' && 9 | theme.reactDatepicker.colors[themeProp] 10 | ) { 11 | return theme.reactDatepicker.colors[themeProp] 12 | } 13 | 14 | return defaultValue 15 | } 16 | 17 | export default getThemeProp 18 | -------------------------------------------------------------------------------- /packages/styled/src/utils/getThemeProp/index.ts: -------------------------------------------------------------------------------- 1 | import getThemeProp from './getThemeProp' 2 | 3 | export default getThemeProp 4 | -------------------------------------------------------------------------------- /packages/styled/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../config/tsconfig.base.json", 3 | "include": ["src"], 4 | "exclude": ["node_modules", "lib", "rollup.config.js", "../../node_modules"], 5 | "compilerOptions": { 6 | "types": ["jest", "./src/@types"] 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /prettier.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | arrowParens: 'avoid', 3 | bracketSpacing: false, 4 | jsxBracketSameLine: false, 5 | printWidth: 100, 6 | proseWrap: 'always', 7 | semi: false, 8 | singleQuote: true, 9 | tabWidth: 2, 10 | trailingComma: 'all', 11 | useTabs: false, 12 | } 13 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["config:base"], 3 | "rangeStrategy": "replace" 4 | } 5 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./config/tsconfig.base.json", 3 | "references": [{"path": "packages/hooks"}, {"path": "packages/styled"}], 4 | "exclude": ["node_modules", "**/lib"] 5 | } 6 | --------------------------------------------------------------------------------