├── .eslintignore
├── .eslintrc.json
├── .github
└── workflows
│ ├── main.yml
│ └── size.yml
├── .gitignore
├── .prettierrc
├── LICENSE
├── README.md
├── __mocks__
└── style-mock.ts
├── docs
├── .eslintrc.json
├── .gitignore
├── README.md
├── components
│ ├── all-badges.jsx
│ ├── all-badges.module.css
│ ├── badge.jsx
│ ├── demo-container.jsx
│ ├── demo-container.module.css
│ ├── edit-link.jsx
│ ├── example-embed.jsx
│ ├── example-embed.module.css
│ ├── features.jsx
│ ├── features.module.css
│ ├── footer.jsx
│ ├── footer.module.css
│ ├── limited-datepicker-demo.jsx
│ ├── limited-datepicker-demo.module.css
│ ├── main-picker.jsx
│ ├── main-picker.module.css
│ ├── time-picker-display-format-demo.jsx
│ ├── time-picker-display-format-demo.module.css
│ ├── time-picker-minutes-interval-demo.jsx
│ ├── time-picker-minutes-interval-demo.module.css
│ ├── week-starts-from-demo.jsx
│ └── week-starts-from-demo.module.css
├── jsconfig.json
├── next.config.js
├── package.json
├── pages
│ ├── _app.jsx
│ ├── _document.jsx
│ ├── _meta.json
│ ├── date-picker.mdx
│ ├── examples
│ │ ├── _meta.json
│ │ └── basic-usage.mdx
│ ├── getting-started.mdx
│ ├── index.mdx
│ ├── theming.mdx
│ ├── time-picker.mdx
│ └── utility-functions.mdx
├── public
│ ├── favicon.ico
│ ├── scripts
│ │ └── ronaldo-goat.js
│ └── vercel.svg
├── styles
│ └── globals.css
├── theme.config.js
└── yarn.lock
├── example
├── .npmignore
├── index.html
├── index.tsx
├── package.json
├── styles.css
├── tsconfig.json
└── yarn.lock
├── jest.config.js
├── package.json
├── src
├── components
│ └── select
│ │ ├── index.tsx
│ │ ├── option.tsx
│ │ └── styles.css
├── date-picker
│ ├── date-button.tsx
│ ├── header.tsx
│ ├── index.tsx
│ ├── methods.ts
│ ├── month-picker.tsx
│ ├── styles.css
│ ├── types.ts
│ └── year-picker.tsx
├── icons
│ ├── left-caret.tsx
│ ├── right-caret.tsx
│ ├── two-dots.tsx
│ └── types.ts
├── index.tsx
├── styles.css
├── time-picker
│ ├── index.tsx
│ ├── methods.ts
│ ├── styles.css
│ └── types.ts
└── util.ts
├── test
├── date-picker
│ ├── date-picker.test.tsx
│ └── methods.test.ts
├── time-picker
│ ├── methods.test.tsx
│ └── time-picker.test.tsx
└── utility.test.ts
├── tsconfig.json
├── tsdx.config.js
└── yarn.lock
/.eslintignore:
--------------------------------------------------------------------------------
1 | docs/
--------------------------------------------------------------------------------
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "browser": true,
4 | "es6": true
5 | },
6 | "extends": ["plugin:react/recommended", "airbnb"],
7 | "globals": {
8 | "Atomics": "readonly",
9 | "SharedArrayBuffer": "readonly"
10 | },
11 | "parser": "@typescript-eslint/parser",
12 | "parserOptions": {
13 | "ecmaFeatures": {
14 | "jsx": true
15 | },
16 | "ecmaVersion": 2021,
17 | "sourceType": "module"
18 | },
19 | "plugins": ["eslint-plugin-react", "@typescript-eslint/eslint-plugin"]
20 | }
21 |
--------------------------------------------------------------------------------
/.github/workflows/main.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 | on: [push]
3 | jobs:
4 | build:
5 | name: Build, lint, and test on Node ${{ matrix.node }} and ${{ matrix.os }}
6 |
7 | runs-on: ${{ matrix.os }}
8 | strategy:
9 | matrix:
10 | node: ['12.x']
11 | os: [ubuntu-latest, windows-latest]
12 |
13 | steps:
14 | - name: Checkout repo
15 | uses: actions/checkout@v2
16 |
17 | - name: Use Node ${{ matrix.node }}
18 | uses: actions/setup-node@v1
19 | with:
20 | node-version: ${{ matrix.node }}
21 |
22 | - name: Install deps and build (with cache)
23 | uses: bahmutov/npm-install@v1
24 |
25 | - name: Lint
26 | run: yarn lint
27 |
28 | - name: Test
29 | run: yarn test --ci --coverage --maxWorkers=2
30 |
31 | - name: Build
32 | run: yarn build
33 |
--------------------------------------------------------------------------------
/.github/workflows/size.yml:
--------------------------------------------------------------------------------
1 | name: size
2 | on: [pull_request]
3 | jobs:
4 | size:
5 | runs-on: ubuntu-latest
6 | env:
7 | CI_JOB_NUMBER: 1
8 | steps:
9 | - uses: actions/checkout@v1
10 | - uses: andresz1/size-limit-action@v1
11 | with:
12 | github_token: ${{ secrets.GITHUB_TOKEN }}
13 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.log
2 | .DS_Store
3 | node_modules
4 | .cache
5 | dist
6 | dev
7 | .parcel-cache
8 | coverage
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "printWidth": 80,
3 | "semi": true,
4 | "singleQuote": true,
5 | "trailingComma": "es5",
6 | "arrowParens": "always",
7 | "endOfLine": "lf",
8 | "jsxSingleQuote": false,
9 | "tabWidth": 2,
10 | "useTabs": false
11 | }
12 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 Siddharth Borderwala
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.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
sassy-datepicker
3 |
4 | [](https://badge.fury.io/js/sassy-datepicker)
5 | [](https://github.com/sassy-labs/datepicker/actions/workflows/main.yml)
6 | [](https://github.com/sassy-labs/datepicker#maintenance-status)
7 | [](https://bundlephobia.com/package/sassy-datepicker)
8 | [](https://github.com/sassy-labs/datepicker/issues)
9 | [](https://github.com/sassy-labs/datepicker/pulls)
10 |
11 | Beautiful, minimal, customizable and accessible date-picker and time-picker for react.
12 |
13 |

14 |
15 |
16 |
17 | Why use sassy-datepicker?
18 |
19 | - Beautiful picker
20 | - Smooth and slick transitions
21 | - Simple and Easy to Use
22 | - Fully Customizable
23 | - First Class Accessibility
24 | - Small bundle size
25 | - Extremely Performant
26 |
27 | ## Contents
28 |
29 | - [Contents](#contents)
30 | - [Installation and Usage](#installation-and-usage)
31 | - [Package Installation](#package-installation)
32 | - [Basic Usage](#basic-usage)
33 | - [Documentation](#documentation)
34 |
35 | ## Installation and Usage
36 |
37 | ### Package Installation
38 |
39 | ```sh
40 | yarn add sassy-datepicker
41 | # or
42 | npm install sassy-datepicker
43 | ```
44 |
45 | ### Basic Usage
46 |
47 | The default export from the library is the `DatePicker` component.
48 |
49 | ```jsx
50 | import { useState } from 'react';
51 | import DatePicker, { TimePicker } from 'sassy-datepicker';
52 | import 'sassy-datepicker/dist/styles.css';
53 |
54 | function DateInput() {
55 | const [date, setDate] = useState(new Date());
56 |
57 | const onChange = newDate => {
58 | console.log(`New date selected - ${newDate.toString()}`);
59 | setDate(newDate);
60 | };
61 |
62 | return ;
63 | }
64 |
65 | function TimeInput() {
66 | const [time, setTime] = useState({ hours: 15, minutes: 30 });
67 |
68 | const onChange = newTime => {
69 | console.log(`New time selected - ${newTime}`);
70 | setTime(newTime);
71 | };
72 |
73 | return ;
74 | }
75 | ```
76 |
77 | ## Documentation
78 |
79 | To view detailed documentation, go to [https://sassy-datepicker.netlify.app](https://sassy-datepicker.netlify.app)
80 |
81 |
82 | Powered By Netlify

83 |
84 |
--------------------------------------------------------------------------------
/__mocks__/style-mock.ts:
--------------------------------------------------------------------------------
1 | export default '';
2 |
--------------------------------------------------------------------------------
/docs/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "next/core-web-vitals",
3 | "rules": {
4 | "react/jsx-props-no-spreading": "off",
5 | "react/function-component-definition": "off",
6 | "jsx-a11y/label-has-associated-control": "off",
7 | "comma-dangle": "off",
8 | "react/jsx-one-expression-per-line": "off",
9 | "implicit-arrow-linebreak": "off",
10 | "arrow-body-style": "off",
11 | "object-curly-newline": "off"
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/docs/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # next.js
12 | /.next/
13 | /out/
14 |
15 | # production
16 | /build
17 |
18 | # misc
19 | .DS_Store
20 | *.pem
21 |
22 | # debug
23 | npm-debug.log*
24 | yarn-debug.log*
25 | yarn-error.log*
26 | .pnpm-debug.log*
27 |
28 | # local env files
29 | .env*.local
30 |
31 | # vercel
32 | .vercel
33 |
34 | # typescript
35 | *.tsbuildinfo
36 | next-env.d.ts
37 |
--------------------------------------------------------------------------------
/docs/README.md:
--------------------------------------------------------------------------------
1 | This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).
2 |
3 | ## Getting Started
4 |
5 | First, run the development server:
6 |
7 | ```bash
8 | npm run dev
9 | # or
10 | yarn dev
11 | ```
12 |
13 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
14 |
15 | You can start editing the page by modifying `pages/index.js`. The page auto-updates as you edit the file.
16 |
17 | [API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited in `pages/api/hello.js`.
18 |
19 | The `pages/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages.
20 |
21 | ## Learn More
22 |
23 | To learn more about Next.js, take a look at the following resources:
24 |
25 | - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
26 | - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
27 |
28 | You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!
29 |
30 | ## Deploy on Vercel
31 |
32 | The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
33 |
34 | Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.
35 |
--------------------------------------------------------------------------------
/docs/components/all-badges.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Badge from './badge';
3 | import styles from './all-badges.module.css';
4 |
5 | const AllBadges = () => (
6 |
7 |
12 |
17 |
22 |
27 |
32 |
37 |
38 | );
39 |
40 | export default AllBadges;
41 |
--------------------------------------------------------------------------------
/docs/components/all-badges.module.css:
--------------------------------------------------------------------------------
1 | .badges {
2 | display: flex;
3 | justify-content: center;
4 | align-items: center;
5 | margin-top: 1rem;
6 | }
7 |
8 | @media screen and (max-width: 42em) {
9 | .badges {
10 | display: none;
11 | }
12 | }
13 |
14 | .badges > a:not(:last-of-type) {
15 | margin-right: 0.25rem;
16 | }
17 |
18 | .badges > a {
19 | display: inline-block;
20 | }
21 |
--------------------------------------------------------------------------------
/docs/components/badge.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | const Badge = ({ href, src, alt }) => (
4 |
5 |
6 |
7 | );
8 |
9 | export default Badge;
10 |
--------------------------------------------------------------------------------
/docs/components/demo-container.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import styles from './demo-container.module.css';
3 |
4 | const DemoContainer = ({ children }) => (
5 | {children}
6 | );
7 |
8 | export default DemoContainer;
9 |
--------------------------------------------------------------------------------
/docs/components/demo-container.module.css:
--------------------------------------------------------------------------------
1 | .demo-container {
2 | width: 100%;
3 | border: none;
4 | border-radius: 1rem;
5 | padding: 2rem;
6 | background-color: var(--code-bg-color);
7 | margin-top: 2rem;
8 | }
9 |
--------------------------------------------------------------------------------
/docs/components/edit-link.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | const EditLink = ({ className, filePath, children }) => {
4 | const editUrl = `https://github.com/sassy-labs/datepicker/tree/main/docs/${filePath}`;
5 |
6 | return (
7 |
8 | {children}
9 |
10 | );
11 | };
12 |
13 | export default EditLink;
14 |
--------------------------------------------------------------------------------
/docs/components/example-embed.jsx:
--------------------------------------------------------------------------------
1 | import React, { useRef } from 'react';
2 | import { ArrowsOutSimple } from 'phosphor-react';
3 | import styles from './example-embed.module.css';
4 |
5 | const ExampleEmbed = ({ src, title }) => {
6 | const ref = useRef(null);
7 |
8 | const handleFullScreenRequest = () => {
9 | if (!ref.current) return;
10 | ref.current.requestFullscreen();
11 | };
12 |
13 | return (
14 |
15 |
25 |
33 |
40 |
41 | );
42 | };
43 |
44 | export default ExampleEmbed;
45 |
--------------------------------------------------------------------------------
/docs/components/example-embed.module.css:
--------------------------------------------------------------------------------
1 | .example-embed {
2 | width: 100%;
3 | height: 100%;
4 | }
5 |
6 | .example-embed--container {
7 | margin-top: 2rem;
8 | width: 100%;
9 | height: 80vh;
10 | }
11 |
12 | .example-embed--fs-btn {
13 | display: flex;
14 | justify-content: space-between;
15 | align-items: center;
16 | margin-bottom: 1rem;
17 | margin-left: auto;
18 | padding: 0.2rem 0.6rem;
19 | transition: all 200ms linear;
20 | border: none;
21 | border-radius: 0.5rem;
22 | }
23 |
24 | .example-embed--fs-btn > span {
25 | margin-right: 1rem;
26 | font-size: 0.8rem;
27 | }
28 |
--------------------------------------------------------------------------------
/docs/components/features.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {
3 | Sparkle,
4 | Cards,
5 | CodeSimple,
6 | PencilSimpleLine,
7 | Wheelchair,
8 | Package,
9 | Lightning,
10 | FileTs,
11 | } from 'phosphor-react';
12 | import styles from './features.module.css';
13 |
14 | const FeatureItem = ({ Icon, label }) => (
15 |
16 |
17 |
{label}
18 |
19 | );
20 |
21 | const Features = () => (
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 | );
33 |
34 | export default Features;
35 |
--------------------------------------------------------------------------------
/docs/components/features.module.css:
--------------------------------------------------------------------------------
1 | .features {
2 | display: grid;
3 | gap: 1rem;
4 | grid-template-columns: repeat(4, 1fr);
5 | max-width: 48rem;
6 | margin: 2rem auto;
7 | }
8 |
9 | .features--item {
10 | display: flex;
11 | align-items: center;
12 | justify-content: center;
13 | }
14 |
15 | .features--item__icon {
16 | font-size: 1.25rem;
17 | }
18 |
19 | .features--item__label {
20 | margin-left: 1rem;
21 | }
22 |
23 | @media screen and (max-width: 42em) {
24 | .features {
25 | grid-template-columns: repeat(2, 1fr);
26 | }
27 | }
28 |
29 | @media screen and (max-width: 28em) {
30 | .features--item {
31 | justify-content: flex-start;
32 | }
33 |
34 | .features--item__label {
35 | font-size: 0.75rem;
36 | margin-left: 0.5rem;
37 | }
38 |
39 | .features--item__icon {
40 | font-size: 1rem;
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/docs/components/footer.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import styles from './footer.module.css';
3 |
4 | const Footer = () => {
5 | return (
6 |
24 | );
25 | };
26 |
27 | export default Footer;
28 |
--------------------------------------------------------------------------------
/docs/components/footer.module.css:
--------------------------------------------------------------------------------
1 | .footer {
2 | display: flex;
3 | justify-content: space-between;
4 | align-items: center;
5 | width: 100%;
6 | padding: 4rem 3rem;
7 | color: currentColor;
8 | background-color: #6e767e1a;
9 | }
10 |
11 | .footer--logo {
12 | display: flex;
13 | justify-content: space-between;
14 | align-items: center;
15 | cursor: pointer;
16 | margin-right: auto;
17 | }
18 |
19 | .footer--logo__img {
20 | height: 1.5rem;
21 | display: inline-block;
22 | margin-left: 0.5rem;
23 | }
24 |
25 | @media screen and (max-width: 600px) {
26 | .footer {
27 | flex-direction: column;
28 | align-items: center;
29 | padding: 3rem 1.5rem;
30 | }
31 | .footer--logo {
32 | margin-right: 0;
33 | margin-bottom: 3rem;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/docs/components/limited-datepicker-demo.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 | import DatePicker from 'sassy-datepicker';
3 | import DemoContainer from './demo-container';
4 | import styles from './limited-datepicker-demo.module.css';
5 |
6 | const min = new Date(2001, 0, 1); // 1st January 2001
7 | const max = new Date(2030, 11, 31); // 31st December 2030
8 | const init = new Date(2001, 8, 30); // 30th September 2001
9 |
10 | const fn = (n) => n.toString().padStart(2, '0');
11 |
12 | const formatDateForInputValue = (d) => {
13 | return d
14 | ? `${d.getFullYear()}-${fn(d.getMonth() + 1)}-${fn(d.getDate())}`
15 | : null;
16 | };
17 |
18 | const LimitedDatePickerDemo = () => {
19 | const [minDate, setMinDate] = useState(min);
20 | const [maxDate, setMaxDate] = useState(max);
21 | const [date, setDate] = useState(init);
22 |
23 | const blockKeyStrokes = (e) => {
24 | e.preventDefault();
25 | e.stopPropagation();
26 | };
27 |
28 | return (
29 |
30 |
31 |
34 |
setMinDate(e.target.valueAsDate)}
39 | onKeyDown={blockKeyStrokes}
40 | />
41 |
42 |
43 |
46 |
setMaxDate(e.target.valueAsDate)}
51 | onKeyDown={blockKeyStrokes}
52 | />
53 |
54 |
61 |
62 | );
63 | };
64 |
65 | export default LimitedDatePickerDemo;
66 |
--------------------------------------------------------------------------------
/docs/components/limited-datepicker-demo.module.css:
--------------------------------------------------------------------------------
1 | .limited-dp--picker {
2 | margin: 0 auto;
3 | margin-top: 2rem;
4 | }
5 |
6 | .limited-dp--date-input {
7 | display: flex;
8 | margin-bottom: 1rem;
9 | }
10 |
11 | .limited-dp--date-input > label {
12 | font-weight: bold;
13 | margin-right: 2rem;
14 | }
15 |
--------------------------------------------------------------------------------
/docs/components/main-picker.jsx:
--------------------------------------------------------------------------------
1 | import { useState } from 'react';
2 | import DatePicker, { TimePicker } from 'sassy-datepicker';
3 | import styles from './main-picker.module.css';
4 |
5 | const MainPicker = () => {
6 | const [date, setDate] = useState(new Date());
7 | const [time, setTime] = useState();
8 |
9 | return (
10 |
11 |
16 |
17 |
18 | );
19 | };
20 |
21 | export default MainPicker;
22 |
--------------------------------------------------------------------------------
/docs/components/main-picker.module.css:
--------------------------------------------------------------------------------
1 | .main-picker--container {
2 | margin: 2.5rem 0;
3 | display: flex;
4 | justify-content: center;
5 | align-items: flex-start;
6 | }
7 |
8 | .main-picker {
9 | margin-right: 2rem;
10 | }
11 |
12 | .main-picker > .sdp--grid > .sdp--text {
13 | margin-top: 0;
14 | }
15 |
16 | @media screen and (max-width: 30em) {
17 | .main-picker--container {
18 | flex-direction: column;
19 | align-items: center;
20 | }
21 |
22 | .main-picker {
23 | margin-right: 0;
24 | margin-bottom: 2rem;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/docs/components/time-picker-display-format-demo.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 | import { TimePicker } from 'sassy-datepicker';
3 | import DemoContainer from './demo-container';
4 | import styles from './time-picker-display-format-demo.module.css';
5 |
6 | const TimePickerDisplayFormatDemo = () => {
7 | const [time, setTime] = useState();
8 | const [displayFormat, setDisplayFormat] = useState('12hr');
9 |
10 | return (
11 |
12 |
13 |
16 |
23 |
24 |
30 |
31 | );
32 | };
33 |
34 | export default TimePickerDisplayFormatDemo;
35 |
--------------------------------------------------------------------------------
/docs/components/time-picker-display-format-demo.module.css:
--------------------------------------------------------------------------------
1 | .display-format--picker {
2 | margin: 1rem auto 0;
3 | }
4 |
5 | .display-format--input {
6 | display: flex;
7 | }
8 |
9 | .display-format--input > label {
10 | font-weight: bold;
11 | margin-right: 2rem;
12 | }
13 |
--------------------------------------------------------------------------------
/docs/components/time-picker-minutes-interval-demo.jsx:
--------------------------------------------------------------------------------
1 | import React, { useCallback, useState } from 'react';
2 | import { TimePicker } from 'sassy-datepicker';
3 | import DemoContainer from './demo-container';
4 | import styles from './time-picker-minutes-interval-demo.module.css';
5 |
6 | const TimePickerMinutesIntervalDemo = () => {
7 | const [time, setTime] = useState();
8 | const [minutesInterval, setMinutesInterval] = useState(5);
9 |
10 | const handleChange = useCallback(
11 | ({ target }) => {
12 | const n = target.valueAsNumber;
13 | if (!Number.isNaN(n)) {
14 | if (!Number.isInteger(n)) {
15 | setMinutesInterval(Math.round(n));
16 | } else {
17 | setMinutesInterval(n);
18 | }
19 | } else {
20 | setMinutesInterval(0);
21 | }
22 | },
23 | [setMinutesInterval]
24 | );
25 |
26 | return (
27 |
28 |
29 |
32 |
39 |
40 |
46 |
47 | );
48 | };
49 |
50 | export default TimePickerMinutesIntervalDemo;
51 |
--------------------------------------------------------------------------------
/docs/components/time-picker-minutes-interval-demo.module.css:
--------------------------------------------------------------------------------
1 | .minutes-interval--picker {
2 | margin: 1rem auto 0;
3 | }
4 |
5 | .minutes-interval--input {
6 | display: flex;
7 | }
8 |
9 | .minutes-interval--input > label {
10 | font-weight: bold;
11 | margin-right: 2rem;
12 | }
13 |
--------------------------------------------------------------------------------
/docs/components/week-starts-from-demo.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 | import DatePicker from 'sassy-datepicker';
3 | import DemoContainer from './demo-container';
4 | import styles from './week-starts-from-demo.module.css';
5 |
6 | const WeekStartsFromDemo = () => {
7 | const [weekStartsFrom, setWeekStartsFrom] = useState('Monday');
8 | const [date, setDate] = useState(new Date());
9 |
10 | return (
11 |
12 |
13 |
16 |
24 |
25 |
31 |
32 | );
33 | };
34 |
35 | export default WeekStartsFromDemo;
36 |
--------------------------------------------------------------------------------
/docs/components/week-starts-from-demo.module.css:
--------------------------------------------------------------------------------
1 | .week-starts--picker {
2 | margin: 2rem auto 0;
3 | }
4 |
5 | .week-starts--input {
6 | display: flex;
7 | }
8 |
9 | .week-starts--input > label {
10 | font-weight: bold;
11 | margin-right: 2rem;
12 | }
13 |
--------------------------------------------------------------------------------
/docs/jsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "baseUrl": ".",
4 | "target": "es6",
5 | "paths": {
6 | "components/*": ["components/*"]
7 | }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/docs/next.config.js:
--------------------------------------------------------------------------------
1 | const nextra = require('nextra');
2 |
3 | const withNextra = nextra({
4 | theme: 'nextra-theme-docs',
5 | themeConfig: './theme.config.js',
6 | // optional: add `unstable_staticImage: true` to enable Nextra's auto image import
7 | });
8 |
9 | module.exports = withNextra();
10 |
--------------------------------------------------------------------------------
/docs/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "docs",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "dev": "next dev",
7 | "build": "next build",
8 | "start": "next start",
9 | "lint": "next lint"
10 | },
11 | "dependencies": {
12 | "next": "^13.0.6",
13 | "nextra": "^2.0.1",
14 | "nextra-theme-docs": "^2.0.1",
15 | "phosphor-react": "^1.4.1",
16 | "react": "18.2.0",
17 | "react-dom": "18.2.0",
18 | "sassy-datepicker": "../dist/"
19 | },
20 | "devDependencies": {
21 | "eslint": "8.23.0",
22 | "eslint-config-next": "12.3.0"
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/docs/pages/_app.jsx:
--------------------------------------------------------------------------------
1 | import { useEffect } from 'react';
2 | import { useRouter } from 'next/router';
3 | import 'nextra-theme-docs/style.css';
4 | import 'sassy-datepicker/styles.css';
5 | import '../styles/globals.css';
6 |
7 | export default function MyApp({ Component, pageProps }) {
8 | const router = useRouter();
9 |
10 | useEffect(() => {
11 | if (typeof window !== 'undefined' && window.goatcounter) {
12 | window.goatcounter.count({
13 | path: router.asPath,
14 | });
15 | }
16 | }, [router]);
17 |
18 | return ;
19 | }
20 |
--------------------------------------------------------------------------------
/docs/pages/_document.jsx:
--------------------------------------------------------------------------------
1 | import Document, { Html, Head, Main, NextScript } from 'next/document';
2 |
3 | class MyDocument extends Document {
4 | render() {
5 | return (
6 |
7 |
8 | {/* add "allow_local": true to data-goatcounter-settings to test in local env */}
9 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | );
22 | }
23 | }
24 |
25 | export default MyDocument;
26 |
--------------------------------------------------------------------------------
/docs/pages/_meta.json:
--------------------------------------------------------------------------------
1 | {
2 | "index": {
3 | "title": "Introduction",
4 | "type": "doc"
5 | },
6 | "getting-started": {
7 | "title": "Getting Started",
8 | "type": "doc"
9 | },
10 | "theming": {
11 | "title": "Theming",
12 | "type": "doc"
13 | },
14 | "date-picker": {
15 | "title": "Date Picker",
16 | "type": "doc"
17 | },
18 | "time-picker": {
19 | "title": "Time Picker",
20 | "type": "doc"
21 | },
22 | "utility-functions": {
23 | "title": "Utility Functions",
24 | "type": "doc"
25 | },
26 | "examples": {
27 | "title": "Examples",
28 | "type": "doc"
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/docs/pages/date-picker.mdx:
--------------------------------------------------------------------------------
1 | import { Callout } from 'nextra-theme-docs';
2 | import LimitedDatepickerDemo from 'components/limited-datepicker-demo';
3 | import WeekStartsFromDemo from 'components/week-starts-from-demo';
4 |
5 | ## Basic Usage
6 |
7 | The `DatePicker` is the default export of the library.
8 |
9 | ```jsx
10 | import React, { useState } from 'react';
11 | import DatePicker from 'sassy-datepicker';
12 |
13 | function Example() {
14 | const [date, setDate] = useState(new Date());
15 |
16 | const onChange = (newDate) => {
17 | console.log(`New date selected - ${newDate.toString()}`);
18 | setDate(newDate);
19 | };
20 |
21 | return ;
22 | }
23 | ```
24 |
25 |
26 | The DatePicker is a [controlled
27 | component](https://reactjs.org/docs/forms.html#controlled-components) so the
28 | `onChange` and `value` props are required. If you don't pass them, the picker
29 | will not re-render with the changed date.
30 |
31 |
32 | ## Customization
33 |
34 | ### Date Limits
35 |
36 | You can set the date limits for the DatePicker using the `minDate` and `maxDate` props. They accept a JavaScript `Date` as props.
37 |
38 | **Default values**
39 |
40 | - `minDate` = 1st January 1900
41 | - `maxDate` = 100 years from now
42 |
43 | ```jsx
44 | const minDate = new Date(2000, 0, 1); // 1st January 2000
45 | const maxDate = new Date(2099, 11, 31); // 31st December 2099
46 |
47 | function LimitedPicker() {
48 | const [date, setDate] = useState(new Date());
49 |
50 | return (
51 |
57 | );
58 | }
59 | ```
60 |
61 | Try out changing the limits here and see how the DatePicker takes care of the rest
62 |
63 |
64 |
65 | It is guaranteed that the DatePicker won't allow selection of a date outside the limits.
66 |
67 |
68 | As the limits are set by the developer, the developer needs to take care of
69 | the logical consistency. If the maxDate is smaller than minDate, or
70 | vice-versa, all the dates will be disabled in the picker.
71 |
72 |
73 | ### First Day of Week
74 |
75 | By default, the date picker has Sunday as the first day of the week but this can be changed to Monday using the `weekStartsFrom` prop. It accepts two values - `"Monday"` or `"Sunday"`.
76 |
77 | ```jsx
78 | function WeekStartsFromMonday() {
79 | const [date, setDate] = useState(new Date());
80 |
81 | return ;
82 | }
83 | ```
84 |
85 | Here's a demo for you to see how the DatePicker updates when the `weekStartsFrom` property is changed
86 |
87 |
88 |
89 | ## Props
90 |
91 | Here is a list of props and their types and description for `DatePicker`
92 |
93 | | Name | Type | Description |
94 | | :------------- | :---------------------: | :---------------------------------------------------------------------------- |
95 | | onChange\* | `(date: Date) => void;` | This function is triggered every time the selected date in the picker changes |
96 | | value\* | `Date` | The selected date |
97 | | weekStartsFrom | `'Sunday' \| 'Monday'` | Some configuration options for the DatePicker |
98 | | minDate | `Date` | The lowest date value allowed |
99 | | maxDate | `Date` | The highest date value allowed |
100 | | disabled | `boolean` | If the date-picker is disabled |
101 | | className | `string` | The className prop |
102 | | ref | `React.ForwardRef` | The ref prop |
103 |
104 | And all the other react props for an `HTMLDivElement`.
105 |
106 | > **Required Props**: Items marked with an asterisk are required
107 |
--------------------------------------------------------------------------------
/docs/pages/examples/_meta.json:
--------------------------------------------------------------------------------
1 | {
2 | "basic-usage": {
3 | "title": "Basic Usage",
4 | "type": "doc"
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/docs/pages/examples/basic-usage.mdx:
--------------------------------------------------------------------------------
1 | import ExampleEmbed from 'components/example-embed';
2 |
3 |
7 |
--------------------------------------------------------------------------------
/docs/pages/getting-started.mdx:
--------------------------------------------------------------------------------
1 | import { Callout } from 'nextra-theme-docs';
2 |
3 | ## Installation
4 |
5 | If you are using a package manager such as npm or yarn, simply run -
6 |
7 | ```sh
8 | yarn add sassy-datepicker
9 | # or
10 | npm install sassy-datepicker
11 | ```
12 |
13 | Delivery through CDN -
14 |
15 | ```html
16 |
20 |
24 | ```
25 |
26 | ## Imports
27 |
28 | The library has a default export and a named export. You will also need to import the stylesheet for the components.
29 |
30 | ```jsx
31 | import DatePicker, { TimePicker } from 'sassy-datepicker';
32 | import 'sassy-datepicker/dist/styles.css';
33 | ```
34 |
35 |
36 | Make sure to load/import both javascript and css files.
37 |
38 |
--------------------------------------------------------------------------------
/docs/pages/index.mdx:
--------------------------------------------------------------------------------
1 | import { Callout } from 'nextra-theme-docs';
2 | import AllBadges from 'components/all-badges';
3 | import Features from 'components/features';
4 | import MainPicker from 'components/main-picker';
5 |
6 | {sassy-datepicker
}
7 |
8 | {Beautiful, minimal, customizable and accessible date-picker and time-picker for react.
}
9 |
10 |
11 |
12 |
13 | [Get Started](/getting-started) · [Examples](/examples/basic-usage) · [GitHub
14 | Repository](https://github.com/sassy-labs/datepicker)
15 |
16 |
17 |
--------------------------------------------------------------------------------
/docs/pages/theming.mdx:
--------------------------------------------------------------------------------
1 | import { Callout } from 'nextra-theme-docs';
2 |
3 | ## Overview
4 |
5 | Sassy DatePicker and TimePicker both have carefully selected beautiful default styles. We understand that based on your needs and design choices, you may need to change the styles for the pickers.
6 |
7 | We provide some default theme variables (css3 custom properties) that you can use for easy customization of the styles. [Here's](#example) an example where we implement a dark mode theme.
8 |
9 | ## Theme Variables
10 |
11 | Here is a list of all theming variables that you can use along with their defualt value and descriptions
12 |
13 | #### _--font_
14 |
15 | - **Description** - The font-famliy used in the pickers
16 | - **Defualt Value** - `inherit`
17 |
18 | #### _--shadow_
19 |
20 | - **Description** - Shadow used for buttons and dropdown options
21 | - **Defualt Value** - `rgba(0, 0, 0, 0) 0px 0px 0px 0px, rgba(0, 0, 0, 0) 0px 0px 0px 0px, rgba(0, 0, 0, 0.1) 0px 1px 3px 0px, rgba(0, 0, 0, 0.06) 0px 1px 2px 0px`
22 |
23 | #### _--shadow-md_
24 |
25 | - **Description** - Shadow used for dropdown and the pickers containers
26 | - **Defualt Value** - `rgba(0, 0, 0, 0) 0px 0px 0px 0px, rgba(0, 0, 0, 0) 0px 0px 0px 0px, rgba(0, 0, 0, 0.1) 0px 4px 6px -1px, rgba(0, 0, 0, 0.06) 0px 2px 4px -1px`
27 |
28 | #### _--theme-color_
29 |
30 | - **Description** - Main theme color for stuff like selection
31 | - **Defualt Value** - `#60a5fa`
32 |
33 | #### _--text-color_
34 |
35 | - **Description** - Color of the text
36 | - **Defualt Value** - `#1f1f1f`
37 |
38 | #### _--background_
39 |
40 | - **Description** - background for the picker
41 | - **Defualt Value** - `#ffffff`
42 |
43 | #### _--btn-background_
44 |
45 | - **Description** - background for the date pickers buttons
46 | - **Defualt Value** - `#ffffff`
47 |
48 | #### _--select-background_
49 |
50 | - **Description** - background for the dropdown
51 | - **Defualt Value** - `#ffffff`
52 |
53 | #### _--option-background_
54 |
55 | - **Description** - background color for the options inside the dropdown
56 | - **Defualt Value** - `#ffffff`
57 |
58 | #### _--selected-date-color_
59 |
60 | - **Description** - text color for the selected date
61 | - **Defualt Value** - `#ffffff`
62 |
63 | #### _--disabled-color_
64 |
65 | - **Description** - text color for disabled state
66 | - **Defualt Value** - `#bdbdbd`
67 |
68 | #### _--disabled-opacity_
69 |
70 | - **Description** - opacity for disabled state
71 | - **Defualt Value** - `50%`
72 |
73 | #### _--outline_
74 |
75 | - **Description** - outline for various elements
76 | - **Defualt Value** - `1px solid #cbd5e1`
77 |
78 | #### _--ring-shadow_
79 |
80 | - **Description** - a box shadow definition for a ring
81 | - **Defualt Value** - `0px 0px 0px 2px hsla(213, 94%, 68%, 0.7)`
82 |
83 | ## Advance Customization
84 |
85 | If you would like to get finer control over the styles of the elements, you have two options -
86 |
87 | 1. `className` prop -
88 | The components have support for the `className` prop, using this you can add your own styling.
89 |
90 | 2. Overriding styles -
91 | For this you can define custom styles in your stylesheets for different elements using their class names which can be found in the DOM tree inspector.
92 |
93 | ## Example
94 |
95 | I am going to show you how to customize the styles for a dark mode theme.
96 |
97 | To scope the styles to dark mode only, you will need a selector. Based on what logic you are using to switch between dark and light mode, you can use that selector. In this example, I am using the `dark` class on the `html` element.
98 |
99 | I will use the following selector -
100 |
101 | ```css
102 | html.dark
103 | ```
104 |
105 | Say you are using `data-theme` attribute on the `html` element to switch between dark and light mode, you can use the following selector -
106 |
107 | ```css
108 | html[data-theme='dark']
109 | ```
110 |
111 | Open your global stylesheet and add the following code -
112 |
113 | ```css
114 | html.dark .sdp,
115 | html.dark .stp {
116 | background-color: #222222;
117 | --disabled-color: #555555;
118 | --outline: 1px solid #555555;
119 | color: #e1e1e1;
120 | }
121 |
122 | html.dark .sdp button,
123 | html.dark .stp button,
124 | html.dark .sassy--select__dropdown {
125 | background-color: #222222;
126 | }
127 |
128 | html.dark .sdp .sassy--option__active,
129 | html.dark .sdp .sassy--option:hover,
130 | html.dark .stp .sassy--option__active,
131 | html.dark .stp .sassy--option:hover {
132 | background-color: var(--theme-color);
133 | }
134 |
135 | html.dark .sdp button.sdp--date-btn__selected {
136 | background-color: var(--theme-color);
137 | }
138 |
139 | html.light {
140 | --code-bg-color: hsla(212deg, 100%, 39%, 5%);
141 | }
142 |
143 | html.dark {
144 | --code-bg-color: hsla(212deg, 100%, 77%, 10%);
145 | }
146 | ```
147 |
148 | For understanding the selectors I have used in this, you can refer to the [above list](#theme-variables)
149 |
--------------------------------------------------------------------------------
/docs/pages/time-picker.mdx:
--------------------------------------------------------------------------------
1 | import { Callout } from 'nextra-theme-docs';
2 | import TimePickerDisplayFormatDemo from 'components/time-picker-display-format-demo';
3 | import TimePickerMinutesIntervalDemo from 'components/time-picker-minutes-interval-demo';
4 |
5 | ## Basic Usage
6 |
7 | The `TimePicker` is a named export of the library.
8 |
9 | ```jsx
10 | import React, { useState } from 'react';
11 | import { TimePicker, getCurrentTime } from 'sassy-datepicker';
12 |
13 | function Example() {
14 | const [time, setTime] = useState(getCurrentTime());
15 |
16 | const onChange = (newTime) => {
17 | console.log(`New time selected - ${newTime.hours}:${newTime.minutes}`);
18 | setTime(newTime);
19 | };
20 |
21 | return ;
22 | }
23 | ```
24 |
25 | The library exports a utility function called `getCurrentTime` which you can use to get the current time in the format being used by the time-picker.
26 |
27 | The `Time` structure looks like the following
28 |
29 | ```js
30 | const time = {
31 | hours: 10,
32 | minutes: 30,
33 | };
34 | ```
35 |
36 |
37 | The TimePicker is a [controlled
38 | component](https://reactjs.org/docs/forms.html#controlled-components) so the
39 | `onChange` and `value` props are required. If you don't pass them, the picker
40 | will not re-render with the changed time.
41 |
42 |
43 | ## Customization
44 |
45 | ### Minutes Interval
46 |
47 | You can choose what options will be shown in the minute selection dropdown. This is regulated by the `minutesInterval` prop.
48 |
49 | **Default value**
50 |
51 | - `minutesInterval` = 5
52 |
53 | ```jsx
54 | import React, { useState } from 'react';
55 | import { TimePicker } from 'sassy-datepicker';
56 |
57 | const minutesInterval = 5;
58 |
59 | function Example() {
60 | const [time, setTime] = useState({ hours: 15, minutes: 30 });
61 |
62 | const onChange = (newTime) => {
63 | console.log(`New time selected - ${newTime.hours}:${newTime.minutes}`);
64 | setTime(newTime);
65 | };
66 |
67 | return (
68 |
73 | );
74 | }
75 | ```
76 |
77 | Try out changing the display format here and see how the TimePicker updates
78 |
79 |
80 |
81 | ### Time Format
82 |
83 | The time picker supports two different time display formats - `12hr` and `24hr`.
84 |
85 | **Default value**
86 |
87 | - `displayFormat` = '12hr'
88 |
89 | ```jsx
90 | import React, { useState } from 'react';
91 | import { TimePicker } from 'sassy-datepicker';
92 |
93 | const displayFormat = '24hr';
94 |
95 | function Example() {
96 | const [time, setTime] = useState({ hours: 15, minutes: 30 });
97 |
98 | const onChange = (newTime) => {
99 | console.log(`New time selected - ${newTime.hours}:${newTime.minutes}`);
100 | setTime(newTime);
101 | };
102 |
103 | return (
104 |
109 | );
110 | }
111 | ```
112 |
113 | Try out changing the display format here and see how the TimePicker updates
114 |
115 |
116 |
117 | ## Props
118 |
119 | | Name | Type | Description |
120 | | :-------------- | :---------------------: | :---------------------------------------------------------------------------- |
121 | | onChange\* | `(date: Time) => void;` | This function is triggered every time the selected time in the picker changes |
122 | | value\* | `Time` | The selected date |
123 | | minutesInterval | `number` | Time interval between the options of minutes dropdown |
124 | | displayFormat | `'12hr' \| '24hr'` | The display format for the time in the Picker |
125 | | disabled | `boolean` | If the time-picker is disabled |
126 | | className | `string` | The className prop |
127 | | ref | `React.ForwardRef` | The ref prop |
128 |
129 | And all the other react props for an `HTMLDivElement`.
130 |
131 | > **Required Props**: Items marked with an asterisk are required
132 |
--------------------------------------------------------------------------------
/docs/pages/utility-functions.mdx:
--------------------------------------------------------------------------------
1 | ## Useful Functions
2 |
3 | The library has exported a few utility functions that can come in handy while working the the DatePicker and TimePicker.
4 |
5 | #### `getCurrentTime`
6 |
7 | This function returns the current time in the format used by the `TimePicker`
8 |
9 | ```js
10 | // { hours: number, minutes: number }
11 | const time = getCurrentTime();
12 | ```
13 |
14 | #### `convertDateToTime`
15 |
16 | This function accepts a date and returns the time in the format used by the `TimePicker`
17 |
18 | ```js
19 | // { hours: 0, minutes: 0 }
20 | const time = convertDateToTime(new Date(2001, 8, 30));
21 | ```
22 |
23 | #### `convertTimeToDate`
24 |
25 | This function accepts a time and an optional date argument and returns a date according to the inputs
26 |
27 | ```js
28 | const time = { hours: 15, minutes: 30 };
29 |
30 | const date1 = convertTimeToDate(time);
31 | // date1 has the current day, month and year with the time set to 15:30
32 |
33 | const date2 = convertTimeToDate(time, new Date(2001, 8, 30));
34 | // date2 has 30th September 2001, month and year with the time set to 15:30
35 | ```
36 |
--------------------------------------------------------------------------------
/docs/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/siddharthborderwala/sassy-datepicker/a943081c474c1eba40c289245d19c70da6a875d9/docs/public/favicon.ico
--------------------------------------------------------------------------------
/docs/public/scripts/ronaldo-goat.js:
--------------------------------------------------------------------------------
1 | // GoatCounter: https://www.goatcounter.com
2 | // This file (and *only* this file) is released under the ISC license:
3 | // https://opensource.org/licenses/ISC
4 | (function() {
5 | 'use strict';
6 |
7 | if (window.goatcounter && window.goatcounter.vars)
8 | // Compatibility with very old version; do not use.
9 | window.goatcounter = window.goatcounter.vars;
10 | else window.goatcounter = window.goatcounter || {};
11 |
12 | // Load settings from data-goatcounter-settings.
13 | var s = document.querySelector('script[data-goatcounter]');
14 | if (s && s.dataset.goatcounterSettings) {
15 | try {
16 | var set = JSON.parse(s.dataset.goatcounterSettings);
17 | } catch (err) {
18 | console.error('invalid JSON in data-goatcounter-settings: ' + err);
19 | }
20 | for (var k in set)
21 | if (
22 | [
23 | 'no_onload',
24 | 'no_events',
25 | 'allow_local',
26 | 'allow_frame',
27 | 'path',
28 | 'title',
29 | 'referrer',
30 | 'event',
31 | ].indexOf(k) > -1
32 | )
33 | window.goatcounter[k] = set[k];
34 | }
35 |
36 | var enc = encodeURIComponent;
37 |
38 | // Get all data we're going to send off to the counter endpoint.
39 | var get_data = function(vars) {
40 | var data = {
41 | p: vars.path === undefined ? goatcounter.path : vars.path,
42 | r: vars.referrer === undefined ? goatcounter.referrer : vars.referrer,
43 | t: vars.title === undefined ? goatcounter.title : vars.title,
44 | e: !!(vars.event || goatcounter.event),
45 | s: [
46 | window.screen.width,
47 | window.screen.height,
48 | window.devicePixelRatio || 1,
49 | ],
50 | b: is_bot(),
51 | q: location.search,
52 | };
53 |
54 | var rcb, pcb, tcb; // Save callbacks to apply later.
55 | if (typeof data.r === 'function') rcb = data.r;
56 | if (typeof data.t === 'function') tcb = data.t;
57 | if (typeof data.p === 'function') pcb = data.p;
58 |
59 | if (is_empty(data.r)) data.r = document.referrer;
60 | if (is_empty(data.t)) data.t = document.title;
61 | if (is_empty(data.p)) data.p = get_path();
62 |
63 | if (rcb) data.r = rcb(data.r);
64 | if (tcb) data.t = tcb(data.t);
65 | if (pcb) data.p = pcb(data.p);
66 | return data;
67 | };
68 |
69 | // Check if a value is "empty" for the purpose of get_data().
70 | var is_empty = function(v) {
71 | return v === null || v === undefined || typeof v === 'function';
72 | };
73 |
74 | // See if this looks like a bot; there is some additional filtering on the
75 | // backend, but these properties can't be fetched from there.
76 | var is_bot = function() {
77 | // Headless browsers are probably a bot.
78 | var w = window,
79 | d = document;
80 | if (w.callPhantom || w._phantom || w.phantom) return 150;
81 | if (w.__nightmare) return 151;
82 | if (d.__selenium_unwrapped || d.__webdriver_evaluate || d.__driver_evaluate)
83 | return 152;
84 | if (navigator.webdriver) return 153;
85 | return 0;
86 | };
87 |
88 | // Object to urlencoded string, starting with a ?.
89 | var urlencode = function(obj) {
90 | var p = [];
91 | for (var k in obj)
92 | if (
93 | obj[k] !== '' &&
94 | obj[k] !== null &&
95 | obj[k] !== undefined &&
96 | obj[k] !== false
97 | )
98 | p.push(enc(k) + '=' + enc(obj[k]));
99 | return '?' + p.join('&');
100 | };
101 |
102 | // Show a warning in the console.
103 | var warn = function(msg) {
104 | if (console && 'warn' in console) console.warn('goatcounter: ' + msg);
105 | };
106 |
107 | // Get the endpoint to send requests to.
108 | var get_endpoint = function() {
109 | var s = document.querySelector('script[data-goatcounter]');
110 | if (s && s.dataset.goatcounter) return s.dataset.goatcounter;
111 | return goatcounter.endpoint || window.counter; // counter is for compat; don't use.
112 | };
113 |
114 | // Get current path.
115 | var get_path = function() {
116 | var loc = location,
117 | c = document.querySelector('link[rel="canonical"][href]');
118 | if (c) {
119 | // May be relative or point to different domain.
120 | var a = document.createElement('a');
121 | a.href = c.href;
122 | if (
123 | a.hostname.replace(/^www\./, '') ===
124 | location.hostname.replace(/^www\./, '')
125 | )
126 | loc = a;
127 | }
128 | return loc.pathname + loc.search || '/';
129 | };
130 |
131 | // Run function after DOM is loaded.
132 | var on_load = function(f) {
133 | if (document.body === null)
134 | document.addEventListener(
135 | 'DOMContentLoaded',
136 | function() {
137 | f();
138 | },
139 | false
140 | );
141 | else f();
142 | };
143 |
144 | // Filter some requests that we (probably) don't want to count.
145 | goatcounter.filter = function() {
146 | if (
147 | 'visibilityState' in document &&
148 | document.visibilityState === 'prerender'
149 | )
150 | return 'visibilityState';
151 | if (!goatcounter.allow_frame && location !== parent.location)
152 | return 'frame';
153 | if (
154 | !goatcounter.allow_local &&
155 | location.hostname.match(
156 | /(localhost$|^127\.|^10\.|^172\.(1[6-9]|2[0-9]|3[0-1])\.|^192\.168\.|^0\.0\.0\.0$)/
157 | )
158 | )
159 | return 'localhost';
160 | if (!goatcounter.allow_local && location.protocol === 'file:')
161 | return 'localfile';
162 | if (localStorage && localStorage.getItem('skipgc') === 't')
163 | return 'disabled with #toggle-goatcounter';
164 | return false;
165 | };
166 |
167 | // Get URL to send to GoatCounter.
168 | window.goatcounter.url = function(vars) {
169 | var data = get_data(vars || {});
170 | if (data.p === null)
171 | // null from user callback.
172 | return;
173 | data.rnd = Math.random()
174 | .toString(36)
175 | .substr(2, 5); // Browsers don't always listen to Cache-Control.
176 |
177 | var endpoint = get_endpoint();
178 | if (!endpoint) return warn('no endpoint found');
179 |
180 | return endpoint + urlencode(data);
181 | };
182 |
183 | // Count a hit.
184 | window.goatcounter.count = function(vars) {
185 | var f = goatcounter.filter();
186 | if (f) return warn('not counting because of: ' + f);
187 |
188 | var url = goatcounter.url(vars);
189 | if (!url) return warn('not counting because path callback returned null');
190 |
191 | var img = document.createElement('img');
192 | img.src = url;
193 | img.style.position = 'absolute'; // Affect layout less.
194 | img.style.bottom = '0px';
195 | img.style.width = '1px';
196 | img.style.height = '1px';
197 | img.loading = 'eager';
198 | img.setAttribute('alt', '');
199 | img.setAttribute('aria-hidden', 'true');
200 |
201 | var rm = function() {
202 | if (img && img.parentNode) img.parentNode.removeChild(img);
203 | };
204 | img.addEventListener('load', rm, false);
205 | document.body.appendChild(img);
206 | };
207 |
208 | // Get a query parameter.
209 | window.goatcounter.get_query = function(name) {
210 | var s = location.search.substr(1).split('&');
211 | for (var i = 0; i < s.length; i++)
212 | if (s[i].toLowerCase().indexOf(name.toLowerCase() + '=') === 0)
213 | return s[i].substr(name.length + 1);
214 | };
215 |
216 | // Track click events.
217 | window.goatcounter.bind_events = function() {
218 | if (!document.querySelectorAll)
219 | // Just in case someone uses an ancient browser.
220 | return;
221 |
222 | var send = function(elem) {
223 | return function() {
224 | goatcounter.count({
225 | event: true,
226 | path: elem.dataset.goatcounterClick || elem.name || elem.id || '',
227 | title:
228 | elem.dataset.goatcounterTitle ||
229 | elem.title ||
230 | (elem.innerHTML || '').substr(0, 200) ||
231 | '',
232 | referrer:
233 | elem.dataset.goatcounterReferrer ||
234 | elem.dataset.goatcounterReferral ||
235 | '',
236 | });
237 | };
238 | };
239 |
240 | Array.prototype.slice
241 | .call(document.querySelectorAll('*[data-goatcounter-click]'))
242 | .forEach(function(elem) {
243 | if (elem.dataset.goatcounterBound) return;
244 | var f = send(elem);
245 | elem.addEventListener('click', f, false);
246 | elem.addEventListener('auxclick', f, false); // Middle click.
247 | elem.dataset.goatcounterBound = 'true';
248 | });
249 | };
250 |
251 | // Add a "visitor counter" frame or image.
252 | window.goatcounter.visit_count = function(opt) {
253 | on_load(function() {
254 | opt = opt || {};
255 | opt.type = opt.type || 'html';
256 | opt.append = opt.append || 'body';
257 | opt.path = opt.path || get_path();
258 | opt.attr = opt.attr || {
259 | width: '200',
260 | height: opt.no_branding ? '60' : '80',
261 | };
262 |
263 | opt.attr['src'] =
264 | get_endpoint() + 'er/' + enc(opt.path) + '.' + enc(opt.type) + '?';
265 | if (opt.no_branding) opt.attr['src'] += '&no_branding=1';
266 | if (opt.style) opt.attr['src'] += '&style=' + enc(opt.style);
267 | if (opt.start) opt.attr['src'] += '&start=' + enc(opt.start);
268 | if (opt.end) opt.attr['src'] += '&end=' + enc(opt.end);
269 |
270 | var tag = { png: 'img', svg: 'img', html: 'iframe' }[opt.type];
271 | if (!tag) return warn('visit_count: unknown type: ' + opt.type);
272 |
273 | if (opt.type === 'html') {
274 | opt.attr['frameborder'] = '0';
275 | opt.attr['scrolling'] = 'no';
276 | }
277 |
278 | var d = document.createElement(tag);
279 | for (var k in opt.attr) d.setAttribute(k, opt.attr[k]);
280 |
281 | var p = document.querySelector(opt.append);
282 | if (!p) return warn('visit_count: append not found: ' + opt.append);
283 | p.appendChild(d);
284 | });
285 | };
286 |
287 | // Make it easy to skip your own views.
288 | if (location.hash === '#toggle-goatcounter') {
289 | if (localStorage.getItem('skipgc') === 't') {
290 | localStorage.removeItem('skipgc', 't');
291 | alert('GoatCounter tracking is now ENABLED in this browser.');
292 | } else {
293 | localStorage.setItem('skipgc', 't');
294 | alert(
295 | 'GoatCounter tracking is now DISABLED in this browser until ' +
296 | location +
297 | ' is loaded again.'
298 | );
299 | }
300 | }
301 |
302 | if (!goatcounter.no_onload)
303 | on_load(function() {
304 | // 1. Page is visible, count request.
305 | // 2. Page is not yet visible; wait until it switches to 'visible' and count.
306 | // See #487
307 | if (
308 | !('visibilityState' in document) ||
309 | document.visibilityState === 'visible'
310 | )
311 | goatcounter.count();
312 | else {
313 | var f = function(e) {
314 | if (document.visibilityState !== 'visible') return;
315 | document.removeEventListener('visibilitychange', f);
316 | goatcounter.count();
317 | };
318 | document.addEventListener('visibilitychange', f);
319 | }
320 |
321 | if (!goatcounter.no_events) goatcounter.bind_events();
322 | });
323 | })();
324 |
--------------------------------------------------------------------------------
/docs/public/vercel.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/docs/styles/globals.css:
--------------------------------------------------------------------------------
1 | html,
2 | body {
3 | box-sizing: border-box;
4 | }
5 |
6 | .heading {
7 | font-size: 2rem;
8 | font-weight: bold;
9 | text-align: center;
10 | margin-top: 2rem;
11 | }
12 |
13 | .heading--sub {
14 | font-size: 1rem;
15 | text-align: center;
16 | margin-top: 1rem;
17 | }
18 |
19 | article.docs-container > main {
20 | width: 100%;
21 | }
22 |
23 | html.dark .sdp,
24 | html.dark .stp {
25 | background-color: #222222;
26 | --disabled-color: #555555;
27 | --outline: 1px solid #555555;
28 | color: #e1e1e1;
29 | }
30 |
31 | html.dark .sdp button,
32 | html.dark .stp button,
33 | html.dark .sassy--select__dropdown {
34 | background-color: #222222;
35 | }
36 |
37 | html.dark .sdp .sassy--option__active,
38 | html.dark .sdp .sassy--option:hover,
39 | html.dark .stp .sassy--option__active,
40 | html.dark .stp .sassy--option:hover {
41 | background-color: var(--theme-color);
42 | }
43 |
44 | html.dark .sdp button.sdp--date-btn__selected {
45 | background-color: var(--theme-color);
46 | }
47 |
48 | html.light {
49 | --code-bg-color: hsla(212deg, 100%, 39%, 5%);
50 | }
51 |
52 | html.dark {
53 | --code-bg-color: hsla(212deg, 100%, 77%, 10%);
54 | }
55 |
--------------------------------------------------------------------------------
/docs/theme.config.js:
--------------------------------------------------------------------------------
1 | import footer from 'components/footer';
2 | import editLink from 'components/edit-link';
3 |
4 | export default {
5 | project: {
6 | link: 'https://github.com/sassy-labs/datepicker',
7 | },
8 | docsRepositoryBase: 'https://github.com/sassy-labs/datepicker',
9 | titleSuffix: ' - Sassy DatePicker',
10 | navigation: {
11 | next: true,
12 | prev: true,
13 | },
14 | unstable_flexsearch: true,
15 | footer: {
16 | component: footer,
17 | },
18 | editLink: {
19 | component: editLink,
20 | text: 'Edit this page on GitHub',
21 | },
22 | logo: (
23 |
24 | sassy-datepicker
25 |
26 | ),
27 | faviconGlyph: '🗓',
28 | head: (
29 | <>
30 |
31 |
35 |
36 | >
37 | ),
38 | };
39 |
--------------------------------------------------------------------------------
/example/.npmignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .parcel-cache
3 | dist
--------------------------------------------------------------------------------
/example/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Playground
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/example/index.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import * as ReactDOM from 'react-dom';
3 | import DatePicker, { TimePicker } from '../dist';
4 | import '../dist/styles.css';
5 | import './styles.css';
6 |
7 | const App = () => {
8 | const [date, setDate] = React.useState(new Date());
9 | const [time, setTime] = React.useState({ hours: 0, minutes: 0 });
10 | const [format, setFormat] = React.useState('12hr');
11 | const [timeDisabled, setTimeDisabled] = React.useState(false);
12 | const [dateDisabled, setDateDisabled] = React.useState(false);
13 |
14 | return (
15 |
16 |
17 | setDateDisabled(e.target.checked)}
21 | />
22 |
23 |
32 |
33 |
34 |
35 |
39 |
40 | setTimeDisabled(e.target.checked)}
44 | />
45 |
52 |
53 |
54 | );
55 | };
56 |
57 | ReactDOM.render(, document.getElementById('root'));
58 |
--------------------------------------------------------------------------------
/example/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "example",
3 | "version": "1.0.0",
4 | "main": "index.js",
5 | "license": "MIT",
6 | "scripts": {
7 | "start": "parcel index.html",
8 | "build": "parcel build index.html"
9 | },
10 | "dependencies": {
11 | "react-app-polyfill": "^1.0.0"
12 | },
13 | "alias": {
14 | "react": "../node_modules/react",
15 | "react-dom": "../node_modules/react-dom/profiling",
16 | "scheduler/tracing": "../node_modules/scheduler/tracing-profiling"
17 | },
18 | "devDependencies": {
19 | "@types/react": "^17.0.2",
20 | "@types/react-dom": "^17.0.2",
21 | "parcel": "^2.7.0",
22 | "typescript": "^4.7.4"
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/example/styles.css:
--------------------------------------------------------------------------------
1 | .date-picker,
2 | .time-picker {
3 | font-family: 'Inter' !important;
4 | }
5 |
--------------------------------------------------------------------------------
/example/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "allowSyntheticDefaultImports": false,
4 | "target": "es5",
5 | "module": "commonjs",
6 | "jsx": "react",
7 | "moduleResolution": "node",
8 | "noImplicitAny": false,
9 | "noUnusedLocals": false,
10 | "noUnusedParameters": false,
11 | "removeComments": true,
12 | "strictNullChecks": true,
13 | "preserveConstEnums": true,
14 | "sourceMap": true,
15 | "lib": ["es2015", "es2016", "dom"],
16 | "types": ["node"]
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/example/yarn.lock:
--------------------------------------------------------------------------------
1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
2 | # yarn lockfile v1
3 |
4 |
5 | "@babel/code-frame@^7.0.0":
6 | version "7.18.6"
7 | resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.18.6.tgz#3b25d38c89600baa2dcc219edfa88a74eb2c427a"
8 | integrity sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==
9 | dependencies:
10 | "@babel/highlight" "^7.18.6"
11 |
12 | "@babel/helper-validator-identifier@^7.18.6":
13 | version "7.18.6"
14 | resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz#9c97e30d31b2b8c72a1d08984f2ca9b574d7a076"
15 | integrity sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==
16 |
17 | "@babel/highlight@^7.18.6":
18 | version "7.18.6"
19 | resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.18.6.tgz#81158601e93e2563795adcbfbdf5d64be3f2ecdf"
20 | integrity sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==
21 | dependencies:
22 | "@babel/helper-validator-identifier" "^7.18.6"
23 | chalk "^2.0.0"
24 | js-tokens "^4.0.0"
25 |
26 | "@jridgewell/gen-mapping@^0.3.0":
27 | version "0.3.2"
28 | resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz#c1aedc61e853f2bb9f5dfe6d4442d3b565b253b9"
29 | integrity sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==
30 | dependencies:
31 | "@jridgewell/set-array" "^1.0.1"
32 | "@jridgewell/sourcemap-codec" "^1.4.10"
33 | "@jridgewell/trace-mapping" "^0.3.9"
34 |
35 | "@jridgewell/resolve-uri@^3.0.3":
36 | version "3.1.0"
37 | resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78"
38 | integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==
39 |
40 | "@jridgewell/set-array@^1.0.1":
41 | version "1.1.2"
42 | resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72"
43 | integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==
44 |
45 | "@jridgewell/source-map@^0.3.2":
46 | version "0.3.2"
47 | resolved "https://registry.yarnpkg.com/@jridgewell/source-map/-/source-map-0.3.2.tgz#f45351aaed4527a298512ec72f81040c998580fb"
48 | integrity sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==
49 | dependencies:
50 | "@jridgewell/gen-mapping" "^0.3.0"
51 | "@jridgewell/trace-mapping" "^0.3.9"
52 |
53 | "@jridgewell/sourcemap-codec@^1.4.10":
54 | version "1.4.14"
55 | resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24"
56 | integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==
57 |
58 | "@jridgewell/trace-mapping@^0.3.9":
59 | version "0.3.15"
60 | resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.15.tgz#aba35c48a38d3fd84b37e66c9c0423f9744f9774"
61 | integrity sha512-oWZNOULl+UbhsgB51uuZzglikfIKSUBO/M9W2OfEjn7cmqoAiCgmv9lyACTUacZwBz0ITnJ2NqjU8Tx0DHL88g==
62 | dependencies:
63 | "@jridgewell/resolve-uri" "^3.0.3"
64 | "@jridgewell/sourcemap-codec" "^1.4.10"
65 |
66 | "@lezer/common@^0.15.0", "@lezer/common@^0.15.7":
67 | version "0.15.12"
68 | resolved "https://registry.yarnpkg.com/@lezer/common/-/common-0.15.12.tgz#2f21aec551dd5fd7d24eb069f90f54d5bc6ee5e9"
69 | integrity sha512-edfwCxNLnzq5pBA/yaIhwJ3U3Kz8VAUOTRg0hhxaizaI1N+qxV7EXDv/kLCkLeq2RzSFvxexlaj5Mzfn2kY0Ig==
70 |
71 | "@lezer/lr@^0.15.4":
72 | version "0.15.8"
73 | resolved "https://registry.yarnpkg.com/@lezer/lr/-/lr-0.15.8.tgz#1564a911e62b0a0f75ca63794a6aa8c5dc63db21"
74 | integrity sha512-bM6oE6VQZ6hIFxDNKk8bKPa14hqFrV07J/vHGOeiAbJReIaQXmkVb6xQu4MR+JBTLa5arGRyAAjJe1qaQt3Uvg==
75 | dependencies:
76 | "@lezer/common" "^0.15.0"
77 |
78 | "@lmdb/lmdb-darwin-arm64@2.5.2":
79 | version "2.5.2"
80 | resolved "https://registry.yarnpkg.com/@lmdb/lmdb-darwin-arm64/-/lmdb-darwin-arm64-2.5.2.tgz#bc66fa43286b5c082e8fee0eacc17995806b6fbe"
81 | integrity sha512-+F8ioQIUN68B4UFiIBYu0QQvgb9FmlKw2ctQMSBfW2QBrZIxz9vD9jCGqTCPqZBRbPHAS/vG1zSXnKqnS2ch/A==
82 |
83 | "@lmdb/lmdb-darwin-x64@2.5.2":
84 | version "2.5.2"
85 | resolved "https://registry.yarnpkg.com/@lmdb/lmdb-darwin-x64/-/lmdb-darwin-x64-2.5.2.tgz#89d8390041bce6bab24a82a20392be22faf54ffc"
86 | integrity sha512-KvPH56KRLLx4KSfKBx0m1r7GGGUMXm0jrKmNE7plbHlesZMuPJICtn07HYgQhj1LNsK7Yqwuvnqh1QxhJnF1EA==
87 |
88 | "@lmdb/lmdb-linux-arm64@2.5.2":
89 | version "2.5.2"
90 | resolved "https://registry.yarnpkg.com/@lmdb/lmdb-linux-arm64/-/lmdb-linux-arm64-2.5.2.tgz#14fe4c96c2bb1285f93797f45915fa35ee047268"
91 | integrity sha512-aLl89VHL/wjhievEOlPocoefUyWdvzVrcQ/MHQYZm2JfV1jUsrbr/ZfkPPUFvZBf+VSE+Q0clWs9l29PCX1hTQ==
92 |
93 | "@lmdb/lmdb-linux-arm@2.5.2":
94 | version "2.5.2"
95 | resolved "https://registry.yarnpkg.com/@lmdb/lmdb-linux-arm/-/lmdb-linux-arm-2.5.2.tgz#05bde4573ab10cf21827339fe687148f2590cfa1"
96 | integrity sha512-5kQAP21hAkfW5Bl+e0P57dV4dGYnkNIpR7f/GAh6QHlgXx+vp/teVj4PGRZaKAvt0GX6++N6hF8NnGElLDuIDw==
97 |
98 | "@lmdb/lmdb-linux-x64@2.5.2":
99 | version "2.5.2"
100 | resolved "https://registry.yarnpkg.com/@lmdb/lmdb-linux-x64/-/lmdb-linux-x64-2.5.2.tgz#d2f85afd857d2c33d2caa5b057944574edafcfee"
101 | integrity sha512-xUdUfwDJLGjOUPH3BuPBt0NlIrR7f/QHKgu3GZIXswMMIihAekj2i97oI0iWG5Bok/b+OBjHPfa8IU9velnP/Q==
102 |
103 | "@lmdb/lmdb-win32-x64@2.5.2":
104 | version "2.5.2"
105 | resolved "https://registry.yarnpkg.com/@lmdb/lmdb-win32-x64/-/lmdb-win32-x64-2.5.2.tgz#28f643fbc0bec30b07fbe95b137879b6b4d1c9c5"
106 | integrity sha512-zrBczSbXKxEyK2ijtbRdICDygRqWSRPpZMN5dD1T8VMEW5RIhIbwFWw2phDRXuBQdVDpSjalCIUMWMV2h3JaZA==
107 |
108 | "@mischnic/json-sourcemap@^0.1.0":
109 | version "0.1.0"
110 | resolved "https://registry.yarnpkg.com/@mischnic/json-sourcemap/-/json-sourcemap-0.1.0.tgz#38af657be4108140a548638267d02a2ea3336507"
111 | integrity sha512-dQb3QnfNqmQNYA4nFSN/uLaByIic58gOXq4Y4XqLOWmOrw73KmJPt/HLyG0wvn1bnR6mBKs/Uwvkh+Hns1T0XA==
112 | dependencies:
113 | "@lezer/common" "^0.15.7"
114 | "@lezer/lr" "^0.15.4"
115 | json5 "^2.2.1"
116 |
117 | "@msgpackr-extract/msgpackr-extract-darwin-arm64@2.1.2":
118 | version "2.1.2"
119 | resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-2.1.2.tgz#9571b87be3a3f2c46de05585470bc4f3af2f6f00"
120 | integrity sha512-TyVLn3S/+ikMDsh0gbKv2YydKClN8HaJDDpONlaZR+LVJmsxLFUgA+O7zu59h9+f9gX1aj/ahw9wqa6rosmrYQ==
121 |
122 | "@msgpackr-extract/msgpackr-extract-darwin-x64@2.1.2":
123 | version "2.1.2"
124 | resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-darwin-x64/-/msgpackr-extract-darwin-x64-2.1.2.tgz#bfbc6936ede2955218f5621a675679a5fe8e6f4c"
125 | integrity sha512-YPXtcVkhmVNoMGlqp81ZHW4dMxK09msWgnxtsDpSiZwTzUBG2N+No2bsr7WMtBKCVJMSD6mbAl7YhKUqkp/Few==
126 |
127 | "@msgpackr-extract/msgpackr-extract-linux-arm64@2.1.2":
128 | version "2.1.2"
129 | resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-linux-arm64/-/msgpackr-extract-linux-arm64-2.1.2.tgz#22555e28382af2922e7450634c8a2f240bb9eb82"
130 | integrity sha512-vHZ2JiOWF2+DN9lzltGbhtQNzDo8fKFGrf37UJrgqxU0yvtERrzUugnfnX1wmVfFhSsF8OxrfqiNOUc5hko1Zg==
131 |
132 | "@msgpackr-extract/msgpackr-extract-linux-arm@2.1.2":
133 | version "2.1.2"
134 | resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-linux-arm/-/msgpackr-extract-linux-arm-2.1.2.tgz#ffb6ae1beea7ac572b6be6bf2a8e8162ebdd8be7"
135 | integrity sha512-42R4MAFeIeNn+L98qwxAt360bwzX2Kf0ZQkBBucJ2Ircza3asoY4CDbgiu9VWklq8gWJVSJSJBwDI+c/THiWkA==
136 |
137 | "@msgpackr-extract/msgpackr-extract-linux-x64@2.1.2":
138 | version "2.1.2"
139 | resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-linux-x64/-/msgpackr-extract-linux-x64-2.1.2.tgz#7caf62eebbfb1345de40f75e89666b3d4194755f"
140 | integrity sha512-RjRoRxg7Q3kPAdUSC5EUUPlwfMkIVhmaRTIe+cqHbKrGZ4M6TyCA/b5qMaukQ/1CHWrqYY2FbKOAU8Hg0pQFzg==
141 |
142 | "@msgpackr-extract/msgpackr-extract-win32-x64@2.1.2":
143 | version "2.1.2"
144 | resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-win32-x64/-/msgpackr-extract-win32-x64-2.1.2.tgz#f2d8b9ddd8d191205ed26ce54aba3dfc5ae3e7c9"
145 | integrity sha512-rIZVR48zA8hGkHIK7ED6+ZiXsjRCcAVBJbm8o89OKAMTmEAQ2QvoOxoiu3w2isAaWwzgtQIOFIqHwvZDyLKCvw==
146 |
147 | "@parcel/bundler-default@2.7.0":
148 | version "2.7.0"
149 | resolved "https://registry.yarnpkg.com/@parcel/bundler-default/-/bundler-default-2.7.0.tgz#17d94be7185f29773aa21454063cbba3cdc03d49"
150 | integrity sha512-PU5MtWWhc+dYI9x8mguYnm9yiG6TkI7niRpxgJgtqAyGHuEyNXVBQQ0X+qyOF4D9LdankBf8uNN18g31IET2Zg==
151 | dependencies:
152 | "@parcel/diagnostic" "2.7.0"
153 | "@parcel/hash" "2.7.0"
154 | "@parcel/plugin" "2.7.0"
155 | "@parcel/utils" "2.7.0"
156 | nullthrows "^1.1.1"
157 |
158 | "@parcel/cache@2.7.0":
159 | version "2.7.0"
160 | resolved "https://registry.yarnpkg.com/@parcel/cache/-/cache-2.7.0.tgz#cc4b99685c7ff0fc20fbc321f4b6850d6e0c6811"
161 | integrity sha512-JlXNoZXcWzLKdDlfeF3dIj5Vtel5T9vtdBN72PJ+cjC4qNHk4Uwvc5sfOBELuibGN0bVu2bwY9nUgSwCiB1iIA==
162 | dependencies:
163 | "@parcel/fs" "2.7.0"
164 | "@parcel/logger" "2.7.0"
165 | "@parcel/utils" "2.7.0"
166 | lmdb "2.5.2"
167 |
168 | "@parcel/codeframe@2.7.0":
169 | version "2.7.0"
170 | resolved "https://registry.yarnpkg.com/@parcel/codeframe/-/codeframe-2.7.0.tgz#b6e4ad6100938edbed1b6c72b37f609e1abaf931"
171 | integrity sha512-UTKx0jejJmmO1dwTHSJuRgrO8N6PMlkxRT6sew8N6NC3Bgv6pu0EbO+RtlWt/jCvzcdLOPdIoTzj4MMZvgcMYg==
172 | dependencies:
173 | chalk "^4.1.0"
174 |
175 | "@parcel/compressor-raw@2.7.0":
176 | version "2.7.0"
177 | resolved "https://registry.yarnpkg.com/@parcel/compressor-raw/-/compressor-raw-2.7.0.tgz#3f8677e6371ef099cd9e4bd2a899884dc8eb571b"
178 | integrity sha512-SCXwnOOQT6EmpusBsYWNQ/RFri+2JnKuE0gMSf2dROl2xbererX45FYzeDplWALCKAdjMNDpFwU+FyMYoVZSCQ==
179 | dependencies:
180 | "@parcel/plugin" "2.7.0"
181 |
182 | "@parcel/config-default@2.7.0":
183 | version "2.7.0"
184 | resolved "https://registry.yarnpkg.com/@parcel/config-default/-/config-default-2.7.0.tgz#2f6cec9c185b89e40f343549295cad21295621a8"
185 | integrity sha512-ZzsLr97AYrz8c9k6qn3DlqPzifi3vbP7q3ynUrAFxmt0L4+K0H9N508ZkORYmCgaFjLIQ8Y3eWpwCJ0AewPNIg==
186 | dependencies:
187 | "@parcel/bundler-default" "2.7.0"
188 | "@parcel/compressor-raw" "2.7.0"
189 | "@parcel/namer-default" "2.7.0"
190 | "@parcel/optimizer-css" "2.7.0"
191 | "@parcel/optimizer-htmlnano" "2.7.0"
192 | "@parcel/optimizer-image" "2.7.0"
193 | "@parcel/optimizer-svgo" "2.7.0"
194 | "@parcel/optimizer-terser" "2.7.0"
195 | "@parcel/packager-css" "2.7.0"
196 | "@parcel/packager-html" "2.7.0"
197 | "@parcel/packager-js" "2.7.0"
198 | "@parcel/packager-raw" "2.7.0"
199 | "@parcel/packager-svg" "2.7.0"
200 | "@parcel/reporter-dev-server" "2.7.0"
201 | "@parcel/resolver-default" "2.7.0"
202 | "@parcel/runtime-browser-hmr" "2.7.0"
203 | "@parcel/runtime-js" "2.7.0"
204 | "@parcel/runtime-react-refresh" "2.7.0"
205 | "@parcel/runtime-service-worker" "2.7.0"
206 | "@parcel/transformer-babel" "2.7.0"
207 | "@parcel/transformer-css" "2.7.0"
208 | "@parcel/transformer-html" "2.7.0"
209 | "@parcel/transformer-image" "2.7.0"
210 | "@parcel/transformer-js" "2.7.0"
211 | "@parcel/transformer-json" "2.7.0"
212 | "@parcel/transformer-postcss" "2.7.0"
213 | "@parcel/transformer-posthtml" "2.7.0"
214 | "@parcel/transformer-raw" "2.7.0"
215 | "@parcel/transformer-react-refresh-wrap" "2.7.0"
216 | "@parcel/transformer-svg" "2.7.0"
217 |
218 | "@parcel/core@2.7.0":
219 | version "2.7.0"
220 | resolved "https://registry.yarnpkg.com/@parcel/core/-/core-2.7.0.tgz#3310f48230bd618735f199f159f37e6b45ed2710"
221 | integrity sha512-7yKZUdh314Q/kU/9+27ZYTfcnXS6VYHuG+iiUlIohnvUUybxLqVJhdMU9Q+z2QcPka1IdJWz4K4Xx0y6/4goyg==
222 | dependencies:
223 | "@mischnic/json-sourcemap" "^0.1.0"
224 | "@parcel/cache" "2.7.0"
225 | "@parcel/diagnostic" "2.7.0"
226 | "@parcel/events" "2.7.0"
227 | "@parcel/fs" "2.7.0"
228 | "@parcel/graph" "2.7.0"
229 | "@parcel/hash" "2.7.0"
230 | "@parcel/logger" "2.7.0"
231 | "@parcel/package-manager" "2.7.0"
232 | "@parcel/plugin" "2.7.0"
233 | "@parcel/source-map" "^2.0.0"
234 | "@parcel/types" "2.7.0"
235 | "@parcel/utils" "2.7.0"
236 | "@parcel/workers" "2.7.0"
237 | abortcontroller-polyfill "^1.1.9"
238 | base-x "^3.0.8"
239 | browserslist "^4.6.6"
240 | clone "^2.1.1"
241 | dotenv "^7.0.0"
242 | dotenv-expand "^5.1.0"
243 | json5 "^2.2.0"
244 | msgpackr "^1.5.4"
245 | nullthrows "^1.1.1"
246 | semver "^5.7.1"
247 |
248 | "@parcel/css-darwin-arm64@1.12.2":
249 | version "1.12.2"
250 | resolved "https://registry.yarnpkg.com/@parcel/css-darwin-arm64/-/css-darwin-arm64-1.12.2.tgz#4215585dac699f0f75015f5b47254867ac1221d3"
251 | integrity sha512-6VvsoYSltBiUh/uyfPzQ+I3DiTFN7tmRv6zm1LH98J7GGCDDhbYEtbQjjCs15ex6fVn1ORZK0JO+mMlsg1JwTA==
252 |
253 | "@parcel/css-darwin-x64@1.12.2":
254 | version "1.12.2"
255 | resolved "https://registry.yarnpkg.com/@parcel/css-darwin-x64/-/css-darwin-x64-1.12.2.tgz#eeb4e04c512580bd531b5ffa9c34456e9799fdb9"
256 | integrity sha512-3J0/LrDvt5vevOisnrE0q5mEcuiAY+K7OZwIv84SAnrbjlL5sshmIaaNzL869kb4thza+RClEj0mS5XTm1IUEw==
257 |
258 | "@parcel/css-linux-arm-gnueabihf@1.12.2":
259 | version "1.12.2"
260 | resolved "https://registry.yarnpkg.com/@parcel/css-linux-arm-gnueabihf/-/css-linux-arm-gnueabihf-1.12.2.tgz#ccd813bbc9b9d845fb8f6ed9c7c22c745cda007b"
261 | integrity sha512-OsX7I3dhBvnxEbAH++08RFe7yhjRp33ulzrCvJTMOP9YkxEEJ8qId3sNzJBHIVQzHyTlPTnBRHbSDhU3TFe/eQ==
262 |
263 | "@parcel/css-linux-arm64-gnu@1.12.2":
264 | version "1.12.2"
265 | resolved "https://registry.yarnpkg.com/@parcel/css-linux-arm64-gnu/-/css-linux-arm64-gnu-1.12.2.tgz#7959fbcbd38c9b9c2c24c6c2def4ec2df370b705"
266 | integrity sha512-R1Kqw+1Rsru9Q4+qvUEC6B8P21bpqhuF9rv8GmBmmnF1i2hMZ1JiY+uh/ej8IaRV0O3fAHeQGIyGBWx6qWDpcw==
267 |
268 | "@parcel/css-linux-arm64-musl@1.12.2":
269 | version "1.12.2"
270 | resolved "https://registry.yarnpkg.com/@parcel/css-linux-arm64-musl/-/css-linux-arm64-musl-1.12.2.tgz#ffc3fc62db9b8a19f8be61028abbcb7c44d90fa6"
271 | integrity sha512-nwixgM4SEgPUQata9aAiJW0A5Q9ms+xim1tXT1i+91kOei4Fu2Wr2OuofMk+mlhbgmGKCTcu4gzMPReGxUhuRA==
272 |
273 | "@parcel/css-linux-x64-gnu@1.12.2":
274 | version "1.12.2"
275 | resolved "https://registry.yarnpkg.com/@parcel/css-linux-x64-gnu/-/css-linux-x64-gnu-1.12.2.tgz#15619756ba62558243ae996e257b1cca90f534eb"
276 | integrity sha512-cJYVMHnQSGhDwQByyvjFZppjMBNlgxXl/R4cX5DwrQE0QZmK/42BYnMp92rvoprEG6LRyRoiGtCjyfYTPWajog==
277 |
278 | "@parcel/css-linux-x64-musl@1.12.2":
279 | version "1.12.2"
280 | resolved "https://registry.yarnpkg.com/@parcel/css-linux-x64-musl/-/css-linux-x64-musl-1.12.2.tgz#de61e2bdec54609f7b681acfbd04e9fb57a5ef02"
281 | integrity sha512-u9zdO/d831/74Tf+TdPUfaIuB9v6FD4Xz8UdWUDOXgQqaOlnJ9fAsAM39EkoWlMxPPljY3f4ay6irSe1a4XgSA==
282 |
283 | "@parcel/css-win32-x64-msvc@1.12.2":
284 | version "1.12.2"
285 | resolved "https://registry.yarnpkg.com/@parcel/css-win32-x64-msvc/-/css-win32-x64-msvc-1.12.2.tgz#086586fce31d1e05340c2e31efc32d40aa9ee05a"
286 | integrity sha512-kCAKr3vKqvPUv9oXBG3pGZQz5il3sEk35dpmTXFa/7eDNKR5XyLpiJs8JwWJTFfuUqroymDSXA1bCcjvNEYcAg==
287 |
288 | "@parcel/css@^1.12.2":
289 | version "1.12.2"
290 | resolved "https://registry.yarnpkg.com/@parcel/css/-/css-1.12.2.tgz#63eacc9fcdf58e4d9639db34271834394705b7b2"
291 | integrity sha512-Sa0PvZu5u877CupQA8IjEATqjJFynBfA7LxbcyutFe2LDCRSqB5Bm08jKFScyaz56qjZNIxZxXk2SApNkOvoAA==
292 | dependencies:
293 | detect-libc "^1.0.3"
294 | optionalDependencies:
295 | "@parcel/css-darwin-arm64" "1.12.2"
296 | "@parcel/css-darwin-x64" "1.12.2"
297 | "@parcel/css-linux-arm-gnueabihf" "1.12.2"
298 | "@parcel/css-linux-arm64-gnu" "1.12.2"
299 | "@parcel/css-linux-arm64-musl" "1.12.2"
300 | "@parcel/css-linux-x64-gnu" "1.12.2"
301 | "@parcel/css-linux-x64-musl" "1.12.2"
302 | "@parcel/css-win32-x64-msvc" "1.12.2"
303 |
304 | "@parcel/diagnostic@2.7.0":
305 | version "2.7.0"
306 | resolved "https://registry.yarnpkg.com/@parcel/diagnostic/-/diagnostic-2.7.0.tgz#cf2596a20ce9277334616e12bbdac98490189e99"
307 | integrity sha512-pdq/cTwVoL0n8yuDCRXFRSQHVWdmmIXPt3R3iT4KtYDYvOrMT2dLPT79IMqQkhYPANW8GuL15n/WxRngfRdkug==
308 | dependencies:
309 | "@mischnic/json-sourcemap" "^0.1.0"
310 | nullthrows "^1.1.1"
311 |
312 | "@parcel/events@2.7.0":
313 | version "2.7.0"
314 | resolved "https://registry.yarnpkg.com/@parcel/events/-/events-2.7.0.tgz#b6db8464d45626686134d412d3a36d024ffb1482"
315 | integrity sha512-kQDwMKgZ1U4M/G17qeDYF6bW5kybluN6ajYPc7mZcrWg+trEI/oXi81GMFaMX0BSUhwhbiN5+/Vb2wiG/Sn6ig==
316 |
317 | "@parcel/fs-search@2.7.0":
318 | version "2.7.0"
319 | resolved "https://registry.yarnpkg.com/@parcel/fs-search/-/fs-search-2.7.0.tgz#15e658006039ddc7b92528df5266ee2b9c47b6a4"
320 | integrity sha512-K1Hv25bnRpwQVA15RvcRuB8ZhfclnCHA8N8L6w7Ul1ncSJDxCIkIAc5hAubYNNYW3kWjCC2SOaEgFKnbvMllEQ==
321 | dependencies:
322 | detect-libc "^1.0.3"
323 |
324 | "@parcel/fs@2.7.0":
325 | version "2.7.0"
326 | resolved "https://registry.yarnpkg.com/@parcel/fs/-/fs-2.7.0.tgz#c9a0c60bdbef7101ff47f2db6b23814c3db06007"
327 | integrity sha512-PU5fo4Hh8y03LZgemgVREttc0wyHQUNmsJCybxTB7EjJie2CqJRumo+DFppArlvdchLwJdc9em03yQV/GNWrEg==
328 | dependencies:
329 | "@parcel/fs-search" "2.7.0"
330 | "@parcel/types" "2.7.0"
331 | "@parcel/utils" "2.7.0"
332 | "@parcel/watcher" "^2.0.0"
333 | "@parcel/workers" "2.7.0"
334 |
335 | "@parcel/graph@2.7.0":
336 | version "2.7.0"
337 | resolved "https://registry.yarnpkg.com/@parcel/graph/-/graph-2.7.0.tgz#2ae326c62764aaa53324b89d9c83ec0bc6ad55bf"
338 | integrity sha512-Q6E94GS6q45PtsZh+m+gvFRp/N1Qopxhu2sxjcWsGs5iBd6IWn2oYLWOH5iVzEjWuYpW2HkB08lH6J50O63uOA==
339 | dependencies:
340 | "@parcel/utils" "2.7.0"
341 | nullthrows "^1.1.1"
342 |
343 | "@parcel/hash@2.7.0":
344 | version "2.7.0"
345 | resolved "https://registry.yarnpkg.com/@parcel/hash/-/hash-2.7.0.tgz#8825cff69a0bc4816737415e6e2aa29e8671c0b1"
346 | integrity sha512-k6bSKnIlPJMPU3yjQzfgfvF9zuJZGOAlJgzpL4BbWvdbE8BTdjzLcFn0Ujrtud94EgIkiXd22sC2HpCUWoHGdA==
347 | dependencies:
348 | detect-libc "^1.0.3"
349 | xxhash-wasm "^0.4.2"
350 |
351 | "@parcel/logger@2.7.0":
352 | version "2.7.0"
353 | resolved "https://registry.yarnpkg.com/@parcel/logger/-/logger-2.7.0.tgz#1aa1de0458bdd613714ce4031134d92135aec590"
354 | integrity sha512-qjMY/bYo38+o+OiIrTRldU9CwL1E7J72t+xkTP8QIcUxLWz5LYR0YbynZUVulmBSfqsykjjxCy4a+8siVr+lPw==
355 | dependencies:
356 | "@parcel/diagnostic" "2.7.0"
357 | "@parcel/events" "2.7.0"
358 |
359 | "@parcel/markdown-ansi@2.7.0":
360 | version "2.7.0"
361 | resolved "https://registry.yarnpkg.com/@parcel/markdown-ansi/-/markdown-ansi-2.7.0.tgz#4ba70e3661ce06cd8fd2eb3f7b84028853a586e4"
362 | integrity sha512-ipOX0D6FVZFEXeb/z8MnTMq2RQEIuaILY90olVIuHEFLHHfOPEn+RK3u13HA1ChF5/9E3cMD79tu6x9JL9Kqag==
363 | dependencies:
364 | chalk "^4.1.0"
365 |
366 | "@parcel/namer-default@2.7.0":
367 | version "2.7.0"
368 | resolved "https://registry.yarnpkg.com/@parcel/namer-default/-/namer-default-2.7.0.tgz#e008097586016f16509834db11985dcc772c314c"
369 | integrity sha512-lIKMdsmi//7fepecNDYmJYzBlL91HifPsX03lJCdu1dC6q5fBs+gG0XjKKG7yPnSCw1qH/4m7drzt9+dRZYAHQ==
370 | dependencies:
371 | "@parcel/diagnostic" "2.7.0"
372 | "@parcel/plugin" "2.7.0"
373 | nullthrows "^1.1.1"
374 |
375 | "@parcel/node-resolver-core@2.7.0":
376 | version "2.7.0"
377 | resolved "https://registry.yarnpkg.com/@parcel/node-resolver-core/-/node-resolver-core-2.7.0.tgz#468074aa58a2f0026a492607153079ebb16308e3"
378 | integrity sha512-5UJQHalqMxdhJIs2hhqQzFfQpF7+NAowsRq064lYtiRvcD8wMr3OOQ9wd1iazGpFSl4JKdT7BwDU9/miDJmanQ==
379 | dependencies:
380 | "@parcel/diagnostic" "2.7.0"
381 | "@parcel/utils" "2.7.0"
382 | nullthrows "^1.1.1"
383 | semver "^5.7.1"
384 |
385 | "@parcel/optimizer-css@2.7.0":
386 | version "2.7.0"
387 | resolved "https://registry.yarnpkg.com/@parcel/optimizer-css/-/optimizer-css-2.7.0.tgz#460cde19b9ee61efed577473cb0822796b6e8b1a"
388 | integrity sha512-IfnOMACqhcAclKyOW9X9JpsknB6OShk9OVvb8EvbDTKHJhQHNNmzE88OkSI/pS3ZVZP9Zj+nWcVHguV+kvDeiQ==
389 | dependencies:
390 | "@parcel/css" "^1.12.2"
391 | "@parcel/diagnostic" "2.7.0"
392 | "@parcel/plugin" "2.7.0"
393 | "@parcel/source-map" "^2.0.0"
394 | "@parcel/utils" "2.7.0"
395 | browserslist "^4.6.6"
396 | nullthrows "^1.1.1"
397 |
398 | "@parcel/optimizer-htmlnano@2.7.0":
399 | version "2.7.0"
400 | resolved "https://registry.yarnpkg.com/@parcel/optimizer-htmlnano/-/optimizer-htmlnano-2.7.0.tgz#d2e843b539a430fcca723f08efcee26f98b3d40b"
401 | integrity sha512-5QrGdWS5Hi4VXE3nQNrGqugmSXt68YIsWwKRAdarOxzyULSJS3gbCiQOXqIPRJobfZjnSIcdtkyxSiCUe1inIA==
402 | dependencies:
403 | "@parcel/plugin" "2.7.0"
404 | htmlnano "^2.0.0"
405 | nullthrows "^1.1.1"
406 | posthtml "^0.16.5"
407 | svgo "^2.4.0"
408 |
409 | "@parcel/optimizer-image@2.7.0":
410 | version "2.7.0"
411 | resolved "https://registry.yarnpkg.com/@parcel/optimizer-image/-/optimizer-image-2.7.0.tgz#180d7709e6268e0634967eb265bf901aba2471ce"
412 | integrity sha512-EnaXz5UjR67FUu0BEcqZTT9LsbB/iFAkkghCotbnbOuC5QQsloq6tw54TKU3y+R3qsjgUoMtGxPcGfVoXxZXYw==
413 | dependencies:
414 | "@parcel/diagnostic" "2.7.0"
415 | "@parcel/plugin" "2.7.0"
416 | "@parcel/utils" "2.7.0"
417 | "@parcel/workers" "2.7.0"
418 | detect-libc "^1.0.3"
419 |
420 | "@parcel/optimizer-svgo@2.7.0":
421 | version "2.7.0"
422 | resolved "https://registry.yarnpkg.com/@parcel/optimizer-svgo/-/optimizer-svgo-2.7.0.tgz#9b4ab38a9d3c99504cf399a5c7709e5d2a615e71"
423 | integrity sha512-IO1JV4NpfP3V7FrhsqCcV8pDQIHraFi1/ZvEJyssITxjH49Im/txKlwMiQuZZryAPn8Xb8g395Muawuk6AK6sg==
424 | dependencies:
425 | "@parcel/diagnostic" "2.7.0"
426 | "@parcel/plugin" "2.7.0"
427 | "@parcel/utils" "2.7.0"
428 | svgo "^2.4.0"
429 |
430 | "@parcel/optimizer-terser@2.7.0":
431 | version "2.7.0"
432 | resolved "https://registry.yarnpkg.com/@parcel/optimizer-terser/-/optimizer-terser-2.7.0.tgz#b9ef408f45714952d1502940b6a63e5ebd3f0940"
433 | integrity sha512-07VZjIO8xsl2/WmS/qHI8lI/cpu47iS9eRpqwfZEEsdk1cfz50jhWkmFudHBxiHGMfcZ//1+DdaPg9RDBWZtZA==
434 | dependencies:
435 | "@parcel/diagnostic" "2.7.0"
436 | "@parcel/plugin" "2.7.0"
437 | "@parcel/source-map" "^2.0.0"
438 | "@parcel/utils" "2.7.0"
439 | nullthrows "^1.1.1"
440 | terser "^5.2.0"
441 |
442 | "@parcel/package-manager@2.7.0":
443 | version "2.7.0"
444 | resolved "https://registry.yarnpkg.com/@parcel/package-manager/-/package-manager-2.7.0.tgz#5de1bf5c94d95330e98dffb2a66c22d1f20c4c8a"
445 | integrity sha512-wmfSX1mRrTi8MeA4KrnPk/x7zGUsILCQmTo6lA4gygzAxDbM1pGuyFN8/Kt0y0SFO2lbljARtD/4an5qdotH+Q==
446 | dependencies:
447 | "@parcel/diagnostic" "2.7.0"
448 | "@parcel/fs" "2.7.0"
449 | "@parcel/logger" "2.7.0"
450 | "@parcel/types" "2.7.0"
451 | "@parcel/utils" "2.7.0"
452 | "@parcel/workers" "2.7.0"
453 | semver "^5.7.1"
454 |
455 | "@parcel/packager-css@2.7.0":
456 | version "2.7.0"
457 | resolved "https://registry.yarnpkg.com/@parcel/packager-css/-/packager-css-2.7.0.tgz#060af8b96e5ad53620b4021610364804e26d69b2"
458 | integrity sha512-44nzZwu+ssGuiFmYM6cf/Y4iChiUZ4DUzzpegnGlhXtKJKe4NHntxThJynuRZWKN2AAf48avApDpimg2jW0KDw==
459 | dependencies:
460 | "@parcel/plugin" "2.7.0"
461 | "@parcel/source-map" "^2.0.0"
462 | "@parcel/utils" "2.7.0"
463 | nullthrows "^1.1.1"
464 |
465 | "@parcel/packager-html@2.7.0":
466 | version "2.7.0"
467 | resolved "https://registry.yarnpkg.com/@parcel/packager-html/-/packager-html-2.7.0.tgz#4f86698d05f5ec5c3ebc8b46102a6ae42c58a24a"
468 | integrity sha512-Zgqd7sdcY/UnR370GR0q2ilmEohUDXsO8A1F28QCJzIsR1iCB6KRUT74+pawfQ1IhXZLaaFLLYe0UWcfm0JeXg==
469 | dependencies:
470 | "@parcel/plugin" "2.7.0"
471 | "@parcel/types" "2.7.0"
472 | "@parcel/utils" "2.7.0"
473 | nullthrows "^1.1.1"
474 | posthtml "^0.16.5"
475 |
476 | "@parcel/packager-js@2.7.0":
477 | version "2.7.0"
478 | resolved "https://registry.yarnpkg.com/@parcel/packager-js/-/packager-js-2.7.0.tgz#e694cc731d75697e63d3d4be0bdbbe4a2ae8f1fc"
479 | integrity sha512-wTRdM81PgRVDzWGXdWmqLwguWnTYWzhEDdjXpW2n8uMOu/CjHhMtogk65aaYk3GOnq6OBL/NsrmBiV/zKPj1vA==
480 | dependencies:
481 | "@parcel/diagnostic" "2.7.0"
482 | "@parcel/hash" "2.7.0"
483 | "@parcel/plugin" "2.7.0"
484 | "@parcel/source-map" "^2.0.0"
485 | "@parcel/utils" "2.7.0"
486 | globals "^13.2.0"
487 | nullthrows "^1.1.1"
488 |
489 | "@parcel/packager-raw@2.7.0":
490 | version "2.7.0"
491 | resolved "https://registry.yarnpkg.com/@parcel/packager-raw/-/packager-raw-2.7.0.tgz#5b68de05c19bbcf438f40b4ae9f45411ba9739bd"
492 | integrity sha512-jg2Zp8dI5VpIQlaeahXDCfrPN9m/DKht1NkR9P2CylMAwqCcc1Xc1RRiF0wfwcPZpPMpq1265n+4qnB7rjGBlA==
493 | dependencies:
494 | "@parcel/plugin" "2.7.0"
495 |
496 | "@parcel/packager-svg@2.7.0":
497 | version "2.7.0"
498 | resolved "https://registry.yarnpkg.com/@parcel/packager-svg/-/packager-svg-2.7.0.tgz#e7e96503c86815eca285b9cc8908105075d9ab38"
499 | integrity sha512-EmJg3HpD6/xxKBjir/CdCKJZwI24iVfBuxRS9LUp3xHAIebOzVh1z6IN+i2Di5+NyRwfOFaLliL4uMa1zwbyCA==
500 | dependencies:
501 | "@parcel/plugin" "2.7.0"
502 | "@parcel/types" "2.7.0"
503 | "@parcel/utils" "2.7.0"
504 | posthtml "^0.16.4"
505 |
506 | "@parcel/plugin@2.7.0":
507 | version "2.7.0"
508 | resolved "https://registry.yarnpkg.com/@parcel/plugin/-/plugin-2.7.0.tgz#0211281025d02afbc5a23fba237b7aae02e34e51"
509 | integrity sha512-qqgx+nnMn6/0lRc4lKbLGmhNtBiT93S2gFNB4Eb4Pfz/SxVYoW+fmml+KdfOSiZffWOAH5L6NwhyD7N8aSikzw==
510 | dependencies:
511 | "@parcel/types" "2.7.0"
512 |
513 | "@parcel/reporter-cli@2.7.0":
514 | version "2.7.0"
515 | resolved "https://registry.yarnpkg.com/@parcel/reporter-cli/-/reporter-cli-2.7.0.tgz#86499624e258034001b64c10b14e23ae4b92f44b"
516 | integrity sha512-80gEODg8cnAmnxGVuaSVDo8JJ54P9AA2bHwSs1cIkHWlJ3BjDQb83H31bBHncJ5Kn5kQ/j+7WjlqHpTCiOR9PA==
517 | dependencies:
518 | "@parcel/plugin" "2.7.0"
519 | "@parcel/types" "2.7.0"
520 | "@parcel/utils" "2.7.0"
521 | chalk "^4.1.0"
522 | term-size "^2.2.1"
523 |
524 | "@parcel/reporter-dev-server@2.7.0":
525 | version "2.7.0"
526 | resolved "https://registry.yarnpkg.com/@parcel/reporter-dev-server/-/reporter-dev-server-2.7.0.tgz#9bd3d10f745e0cbc9ab983ec046953c2c564dcb2"
527 | integrity sha512-ySuou5addK8fGue8aXzo536BaEjMujDrEc1xkp4TasInXHVcA98b+SYX5NAZTGob5CxKvZQ5ylhg77zW30B+iA==
528 | dependencies:
529 | "@parcel/plugin" "2.7.0"
530 | "@parcel/utils" "2.7.0"
531 |
532 | "@parcel/resolver-default@2.7.0":
533 | version "2.7.0"
534 | resolved "https://registry.yarnpkg.com/@parcel/resolver-default/-/resolver-default-2.7.0.tgz#648a257b81abe2eda09700d8f36348a88ea0442e"
535 | integrity sha512-v8TvWsbLK7/q7n4gv6OrYNbW18xUx4zKbVMGZb1u4yMhzEH4HFr1D9OeoTq3jk+ximAigds8B6triQbL5exF7A==
536 | dependencies:
537 | "@parcel/node-resolver-core" "2.7.0"
538 | "@parcel/plugin" "2.7.0"
539 |
540 | "@parcel/runtime-browser-hmr@2.7.0":
541 | version "2.7.0"
542 | resolved "https://registry.yarnpkg.com/@parcel/runtime-browser-hmr/-/runtime-browser-hmr-2.7.0.tgz#aed79b96c0d97021f56f2b7e35bc2d4f70869e26"
543 | integrity sha512-PLbMLdclQeYsi2LkilZVGFV1n3y55G1jaBvby4ekedUZjMw3SWdMY2tDxgSDdFWfLCnYHJXdGUQSzGGi1kPzjA==
544 | dependencies:
545 | "@parcel/plugin" "2.7.0"
546 | "@parcel/utils" "2.7.0"
547 |
548 | "@parcel/runtime-js@2.7.0":
549 | version "2.7.0"
550 | resolved "https://registry.yarnpkg.com/@parcel/runtime-js/-/runtime-js-2.7.0.tgz#63dd744e96c3554ac86778ffce1c8055e7653fce"
551 | integrity sha512-9/YUZTBNrSN2H6rbz/o1EOM0O7I3ZR/x9IDzxjJBD6Mi+0uCgCD02aedare/SNr1qgnbZZWmhpOzC+YgREcfLA==
552 | dependencies:
553 | "@parcel/plugin" "2.7.0"
554 | "@parcel/utils" "2.7.0"
555 | nullthrows "^1.1.1"
556 |
557 | "@parcel/runtime-react-refresh@2.7.0":
558 | version "2.7.0"
559 | resolved "https://registry.yarnpkg.com/@parcel/runtime-react-refresh/-/runtime-react-refresh-2.7.0.tgz#c56b847ef1144264e918339381e040ffe811efc5"
560 | integrity sha512-vDKO0rWqRzEpmvoZ4kkYUiSsTxT5NnH904BFPFxKI0wJCl6yEmPuEifmATo73OuYhP6jIP3Qfl1R4TtiDFPJ1Q==
561 | dependencies:
562 | "@parcel/plugin" "2.7.0"
563 | "@parcel/utils" "2.7.0"
564 | react-error-overlay "6.0.9"
565 | react-refresh "^0.9.0"
566 |
567 | "@parcel/runtime-service-worker@2.7.0":
568 | version "2.7.0"
569 | resolved "https://registry.yarnpkg.com/@parcel/runtime-service-worker/-/runtime-service-worker-2.7.0.tgz#352c3722ec635eee2898d9698541e3c1f53e8906"
570 | integrity sha512-uD2pAV0yV6+e7JaWH4KVPbG+zRCrxr/OACyS9tIh+Q/R1vRmh8zGM3yhdrcoiZ7tFOnM72vd6xY11eTrUsSVig==
571 | dependencies:
572 | "@parcel/plugin" "2.7.0"
573 | "@parcel/utils" "2.7.0"
574 | nullthrows "^1.1.1"
575 |
576 | "@parcel/source-map@^2.0.0":
577 | version "2.1.0"
578 | resolved "https://registry.yarnpkg.com/@parcel/source-map/-/source-map-2.1.0.tgz#bd47aa0a93ae261436f7c5da40b09856e1a331d5"
579 | integrity sha512-E7UOEIof2o89LrKk1agSLmwakjigmEdDp1ZaEdsLVEvq63R/bul4Ij5CT+0ZDcijGpl5tnTbQADY9EyYGtjYgQ==
580 | dependencies:
581 | detect-libc "^1.0.3"
582 |
583 | "@parcel/transformer-babel@2.7.0":
584 | version "2.7.0"
585 | resolved "https://registry.yarnpkg.com/@parcel/transformer-babel/-/transformer-babel-2.7.0.tgz#eae98d50a99cd722c3146cd57c479bfb86f537b2"
586 | integrity sha512-7iklDXXnKH1530+QbI+e4kIJ+Q1puA1ulRS10db3aUJMj5GnvXGDFwhSZ7+T1ps66QHO7cVO29VlbqiRDarH1Q==
587 | dependencies:
588 | "@parcel/diagnostic" "2.7.0"
589 | "@parcel/plugin" "2.7.0"
590 | "@parcel/source-map" "^2.0.0"
591 | "@parcel/utils" "2.7.0"
592 | browserslist "^4.6.6"
593 | json5 "^2.2.0"
594 | nullthrows "^1.1.1"
595 | semver "^5.7.0"
596 |
597 | "@parcel/transformer-css@2.7.0":
598 | version "2.7.0"
599 | resolved "https://registry.yarnpkg.com/@parcel/transformer-css/-/transformer-css-2.7.0.tgz#d0879ec04191e5ba3eadb6fc06b7ec0db3f5c3f6"
600 | integrity sha512-J4EpWK9spQpXyNCmKK8Xnane0xW/1B/EAmfp7Fiv7g+5yUjY4ODf4KUugvE+Eb2gekPkhOKNHermO2KrX0/PFA==
601 | dependencies:
602 | "@parcel/css" "^1.12.2"
603 | "@parcel/diagnostic" "2.7.0"
604 | "@parcel/plugin" "2.7.0"
605 | "@parcel/source-map" "^2.0.0"
606 | "@parcel/utils" "2.7.0"
607 | browserslist "^4.6.6"
608 | nullthrows "^1.1.1"
609 |
610 | "@parcel/transformer-html@2.7.0":
611 | version "2.7.0"
612 | resolved "https://registry.yarnpkg.com/@parcel/transformer-html/-/transformer-html-2.7.0.tgz#5397a924fea683ef2c345f36f99f67f0181d6967"
613 | integrity sha512-wYJl5rn81W+Rlk9oQwDJcjoVsWVDKyeri84FzmlGXOsg0EYgnqOiG+3MDM8GeZjfuGe5fuoum4eqZeS0WdUHXw==
614 | dependencies:
615 | "@parcel/diagnostic" "2.7.0"
616 | "@parcel/hash" "2.7.0"
617 | "@parcel/plugin" "2.7.0"
618 | nullthrows "^1.1.1"
619 | posthtml "^0.16.5"
620 | posthtml-parser "^0.10.1"
621 | posthtml-render "^3.0.0"
622 | semver "^5.7.1"
623 |
624 | "@parcel/transformer-image@2.7.0":
625 | version "2.7.0"
626 | resolved "https://registry.yarnpkg.com/@parcel/transformer-image/-/transformer-image-2.7.0.tgz#e569ffc426c6060bc4dcccc0347c526930abfba4"
627 | integrity sha512-mhi9/R5/ULhCkL2COVIKhNFoLDiZwQgprdaTJr5fnODggVxEX5o7ebFV6KNLMTEkwZUJWoB1hL0ziI0++DtoFA==
628 | dependencies:
629 | "@parcel/plugin" "2.7.0"
630 | "@parcel/utils" "2.7.0"
631 | "@parcel/workers" "2.7.0"
632 | nullthrows "^1.1.1"
633 |
634 | "@parcel/transformer-js@2.7.0":
635 | version "2.7.0"
636 | resolved "https://registry.yarnpkg.com/@parcel/transformer-js/-/transformer-js-2.7.0.tgz#1e69295a11bf70d880cdd3846cf89016a74aac50"
637 | integrity sha512-mzerR+D4rDomUSIk5RSTa2w+DXBdXUeQrpDO74WCDdpDi1lIl8ppFpqtmU7O6y6p8QsgkmS9b0g/vhcry6CJTA==
638 | dependencies:
639 | "@parcel/diagnostic" "2.7.0"
640 | "@parcel/plugin" "2.7.0"
641 | "@parcel/source-map" "^2.0.0"
642 | "@parcel/utils" "2.7.0"
643 | "@parcel/workers" "2.7.0"
644 | "@swc/helpers" "^0.4.2"
645 | browserslist "^4.6.6"
646 | detect-libc "^1.0.3"
647 | nullthrows "^1.1.1"
648 | regenerator-runtime "^0.13.7"
649 | semver "^5.7.1"
650 |
651 | "@parcel/transformer-json@2.7.0":
652 | version "2.7.0"
653 | resolved "https://registry.yarnpkg.com/@parcel/transformer-json/-/transformer-json-2.7.0.tgz#c203f74cd445ce93eb833dd88be8127d1eadc6c3"
654 | integrity sha512-RQjuxBpYOch+kr4a0zi77KJtOLTPYRM7iq4NN80zKnA0r0dwDUCxZBtaj2l0O0o3R4MMJnm+ncP+cB7XR7dZYA==
655 | dependencies:
656 | "@parcel/plugin" "2.7.0"
657 | json5 "^2.2.0"
658 |
659 | "@parcel/transformer-postcss@2.7.0":
660 | version "2.7.0"
661 | resolved "https://registry.yarnpkg.com/@parcel/transformer-postcss/-/transformer-postcss-2.7.0.tgz#66be4469ae9186c89638ff67ec5808139caaeb8e"
662 | integrity sha512-b6RskXBWf0MjpC9qjR2dQ1ZdRnlOiKYseG5CEovWCqM218RtdydFKz7jS+5Gxkb6qBtOG7zGPONXdPe+gTILcA==
663 | dependencies:
664 | "@parcel/diagnostic" "2.7.0"
665 | "@parcel/hash" "2.7.0"
666 | "@parcel/plugin" "2.7.0"
667 | "@parcel/utils" "2.7.0"
668 | clone "^2.1.1"
669 | nullthrows "^1.1.1"
670 | postcss-value-parser "^4.2.0"
671 | semver "^5.7.1"
672 |
673 | "@parcel/transformer-posthtml@2.7.0":
674 | version "2.7.0"
675 | resolved "https://registry.yarnpkg.com/@parcel/transformer-posthtml/-/transformer-posthtml-2.7.0.tgz#67d5761b895574edb771f7ab1b24ec80775f58bd"
676 | integrity sha512-cP8YOiSynWJ1ycmBlhnnHeuQb2cwmklZ+BNyLUktj5p78kDy2de7VjX+dRNRHoW4H9OgEcSF4UEfDVVz5RYIhw==
677 | dependencies:
678 | "@parcel/plugin" "2.7.0"
679 | "@parcel/utils" "2.7.0"
680 | nullthrows "^1.1.1"
681 | posthtml "^0.16.5"
682 | posthtml-parser "^0.10.1"
683 | posthtml-render "^3.0.0"
684 | semver "^5.7.1"
685 |
686 | "@parcel/transformer-raw@2.7.0":
687 | version "2.7.0"
688 | resolved "https://registry.yarnpkg.com/@parcel/transformer-raw/-/transformer-raw-2.7.0.tgz#d6d8b94d1b33efc3dbf748ec1954c8917a2e1566"
689 | integrity sha512-sDnItWCFSDez0izK1i5cgv+kXzZTbcJh4rNpVIgmE1kBLvAz608sqgcCkavb2wVJIvLesxYM+5G4p1CwkDlZ1g==
690 | dependencies:
691 | "@parcel/plugin" "2.7.0"
692 |
693 | "@parcel/transformer-react-refresh-wrap@2.7.0":
694 | version "2.7.0"
695 | resolved "https://registry.yarnpkg.com/@parcel/transformer-react-refresh-wrap/-/transformer-react-refresh-wrap-2.7.0.tgz#e206b529d4a3444e14ba329d3323c5be3ded25d2"
696 | integrity sha512-1vRmIJzyBA1nIiXTAU6tZExq2FvJj/2F0ft6KDw8GYPv0KjmdiPo/PmaZ7JeSVOM6SdXQIQCbTmp1vkMP7DtkA==
697 | dependencies:
698 | "@parcel/plugin" "2.7.0"
699 | "@parcel/utils" "2.7.0"
700 | react-refresh "^0.9.0"
701 |
702 | "@parcel/transformer-svg@2.7.0":
703 | version "2.7.0"
704 | resolved "https://registry.yarnpkg.com/@parcel/transformer-svg/-/transformer-svg-2.7.0.tgz#c2a7d10bdbc6aeb2ae7ef85db5b583574807071c"
705 | integrity sha512-ioER37zceuuE+K6ZrnjCyMUWEnv+63hIAFResc1OXxRhyt+7kzMz9ZqK0Mt6QMLwl1dxhkLmrU41n9IxzKZuSQ==
706 | dependencies:
707 | "@parcel/diagnostic" "2.7.0"
708 | "@parcel/hash" "2.7.0"
709 | "@parcel/plugin" "2.7.0"
710 | nullthrows "^1.1.1"
711 | posthtml "^0.16.5"
712 | posthtml-parser "^0.10.1"
713 | posthtml-render "^3.0.0"
714 | semver "^5.7.1"
715 |
716 | "@parcel/types@2.7.0":
717 | version "2.7.0"
718 | resolved "https://registry.yarnpkg.com/@parcel/types/-/types-2.7.0.tgz#c89e95964339324c1931ef7a17906a72291d6b73"
719 | integrity sha512-+dhXVUnseTCpJvBTGMp0V6X13z6O/A/+CUtwEpMGZ8XSmZ4Gk44GvaTiBOp0bJpWG4fvCKp+UmC8PYbrDiiziw==
720 | dependencies:
721 | "@parcel/cache" "2.7.0"
722 | "@parcel/diagnostic" "2.7.0"
723 | "@parcel/fs" "2.7.0"
724 | "@parcel/package-manager" "2.7.0"
725 | "@parcel/source-map" "^2.0.0"
726 | "@parcel/workers" "2.7.0"
727 | utility-types "^3.10.0"
728 |
729 | "@parcel/utils@2.7.0":
730 | version "2.7.0"
731 | resolved "https://registry.yarnpkg.com/@parcel/utils/-/utils-2.7.0.tgz#f795d0f43efdd449ab0bbfac3632cd7f3ec0e4dd"
732 | integrity sha512-jNZ5bIGg1r1RDRKi562o4kuVwnz+XJ2Ie3b0Zwrqwvgfj6AbRFIKzDd+h85dWWmcDYzKUbHp11u6VJl1u8Vapg==
733 | dependencies:
734 | "@parcel/codeframe" "2.7.0"
735 | "@parcel/diagnostic" "2.7.0"
736 | "@parcel/hash" "2.7.0"
737 | "@parcel/logger" "2.7.0"
738 | "@parcel/markdown-ansi" "2.7.0"
739 | "@parcel/source-map" "^2.0.0"
740 | chalk "^4.1.0"
741 |
742 | "@parcel/watcher@^2.0.0":
743 | version "2.0.5"
744 | resolved "https://registry.yarnpkg.com/@parcel/watcher/-/watcher-2.0.5.tgz#f913a54e1601b0aac972803829b0eece48de215b"
745 | integrity sha512-x0hUbjv891omnkcHD7ZOhiyyUqUUR6MNjq89JhEI3BxppeKWAm6NPQsqqRrAkCJBogdT/o/My21sXtTI9rJIsw==
746 | dependencies:
747 | node-addon-api "^3.2.1"
748 | node-gyp-build "^4.3.0"
749 |
750 | "@parcel/workers@2.7.0":
751 | version "2.7.0"
752 | resolved "https://registry.yarnpkg.com/@parcel/workers/-/workers-2.7.0.tgz#d74955d361337127227912a5ab26cb3079ebfc78"
753 | integrity sha512-99VfaOX+89+RaoTSyH9ZQtkMBFZBFMvJmVJ/GeJT6QCd2wtKBStTHlaSnQOkLD/iRjJCNwV2xpZmm8YkTwV+hg==
754 | dependencies:
755 | "@parcel/diagnostic" "2.7.0"
756 | "@parcel/logger" "2.7.0"
757 | "@parcel/types" "2.7.0"
758 | "@parcel/utils" "2.7.0"
759 | chrome-trace-event "^1.0.2"
760 | nullthrows "^1.1.1"
761 |
762 | "@swc/helpers@^0.4.2":
763 | version "0.4.7"
764 | resolved "https://registry.yarnpkg.com/@swc/helpers/-/helpers-0.4.7.tgz#25a32e462e799a5a102eb9c241f73bbc4cb806a7"
765 | integrity sha512-jJKr/2JOivCQxb5Xpli3asedRLH34QgJ3G+7gm6CoCOwt/LDDX9g67OuxvjFOiYZfngWYB66ZbjU6cUNtQdavg==
766 | dependencies:
767 | tslib "^2.4.0"
768 |
769 | "@trysound/sax@0.2.0":
770 | version "0.2.0"
771 | resolved "https://registry.yarnpkg.com/@trysound/sax/-/sax-0.2.0.tgz#cccaab758af56761eb7bf37af6f03f326dd798ad"
772 | integrity sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==
773 |
774 | "@types/parse-json@^4.0.0":
775 | version "4.0.0"
776 | resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0"
777 | integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==
778 |
779 | "@types/prop-types@*":
780 | version "15.7.5"
781 | resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.5.tgz#5f19d2b85a98e9558036f6a3cacc8819420f05cf"
782 | integrity sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==
783 |
784 | "@types/react-dom@^17.0.2":
785 | version "17.0.17"
786 | resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-17.0.17.tgz#2e3743277a793a96a99f1bf87614598289da68a1"
787 | integrity sha512-VjnqEmqGnasQKV0CWLevqMTXBYG9GbwuE6x3VetERLh0cq2LTptFE73MrQi2S7GkKXCf2GgwItB/melLnxfnsg==
788 | dependencies:
789 | "@types/react" "^17"
790 |
791 | "@types/react@^17", "@types/react@^17.0.2":
792 | version "17.0.48"
793 | resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.48.tgz#a4532a8b91d7b27b8768b6fc0c3bccb760d15a6c"
794 | integrity sha512-zJ6IYlJ8cYYxiJfUaZOQee4lh99mFihBoqkOSEGV+dFi9leROW6+PgstzQ+w3gWTnUfskALtQPGHK6dYmPj+2A==
795 | dependencies:
796 | "@types/prop-types" "*"
797 | "@types/scheduler" "*"
798 | csstype "^3.0.2"
799 |
800 | "@types/scheduler@*":
801 | version "0.16.2"
802 | resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.2.tgz#1a62f89525723dde24ba1b01b092bf5df8ad4d39"
803 | integrity sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==
804 |
805 | abortcontroller-polyfill@^1.1.9:
806 | version "1.7.3"
807 | resolved "https://registry.yarnpkg.com/abortcontroller-polyfill/-/abortcontroller-polyfill-1.7.3.tgz#1b5b487bd6436b5b764fd52a612509702c3144b5"
808 | integrity sha512-zetDJxd89y3X99Kvo4qFx8GKlt6GsvN3UcRZHwU6iFA/0KiOmhkTVhe8oRoTBiTVPZu09x3vCra47+w8Yz1+2Q==
809 |
810 | acorn@^8.5.0:
811 | version "8.8.0"
812 | resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.0.tgz#88c0187620435c7f6015803f5539dae05a9dbea8"
813 | integrity sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==
814 |
815 | ansi-styles@^3.2.1:
816 | version "3.2.1"
817 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
818 | integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==
819 | dependencies:
820 | color-convert "^1.9.0"
821 |
822 | ansi-styles@^4.1.0:
823 | version "4.3.0"
824 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937"
825 | integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==
826 | dependencies:
827 | color-convert "^2.0.1"
828 |
829 | asap@~2.0.6:
830 | version "2.0.6"
831 | resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46"
832 | integrity sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==
833 |
834 | base-x@^3.0.8:
835 | version "3.0.9"
836 | resolved "https://registry.yarnpkg.com/base-x/-/base-x-3.0.9.tgz#6349aaabb58526332de9f60995e548a53fe21320"
837 | integrity sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ==
838 | dependencies:
839 | safe-buffer "^5.0.1"
840 |
841 | boolbase@^1.0.0:
842 | version "1.0.0"
843 | resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e"
844 | integrity sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==
845 |
846 | browserslist@^4.6.6:
847 | version "4.21.3"
848 | resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.3.tgz#5df277694eb3c48bc5c4b05af3e8b7e09c5a6d1a"
849 | integrity sha512-898rgRXLAyRkM1GryrrBHGkqA5hlpkV5MhtZwg9QXeiyLUYs2k00Un05aX5l2/yJIOObYKOpS2JNo8nJDE7fWQ==
850 | dependencies:
851 | caniuse-lite "^1.0.30001370"
852 | electron-to-chromium "^1.4.202"
853 | node-releases "^2.0.6"
854 | update-browserslist-db "^1.0.5"
855 |
856 | buffer-from@^1.0.0:
857 | version "1.1.2"
858 | resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5"
859 | integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==
860 |
861 | callsites@^3.0.0:
862 | version "3.1.0"
863 | resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73"
864 | integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==
865 |
866 | caniuse-lite@^1.0.30001370:
867 | version "1.0.30001379"
868 | resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001379.tgz#c42f61d3ee45152ad0fa5005a6b5b34c27797a07"
869 | integrity sha512-zXf+qxuN8OJrK5Bl5HbJg8cc5/Zm01WNW4ooVWUh92YlKqQZW3fwN5lXLB+kI8wkP5vTWkIIN+rutZuJhf4ykw==
870 |
871 | chalk@^2.0.0:
872 | version "2.4.2"
873 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
874 | integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
875 | dependencies:
876 | ansi-styles "^3.2.1"
877 | escape-string-regexp "^1.0.5"
878 | supports-color "^5.3.0"
879 |
880 | chalk@^4.1.0:
881 | version "4.1.2"
882 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01"
883 | integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==
884 | dependencies:
885 | ansi-styles "^4.1.0"
886 | supports-color "^7.1.0"
887 |
888 | chrome-trace-event@^1.0.2:
889 | version "1.0.3"
890 | resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz#1015eced4741e15d06664a957dbbf50d041e26ac"
891 | integrity sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==
892 |
893 | clone@^2.1.1:
894 | version "2.1.2"
895 | resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f"
896 | integrity sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==
897 |
898 | color-convert@^1.9.0:
899 | version "1.9.3"
900 | resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
901 | integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==
902 | dependencies:
903 | color-name "1.1.3"
904 |
905 | color-convert@^2.0.1:
906 | version "2.0.1"
907 | resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3"
908 | integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==
909 | dependencies:
910 | color-name "~1.1.4"
911 |
912 | color-name@1.1.3:
913 | version "1.1.3"
914 | resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
915 | integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==
916 |
917 | color-name@~1.1.4:
918 | version "1.1.4"
919 | resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
920 | integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
921 |
922 | commander@^2.20.0:
923 | version "2.20.3"
924 | resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
925 | integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
926 |
927 | commander@^7.0.0, commander@^7.2.0:
928 | version "7.2.0"
929 | resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7"
930 | integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==
931 |
932 | core-js@^3.5.0:
933 | version "3.24.1"
934 | resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.24.1.tgz#cf7724d41724154010a6576b7b57d94c5d66e64f"
935 | integrity sha512-0QTBSYSUZ6Gq21utGzkfITDylE8jWC9Ne1D2MrhvlsZBI1x39OdDIVbzSqtgMndIy6BlHxBXpMGqzZmnztg2rg==
936 |
937 | cosmiconfig@^7.0.1:
938 | version "7.0.1"
939 | resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.0.1.tgz#714d756522cace867867ccb4474c5d01bbae5d6d"
940 | integrity sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ==
941 | dependencies:
942 | "@types/parse-json" "^4.0.0"
943 | import-fresh "^3.2.1"
944 | parse-json "^5.0.0"
945 | path-type "^4.0.0"
946 | yaml "^1.10.0"
947 |
948 | css-select@^4.1.3:
949 | version "4.3.0"
950 | resolved "https://registry.yarnpkg.com/css-select/-/css-select-4.3.0.tgz#db7129b2846662fd8628cfc496abb2b59e41529b"
951 | integrity sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==
952 | dependencies:
953 | boolbase "^1.0.0"
954 | css-what "^6.0.1"
955 | domhandler "^4.3.1"
956 | domutils "^2.8.0"
957 | nth-check "^2.0.1"
958 |
959 | css-tree@^1.1.2, css-tree@^1.1.3:
960 | version "1.1.3"
961 | resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.1.3.tgz#eb4870fb6fd7707327ec95c2ff2ab09b5e8db91d"
962 | integrity sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==
963 | dependencies:
964 | mdn-data "2.0.14"
965 | source-map "^0.6.1"
966 |
967 | css-what@^6.0.1:
968 | version "6.1.0"
969 | resolved "https://registry.yarnpkg.com/css-what/-/css-what-6.1.0.tgz#fb5effcf76f1ddea2c81bdfaa4de44e79bac70f4"
970 | integrity sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==
971 |
972 | csso@^4.2.0:
973 | version "4.2.0"
974 | resolved "https://registry.yarnpkg.com/csso/-/csso-4.2.0.tgz#ea3a561346e8dc9f546d6febedd50187cf389529"
975 | integrity sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==
976 | dependencies:
977 | css-tree "^1.1.2"
978 |
979 | csstype@^3.0.2:
980 | version "3.1.0"
981 | resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.0.tgz#4ddcac3718d787cf9df0d1b7d15033925c8f29f2"
982 | integrity sha512-uX1KG+x9h5hIJsaKR9xHUeUraxf8IODOwq9JLNPq6BwB04a/xgpq3rcx47l5BZu5zBPlgD342tdke3Hom/nJRA==
983 |
984 | detect-libc@^1.0.3:
985 | version "1.0.3"
986 | resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b"
987 | integrity sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==
988 |
989 | dom-serializer@^1.0.1:
990 | version "1.4.1"
991 | resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-1.4.1.tgz#de5d41b1aea290215dc45a6dae8adcf1d32e2d30"
992 | integrity sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==
993 | dependencies:
994 | domelementtype "^2.0.1"
995 | domhandler "^4.2.0"
996 | entities "^2.0.0"
997 |
998 | domelementtype@^2.0.1, domelementtype@^2.2.0:
999 | version "2.3.0"
1000 | resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.3.0.tgz#5c45e8e869952626331d7aab326d01daf65d589d"
1001 | integrity sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==
1002 |
1003 | domhandler@^4.2.0, domhandler@^4.2.2, domhandler@^4.3.1:
1004 | version "4.3.1"
1005 | resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-4.3.1.tgz#8d792033416f59d68bc03a5aa7b018c1ca89279c"
1006 | integrity sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==
1007 | dependencies:
1008 | domelementtype "^2.2.0"
1009 |
1010 | domutils@^2.8.0:
1011 | version "2.8.0"
1012 | resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.8.0.tgz#4437def5db6e2d1f5d6ee859bd95ca7d02048135"
1013 | integrity sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==
1014 | dependencies:
1015 | dom-serializer "^1.0.1"
1016 | domelementtype "^2.2.0"
1017 | domhandler "^4.2.0"
1018 |
1019 | dotenv-expand@^5.1.0:
1020 | version "5.1.0"
1021 | resolved "https://registry.yarnpkg.com/dotenv-expand/-/dotenv-expand-5.1.0.tgz#3fbaf020bfd794884072ea26b1e9791d45a629f0"
1022 | integrity sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==
1023 |
1024 | dotenv@^7.0.0:
1025 | version "7.0.0"
1026 | resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-7.0.0.tgz#a2be3cd52736673206e8a85fb5210eea29628e7c"
1027 | integrity sha512-M3NhsLbV1i6HuGzBUH8vXrtxOk+tWmzWKDMbAVSUp3Zsjm7ywFeuwrUXhmhQyRK1q5B5GGy7hcXPbj3bnfZg2g==
1028 |
1029 | electron-to-chromium@^1.4.202:
1030 | version "1.4.225"
1031 | resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.225.tgz#3e27bdd157cbaf19768141f2e0f0f45071e52338"
1032 | integrity sha512-ICHvGaCIQR3P88uK8aRtx8gmejbVJyC6bB4LEC3anzBrIzdzC7aiZHY4iFfXhN4st6I7lMO0x4sgBHf/7kBvRw==
1033 |
1034 | entities@^2.0.0:
1035 | version "2.2.0"
1036 | resolved "https://registry.yarnpkg.com/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55"
1037 | integrity sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==
1038 |
1039 | entities@^3.0.1:
1040 | version "3.0.1"
1041 | resolved "https://registry.yarnpkg.com/entities/-/entities-3.0.1.tgz#2b887ca62585e96db3903482d336c1006c3001d4"
1042 | integrity sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==
1043 |
1044 | error-ex@^1.3.1:
1045 | version "1.3.2"
1046 | resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf"
1047 | integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==
1048 | dependencies:
1049 | is-arrayish "^0.2.1"
1050 |
1051 | escalade@^3.1.1:
1052 | version "3.1.1"
1053 | resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40"
1054 | integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==
1055 |
1056 | escape-string-regexp@^1.0.5:
1057 | version "1.0.5"
1058 | resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
1059 | integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==
1060 |
1061 | get-port@^4.2.0:
1062 | version "4.2.0"
1063 | resolved "https://registry.yarnpkg.com/get-port/-/get-port-4.2.0.tgz#e37368b1e863b7629c43c5a323625f95cf24b119"
1064 | integrity sha512-/b3jarXkH8KJoOMQc3uVGHASwGLPq3gSFJ7tgJm2diza+bydJPTGOibin2steecKeOylE8oY2JERlVWkAJO6yw==
1065 |
1066 | globals@^13.2.0:
1067 | version "13.17.0"
1068 | resolved "https://registry.yarnpkg.com/globals/-/globals-13.17.0.tgz#902eb1e680a41da93945adbdcb5a9f361ba69bd4"
1069 | integrity sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==
1070 | dependencies:
1071 | type-fest "^0.20.2"
1072 |
1073 | has-flag@^3.0.0:
1074 | version "3.0.0"
1075 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
1076 | integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==
1077 |
1078 | has-flag@^4.0.0:
1079 | version "4.0.0"
1080 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b"
1081 | integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==
1082 |
1083 | htmlnano@^2.0.0:
1084 | version "2.0.2"
1085 | resolved "https://registry.yarnpkg.com/htmlnano/-/htmlnano-2.0.2.tgz#3e3170941e2446a86211196d740272ebca78f878"
1086 | integrity sha512-+ZrQFS4Ub+zd+/fWwfvoYCEGNEa0/zrpys6CyXxvZDwtL7Pl+pOtRkiujyvBQ7Lmfp7/iEPxtOFgxWA16Gkj3w==
1087 | dependencies:
1088 | cosmiconfig "^7.0.1"
1089 | posthtml "^0.16.5"
1090 | timsort "^0.3.0"
1091 |
1092 | htmlparser2@^7.1.1:
1093 | version "7.2.0"
1094 | resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-7.2.0.tgz#8817cdea38bbc324392a90b1990908e81a65f5a5"
1095 | integrity sha512-H7MImA4MS6cw7nbyURtLPO1Tms7C5H602LRETv95z1MxO/7CP7rDVROehUYeYBUYEON94NXXDEPmZuq+hX4sog==
1096 | dependencies:
1097 | domelementtype "^2.0.1"
1098 | domhandler "^4.2.2"
1099 | domutils "^2.8.0"
1100 | entities "^3.0.1"
1101 |
1102 | import-fresh@^3.2.1:
1103 | version "3.3.0"
1104 | resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b"
1105 | integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==
1106 | dependencies:
1107 | parent-module "^1.0.0"
1108 | resolve-from "^4.0.0"
1109 |
1110 | is-arrayish@^0.2.1:
1111 | version "0.2.1"
1112 | resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d"
1113 | integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==
1114 |
1115 | is-json@^2.0.1:
1116 | version "2.0.1"
1117 | resolved "https://registry.yarnpkg.com/is-json/-/is-json-2.0.1.tgz#6be166d144828a131d686891b983df62c39491ff"
1118 | integrity sha512-6BEnpVn1rcf3ngfmViLM6vjUjGErbdrL4rwlv+u1NO1XO8kqT4YGL8+19Q+Z/bas8tY90BTWMk2+fW1g6hQjbA==
1119 |
1120 | js-tokens@^4.0.0:
1121 | version "4.0.0"
1122 | resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
1123 | integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
1124 |
1125 | json-parse-even-better-errors@^2.3.0:
1126 | version "2.3.1"
1127 | resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d"
1128 | integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==
1129 |
1130 | json5@^2.2.0, json5@^2.2.1:
1131 | version "2.2.1"
1132 | resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.1.tgz#655d50ed1e6f95ad1a3caababd2b0efda10b395c"
1133 | integrity sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==
1134 |
1135 | lines-and-columns@^1.1.6:
1136 | version "1.2.4"
1137 | resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632"
1138 | integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==
1139 |
1140 | lmdb@2.5.2:
1141 | version "2.5.2"
1142 | resolved "https://registry.yarnpkg.com/lmdb/-/lmdb-2.5.2.tgz#37e28a9fb43405f4dc48c44cec0e13a14c4a6ff1"
1143 | integrity sha512-V5V5Xa2Hp9i2XsbDALkBTeHXnBXh/lEmk9p22zdr7jtuOIY9TGhjK6vAvTpOOx9IKU4hJkRWZxn/HsvR1ELLtA==
1144 | dependencies:
1145 | msgpackr "^1.5.4"
1146 | node-addon-api "^4.3.0"
1147 | node-gyp-build-optional-packages "5.0.3"
1148 | ordered-binary "^1.2.4"
1149 | weak-lru-cache "^1.2.2"
1150 | optionalDependencies:
1151 | "@lmdb/lmdb-darwin-arm64" "2.5.2"
1152 | "@lmdb/lmdb-darwin-x64" "2.5.2"
1153 | "@lmdb/lmdb-linux-arm" "2.5.2"
1154 | "@lmdb/lmdb-linux-arm64" "2.5.2"
1155 | "@lmdb/lmdb-linux-x64" "2.5.2"
1156 | "@lmdb/lmdb-win32-x64" "2.5.2"
1157 |
1158 | mdn-data@2.0.14:
1159 | version "2.0.14"
1160 | resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.14.tgz#7113fc4281917d63ce29b43446f701e68c25ba50"
1161 | integrity sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==
1162 |
1163 | msgpackr-extract@^2.0.2:
1164 | version "2.1.2"
1165 | resolved "https://registry.yarnpkg.com/msgpackr-extract/-/msgpackr-extract-2.1.2.tgz#56272030f3e163e1b51964ef8b1cd5e7240c03ed"
1166 | integrity sha512-cmrmERQFb19NX2JABOGtrKdHMyI6RUyceaPBQ2iRz9GnDkjBWFjNJC0jyyoOfZl2U/LZE3tQCCQc4dlRyA8mcA==
1167 | dependencies:
1168 | node-gyp-build-optional-packages "5.0.3"
1169 | optionalDependencies:
1170 | "@msgpackr-extract/msgpackr-extract-darwin-arm64" "2.1.2"
1171 | "@msgpackr-extract/msgpackr-extract-darwin-x64" "2.1.2"
1172 | "@msgpackr-extract/msgpackr-extract-linux-arm" "2.1.2"
1173 | "@msgpackr-extract/msgpackr-extract-linux-arm64" "2.1.2"
1174 | "@msgpackr-extract/msgpackr-extract-linux-x64" "2.1.2"
1175 | "@msgpackr-extract/msgpackr-extract-win32-x64" "2.1.2"
1176 |
1177 | msgpackr@^1.5.4:
1178 | version "1.6.2"
1179 | resolved "https://registry.yarnpkg.com/msgpackr/-/msgpackr-1.6.2.tgz#176cd9f6b4437dad87a839b37f23c2dfee408d9a"
1180 | integrity sha512-bqSQ0DYJbXbrJcrZFmMygUZmqQiDfI2ewFVWcrZY12w5XHWtPuW4WppDT/e63Uu311ajwkRRXSoF0uILroBeTA==
1181 | optionalDependencies:
1182 | msgpackr-extract "^2.0.2"
1183 |
1184 | node-addon-api@^3.2.1:
1185 | version "3.2.1"
1186 | resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-3.2.1.tgz#81325e0a2117789c0128dab65e7e38f07ceba161"
1187 | integrity sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==
1188 |
1189 | node-addon-api@^4.3.0:
1190 | version "4.3.0"
1191 | resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-4.3.0.tgz#52a1a0b475193e0928e98e0426a0d1254782b77f"
1192 | integrity sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==
1193 |
1194 | node-gyp-build-optional-packages@5.0.3:
1195 | version "5.0.3"
1196 | resolved "https://registry.yarnpkg.com/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.0.3.tgz#92a89d400352c44ad3975010368072b41ad66c17"
1197 | integrity sha512-k75jcVzk5wnnc/FMxsf4udAoTEUv2jY3ycfdSd3yWu6Cnd1oee6/CfZJApyscA4FJOmdoixWwiwOyf16RzD5JA==
1198 |
1199 | node-gyp-build@^4.3.0:
1200 | version "4.5.0"
1201 | resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.5.0.tgz#7a64eefa0b21112f89f58379da128ac177f20e40"
1202 | integrity sha512-2iGbaQBV+ITgCz76ZEjmhUKAKVf7xfY1sRl4UiKQspfZMH2h06SyhNsnSVy50cwkFQDGLyif6m/6uFXHkOZ6rg==
1203 |
1204 | node-releases@^2.0.6:
1205 | version "2.0.6"
1206 | resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.6.tgz#8a7088c63a55e493845683ebf3c828d8c51c5503"
1207 | integrity sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==
1208 |
1209 | nth-check@^2.0.1:
1210 | version "2.1.1"
1211 | resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-2.1.1.tgz#c9eab428effce36cd6b92c924bdb000ef1f1ed1d"
1212 | integrity sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==
1213 | dependencies:
1214 | boolbase "^1.0.0"
1215 |
1216 | nullthrows@^1.1.1:
1217 | version "1.1.1"
1218 | resolved "https://registry.yarnpkg.com/nullthrows/-/nullthrows-1.1.1.tgz#7818258843856ae971eae4208ad7d7eb19a431b1"
1219 | integrity sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw==
1220 |
1221 | object-assign@^4.1.1:
1222 | version "4.1.1"
1223 | resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
1224 | integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==
1225 |
1226 | ordered-binary@^1.2.4:
1227 | version "1.3.0"
1228 | resolved "https://registry.yarnpkg.com/ordered-binary/-/ordered-binary-1.3.0.tgz#a116d64c923278216e335602d279750b2ebd746e"
1229 | integrity sha512-knIeYepTI6BDAzGxqFEDGtI/iGqs57H32CInAIxEvAHG46vk1Di0CEpyc1A7iY39B1mfik3g3KLYwOTNnnMHLA==
1230 |
1231 | parcel@^2.7.0:
1232 | version "2.7.0"
1233 | resolved "https://registry.yarnpkg.com/parcel/-/parcel-2.7.0.tgz#41fdd3e5c7144d4cf7f1fa3ab8d0ea0d47d31f77"
1234 | integrity sha512-pRYwnivwtNP0tip8xYSo4zCB0XhLt7/gJzP1p8OovCqkmFjG9VG+GW9TcAKqMIo0ovEa9tT+/s6gY1Qy+BONGQ==
1235 | dependencies:
1236 | "@parcel/config-default" "2.7.0"
1237 | "@parcel/core" "2.7.0"
1238 | "@parcel/diagnostic" "2.7.0"
1239 | "@parcel/events" "2.7.0"
1240 | "@parcel/fs" "2.7.0"
1241 | "@parcel/logger" "2.7.0"
1242 | "@parcel/package-manager" "2.7.0"
1243 | "@parcel/reporter-cli" "2.7.0"
1244 | "@parcel/reporter-dev-server" "2.7.0"
1245 | "@parcel/utils" "2.7.0"
1246 | chalk "^4.1.0"
1247 | commander "^7.0.0"
1248 | get-port "^4.2.0"
1249 | v8-compile-cache "^2.0.0"
1250 |
1251 | parent-module@^1.0.0:
1252 | version "1.0.1"
1253 | resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2"
1254 | integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==
1255 | dependencies:
1256 | callsites "^3.0.0"
1257 |
1258 | parse-json@^5.0.0:
1259 | version "5.2.0"
1260 | resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd"
1261 | integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==
1262 | dependencies:
1263 | "@babel/code-frame" "^7.0.0"
1264 | error-ex "^1.3.1"
1265 | json-parse-even-better-errors "^2.3.0"
1266 | lines-and-columns "^1.1.6"
1267 |
1268 | path-type@^4.0.0:
1269 | version "4.0.0"
1270 | resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b"
1271 | integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==
1272 |
1273 | performance-now@^2.1.0:
1274 | version "2.1.0"
1275 | resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b"
1276 | integrity sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==
1277 |
1278 | picocolors@^1.0.0:
1279 | version "1.0.0"
1280 | resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c"
1281 | integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==
1282 |
1283 | postcss-value-parser@^4.2.0:
1284 | version "4.2.0"
1285 | resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514"
1286 | integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==
1287 |
1288 | posthtml-parser@^0.10.1:
1289 | version "0.10.2"
1290 | resolved "https://registry.yarnpkg.com/posthtml-parser/-/posthtml-parser-0.10.2.tgz#df364d7b179f2a6bf0466b56be7b98fd4e97c573"
1291 | integrity sha512-PId6zZ/2lyJi9LiKfe+i2xv57oEjJgWbsHGGANwos5AvdQp98i6AtamAl8gzSVFGfQ43Glb5D614cvZf012VKg==
1292 | dependencies:
1293 | htmlparser2 "^7.1.1"
1294 |
1295 | posthtml-parser@^0.11.0:
1296 | version "0.11.0"
1297 | resolved "https://registry.yarnpkg.com/posthtml-parser/-/posthtml-parser-0.11.0.tgz#25d1c7bf811ea83559bc4c21c189a29747a24b7a"
1298 | integrity sha512-QecJtfLekJbWVo/dMAA+OSwY79wpRmbqS5TeXvXSX+f0c6pW4/SE6inzZ2qkU7oAMCPqIDkZDvd/bQsSFUnKyw==
1299 | dependencies:
1300 | htmlparser2 "^7.1.1"
1301 |
1302 | posthtml-render@^3.0.0:
1303 | version "3.0.0"
1304 | resolved "https://registry.yarnpkg.com/posthtml-render/-/posthtml-render-3.0.0.tgz#97be44931496f495b4f07b99e903cc70ad6a3205"
1305 | integrity sha512-z+16RoxK3fUPgwaIgH9NGnK1HKY9XIDpydky5eQGgAFVXTCSezalv9U2jQuNV+Z9qV1fDWNzldcw4eK0SSbqKA==
1306 | dependencies:
1307 | is-json "^2.0.1"
1308 |
1309 | posthtml@^0.16.4, posthtml@^0.16.5:
1310 | version "0.16.6"
1311 | resolved "https://registry.yarnpkg.com/posthtml/-/posthtml-0.16.6.tgz#e2fc407f67a64d2fa3567afe770409ffdadafe59"
1312 | integrity sha512-JcEmHlyLK/o0uGAlj65vgg+7LIms0xKXe60lcDOTU7oVX/3LuEuLwrQpW3VJ7de5TaFKiW4kWkaIpJL42FEgxQ==
1313 | dependencies:
1314 | posthtml-parser "^0.11.0"
1315 | posthtml-render "^3.0.0"
1316 |
1317 | promise@^8.0.3:
1318 | version "8.1.0"
1319 | resolved "https://registry.yarnpkg.com/promise/-/promise-8.1.0.tgz#697c25c3dfe7435dd79fcd58c38a135888eaf05e"
1320 | integrity sha512-W04AqnILOL/sPRXziNicCjSNRruLAuIHEOVBazepu0545DDNGYHz7ar9ZgZ1fMU8/MA4mVxp5rkBWRi6OXIy3Q==
1321 | dependencies:
1322 | asap "~2.0.6"
1323 |
1324 | raf@^3.4.1:
1325 | version "3.4.1"
1326 | resolved "https://registry.yarnpkg.com/raf/-/raf-3.4.1.tgz#0742e99a4a6552f445d73e3ee0328af0ff1ede39"
1327 | integrity sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==
1328 | dependencies:
1329 | performance-now "^2.1.0"
1330 |
1331 | react-app-polyfill@^1.0.0:
1332 | version "1.0.6"
1333 | resolved "https://registry.yarnpkg.com/react-app-polyfill/-/react-app-polyfill-1.0.6.tgz#890f8d7f2842ce6073f030b117de9130a5f385f0"
1334 | integrity sha512-OfBnObtnGgLGfweORmdZbyEz+3dgVePQBb3zipiaDsMHV1NpWm0rDFYIVXFV/AK+x4VIIfWHhrdMIeoTLyRr2g==
1335 | dependencies:
1336 | core-js "^3.5.0"
1337 | object-assign "^4.1.1"
1338 | promise "^8.0.3"
1339 | raf "^3.4.1"
1340 | regenerator-runtime "^0.13.3"
1341 | whatwg-fetch "^3.0.0"
1342 |
1343 | react-error-overlay@6.0.9:
1344 | version "6.0.9"
1345 | resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.9.tgz#3c743010c9359608c375ecd6bc76f35d93995b0a"
1346 | integrity sha512-nQTTcUu+ATDbrSD1BZHr5kgSD4oF8OFjxun8uAaL8RwPBacGBNPf/yAuVVdx17N8XNzRDMrZ9XcKZHCjPW+9ew==
1347 |
1348 | react-refresh@^0.9.0:
1349 | version "0.9.0"
1350 | resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.9.0.tgz#71863337adc3e5c2f8a6bfddd12ae3bfe32aafbf"
1351 | integrity sha512-Gvzk7OZpiqKSkxsQvO/mbTN1poglhmAV7gR/DdIrRrSMXraRQQlfikRJOr3Nb9GTMPC5kof948Zy6jJZIFtDvQ==
1352 |
1353 | regenerator-runtime@^0.13.3, regenerator-runtime@^0.13.7:
1354 | version "0.13.9"
1355 | resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52"
1356 | integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==
1357 |
1358 | resolve-from@^4.0.0:
1359 | version "4.0.0"
1360 | resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6"
1361 | integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==
1362 |
1363 | safe-buffer@^5.0.1:
1364 | version "5.2.1"
1365 | resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
1366 | integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
1367 |
1368 | semver@^5.7.0, semver@^5.7.1:
1369 | version "5.7.1"
1370 | resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
1371 | integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
1372 |
1373 | source-map-support@~0.5.20:
1374 | version "0.5.21"
1375 | resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f"
1376 | integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==
1377 | dependencies:
1378 | buffer-from "^1.0.0"
1379 | source-map "^0.6.0"
1380 |
1381 | source-map@^0.6.0, source-map@^0.6.1:
1382 | version "0.6.1"
1383 | resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
1384 | integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
1385 |
1386 | stable@^0.1.8:
1387 | version "0.1.8"
1388 | resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf"
1389 | integrity sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==
1390 |
1391 | supports-color@^5.3.0:
1392 | version "5.5.0"
1393 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
1394 | integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==
1395 | dependencies:
1396 | has-flag "^3.0.0"
1397 |
1398 | supports-color@^7.1.0:
1399 | version "7.2.0"
1400 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da"
1401 | integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==
1402 | dependencies:
1403 | has-flag "^4.0.0"
1404 |
1405 | svgo@^2.4.0:
1406 | version "2.8.0"
1407 | resolved "https://registry.yarnpkg.com/svgo/-/svgo-2.8.0.tgz#4ff80cce6710dc2795f0c7c74101e6764cfccd24"
1408 | integrity sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg==
1409 | dependencies:
1410 | "@trysound/sax" "0.2.0"
1411 | commander "^7.2.0"
1412 | css-select "^4.1.3"
1413 | css-tree "^1.1.3"
1414 | csso "^4.2.0"
1415 | picocolors "^1.0.0"
1416 | stable "^0.1.8"
1417 |
1418 | term-size@^2.2.1:
1419 | version "2.2.1"
1420 | resolved "https://registry.yarnpkg.com/term-size/-/term-size-2.2.1.tgz#2a6a54840432c2fb6320fea0f415531e90189f54"
1421 | integrity sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==
1422 |
1423 | terser@^5.2.0:
1424 | version "5.14.2"
1425 | resolved "https://registry.yarnpkg.com/terser/-/terser-5.14.2.tgz#9ac9f22b06994d736174f4091aa368db896f1c10"
1426 | integrity sha512-oL0rGeM/WFQCUd0y2QrWxYnq7tfSuKBiqTjRPWrRgB46WD/kiwHwF8T23z78H6Q6kGCuuHcPB+KULHRdxvVGQA==
1427 | dependencies:
1428 | "@jridgewell/source-map" "^0.3.2"
1429 | acorn "^8.5.0"
1430 | commander "^2.20.0"
1431 | source-map-support "~0.5.20"
1432 |
1433 | timsort@^0.3.0:
1434 | version "0.3.0"
1435 | resolved "https://registry.yarnpkg.com/timsort/-/timsort-0.3.0.tgz#405411a8e7e6339fe64db9a234de11dc31e02bd4"
1436 | integrity sha512-qsdtZH+vMoCARQtyod4imc2nIJwg9Cc7lPRrw9CzF8ZKR0khdr8+2nX80PBhET3tcyTtJDxAffGh2rXH4tyU8A==
1437 |
1438 | tslib@^2.4.0:
1439 | version "2.4.0"
1440 | resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3"
1441 | integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==
1442 |
1443 | type-fest@^0.20.2:
1444 | version "0.20.2"
1445 | resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4"
1446 | integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==
1447 |
1448 | typescript@^4.7.4:
1449 | version "4.7.4"
1450 | resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.7.4.tgz#1a88596d1cf47d59507a1bcdfb5b9dfe4d488235"
1451 | integrity sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==
1452 |
1453 | update-browserslist-db@^1.0.5:
1454 | version "1.0.5"
1455 | resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.5.tgz#be06a5eedd62f107b7c19eb5bcefb194411abf38"
1456 | integrity sha512-dteFFpCyvuDdr9S/ff1ISkKt/9YZxKjI9WlRR99c180GaztJtRa/fn18FdxGVKVsnPY7/a/FDN68mcvUmP4U7Q==
1457 | dependencies:
1458 | escalade "^3.1.1"
1459 | picocolors "^1.0.0"
1460 |
1461 | utility-types@^3.10.0:
1462 | version "3.10.0"
1463 | resolved "https://registry.yarnpkg.com/utility-types/-/utility-types-3.10.0.tgz#ea4148f9a741015f05ed74fd615e1d20e6bed82b"
1464 | integrity sha512-O11mqxmi7wMKCo6HKFt5AhO4BwY3VV68YU07tgxfz8zJTIxr4BpsezN49Ffwy9j3ZpwwJp4fkRwjRzq3uWE6Rg==
1465 |
1466 | v8-compile-cache@^2.0.0:
1467 | version "2.3.0"
1468 | resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee"
1469 | integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==
1470 |
1471 | weak-lru-cache@^1.2.2:
1472 | version "1.2.2"
1473 | resolved "https://registry.yarnpkg.com/weak-lru-cache/-/weak-lru-cache-1.2.2.tgz#fdbb6741f36bae9540d12f480ce8254060dccd19"
1474 | integrity sha512-DEAoo25RfSYMuTGc9vPJzZcZullwIqRDSI9LOy+fkCJPi6hykCnfKaXTuPBDuXAUcqHXyOgFtHNp/kB2FjYHbw==
1475 |
1476 | whatwg-fetch@^3.0.0:
1477 | version "3.6.2"
1478 | resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.6.2.tgz#dced24f37f2624ed0281725d51d0e2e3fe677f8c"
1479 | integrity sha512-bJlen0FcuU/0EMLrdbJ7zOnW6ITZLrZMIarMUVmdKtsGvZna8vxKYaexICWPfZ8qwf9fzNq+UEIZrnSaApt6RA==
1480 |
1481 | xxhash-wasm@^0.4.2:
1482 | version "0.4.2"
1483 | resolved "https://registry.yarnpkg.com/xxhash-wasm/-/xxhash-wasm-0.4.2.tgz#752398c131a4dd407b5132ba62ad372029be6f79"
1484 | integrity sha512-/eyHVRJQCirEkSZ1agRSCwriMhwlyUcFkXD5TPVSLP+IPzjsqMVzZwdoczLp1SoQU0R3dxz1RpIK+4YNQbCVOA==
1485 |
1486 | yaml@^1.10.0:
1487 | version "1.10.2"
1488 | resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b"
1489 | integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==
1490 |
--------------------------------------------------------------------------------
/jest.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | moduleNameMapper: {
3 | '\\.(css)$': '/__mocks__/style-mock.ts',
4 | },
5 | };
6 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "sassy-datepicker",
3 | "description": "Beautiful, minimal, customizable and accessible date-picker for react.",
4 | "author": "Siddharth Borderwala",
5 | "version": "0.10.2",
6 | "license": "MIT",
7 | "homepage": "https://sassy-datepicker.netlify.app",
8 | "repository": {
9 | "type": "git",
10 | "url": "https://github.com/sassy-labs/datepicker.git"
11 | },
12 | "bugs": {
13 | "url": "https://github.com/sassy-labs/datepicker/issues"
14 | },
15 | "keywords": [
16 | "react",
17 | "date-picker",
18 | "time-picker",
19 | "date",
20 | "calendar",
21 | "react-component"
22 | ],
23 | "scripts": {
24 | "start": "tsdx watch",
25 | "build": "tsdx build",
26 | "test": "tsdx test --passWithNoTests",
27 | "lint": "tsdx lint",
28 | "prepare": "tsdx build",
29 | "size": "size-limit",
30 | "analyze": "size-limit --why",
31 | "build:docs": "yarn build && cd docs && yarn install && yarn build"
32 | },
33 | "files": [
34 | "dist",
35 | "src"
36 | ],
37 | "main": "dist/index.js",
38 | "types": "dist/index.d.ts",
39 | "module": "dist/sassy-datepicker.esm.js",
40 | "exports": {
41 | "require": "./dist/sassy-datepicker.cjs.production.min.js",
42 | "import": "./dist/sassy-datepicker.esm.js",
43 | "default": "./dist/index.js"
44 | },
45 | "devDependencies": {
46 | "@size-limit/preset-small-lib": "^6.0.4",
47 | "@types/react": "^17.0.34",
48 | "@types/react-dom": "^17.0.11",
49 | "@typescript-eslint/eslint-plugin": "^5.33.1",
50 | "autoprefixer": "^10.4.0",
51 | "cssnano": "^5.0.10",
52 | "eslint": "^7.32.0",
53 | "eslint-config-airbnb": "^19.0.4",
54 | "eslint-plugin-react": "^7.30.1",
55 | "husky": "^7.0.4",
56 | "react": "^17.0.2",
57 | "react-dom": "^17.0.2",
58 | "rollup-plugin-postcss": "^4.0.1",
59 | "size-limit": "^6.0.4",
60 | "tsdx": "^0.14.1",
61 | "tslib": "^2.3.1",
62 | "typescript": "^4.4.4"
63 | },
64 | "peerDependencies": {
65 | "react": ">=16.8.0"
66 | },
67 | "husky": {
68 | "hooks": {
69 | "pre-commit": "tsdx lint"
70 | }
71 | },
72 | "size-limit": [
73 | {
74 | "path": "dist/sassy-datepicker.cjs.production.min.js",
75 | "limit": "10 KB"
76 | },
77 | {
78 | "path": "dist/sassy-datepicker.esm.js",
79 | "limit": "10 KB"
80 | }
81 | ],
82 | "dependencies": {
83 | "date-and-time": "^2.4.1"
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/src/components/select/index.tsx:
--------------------------------------------------------------------------------
1 | import React, {
2 | HTMLProps,
3 | PropsWithChildren,
4 | useCallback,
5 | useEffect,
6 | useMemo,
7 | useRef,
8 | useState,
9 | } from 'react';
10 | import CustomOption from './option';
11 |
12 | import './styles.css';
13 |
14 | export type OptionType = {
15 | value: T;
16 | label: string;
17 | disabled: boolean;
18 | };
19 |
20 | type CustomSelectProps = {
21 | /**
22 | * The value of the select.
23 | */
24 | value: T;
25 | /**
26 | * A callback triggered whenever the value of the select changes.
27 | */
28 | onChange: (value: T) => void;
29 | /**
30 | * The options to display in the select.
31 | *
32 | * Format - [{value: [value, label], disabled: boolean}, ...]
33 | */
34 | options: OptionType[];
35 | /**
36 | * If this input element is disabled
37 | */
38 | disabled?: boolean;
39 | /**
40 | * How to format the display value
41 | */
42 | formatValue?: (value: T) => string;
43 | } & Omit<
44 | PropsWithChildren>,
45 | 'onChange' | 'value' | 'disabled'
46 | >;
47 |
48 | /**
49 | * A custom select component.
50 | *
51 | */
52 | function CustomSelect({
53 | value,
54 | options,
55 | onChange,
56 | className,
57 | disabled,
58 | formatValue,
59 | }: CustomSelectProps): JSX.Element {
60 | const ref = useRef(null);
61 | const [isOpen, setIsOpen] = useState(false);
62 |
63 | const openOptionsDropdown = useCallback(() => {
64 | if (!disabled) setIsOpen(true);
65 | }, [setIsOpen, disabled]);
66 |
67 | const closeOptionsDropdown = useCallback(() => {
68 | setIsOpen(false);
69 | }, [setIsOpen]);
70 |
71 | const handleOptionSelect = useCallback(
72 | (v) => {
73 | onChange(v);
74 | closeOptionsDropdown();
75 | },
76 | [onChange, closeOptionsDropdown]
77 | );
78 |
79 | const showDropDown = useMemo(() => isOpen && !disabled, [isOpen, disabled]);
80 |
81 | const displayValue = useMemo(() => formatValue?.(value) ?? value, [
82 | formatValue,
83 | value,
84 | ]);
85 |
86 | useEffect(() => {
87 | const clickListener = (e: MouseEvent) => {
88 | if (!ref.current?.contains(e.target as Node)) {
89 | closeOptionsDropdown();
90 | }
91 | };
92 |
93 | const focusOutListener = (e: FocusEvent) => {
94 | if (!ref.current?.contains(e.relatedTarget as Node)) {
95 | closeOptionsDropdown();
96 | }
97 | };
98 |
99 | document.addEventListener('click', clickListener);
100 | ref.current?.addEventListener('focusout', focusOutListener);
101 |
102 | return () => {
103 | document.removeEventListener('click', clickListener);
104 | ref.current?.removeEventListener('focusout', focusOutListener);
105 | };
106 | }, [closeOptionsDropdown, ref.current]);
107 |
108 | return (
109 |
114 |
120 | {displayValue}
121 |
122 | {showDropDown && (
123 |
124 | {options.map(({ value: currValue, label, disabled }) => (
125 |
134 | ))}
135 |
136 | )}
137 |
138 | );
139 | }
140 |
141 | export default CustomSelect;
142 |
--------------------------------------------------------------------------------
/src/components/select/option.tsx:
--------------------------------------------------------------------------------
1 | import React, { useCallback, useEffect, useRef } from 'react';
2 |
3 | type OptionProps = {
4 | /**
5 | * If the option is currently selected.
6 | */
7 | selected: boolean;
8 | /**
9 | * The label to display for the option.
10 | */
11 | label: string;
12 | /**
13 | * The value of the option.
14 | */
15 | value: T;
16 | /**
17 | * A callback triggered when the option is clicked.
18 | */
19 | onClick: (v: T) => void;
20 | /**
21 | * If the option is disabled.
22 | */
23 | disabled: boolean;
24 | };
25 |
26 | /**
27 | * Custom Option component.
28 | */
29 | function Option({
30 | selected,
31 | value,
32 | label,
33 | onClick,
34 | disabled,
35 | ...props
36 | }: OptionProps): JSX.Element {
37 | const ref = useRef(null);
38 |
39 | const handleClick = useCallback(() => {
40 | if (!disabled) {
41 | onClick(value);
42 | }
43 | }, [onClick, disabled, value]);
44 |
45 | useEffect(() => {
46 | if (selected) {
47 | ref.current?.focus();
48 | }
49 |
50 | return () => ref.current?.blur();
51 | }, [selected]);
52 |
53 | return (
54 |
66 | );
67 | }
68 |
69 | export default Option;
70 |
--------------------------------------------------------------------------------
/src/components/select/styles.css:
--------------------------------------------------------------------------------
1 | .sassy--select {
2 | border: none;
3 | border-radius: 0.25rem;
4 | display: inline;
5 | padding: 0.2rem 0.4rem;
6 | }
7 |
8 | .sassy--select__container {
9 | border-radius: 0.25rem;
10 | position: relative;
11 | }
12 |
13 | .sassy--select:focus {
14 | outline: none;
15 | box-shadow: var(--ring-shadow);
16 | }
17 |
18 | .sassy--select.sassy--select__disabled {
19 | opacity: var(--disabled-opacity);
20 | pointer-events: none;
21 | }
22 |
23 | .sassy--select.sassy--select__disabled:focus {
24 | box-shadow: none;
25 | }
26 |
27 | .sassy--select__dropdown {
28 | position: absolute;
29 | z-index: 2;
30 | display: flex;
31 | flex-direction: column;
32 | top: 1.5rem;
33 | max-height: 40vh;
34 | overflow: auto;
35 | padding: 0.5rem;
36 | background: var(--select-background);
37 | border: none;
38 | border-radius: 0.5rem;
39 | scrollbar-width: none;
40 | box-shadow: var(--shadow-md);
41 | border: var(--outline);
42 | }
43 |
44 | .sassy--select__dropdown::-webkit-scrollbar {
45 | display: none;
46 | }
47 |
48 | .sassy--select,
49 | .sassy--option {
50 | font-weight: 500;
51 | font-family: var(--font);
52 | font-size: 1rem;
53 | }
54 |
55 | .sassy--option:focus {
56 | outline: none;
57 | box-shadow: var(--ring-shadow);
58 | }
59 |
60 | .sassy--option__disabled {
61 | color: var(--disabled-color);
62 | pointer-events: none;
63 | }
64 |
65 | .sassy--select:hover {
66 | cursor: context-menu;
67 | }
68 |
69 | .sassy--option {
70 | transition: all 0.1s ease;
71 | cursor: pointer;
72 | padding: 0.25rem 0.4rem;
73 | border: none;
74 | border-radius: 0.25rem;
75 | background: var(--option-background);
76 | margin-top: 0.25rem;
77 | }
78 |
79 | .sassy--option:first-of-type {
80 | margin-top: 0;
81 | }
82 |
83 | .sassy--option__active,
84 | .sassy--option:hover {
85 | color: var(--selected-date-color);
86 | background-color: var(--theme-color);
87 | box-shadow: var(--shadow);
88 | }
89 |
--------------------------------------------------------------------------------
/src/date-picker/date-button.tsx:
--------------------------------------------------------------------------------
1 | import React, { memo, useCallback, useMemo } from 'react';
2 | import dt from 'date-and-time';
3 |
4 | type DateButtonProps = {
5 | date: Date;
6 | active: boolean;
7 | selected: boolean;
8 | onClick: (date: Date) => void;
9 | };
10 |
11 | const dateOptions: Intl.DateTimeFormatOptions = {
12 | weekday: 'long',
13 | month: 'long',
14 | day: 'numeric',
15 | year: 'numeric',
16 | };
17 |
18 | const DateButton: React.FC = ({
19 | date,
20 | active,
21 | onClick,
22 | selected,
23 | }) => {
24 | const handleClick = useCallback(() => {
25 | onClick(date);
26 | }, [onClick, date]);
27 |
28 | const dateAriaLabel = useMemo(
29 | () => date.toLocaleDateString('en-US', dateOptions),
30 | [date, dateOptions]
31 | );
32 |
33 | return (
34 |
47 | );
48 | };
49 |
50 | // take care of onClick
51 | export default memo(
52 | DateButton,
53 | (p, n) =>
54 | dt.isSameDay(p.date, n.date) &&
55 | p.active === n.active &&
56 | p.selected === n.selected
57 | );
58 |
--------------------------------------------------------------------------------
/src/date-picker/header.tsx:
--------------------------------------------------------------------------------
1 | import React, { useMemo } from 'react';
2 | import LeftCaret from '../icons/left-caret';
3 | import RightCaret from '../icons/right-caret';
4 | import { getMonthNameFromNumber } from './methods';
5 | import MonthPicker from './month-picker';
6 | import YearPicker from './year-picker';
7 |
8 | export type HeaderProps = {
9 | month: number;
10 | year: number;
11 | minDateValue: number;
12 | maxDateValue: number;
13 | nextMonth: () => void;
14 | prevMonth: () => void;
15 | onMonthChange: (_: string) => void;
16 | onYearChange: (_: number) => void;
17 | disabled: boolean;
18 | };
19 |
20 | const Header: React.FC = ({
21 | month,
22 | year,
23 | minDateValue,
24 | maxDateValue,
25 | nextMonth,
26 | prevMonth,
27 | onMonthChange,
28 | onYearChange,
29 | disabled,
30 | }) => {
31 | const fromYear = useMemo(() => new Date(minDateValue).getFullYear(), [
32 | minDateValue,
33 | ]);
34 | const toYear = useMemo(() => new Date(maxDateValue).getFullYear(), [
35 | maxDateValue,
36 | ]);
37 |
38 | return (
39 |
40 |
49 |
50 |
55 |
62 |
63 |
72 |
73 | );
74 | };
75 |
76 | export default Header;
77 |
--------------------------------------------------------------------------------
/src/date-picker/index.tsx:
--------------------------------------------------------------------------------
1 | import React, {
2 | forwardRef,
3 | HTMLProps,
4 | PropsWithRef,
5 | useCallback,
6 | useMemo,
7 | useState,
8 | } from 'react';
9 | import dt from 'date-and-time';
10 |
11 | import Header from './header';
12 | import DateButton from './date-button';
13 | import {
14 | getDatesOfMonth,
15 | getDaysOfWeek,
16 | getMonthNumberFromName,
17 | } from './methods';
18 | import { WeekStartDay } from './types';
19 |
20 | import './styles.css';
21 |
22 | export type DatePickerProps = {
23 | /**
24 | * This function is called when the selected date is changed.
25 | */
26 | onChange: (date: Date) => void;
27 | /**
28 | * The selected date.
29 | */
30 | value: Date;
31 | /**
32 | * The minimum date that can be selected (inclusive).
33 | * Default is 1st January 1900
34 | */
35 | minDate?: Date;
36 | /**
37 | * The maximum date that can be selected (inclusive).
38 | * Default is 100 years from now
39 | */
40 | maxDate?: Date;
41 | /**
42 | * Week starts from which day
43 | */
44 | weekStartsFrom?: WeekStartDay;
45 | /**
46 | * If the DatePicker is disabled
47 | */
48 | disabled?: boolean;
49 | } & PropsWithRef<
50 | Omit<
51 | HTMLProps,
52 | 'onChange' | 'selected' | 'options' | 'value' | 'type' | 'name' | 'disabled'
53 | >
54 | >;
55 |
56 | /**
57 | * DatePicker component to pick dates
58 | */
59 | const DatePicker = forwardRef(
60 | (
61 | {
62 | onChange,
63 | value = new Date(),
64 | minDate,
65 | maxDate,
66 | weekStartsFrom = 'Sunday',
67 | className,
68 | disabled = false,
69 | ...props
70 | },
71 | ref
72 | ) => {
73 | const minDateValue = useMemo(
74 | () => minDate?.valueOf() ?? new Date(1900, 0, 1).valueOf(),
75 | [minDate]
76 | );
77 | const maxDateValue = useMemo(
78 | () => maxDate?.valueOf() ?? dt.addYears(new Date(), 100).valueOf(),
79 | [maxDate]
80 | );
81 |
82 | // current month and year the user is viewing
83 | const [openedDate, setOpenedDate] = useState(value);
84 |
85 | const nextMonth = useCallback(
86 | () => setOpenedDate((d) => dt.addMonths(d, 1)),
87 | [setOpenedDate]
88 | );
89 |
90 | const prevMonth = useCallback(
91 | () => setOpenedDate((d) => dt.addMonths(d, -1)),
92 | [setOpenedDate]
93 | );
94 |
95 | const onMonthChange = useCallback(
96 | (month: string) => {
97 | setOpenedDate(
98 | (d) =>
99 | new Date(
100 | d.getFullYear(),
101 | getMonthNumberFromName(month),
102 | d.getDate()
103 | )
104 | );
105 | },
106 | [setOpenedDate]
107 | );
108 |
109 | const onYearChange = useCallback(
110 | (year: number) => {
111 | setOpenedDate((d) => new Date(year, d.getMonth(), d.getDate()));
112 | },
113 | [setOpenedDate]
114 | );
115 |
116 | const handleClick = useCallback((d: Date) => onChange(d), [onChange]);
117 |
118 | const daysOfWeekElements = useMemo(
119 | () =>
120 | getDaysOfWeek(weekStartsFrom).map((v) => (
121 |
125 | {v}
126 |
127 | )),
128 | [weekStartsFrom, disabled]
129 | );
130 |
131 | const daysOfMonthList = useMemo(
132 | () =>
133 | getDatesOfMonth(openedDate, minDateValue, maxDateValue, weekStartsFrom),
134 | [openedDate, minDateValue, maxDateValue, weekStartsFrom]
135 | );
136 |
137 | return (
138 |
145 |
156 |
{daysOfWeekElements}
157 |
158 | {daysOfMonthList.map(({ date, active, ms }) => (
159 |
166 | ))}
167 |
168 |
169 | );
170 | }
171 | );
172 |
173 | DatePicker.displayName = 'DatePicker';
174 |
175 | export default DatePicker;
176 |
--------------------------------------------------------------------------------
/src/date-picker/methods.ts:
--------------------------------------------------------------------------------
1 | import dt from 'date-and-time';
2 | import type { DisplayDate, WeekStartDay } from './types';
3 |
4 | enum DAYS {
5 | 'Sunday' = 0,
6 | 'Monday' = 1,
7 | 'Tuesday' = 2,
8 | 'Wednesday' = 3,
9 | 'Thursday' = 4,
10 | 'Friday' = 5,
11 | 'Saturday' = 6,
12 | }
13 |
14 | export enum MONTHS {
15 | 'January' = 0,
16 | 'February' = 1,
17 | 'March' = 2,
18 | 'April' = 3,
19 | 'May' = 4,
20 | 'June' = 5,
21 | 'July' = 6,
22 | 'August' = 7,
23 | 'September' = 8,
24 | 'October' = 9,
25 | 'November' = 10,
26 | 'December' = 11,
27 | }
28 |
29 | export const getMonthNameFromNumber = (month: number): string => {
30 | if (month < 0 || month > 11) {
31 | throw new Error(`Invalid month number: ${month}`);
32 | }
33 | return MONTHS[month];
34 | };
35 |
36 | export const getMonthNumberFromName = (month: string): number => {
37 | switch (month) {
38 | case 'January':
39 | return 0
40 | case 'February':
41 | return 1
42 | case 'March':
43 | return 2
44 | case 'April':
45 | return 3
46 | case 'May':
47 | return 4
48 | case 'June':
49 | return 5
50 | case 'July':
51 | return 6
52 | case 'August':
53 | return 7
54 | case 'September':
55 | return 8
56 | case 'October':
57 | return 9
58 | case 'November':
59 | return 10
60 | case 'December':
61 | return 11
62 | default:
63 | throw new Error(`Invalid month name: ${month}`)
64 | }
65 | };
66 |
67 |
68 | export const getDayFromNumber = (
69 | day: number,
70 | weekStartsFrom: WeekStartDay
71 | ): string => {
72 | if (day < 0 || day > 6) {
73 | throw new Error(`Invalid month number: ${day}`);
74 | }
75 | switch (weekStartsFrom) {
76 | case 'Monday':
77 | return DAYS[(day + 1) % 7];
78 | case 'Sunday':
79 | return DAYS[day];
80 | default:
81 | throw new Error(`Invalid week start day: ${weekStartsFrom}`);
82 | }
83 | };
84 |
85 | export const getDaysOfWeek = (weekStartsFrom: WeekStartDay) => {
86 | if (weekStartsFrom === 'Monday') {
87 | return ['Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa', 'Su'];
88 | }
89 | return ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'];
90 | };
91 |
92 | const getMidnight = (n: number): number => {
93 | const d = new Date(n);
94 | d.setHours(0, 0, 0, 0);
95 | return d.valueOf();
96 | }
97 |
98 | export const getDatesOfMonth = (date: Date, minDateValue: number, maxDateValue: number, weekStartsFrom: WeekStartDay): DisplayDate[] => {
99 | const currentYear = date.getFullYear();
100 | const currentMonth = date.getMonth();
101 | const minDate = getMidnight(minDateValue);
102 | const maxDate = getMidnight(maxDateValue);
103 |
104 | // generate dates of each week of the month including the residue dates
105 | // of the last week of previous month and first week of next month
106 | const firstDayOfMonth = new Date(currentYear, currentMonth, 1);
107 | const lastDayOfMonth = new Date(currentYear, currentMonth + 1, 0);
108 |
109 | // first day of the pervious month
110 | // const previousMonth = dt.addMonths(firstDayOfMonth, -1);
111 | // last day of the pervious month
112 | const previousMonthLastDay = dt.addDays(firstDayOfMonth, -1);
113 |
114 | const dates: DisplayDate[] = [];
115 |
116 | // the number of the weekday of the first day of the month
117 | const firstWeekDayOfMonth = firstDayOfMonth.getDay();
118 | // the number of the weekday of the last day of the month
119 | const lastWeekDayOfMonth = lastDayOfMonth.getDay();
120 |
121 | if (weekStartsFrom === 'Sunday') {
122 | // insert the residual dates of previous month's last week
123 | for (let i = 1; i <= firstWeekDayOfMonth; i++) {
124 | const d = dt.addDays(previousMonthLastDay, (i - firstWeekDayOfMonth));
125 | dates.push({
126 | date: d,
127 | active: false,
128 | ms: d.valueOf(),
129 | });
130 | }
131 |
132 | const fullYear = date.getFullYear();
133 | const fullMonth = date.getMonth();
134 | // insert the dates of the current month
135 | for (let i = 1; i <= lastDayOfMonth.getDate(); i++) {
136 | const d = new Date(fullYear, fullMonth, i);
137 | const dValue = d.valueOf();
138 | // compare day of month
139 | dates.push({
140 | date: d,
141 | active: dValue >= minDate && dValue <= maxDate,
142 | ms: dValue,
143 | });
144 | }
145 |
146 | let i = lastWeekDayOfMonth + 1;
147 | let counter = 1;
148 | // insert the residual dates of the next month
149 | while (i <= 6) {
150 | const d = dt.addDays(lastDayOfMonth, counter++);
151 | dates.push({
152 | date: d,
153 | active: false,
154 | ms: d.valueOf(),
155 | });
156 | i++;
157 | }
158 | } else {
159 | // insert the residual dates of previous month's last week
160 | for (let i = 1; i < firstWeekDayOfMonth; i++) {
161 | const d= dt.addDays(previousMonthLastDay, (i - firstWeekDayOfMonth + 1));
162 | dates.push({
163 | date: d,
164 | active: false,
165 | ms: d.valueOf(),
166 | });
167 | }
168 |
169 | const fullYear = date.getFullYear();
170 | const fullMonth = date.getMonth();
171 | // insert the dates of the current month
172 | for (let i = 1; i <= lastDayOfMonth.getDate(); i++) {
173 | const d = new Date(fullYear, fullMonth, i);
174 | const dValue = d.valueOf();
175 | // compare day of month
176 | dates.push({
177 | date: d,
178 | active: dValue >= minDate && dValue <= maxDate,
179 | ms: dValue,
180 | });
181 | }
182 |
183 | let i = lastWeekDayOfMonth;
184 | let counter = 1;
185 | // insert the residual dates of the next month
186 | while (i <= 6) {
187 | const d = dt.addDays(lastDayOfMonth, counter++);
188 | dates.push({
189 | date: d,
190 | active: false,
191 | ms: d.valueOf(),
192 | });
193 | i++;
194 | }
195 | }
196 |
197 | return dates;
198 | };
199 |
--------------------------------------------------------------------------------
/src/date-picker/month-picker.tsx:
--------------------------------------------------------------------------------
1 | import React, { useMemo } from 'react';
2 | import CustomSelect, { OptionType } from '../components/select';
3 |
4 | export type MonthPickerProps = {
5 | value: string;
6 | onChange: (year: string) => void;
7 | disabled: boolean;
8 | };
9 |
10 | const months = [
11 | 'January',
12 | 'February',
13 | 'March',
14 | 'April',
15 | 'May',
16 | 'June',
17 | 'July',
18 | 'August',
19 | 'September',
20 | 'October',
21 | 'November',
22 | 'December',
23 | ];
24 |
25 | const MonthPicker: React.FC = ({
26 | value,
27 | onChange,
28 | disabled,
29 | }) => {
30 | const options = useMemo(
31 | () =>
32 | months.map(
33 | (m) =>
34 | ({
35 | value: m,
36 | label: m,
37 | disabled: false,
38 | } as OptionType)
39 | ),
40 | []
41 | );
42 |
43 | return (
44 |
51 | );
52 | };
53 |
54 | export default MonthPicker;
55 |
--------------------------------------------------------------------------------
/src/date-picker/styles.css:
--------------------------------------------------------------------------------
1 | .sdp {
2 | width: 16rem;
3 | border: none;
4 | border-radius: 0.5rem;
5 | box-shadow: var(--shadow);
6 | background: var(--background);
7 | padding: 0.75rem;
8 | border: var(--outline);
9 | }
10 |
11 | .sdp--disabled {
12 | pointer-events: none;
13 | }
14 |
15 | .sdp:focus,
16 | .sdp--month-name:focus,
17 | .sdp--square-btn:focus {
18 | outline: none;
19 | box-shadow: var(--ring-shadow);
20 | }
21 |
22 | .sdp--month-name {
23 | padding: 0.5rem;
24 | border: none;
25 | border-radius: 0.5rem;
26 | }
27 |
28 | .sdp--text {
29 | font-weight: 500;
30 | margin: 0;
31 | font-family: var(--font);
32 | }
33 |
34 | .sdp--text__inactive {
35 | color: var(--disabled-color);
36 | pointer-events: none;
37 | }
38 |
39 | .sdp--square-btn {
40 | height: 1.8rem;
41 | width: 1.8rem;
42 | display: flex;
43 | justify-content: center;
44 | align-items: center;
45 | border-radius: 0.5rem;
46 | border: none;
47 | background-color: var(--btn-background);
48 | cursor: pointer;
49 | transition: all 0.2s ease-in-out;
50 | font-family: var(--font);
51 | }
52 |
53 | .sdp--square-btn__outlined {
54 | border: var(--outline);
55 | }
56 |
57 | .sdp--square-btn__outlined:focus:hover {
58 | border: var(--outline);
59 | }
60 |
61 | .sdp--square-btn:focus:hover {
62 | box-shadow: none;
63 | }
64 |
65 | .sdp--square-btn__shadowed {
66 | box-shadow: var(--shadow);
67 | }
68 |
69 | .sdp--square-btn__shadowed:focus:hover {
70 | box-shadow: var(--shadow);
71 | }
72 |
73 | .sdp--date-btn__selected {
74 | background-color: var(--theme-color);
75 | color: var(--selected-date-color);
76 | box-shadow: var(--shadow);
77 | }
78 |
79 | .sdp--date-btn__selected.sdp--square-btn:focus {
80 | box-shadow: var(--shadow);
81 | }
82 |
83 | .sdp--header {
84 | display: flex;
85 | justify-content: space-between;
86 | align-items: center;
87 | }
88 |
89 | .sdp--grid {
90 | display: grid;
91 | grid-template-columns: repeat(7, 1fr);
92 | gap: 4px;
93 | margin: 0.5rem 0 0;
94 | justify-items: center;
95 | }
96 |
97 | .sdp--grid > p.sdp--text {
98 | padding: 0.5rem 0;
99 | }
100 |
101 | .sdp--header__main {
102 | display: flex;
103 | justify-content: center;
104 | align-items: center;
105 | font-weight: bold;
106 | }
107 |
108 | .sdp--select__month button {
109 | text-align: left;
110 | }
111 |
--------------------------------------------------------------------------------
/src/date-picker/types.ts:
--------------------------------------------------------------------------------
1 | export type WeekStartDay = 'Sunday' | 'Monday';
2 |
3 | export type DisplayDate = {
4 | date: Date;
5 | active: boolean;
6 | ms: number;
7 | };
8 |
--------------------------------------------------------------------------------
/src/date-picker/year-picker.tsx:
--------------------------------------------------------------------------------
1 | import React, { useMemo } from 'react';
2 | import CustomSelect, { OptionType } from '../components/select';
3 |
4 | export type YearPickerProps = {
5 | fromYear: number;
6 | toYear: number;
7 | value: number;
8 | onChange: (year: number) => void;
9 | disabled: boolean;
10 | };
11 |
12 | function* generateRange(from: number, to: number, step: number) {
13 | for (let i = from; i <= to; i += step) {
14 | yield i;
15 | }
16 | }
17 |
18 | const YearPicker: React.FC = ({
19 | fromYear,
20 | toYear,
21 | value,
22 | onChange,
23 | disabled,
24 | }) => {
25 | const options = useMemo(
26 | () =>
27 | Array.from(generateRange(fromYear, toYear, 1)).map(
28 | (v) =>
29 | ({
30 | value: v,
31 | label: v.toString(),
32 | disabled: false,
33 | } as OptionType)
34 | ),
35 | [fromYear, toYear]
36 | );
37 |
38 | return (
39 |
45 | );
46 | };
47 |
48 | export default YearPicker;
49 |
--------------------------------------------------------------------------------
/src/icons/left-caret.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { IconProps } from './types';
3 |
4 | const LeftCaret: React.FC = ({
5 | height = '16',
6 | width = '16',
7 | color = 'currentColor',
8 | strokeWidth = '24',
9 | }) => (
10 |
27 | );
28 |
29 | export default LeftCaret;
30 |
--------------------------------------------------------------------------------
/src/icons/right-caret.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { IconProps } from './types';
3 |
4 | const RightCaret: React.FC = ({
5 | height = '16',
6 | width = '16',
7 | color = 'currentColor',
8 | strokeWidth = '24',
9 | }) => (
10 |
27 | );
28 |
29 | export default RightCaret;
30 |
--------------------------------------------------------------------------------
/src/icons/two-dots.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { IconProps } from './types';
3 |
4 | const TwoDots: React.FC = ({
5 | height = '16',
6 | width = '16',
7 | color = 'currentColor',
8 | }) => (
9 |
20 | );
21 |
22 | export default TwoDots;
23 |
--------------------------------------------------------------------------------
/src/icons/types.ts:
--------------------------------------------------------------------------------
1 | export type IconProps = {
2 | height?: string | number;
3 | width?: string | number;
4 | color?: string;
5 | strokeWidth?: string | number;
6 | };
7 |
--------------------------------------------------------------------------------
/src/index.tsx:
--------------------------------------------------------------------------------
1 | import DatePicker from './date-picker';
2 | import './styles.css';
3 |
4 | export * from './util';
5 | export { default as TimePicker } from './time-picker';
6 | export default DatePicker;
7 |
--------------------------------------------------------------------------------
/src/styles.css:
--------------------------------------------------------------------------------
1 | .sdp,
2 | .stp {
3 | /* font family */
4 | --font: inherit;
5 | --shadow: rgba(0, 0, 0, 0) 0px 0px 0px 0px, rgba(0, 0, 0, 0) 0px 0px 0px 0px,
6 | rgba(0, 0, 0, 0.1) 0px 1px 3px 0px, rgba(0, 0, 0, 0.06) 0px 1px 2px 0px;
7 | --shadow-md: rgba(0, 0, 0, 0) 0px 0px 0px 0px,
8 | rgba(0, 0, 0, 0) 0px 0px 0px 0px, rgba(0, 0, 0, 0.1) 0px 4px 6px -1px,
9 | rgba(0, 0, 0, 0.06) 0px 2px 4px -1px;
10 | /* main theme color for stuff like selection */
11 | --theme-color: #60a5fa;
12 | /* color of the text */
13 | --text-color: #1f1f1f;
14 | /* background for the picker */
15 | --background: #ffffff;
16 | /* background for the date pickers buttons */
17 | --btn-background: #ffffff;
18 | /* background for the dropdown */
19 | --select-background: #ffffff;
20 | /* background color for the options inside the dropdown */
21 | --option-background: #ffffff;
22 | /* text color for the selected date */
23 | --selected-date-color: #ffffff;
24 | /* text color for disabled state */
25 | --disabled-color: #bdbdbd;
26 | /* opacity for disabled state */
27 | --disabled-opacity: 50%;
28 | /* outline for various elements */
29 | --outline: 1px solid #cbd5e1;
30 | /* a box shadow definition for a ring */
31 | --ring-shadow: 0px 0px 0px 2px hsla(213, 94%, 68%, 0.7);
32 |
33 | color: var(--text-color);
34 | background: var(--background);
35 | }
36 |
--------------------------------------------------------------------------------
/src/time-picker/index.tsx:
--------------------------------------------------------------------------------
1 | import React, {
2 | forwardRef,
3 | HTMLProps,
4 | PropsWithRef,
5 | useCallback,
6 | useEffect,
7 | useMemo,
8 | useState,
9 | } from 'react';
10 | import CustomSelect, { OptionType } from '../components/select';
11 | import { DisplayFormat, Meridiem, Time } from './types';
12 |
13 | import './styles.css';
14 | import {
15 | alignTime,
16 | generateHourOptions,
17 | generateMinuteOptions,
18 | convertHourFrom12HrTo24Hr,
19 | } from './methods';
20 | import TwoDots from '../icons/two-dots';
21 |
22 | /**
23 | * Props for TimePicker React Component
24 | */
25 | export type TimePickerProps = {
26 | /**
27 | * This function is called when the selected date is changed.
28 | */
29 | onChange: (time: Time) => void;
30 | /**
31 | * The selected date.
32 | */
33 | value: Time;
34 | /**
35 | * If the TimePicker is disabled
36 | */
37 | disabled?: boolean;
38 | /**
39 | * Which time format to use
40 | */
41 | displayFormat?: DisplayFormat;
42 | /**
43 | * The number of minutes between each minute select option - default is 30
44 | */
45 | minutesInterval?: number;
46 | } & PropsWithRef<
47 | Omit<
48 | HTMLProps,
49 | 'onChange' | 'selected' | 'options' | 'value' | 'disabled'
50 | >
51 | >;
52 |
53 | const meridiemOptions: OptionType[] = [
54 | { value: Meridiem.AM, label: Meridiem.AM, disabled: false },
55 | { value: Meridiem.PM, label: Meridiem.PM, disabled: false },
56 | ];
57 |
58 | const formatNumber = (v: number) => v.toString().padStart(2, '0');
59 |
60 | /**
61 | * TimePicker React Component
62 | */
63 | const TimePicker = forwardRef(
64 | (
65 | {
66 | onChange,
67 | value,
68 | className,
69 | disabled,
70 | displayFormat = '12hr',
71 | minutesInterval = 5,
72 | ...props
73 | },
74 | ref
75 | ) => {
76 | if (
77 | typeof minutesInterval !== 'number' &&
78 | minutesInterval < 1 &&
79 | Number.isInteger(minutesInterval)
80 | ) {
81 | throw new Error('minutesInterval must be an integer greater than 0');
82 | }
83 |
84 | const [selectedTime, setSelectedTime] = useState(() => {
85 | if (value !== undefined) return alignTime(value, minutesInterval);
86 | const d = new Date();
87 | return alignTime(
88 | { minutes: d.getMinutes(), hours: d.getHours() },
89 | minutesInterval
90 | );
91 | });
92 |
93 | const [currentMeridiem, setCurrentMeridiem] = useState(() =>
94 | selectedTime.hours <= 11 ? Meridiem.AM : Meridiem.PM
95 | );
96 |
97 | const handleMinutesChange = useCallback(
98 | (v: number) => {
99 | setSelectedTime((t) => {
100 | return alignTime({ ...t, minutes: v }, minutesInterval);
101 | });
102 | },
103 | [minutesInterval]
104 | );
105 |
106 | const handleHoursChange = useCallback(
107 | (v: number) => {
108 | setSelectedTime((t) => {
109 | let hours = v;
110 | if (displayFormat === '12hr') {
111 | hours = convertHourFrom12HrTo24Hr(hours, currentMeridiem);
112 | }
113 | return alignTime({ ...t, hours }, minutesInterval);
114 | });
115 | },
116 | [minutesInterval, currentMeridiem, displayFormat]
117 | );
118 |
119 | const handleMeridiemChange = useCallback((v: Meridiem) => {
120 | setCurrentMeridiem(v);
121 | setSelectedTime((t) => {
122 | if (v === Meridiem.AM) {
123 | return {
124 | minutes: t.minutes,
125 | hours: t.hours - 12,
126 | };
127 | }
128 | return {
129 | minutes: t.minutes,
130 | hours: t.hours + 12,
131 | };
132 | });
133 | }, []);
134 |
135 | // the array of options of minutes to select from
136 | const minuteOptions = useMemo(
137 | () => generateMinuteOptions(minutesInterval),
138 | [minutesInterval]
139 | );
140 |
141 | // the array of options of hours to select from
142 | const hourOptions = useMemo(() => generateHourOptions(displayFormat), [
143 | displayFormat,
144 | ]);
145 |
146 | //
147 | const currentHourDisplayValue = useMemo(() => {
148 | if (displayFormat === '24hr') return selectedTime.hours;
149 | const h =
150 | currentMeridiem === Meridiem.AM
151 | ? selectedTime.hours
152 | : selectedTime.hours - 12;
153 | if (h === 0) return 12;
154 | return h;
155 | }, [selectedTime.hours, displayFormat, currentMeridiem]);
156 |
157 | useEffect(() => {
158 | onChange(selectedTime);
159 | }, [selectedTime, onChange]);
160 |
161 | useEffect(() => {
162 | setSelectedTime(alignTime(selectedTime, minutesInterval));
163 | }, [minutesInterval]);
164 |
165 | return (
166 |
171 |
178 |
181 |
182 |
183 |
190 | {displayFormat === '12hr' && (
191 |
197 | )}
198 |
199 | );
200 | }
201 | );
202 |
203 | TimePicker.displayName = 'TimePicker';
204 |
205 | export default TimePicker;
206 |
--------------------------------------------------------------------------------
/src/time-picker/methods.ts:
--------------------------------------------------------------------------------
1 | import { OptionType } from './../components/select';
2 | import { Time, Meridiem, TimeDisplay, DisplayFormat } from './types';
3 |
4 | const option = (n: number) => ({
5 | value: n,
6 | label: n.toString().padStart(2, '0'),
7 | disabled: false,
8 | });
9 |
10 | /**
11 | * Creates a time value aligned with the minutes interval from am raw time input
12 | *
13 | * @param {Time} time The time value
14 | * @param {number} interval The interval between each minute select option
15 | * @returns {Time} Time value rounded to the nearest interval
16 | */
17 | export const alignTime = (
18 | { hours, minutes }: Time,
19 | interval: number,
20 | lower: boolean = true
21 | ): Time => {
22 | const rem = minutes % interval;
23 | // round minutes to nearest interval
24 | if (rem !== 0) {
25 | minutes = lower ? minutes - rem : minutes + interval - rem;
26 | }
27 | return {
28 | hours,
29 | minutes,
30 | };
31 | };
32 |
33 | /**
34 | * Convert Time to a 12hr TimeDisplay format
35 | *
36 | * @param selectedTime
37 | */
38 | export const timeToTimeDisplay = (selectedTime: Time): TimeDisplay => {
39 | let hours;
40 | let meridiem = Meridiem.AM;
41 | if (selectedTime.hours === 0) {
42 | hours = 12;
43 | } else if (selectedTime.hours === 12) {
44 | hours = 12;
45 | meridiem = Meridiem.PM;
46 | } else if (selectedTime.hours > 12) {
47 | hours = selectedTime.hours - 12;
48 | meridiem = Meridiem.PM;
49 | } else {
50 | hours = selectedTime.hours;
51 | }
52 |
53 | return {
54 | hours,
55 | minutes: selectedTime.minutes,
56 | meridiem,
57 | };
58 | };
59 |
60 | export const generateHourOptions = (
61 | timeFormat: DisplayFormat
62 | ): OptionType[] => {
63 | if (timeFormat === '12hr') {
64 | const listOfOptions: OptionType[] = new Array(12);
65 | listOfOptions[0] = option(12);
66 | for (let i = 1; i <= 11; i += 1) {
67 | listOfOptions[i] = option(i);
68 | }
69 | return listOfOptions;
70 | }
71 | const listOfOptions: OptionType[] = new Array(24);
72 | for (let i = 0; i <= 23; i += 1) {
73 | listOfOptions[i] = option(i);
74 | }
75 | return listOfOptions;
76 | };
77 |
78 | export const generateMinuteOptions = (
79 | minutesInterval: number
80 | ): OptionType[] => {
81 | let options: OptionType[] = [];
82 | for (let i = 0; i < 60; i += minutesInterval) {
83 | options.push(option(i));
84 | }
85 | return options;
86 | };
87 |
88 | /**
89 | * Convert a value from 12 hour time format to 24 hour format
90 | *
91 | * @param hour hour to convert
92 | * @param meridiem am or pm
93 | */
94 | export const convertHourFrom12HrTo24Hr = (
95 | hour: number,
96 | meridiem: Meridiem
97 | ): number => {
98 | if (hour === 12) {
99 | return meridiem === Meridiem.AM ? 0 : 12;
100 | } else if (meridiem === Meridiem.PM) {
101 | return hour + 12;
102 | } else {
103 | return hour;
104 | }
105 | };
106 |
--------------------------------------------------------------------------------
/src/time-picker/styles.css:
--------------------------------------------------------------------------------
1 | .stp {
2 | padding: 0.5rem 0.4rem;
3 | outline: none;
4 | font-family: var(--font);
5 | border: none;
6 | border-radius: 0.5rem;
7 | box-shadow: var(--shadow);
8 | display: inline-flex;
9 | border: var(--outline);
10 | }
11 |
12 | .stp--disabled {
13 | pointer-events: none;
14 | }
15 |
16 | .stp--divider {
17 | display: inline-flex;
18 | align-items: center;
19 | justify-content: center;
20 | }
21 |
22 | .stp--divider__disabled {
23 | opacity: var(--disabled-opacity);
24 | }
25 |
26 | .stp * {
27 | outline: none;
28 | }
29 |
30 | .stp:focus {
31 | box-shadow: var(--ring-shadow);
32 | }
33 |
34 | .stp > p {
35 | margin: 0 2px;
36 | display: inline;
37 | }
38 |
--------------------------------------------------------------------------------
/src/time-picker/types.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Time type
3 | */
4 | export type Time = {
5 | hours: number;
6 | minutes: number;
7 | };
8 |
9 | /**
10 | * Time display type
11 | */
12 | export type TimeDisplay = {
13 | hours: number;
14 | minutes: number;
15 | meridiem?: Meridiem;
16 | };
17 |
18 | export type DisplayFormat = '12hr' | '24hr';
19 |
20 | export enum Meridiem {
21 | AM = 'AM',
22 | PM = 'PM',
23 | }
24 |
--------------------------------------------------------------------------------
/src/util.ts:
--------------------------------------------------------------------------------
1 | import { Time } from './time-picker/types';
2 |
3 | export const getCurrentTime = (): Time => convertDateToTime(new Date());
4 |
5 | export const convertDateToTime = (d: Date): Time => ({
6 | hours: d.getHours(),
7 | minutes: d.getMinutes(),
8 | });
9 |
10 | export const convertTimeToDate = (t: Time, d?: Date): Date => {
11 | const newDate = d ? new Date(d.valueOf()) : new Date();
12 | newDate.setHours(t.hours);
13 | newDate.setMinutes(t.minutes);
14 | return newDate;
15 | };
16 |
--------------------------------------------------------------------------------
/test/date-picker/date-picker.test.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import * as ReactDOM from 'react-dom';
3 | import DatePicker from '../../src';
4 |
5 | describe('DatePicker', () => {
6 | it('renders without crashing', () => {
7 | const div = document.createElement('div');
8 | const onChange = jest.fn();
9 | const value = new Date();
10 | ReactDOM.render(, div);
11 | });
12 | });
13 |
--------------------------------------------------------------------------------
/test/date-picker/methods.test.ts:
--------------------------------------------------------------------------------
1 | import {
2 | getMonthNumberFromName,
3 | getMonthNameFromNumber,
4 | getDayFromNumber,
5 | getDaysOfWeek,
6 | } from '../../src/date-picker/methods';
7 |
8 | const testName = (fn: (...args: any) => any) =>
9 | `DatePicker method - ${fn.name}`;
10 |
11 | describe(testName(getMonthNameFromNumber), () => {
12 | it('gives correct name', () => {
13 | expect(getMonthNameFromNumber(0)).toBe('January');
14 | expect(getMonthNameFromNumber(5)).toBe('June');
15 | expect(getMonthNameFromNumber(11)).toBe('December');
16 | // no need to check all - typescript enum guarantees that this will work
17 | });
18 | });
19 |
20 | describe(testName(getMonthNumberFromName), () => {
21 | it('gives correct name', () => {
22 | expect(getMonthNumberFromName('January')).toBe(0);
23 | expect(getMonthNumberFromName('February')).toBe(1);
24 | expect(getMonthNumberFromName('March')).toBe(2);
25 | expect(getMonthNumberFromName('April')).toBe(3);
26 | expect(getMonthNumberFromName('May')).toBe(4);
27 | expect(getMonthNumberFromName('June')).toBe(5);
28 | expect(getMonthNumberFromName('July')).toBe(6);
29 | expect(getMonthNumberFromName('August')).toBe(7);
30 | expect(getMonthNumberFromName('September')).toBe(8);
31 | expect(getMonthNumberFromName('October')).toBe(9);
32 | expect(getMonthNumberFromName('November')).toBe(10);
33 | expect(getMonthNumberFromName('December')).toBe(11);
34 | });
35 | });
36 |
37 | describe(testName(getDayFromNumber), () => {
38 | it('gives correct name - week starts from monday', () => {
39 | const day = 'Monday';
40 | expect(getDayFromNumber(0, day)).toBe('Monday');
41 | expect(getDayFromNumber(1, day)).toBe('Tuesday');
42 | expect(getDayFromNumber(2, day)).toBe('Wednesday');
43 | expect(getDayFromNumber(3, day)).toBe('Thursday');
44 | expect(getDayFromNumber(4, day)).toBe('Friday');
45 | expect(getDayFromNumber(5, day)).toBe('Saturday');
46 | expect(getDayFromNumber(6, day)).toBe('Sunday');
47 | });
48 |
49 | it('gives correct name - week starts from sunday', () => {
50 | const day = 'Sunday';
51 | expect(getDayFromNumber(0, day)).toBe('Sunday');
52 | expect(getDayFromNumber(1, day)).toBe('Monday');
53 | expect(getDayFromNumber(2, day)).toBe('Tuesday');
54 | expect(getDayFromNumber(3, day)).toBe('Wednesday');
55 | expect(getDayFromNumber(4, day)).toBe('Thursday');
56 | expect(getDayFromNumber(5, day)).toBe('Friday');
57 | expect(getDayFromNumber(6, day)).toBe('Saturday');
58 | });
59 | });
60 |
61 | describe(testName(getDaysOfWeek), () => {
62 | it('gives correct weekdays order - week starts from monday', () => {
63 | expect(getDaysOfWeek('Monday')).toStrictEqual([
64 | 'Mo',
65 | 'Tu',
66 | 'We',
67 | 'Th',
68 | 'Fr',
69 | 'Sa',
70 | 'Su',
71 | ]);
72 | });
73 |
74 | it('gives correct weekdays order - week starts from sunday', () => {
75 | expect(getDaysOfWeek('Sunday')).toStrictEqual([
76 | 'Su',
77 | 'Mo',
78 | 'Tu',
79 | 'We',
80 | 'Th',
81 | 'Fr',
82 | 'Sa',
83 | ]);
84 | });
85 | });
86 |
--------------------------------------------------------------------------------
/test/time-picker/methods.test.tsx:
--------------------------------------------------------------------------------
1 | import { OptionType } from '../../src/components/select';
2 | import {
3 | alignTime,
4 | generateHourOptions,
5 | generateMinuteOptions,
6 | timeToTimeDisplay,
7 | convertHourFrom12HrTo24Hr,
8 | } from '../../src/time-picker/methods';
9 | import { Meridiem } from '../../src/time-picker/types';
10 |
11 | const testName = (fn: (...args: any) => any) =>
12 | `TimePicker method - ${fn.name}`;
13 |
14 | describe(testName(alignTime), () => {
15 | const t = { hours: 2, minutes: 12 };
16 | it('align to previous interval works', () => {
17 | const t1 = alignTime(t, 5);
18 | expect(t1.hours).toBe(2);
19 | expect(t1.minutes).toBe(10);
20 | });
21 |
22 | it('align to next interval works', () => {
23 | const t2 = alignTime(t, 5, false);
24 | expect(t2.hours).toBe(2);
25 | expect(t2.minutes).toBe(15);
26 | });
27 | });
28 |
29 | describe(testName(generateHourOptions), () => {
30 | const mapToNumbersArray = (a: OptionType[]) =>
31 | a.map(({ value }) => value);
32 |
33 | it('24hr hour options generate', () => {
34 | const options12Hr = mapToNumbersArray(generateHourOptions('12hr'));
35 | expect(options12Hr).toStrictEqual([12, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]);
36 | });
37 |
38 | it('24hr hour options generate', () => {
39 | const options24Hr = mapToNumbersArray(generateHourOptions('24hr'));
40 | const zeroToTwelve = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
41 | const twelveToEnd = [12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23];
42 | expect(options24Hr).toStrictEqual([...zeroToTwelve, ...twelveToEnd]);
43 | });
44 | });
45 |
46 | describe(testName(generateMinuteOptions), () => {
47 | const mapToNumbersArray = (a: OptionType[]) =>
48 | a.map(({ value }) => value);
49 |
50 | it('minute options get generated', () => {
51 | const options = mapToNumbersArray(generateMinuteOptions(10));
52 | expect(options).toStrictEqual([0, 10, 20, 30, 40, 50]);
53 | });
54 | });
55 |
56 | describe(testName(timeToTimeDisplay), () => {
57 | it('converts', () => {
58 | const td = timeToTimeDisplay({ hours: 15, minutes: 10 });
59 | expect(td).toStrictEqual({ hours: 3, minutes: 10, meridiem: 'PM' });
60 | });
61 | });
62 |
63 | describe(testName(convertHourFrom12HrTo24Hr), () => {
64 | it('converts PM', () => {
65 | const h = convertHourFrom12HrTo24Hr(3, Meridiem.PM);
66 | expect(h).toBe(15);
67 | });
68 |
69 | it('converts AM', () => {
70 | const h = convertHourFrom12HrTo24Hr(3, Meridiem.AM);
71 | expect(h).toBe(3);
72 | });
73 | });
74 |
--------------------------------------------------------------------------------
/test/time-picker/time-picker.test.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import * as ReactDOM from 'react-dom';
3 | import { TimePicker } from '../../src';
4 |
5 | describe('DatePicker', () => {
6 | it('renders without crashing', () => {
7 | const div = document.createElement('div');
8 | const onChange = jest.fn();
9 | ReactDOM.render(
10 | ,
11 | div
12 | );
13 | });
14 | });
15 |
--------------------------------------------------------------------------------
/test/utility.test.ts:
--------------------------------------------------------------------------------
1 | import { convertDateToTime, convertTimeToDate } from './../src/util';
2 |
3 | const testName = (fn: (...args: any) => any) => `Utility function - ${fn.name}`;
4 |
5 | describe(testName(convertDateToTime), () => {
6 | it('converts correctly', () => {
7 | const d = new Date();
8 | const t = convertDateToTime(d);
9 | expect(t.hours).toBe(d.getHours());
10 | expect(t.minutes).toBe(d.getMinutes());
11 | });
12 | });
13 |
14 | describe(testName(convertTimeToDate), () => {
15 | const t = { hours: 15, minutes: 30 };
16 |
17 | it('converts correctly without parent date', () => {
18 | const d = convertTimeToDate(t);
19 | expect(d.getHours()).toBe(t.hours);
20 | expect(d.getMinutes()).toBe(t.minutes);
21 | });
22 |
23 | it('converts correctly with parent date', () => {
24 | const d = convertTimeToDate(t, new Date(2001, 8, 30));
25 | expect(d.getHours()).toBe(t.hours);
26 | expect(d.getMinutes()).toBe(t.minutes);
27 | expect(d.getFullYear()).toBe(2001);
28 | expect(d.getMonth()).toBe(8);
29 | expect(d.getDate()).toBe(30);
30 | });
31 | });
32 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | // see https://www.typescriptlang.org/tsconfig to better understand tsconfigs
3 | "include": ["src", "types"],
4 | "compilerOptions": {
5 | "module": "esnext",
6 | "lib": ["dom", "esnext"],
7 | "importHelpers": true,
8 | // output .d.ts declaration files for consumers
9 | "declaration": true,
10 | // output .js.map sourcemap files for consumers
11 | "sourceMap": true,
12 | // match output dir to input dir. e.g. dist/index instead of dist/src/index
13 | "rootDir": "./src",
14 | // stricter type-checking for stronger correctness. Recommended by TS
15 | "strict": true,
16 | // linter checks for common issues
17 | "noImplicitReturns": true,
18 | "noFallthroughCasesInSwitch": true,
19 | // noUnused* overlap with @typescript-eslint/no-unused-vars, can disable if duplicative
20 | "noUnusedLocals": true,
21 | "noUnusedParameters": true,
22 | // use Node's module resolution algorithm, instead of the legacy TS one
23 | "moduleResolution": "node",
24 | // transpile JSX to React.createElement
25 | "jsx": "react",
26 | // interop between ESM and CJS modules. Recommended by TS
27 | "esModuleInterop": true,
28 | // significant perf increase by skipping checking .d.ts files, particularly those in node_modules. Recommended by TS
29 | "skipLibCheck": true,
30 | // error out if import and file system have a casing mismatch. Recommended by TS
31 | "forceConsistentCasingInFileNames": true,
32 | // `tsdx build` ignores this option, but it is commonly used when type-checking separately with `tsc`
33 | "noEmit": true,
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/tsdx.config.js:
--------------------------------------------------------------------------------
1 | const postcss = require('rollup-plugin-postcss');
2 | const autoprefixer = require('autoprefixer');
3 | const cssnano = require('cssnano');
4 |
5 | module.exports = {
6 | rollup(config, options) {
7 | config.plugins.push(
8 | postcss({
9 | plugins: [
10 | autoprefixer(),
11 | cssnano({
12 | preset: 'default',
13 | }),
14 | ],
15 | inject: false,
16 | extract: 'styles.css',
17 | })
18 | );
19 | return config;
20 | },
21 | };
22 |
--------------------------------------------------------------------------------