├── .github
├── FUNDING.yml
├── ISSUE_TEMPLATE.md
├── PULL_REQUEST_TEMPLATE.md
└── workflows
│ └── build.yaml
├── .gitignore
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── cypress.config.ts
├── cypress
├── .gitignore
├── e2e
│ ├── context-menu.spec.ts
│ ├── item.spec.ts
│ └── keyboard.spec.ts
├── fixtures
│ └── constant.ts
├── plugins
│ └── index.js
├── support
│ ├── commands.ts
│ ├── data-test.ts
│ ├── e2e.ts
│ └── is-in-viewport.ts
└── tsconfig.json
├── example
├── .gitignore
├── .npmignore
├── components
│ ├── App.tsx
│ └── Select.tsx
├── constants.ts
├── index.css
├── index.html
├── index.tsx
├── package.json
├── tsconfig.json
└── yarn.lock
├── package.json
├── scss
├── _menu.scss
├── _themes.scss
├── animations
│ ├── _fade.scss
│ ├── _flip.scss
│ ├── _scale.scss
│ └── _slide.scss
└── main.scss
├── src
├── components
│ ├── Arrow.tsx
│ ├── Item.tsx
│ ├── ItemTrackerProvider.tsx
│ ├── Menu.tsx
│ ├── RightSlot.tsx
│ ├── Separator.tsx
│ ├── Submenu.tsx
│ ├── keyboardController.ts
│ └── utils.ts
├── constants.ts
├── core
│ ├── contextMenu.ts
│ ├── eventManager.ts
│ └── index.ts
├── hooks
│ ├── index.ts
│ ├── useContextMenu.ts
│ └── useItemTracker.ts
├── index.ts
└── types
│ └── index.ts
├── tsconfig.json
├── tsup.config.ts
└── yarn.lock
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | github: fkhadra
4 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | **Do you want to request a *feature* or report a *bug*?**
2 |
3 | **What is the current behavior?**
4 |
5 | **If the current behavior is a bug, please provide the steps to reproduce and if possible a minimal demo of the problem. Your bug will get fixed much faster if we can run your code and it doesn't have dependencies other than React. Paste the link to your CodeSandbox (https://codesandbox.io/s/new) example below:**
6 |
7 | **What is the expected behavior?**
8 |
9 | **Which versions of React, and which browser / OS are affected by this issue? Did this work in previous versions of React?**
10 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | **Before submitting a pull request,** please make sure the following is done:
2 |
3 | 1. Fork [the repository](https://github.com/fkhadra/react-contexify) and create your branch from `master`.
4 | 2. Run `yarn` in the repository root.
5 | 3. If you've fixed a bug or added code that should be tested, add tests!
6 | 4. Run `yarn start` in the example folder to test your changes.
7 | 5. Ensure the test suite passes (`yarn test`). It uses the example
8 | 6. Update the readme if needed or the documentation
9 | 7. Update the typescript definition is needed
10 | 8. Make sure your code lints (`yarn lint --fix`).
11 |
12 | **Learn more about contributing [here](https://github.com/fkhadra/react-contexify/blob/master/CONTRIBUTING.md)**
--------------------------------------------------------------------------------
/.github/workflows/build.yaml:
--------------------------------------------------------------------------------
1 | name: React-contexify CI
2 |
3 | on: [push, pull_request]
4 |
5 | jobs:
6 | build:
7 | runs-on: ubuntu-latest
8 |
9 | steps:
10 | - uses: actions/checkout@v2
11 | - name: Install node
12 | uses: actions/setup-node@v1
13 | with:
14 | node-version: '16.x'
15 | - name: Install example dependencies
16 | run: cd example && yarn
17 | - name: Install dependencies & build
18 | run: yarn
19 | - name: Run cypress
20 | uses: cypress-io/github-action@v4
21 | with:
22 | browser: chrome
23 | start: yarn start
24 | wait-on: 'http://localhost:1234'
25 | - uses: actions/upload-artifact@v1
26 | if: failure()
27 | with:
28 | name: cypress-screenshots
29 | path: cypress/screenshots
30 |
31 | - uses: actions/upload-artifact@v1
32 | if: always()
33 | with:
34 | name: cypress-videos
35 | path: cypress/videos
36 |
37 |
38 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea/
2 | node_modules/
3 | .sass-cache/
4 | lib/
5 | npm-debug.log
6 | coverage/
7 | yarn-error.log*
8 | .DS_STORE
9 | .docz
10 | .vscode
11 | .cache
12 | dist
13 | *.log
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | In the interest of fostering an open and welcoming environment, we as
6 | contributors and maintainers pledge to making participation in our project and
7 | our community a harassment-free experience for everyone, regardless of age, body
8 | size, disability, ethnicity, sex characteristics, gender identity and expression,
9 | level of experience, education, socio-economic status, nationality, personal
10 | appearance, race, religion, or sexual identity and orientation.
11 |
12 | ## Our Standards
13 |
14 | Examples of behavior that contributes to creating a positive environment
15 | include:
16 |
17 | * Using welcoming and inclusive language
18 | * Being respectful of differing viewpoints and experiences
19 | * Gracefully accepting constructive criticism
20 | * Focusing on what is best for the community
21 | * Showing empathy towards other community members
22 |
23 | Examples of unacceptable behavior by participants include:
24 |
25 | * The use of sexualized language or imagery and unwelcome sexual attention or
26 | advances
27 | * Trolling, insulting/derogatory comments, and personal or political attacks
28 | * Public or private harassment
29 | * Publishing others' private information, such as a physical or electronic
30 | address, without explicit permission
31 | * Other conduct which could reasonably be considered inappropriate in a
32 | professional setting
33 |
34 | ## Our Responsibilities
35 |
36 | Project maintainers are responsible for clarifying the standards of acceptable
37 | behavior and are expected to take appropriate and fair corrective action in
38 | response to any instances of unacceptable behavior.
39 |
40 | Project maintainers have the right and responsibility to remove, edit, or
41 | reject comments, commits, code, wiki edits, issues, and other contributions
42 | that are not aligned to this Code of Conduct, or to ban temporarily or
43 | permanently any contributor for other behaviors that they deem inappropriate,
44 | threatening, offensive, or harmful.
45 |
46 | ## Scope
47 |
48 | This Code of Conduct applies both within project spaces and in public spaces
49 | when an individual is representing the project or its community. Examples of
50 | representing a project or community include using an official project e-mail
51 | address, posting via an official social media account, or acting as an appointed
52 | representative at an online or offline event. Representation of a project may be
53 | further defined and clarified by project maintainers.
54 |
55 | ## Enforcement
56 |
57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
58 | reported by contacting the project team at fdkhadra@gmail.com. All
59 | complaints will be reviewed and investigated and will result in a response that
60 | is deemed necessary and appropriate to the circumstances. The project team is
61 | obligated to maintain confidentiality with regard to the reporter of an incident.
62 | Further details of specific enforcement policies may be posted separately.
63 |
64 | Project maintainers who do not follow or enforce the Code of Conduct in good
65 | faith may face temporary or permanent repercussions as determined by other
66 | members of the project's leadership.
67 |
68 | ## Attribution
69 |
70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
72 |
73 | [homepage]: https://www.contributor-covenant.org
74 |
75 | For answers to common questions about this code of conduct, see
76 | https://www.contributor-covenant.org/faq
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | :+1::tada: First off, thanks for taking the time to contribute! :tada::+1:
4 |
5 | When contributing to this repository, please first discuss the change you wish to make via issue before making a change.
6 |
7 | Please note we have a code of conduct, please follow it in all your interactions with the project.
8 |
9 | ## General Guidelines
10 |
11 | - If adding a new feature, write the corresponding test
12 | - Ensure that nothing get broke. You can use the example for that
13 | - If applicable, update the [documentation](https://github.com/fkhadra/react-contexify-doc)
14 | - Use prettier before commiting 😭
15 | - When solving a bug, please provide the steps to reproduce it(codesandbox is our best friend for that)
16 | - Tchill 👌
17 |
18 | ## Setup
19 |
20 | ### Pre-requisites
21 |
22 | - *Node:* `^14.0.0`
23 | - *Yarn*
24 |
25 | ### Install
26 |
27 | Clone the repository and create a local branch:
28 |
29 | ```sh
30 | git clone https://github.com/fkhadra/react-contexify.git
31 | cd react-contexify
32 |
33 | git checkout -b my-branch
34 | ```
35 |
36 | Install dependencies:
37 |
38 | ```sh
39 | yarn install
40 | ```
41 |
42 | ### Project structure
43 |
44 | TO COMPLETE
45 |
46 | ## License
47 | By contributing, you agree that your contributions will be licensed under its MIT License.
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Fadi Khadra
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 |
3 |  []() []() []()
4 |
5 |
6 |
7 | 
8 |
9 |
10 |
11 | ## Features
12 |
13 | - Easy to set up for real, you can make it work in less than 10sec!
14 | - Super easy to customize thanks to css variables 💅
15 | - Custom position
16 | - Sub menu support
17 | - Does not go offscreen
18 | - Dark mode 🌒
19 | - Keyboard navigation + keyboard shortcut!
20 | - Built-in animations
21 | - Easy to test!
22 | - Written in Typescript 💪
23 | - Tiny! (3k gzipped)
24 |
25 | Check the documentation for more!
26 |
27 |
28 | ## Documentation
29 |
30 | Go [here](https://fkhadra.github.io/react-contexify).
31 |
32 | ## Installation
33 |
34 | Using yarn
35 |
36 | ```sh
37 | $ yarn add react-contexify
38 | ```
39 |
40 | Using npm
41 |
42 | ```sh
43 | $ npm install --save react-contexify
44 | ```
45 |
46 | ## The gist
47 |
48 | ```js
49 | import { Menu, Item, Separator, Submenu, useContextMenu } from 'react-contexify';
50 | import 'react-contexify/ReactContexify.css';
51 |
52 | const MENU_ID = 'blahblah';
53 |
54 | function App() {
55 | const { show } = useContextMenu({
56 | id: MENU_ID,
57 | });
58 |
59 | function handleContextMenu(event){
60 | show({
61 | event,
62 | props: {
63 | key: 'value'
64 | }
65 | })
66 | }
67 |
68 | // I'm using a single event handler for all items
69 | // but you don't have too :)
70 | const handleItemClick = ({ id, event, props }) => {
71 | switch (id) {
72 | case "copy":
73 | console.log(event, props)
74 | break;
75 | case "cut";
76 | console.log(event, props);
77 | break;
78 | //etc...
79 | }
80 | }
81 |
82 | return (
83 |
84 |
lorem ipsum blabladhasi blaghs blah
85 |
96 |
97 | );
98 | }
99 | ```
100 |
101 | ## Contribute
102 |
103 | Any idea and suggestions are welcome. Please have a look at the contributing guide.
104 |
105 | ## License
106 |
107 | React Contexify is licensed under MIT.
108 |
--------------------------------------------------------------------------------
/cypress.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'cypress'
2 |
3 | export default defineConfig({
4 | projectId: 'fwfrp4',
5 | e2e: {
6 | // We've imported your old cypress plugins here.
7 | // You may want to clean this up later by importing these.
8 | setupNodeEvents(on, config) {
9 | return require('./cypress/plugins/index.js')(on, config)
10 | },
11 | baseUrl: 'http://localhost:1234',
12 | specPattern: 'cypress/e2e/**/*.{js,jsx,ts,tsx}',
13 | },
14 | })
15 |
--------------------------------------------------------------------------------
/cypress/.gitignore:
--------------------------------------------------------------------------------
1 | videos
--------------------------------------------------------------------------------
/cypress/e2e/context-menu.spec.ts:
--------------------------------------------------------------------------------
1 | import { DATA_TEST } from '../../example/constants';
2 | import { CssClass } from '../../src/constants';
3 | import { animation, theme } from '../fixtures/constant';
4 |
5 | const builtInAnimationClasses = Object.keys(animation).map(k => ({
6 | name: k,
7 | enter: `${CssClass.animationWillEnter}${animation[k]}`,
8 | exit: `${CssClass.animationWillLeave}${animation[k]}`,
9 | }));
10 |
11 | describe('Context menu', () => {
12 | beforeEach(() => {
13 | cy.visit('/');
14 | });
15 |
16 | it('Should not be mounted by default', () => {
17 | cy.getByDataTest(DATA_TEST.CONTEXT_MENU).should('not.exist');
18 | });
19 |
20 | it('Display the context menu', () => {
21 | cy.getByDataTest(DATA_TEST.CONTEXT_MENU_TRIGGER).rightclick();
22 | cy.getByDataTest(DATA_TEST.CONTEXT_MENU).should('be.visible');
23 | });
24 |
25 | it('Close on Escape', () => {
26 | cy.getByDataTest(DATA_TEST.CONTEXT_MENU_TRIGGER).rightclick();
27 | cy.getByDataTest(DATA_TEST.CONTEXT_MENU).should('be.visible');
28 | cy.get('body').type('{esc}');
29 | cy.getByDataTest(DATA_TEST.CONTEXT_MENU).should('not.exist');
30 | });
31 |
32 | it('Close on Enter', () => {
33 | cy.getByDataTest(DATA_TEST.CONTEXT_MENU_TRIGGER).rightclick();
34 | cy.getByDataTest(DATA_TEST.CONTEXT_MENU).should('be.visible');
35 | cy.get('body').type('{enter}');
36 | cy.getByDataTest(DATA_TEST.CONTEXT_MENU).should('not.exist');
37 | });
38 |
39 | it('Close on window resize', () => {
40 | cy.getByDataTest(DATA_TEST.CONTEXT_MENU_TRIGGER).rightclick();
41 | cy.getByDataTest(DATA_TEST.CONTEXT_MENU).should('be.visible');
42 |
43 | cy.viewport(123, 456);
44 | cy.getByDataTest(DATA_TEST.CONTEXT_MENU).should('not.exist');
45 | });
46 |
47 | it('Prevent from rendering outside of the viewport if possible', () => {
48 | cy.viewport(500, 500);
49 | cy.getByDataTest(DATA_TEST.CONTEXT_MENU_TRIGGER).rightclick(10, 170);
50 | cy.getByDataTest(DATA_TEST.CONTEXT_MENU).should('be.visible');
51 | cy.getByDataTest(DATA_TEST.CONTEXT_MENU).isWithinViewport();
52 | });
53 |
54 | it('Can change trigger event', () => {
55 | cy.getByDataTest(DATA_TEST.EVENT_SELECTOR).select('onClick');
56 | cy.getByDataTest(DATA_TEST.CONTEXT_MENU_TRIGGER).rightclick();
57 | cy.getByDataTest(DATA_TEST.CONTEXT_MENU).should('not.exist');
58 |
59 | cy.getByDataTest(DATA_TEST.CONTEXT_MENU_TRIGGER).click();
60 | cy.getByDataTest(DATA_TEST.CONTEXT_MENU).should('be.visible');
61 |
62 | cy.getByDataTest(DATA_TEST.EVENT_SELECTOR).select('onDoubleClick');
63 | cy.getByDataTest(DATA_TEST.CONTEXT_MENU).should('not.exist');
64 |
65 | cy.getByDataTest(DATA_TEST.CONTEXT_MENU_TRIGGER).dblclick();
66 | cy.getByDataTest(DATA_TEST.CONTEXT_MENU).should('be.visible');
67 | });
68 |
69 | it('Can use built-in theme', () => {
70 | cy.getByDataTest(DATA_TEST.CONTEXT_MENU_TRIGGER).rightclick();
71 |
72 | // no theme selected
73 | cy.getByDataTest(DATA_TEST.CONTEXT_MENU).should(
74 | 'have.class',
75 | `${CssClass.theme}none`
76 | );
77 |
78 | cy.getByDataTest(DATA_TEST.THEME_SELECTOR).select(theme.light);
79 |
80 | cy.getByDataTest(DATA_TEST.CONTEXT_MENU_TRIGGER).rightclick();
81 |
82 | cy.getByDataTest(DATA_TEST.CONTEXT_MENU).should(
83 | 'have.class',
84 | `${CssClass.theme}${theme.light}`
85 | );
86 |
87 | cy.getByDataTest(DATA_TEST.THEME_SELECTOR).select(theme.dark);
88 |
89 | cy.getByDataTest(DATA_TEST.CONTEXT_MENU_TRIGGER).rightclick();
90 |
91 | cy.getByDataTest(DATA_TEST.CONTEXT_MENU).should(
92 | 'have.class',
93 | `${CssClass.theme}${theme.dark}`
94 | );
95 | });
96 |
97 | it('Can use built-in animation', () => {
98 | builtInAnimationClasses.forEach(builtInAnimation => {
99 | cy.getByDataTest(DATA_TEST.ANIMATION_SELECTOR).select(
100 | builtInAnimation.name
101 | );
102 | cy.getByDataTest(DATA_TEST.CONTEXT_MENU_TRIGGER).rightclick();
103 | cy.getByDataTest(DATA_TEST.CONTEXT_MENU).should(
104 | 'have.class',
105 | builtInAnimation.enter
106 | );
107 | // close the menu
108 | cy.get('body').type('{esc}');
109 |
110 | cy.getByDataTest(DATA_TEST.CONTEXT_MENU).should(
111 | 'have.class',
112 | builtInAnimation.exit
113 | );
114 |
115 | // wait for exit animation to complete
116 | cy.wait(500);
117 | });
118 | });
119 |
120 | it('Can disable animation', () => {
121 | cy.getByDataTest(DATA_TEST.ANIMATION_SELECTOR).select('none');
122 |
123 | builtInAnimationClasses.forEach(builtInAnimation => {
124 | cy.getByDataTest(DATA_TEST.CONTEXT_MENU_TRIGGER).rightclick();
125 | cy.getByDataTest(DATA_TEST.CONTEXT_MENU).should(
126 | 'not.have.class',
127 | builtInAnimation.enter
128 | );
129 |
130 | cy.get('body').type('{esc}');
131 |
132 | cy.getByDataTest(DATA_TEST.CONTEXT_MENU).should('not.exist');
133 | });
134 | });
135 |
136 | it('Can disable enter animation only', () => {
137 | cy.getByDataTest(DATA_TEST.TOGGLE_DISABLE_ENTER_ANIMATION).check();
138 |
139 | builtInAnimationClasses.forEach(builtInAnimation => {
140 | cy.getByDataTest(DATA_TEST.ANIMATION_SELECTOR).select(
141 | builtInAnimation.name
142 | );
143 | cy.getByDataTest(DATA_TEST.CONTEXT_MENU_TRIGGER).rightclick();
144 | cy.getByDataTest(DATA_TEST.CONTEXT_MENU).should(
145 | 'not.have.class',
146 | builtInAnimation.enter
147 | );
148 | // close the menu
149 | cy.get('body').type('{esc}');
150 |
151 | cy.getByDataTest(DATA_TEST.CONTEXT_MENU).should(
152 | 'have.class',
153 | builtInAnimation.exit
154 | );
155 |
156 | // wait for exit animation to complete
157 | cy.wait(500);
158 | });
159 | });
160 |
161 | it('Can disable exit animation only', () => {
162 | cy.getByDataTest(DATA_TEST.TOGGLE_DISABLE_EXIT_ANIMATION).check();
163 |
164 | builtInAnimationClasses.forEach(builtInAnimation => {
165 | cy.getByDataTest(DATA_TEST.ANIMATION_SELECTOR).select(
166 | builtInAnimation.name
167 | );
168 | cy.getByDataTest(DATA_TEST.CONTEXT_MENU_TRIGGER).rightclick();
169 | cy.getByDataTest(DATA_TEST.CONTEXT_MENU).should(
170 | 'have.class',
171 | builtInAnimation.enter
172 | );
173 | // close the menu
174 | cy.get('body').type('{esc}');
175 |
176 | cy.getByDataTest(DATA_TEST.CONTEXT_MENU).should('not.exist');
177 |
178 | // wait for exit animation to complete
179 | cy.wait(500);
180 | });
181 | });
182 |
183 | it('Can specify a custom position', () => {
184 | cy.getByDataTest(DATA_TEST.TOGGLE_CUSTOM_POSITION).check();
185 | cy.getByDataTest(DATA_TEST.CONTEXT_MENU_TRIGGER).rightclick();
186 | cy.getByDataTest(DATA_TEST.CONTEXT_MENU).should('be.visible');
187 |
188 | cy.getByDataTest(DATA_TEST.CONTEXT_MENU).then(el => {
189 | const { x, y } = el[0].getBoundingClientRect();
190 |
191 | expect(x).to.be.eq(0, 'x match custom coordinate');
192 | expect(y).to.be.eq(0, 'y match custom coordinate');
193 | });
194 | });
195 |
196 | it('Should not close when clicking a disabled item', () => {
197 | cy.getByDataTest(DATA_TEST.CONTEXT_MENU_TRIGGER).rightclick();
198 | cy.getByDataTest(DATA_TEST.CONTEXT_MENU).should('be.visible');
199 |
200 | cy.getByDataTest(DATA_TEST.DISABLED_ITEM_VIA_BOOLEAN).click();
201 | cy.getByDataTest(DATA_TEST.CONTEXT_MENU).should('be.visible');
202 |
203 | cy.getByDataTest(DATA_TEST.DISABLED_ITEM_VIA_FUNCTION).click();
204 | cy.getByDataTest(DATA_TEST.CONTEXT_MENU).should('be.visible');
205 | });
206 |
207 | it('Should not close when clicking on submenu', () => {
208 | cy.getByDataTest(DATA_TEST.CONTEXT_MENU_TRIGGER).rightclick();
209 | cy.getByDataTest(DATA_TEST.CONTEXT_MENU).should('be.visible');
210 |
211 | cy.getByDataTest(DATA_TEST.SUBMENU).click();
212 | cy.getByDataTest(DATA_TEST.CONTEXT_MENU).should('be.visible');
213 | });
214 |
215 | it('Should close when clicking on an item', () => {
216 | cy.getByDataTest(DATA_TEST.CONTEXT_MENU_TRIGGER).rightclick();
217 | cy.getByDataTest(DATA_TEST.CONTEXT_MENU).should('be.visible');
218 |
219 | cy.getByDataTest(DATA_TEST.MENU_FIRST_ITEM).click();
220 | cy.getByDataTest(DATA_TEST.CONTEXT_MENU).should('not.exist');
221 | });
222 | });
223 |
--------------------------------------------------------------------------------
/cypress/e2e/item.spec.ts:
--------------------------------------------------------------------------------
1 | import { DATA_TEST } from '../../example/constants';
2 |
3 | function showContextMenu() {
4 | cy.getByDataTest(DATA_TEST.CONTEXT_MENU_TRIGGER).rightclick();
5 | }
6 |
7 | describe('Menu item', () => {
8 | beforeEach(() => {
9 | cy.visit('/');
10 | });
11 |
12 | it('Can be disabled by passing a boolean or a function that return a boolean', () => {
13 | showContextMenu();
14 |
15 | cy.getByDataTest(DATA_TEST.DISABLED_ITEM_VIA_BOOLEAN).should(
16 | 'have.attr',
17 | 'aria-disabled',
18 | 'true'
19 | );
20 |
21 | cy.getByDataTest(DATA_TEST.DISABLED_ITEM_VIA_FUNCTION).should(
22 | 'have.attr',
23 | 'aria-disabled',
24 | 'true'
25 | );
26 | });
27 |
28 | it('Can be hidden by passing a boolean or a function that return a boolean', () => {
29 | showContextMenu();
30 | cy.getByDataTest(DATA_TEST.MENU_FIRST_ITEM).should('be.visible');
31 | cy.getByDataTest(DATA_TEST.MENU_SECOND_ITEM).should('be.visible');
32 |
33 | cy.getByDataTest(DATA_TEST.TOGGLE_HIDE_ITEMS).check();
34 | showContextMenu();
35 |
36 | cy.getByDataTest(DATA_TEST.MENU_FIRST_ITEM).should('not.exist');
37 | cy.getByDataTest(DATA_TEST.MENU_SECOND_ITEM).should('not.exist');
38 | });
39 |
40 | it('Should pass payload when clicking on an Item', () => {
41 | cy.getByDataTest(DATA_TEST.CONTEXT_MENU_TRIGGER).rightclick();
42 |
43 | cy.getByDataTest(DATA_TEST.MENU_FIRST_ITEM).click();
44 |
45 | cy.getByDataTest(DATA_TEST.ONCLICK_PAYLOAD).then(el => {
46 | const payload = JSON.parse(el.text());
47 | expect(payload).to.deep.include({
48 | data: { id: 1 },
49 | props: { key: 'value' },
50 | });
51 | });
52 | });
53 | });
54 |
--------------------------------------------------------------------------------
/cypress/e2e/keyboard.spec.ts:
--------------------------------------------------------------------------------
1 | import { DATA_TEST } from '../../example/constants';
2 |
3 | describe('Context menu keyboard interaction', () => {
4 | beforeEach(() => {
5 | cy.visit('/');
6 | });
7 |
8 | it('Select first menu item when pressing arrow down', () => {
9 | cy.getByDataTest(DATA_TEST.CONTEXT_MENU_TRIGGER).rightclick();
10 | cy.get('body').type('{downarrow}');
11 |
12 | cy.focused().should('have.attr', 'data-test', DATA_TEST.MENU_FIRST_ITEM);
13 | });
14 |
15 | it('Select the last item when pressing arrow up', () => {
16 | cy.getByDataTest(DATA_TEST.CONTEXT_MENU_TRIGGER).rightclick();
17 | cy.get('body').type('{uparrow}');
18 |
19 | cy.focused().should('have.attr', 'data-test', DATA_TEST.MENU_LAST_ITEM);
20 | });
21 |
22 | it('Should not select disabled items', () => {
23 | cy.getByDataTest(DATA_TEST.CONTEXT_MENU_TRIGGER).rightclick();
24 |
25 | //🙅♀️ go to item 4 and skip disabled items
26 | for (let i = 0; i < 4; i++) {
27 | cy.get('body').type('{downarrow}');
28 | cy.focused().should('have.attr', 'aria-disabled', 'false');
29 | }
30 | });
31 |
32 | describe('Open submenu and focus first item', () => {
33 | for (const key of ['{enter}', ' ', '{rightarrow}']) {
34 | it(`When ${key} is pressed`, () => {
35 | cy.getByDataTest(DATA_TEST.CONTEXT_MENU_TRIGGER).rightclick();
36 |
37 | //🙅♀️ go to submenu
38 | cy.get('body').type('{uparrow}');
39 | cy.get('body').type('{uparrow}');
40 |
41 | cy.focused().should('have.attr', 'data-test', DATA_TEST.SUBMENU);
42 |
43 | cy.getByDataTest(DATA_TEST.SUBMENU_FIRST_ITEM).should('not.be.visible');
44 | cy.get('body').type(key);
45 |
46 | // wait for transition
47 | cy.wait(500);
48 | cy.focused().should(
49 | 'have.attr',
50 | 'data-test',
51 | DATA_TEST.SUBMENU_FIRST_ITEM
52 | );
53 | });
54 | }
55 | });
56 |
57 | it('Close submenu on left arrow press', () => {
58 | cy.getByDataTest(DATA_TEST.CONTEXT_MENU_TRIGGER).rightclick();
59 |
60 | //🙅♀️ go to submenu
61 | cy.get('body').type('{uparrow}');
62 | cy.get('body').type('{uparrow}');
63 |
64 | cy.get('body').type('{rightarrow}');
65 |
66 | // wait for transition
67 | cy.wait(500);
68 | cy.focused().should('have.attr', 'data-test', DATA_TEST.SUBMENU_FIRST_ITEM);
69 |
70 | cy.get('body').type('{leftarrow}');
71 | cy.focused().should('have.attr', 'data-test', DATA_TEST.SUBMENU);
72 | });
73 |
74 | it('Should handle keyboard shortcut', () => {
75 | cy.getByDataTest(DATA_TEST.CONTEXT_MENU_TRIGGER).rightclick();
76 |
77 | cy.get('body').type('{ctrl}{u}');
78 | cy.wait(500);
79 | cy.getByDataTest(DATA_TEST.KDB_SHORTCUT).then((el) => {
80 | expect(el.text()).eq('ctrl+u');
81 | });
82 |
83 | // nested shortcut
84 | cy.getByDataTest(DATA_TEST.CONTEXT_MENU_TRIGGER).rightclick();
85 |
86 | cy.get('body').type('{ctrl}{s}');
87 | cy.wait(500);
88 | cy.getByDataTest(DATA_TEST.KDB_SHORTCUT).then((el) => {
89 | expect(el.text()).eq('ctrl+s');
90 | });
91 | });
92 | });
93 |
--------------------------------------------------------------------------------
/cypress/fixtures/constant.ts:
--------------------------------------------------------------------------------
1 | export const animation = {
2 | fade: 'fade',
3 | flip: 'flip',
4 | scale: 'scale',
5 | slide: 'slide',
6 | };
7 |
8 | export const theme = {
9 | light: 'light',
10 | dark: 'dark',
11 | };
12 |
--------------------------------------------------------------------------------
/cypress/plugins/index.js:
--------------------------------------------------------------------------------
1 | ///
2 | // ***********************************************************
3 | // This example plugins/index.js can be used to load plugins
4 | //
5 | // You can change the location of this file or turn off loading
6 | // the plugins file with the 'pluginsFile' configuration option.
7 | //
8 | // You can read more here:
9 | // https://on.cypress.io/plugins-guide
10 | // ***********************************************************
11 |
12 | // This function is called when a project is opened or re-opened (e.g. due to
13 | // the project's config changing)
14 |
15 | /**
16 | * @type {Cypress.PluginConfig}
17 | */
18 | module.exports = (on, config) => {
19 | // `on` is used to hook into various events Cypress emits
20 | // `config` is the resolved Cypress config
21 | }
22 |
--------------------------------------------------------------------------------
/cypress/support/commands.ts:
--------------------------------------------------------------------------------
1 | import './data-test';
2 | import './is-in-viewport';
3 |
--------------------------------------------------------------------------------
/cypress/support/data-test.ts:
--------------------------------------------------------------------------------
1 | declare namespace Cypress {
2 | interface Chainable {
3 | getByDataTest: (dataTest: string) => Cypress.Chainable>;
4 | findByDataTest: (
5 | dataTest: string
6 | ) => Cypress.Chainable>;
7 | }
8 | }
9 |
10 | Cypress.Commands.add("getByDataTest", (dataTest) => {
11 | cy.get(`[data-test="${dataTest}"]`);
12 | });
13 |
14 | Cypress.Commands.add(
15 | "findByDataTest",
16 | { prevSubject: true },
17 | (subject, dataTest) => subject.find(`[data-test="${dataTest}"]`)
18 | );
19 |
--------------------------------------------------------------------------------
/cypress/support/e2e.ts:
--------------------------------------------------------------------------------
1 | import './commands';
2 |
--------------------------------------------------------------------------------
/cypress/support/is-in-viewport.ts:
--------------------------------------------------------------------------------
1 | declare namespace Cypress {
2 | interface Chainable {
3 | isWithinViewport: () => Cypress.Chainable>;
4 | }
5 | }
6 |
7 | Cypress.Commands.add('isWithinViewport', { prevSubject: true }, subject => {
8 | const windowInnerWidth = Cypress.config(`viewportWidth`);
9 | const windowInnerHeight = Cypress.config(`viewportHeight`);
10 |
11 | const bounding = subject[0].getBoundingClientRect();
12 |
13 | const rightBoundOfWindow = windowInnerWidth;
14 | const bottomBoundOfWindow = windowInnerHeight;
15 |
16 | Cypress.log({
17 | message: 'Checking bounding client rect',
18 | });
19 | expect(bounding.top).to.be.at.least(0);
20 | expect(bounding.left).to.be.at.least(0);
21 | expect(bounding.right).to.be.lessThan(rightBoundOfWindow);
22 | expect(bounding.bottom).to.be.lessThan(bottomBoundOfWindow);
23 |
24 | return subject;
25 | });
26 |
--------------------------------------------------------------------------------
/cypress/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es5",
4 | "lib": ["es5", "dom"],
5 | "types": ["cypress"]
6 | },
7 | "include": [
8 | "**/*.ts"
9 | ]
10 | }
--------------------------------------------------------------------------------
/example/.gitignore:
--------------------------------------------------------------------------------
1 | .parcel-cache
--------------------------------------------------------------------------------
/example/.npmignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .cache
3 | dist
--------------------------------------------------------------------------------
/example/components/App.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 |
3 | import { Select } from './Select';
4 | import { DATA_TEST, MENU_ID } from '../constants';
5 |
6 | import {
7 | Menu,
8 | Item,
9 | Separator,
10 | Submenu,
11 | useContextMenu,
12 | ItemParams,
13 | RightSlot,
14 | } from '../../src';
15 |
16 | const builtInAnimation = {
17 | fade: 'fade',
18 | flip: 'flip',
19 | scale: 'scale',
20 | slide: 'slide',
21 | };
22 |
23 | const builtInTheme = {
24 | light: 'light',
25 | dark: 'dark',
26 | };
27 |
28 | const selector = {
29 | events: ['onContextMenu', 'onClick', 'onDoubleClick'],
30 | themes: [
31 | 'none',
32 | ...Object.keys(builtInTheme).map(
33 | (k) => builtInTheme[k as keyof typeof builtInTheme]
34 | ),
35 | ],
36 | animations: [
37 | 'none',
38 | ...Object.keys(builtInAnimation).map(
39 | (k) => builtInAnimation[k as keyof typeof builtInAnimation]
40 | ),
41 | ],
42 | };
43 |
44 | interface SelectorState {
45 | theme: string;
46 | animation: string | false;
47 | event: string;
48 | hideItems: boolean;
49 | customPosition: boolean;
50 | disableEnterAnimation: boolean;
51 | disableExitAnimation: boolean;
52 | kbdShortcut: string;
53 | }
54 |
55 | function selectorReducer(
56 | state: SelectorState,
57 | nextState: Partial
58 | ) {
59 | return { ...state, ...nextState };
60 | }
61 |
62 | function singularize(s: string) {
63 | return s.slice(0, -1);
64 | }
65 |
66 | function getDataTestSelector(key: string) {
67 | switch (key) {
68 | case 'animations':
69 | return DATA_TEST.ANIMATION_SELECTOR;
70 | case 'events':
71 | return DATA_TEST.EVENT_SELECTOR;
72 | case 'themes':
73 | return DATA_TEST.THEME_SELECTOR;
74 | }
75 | }
76 |
77 | export function App() {
78 | const [state, setState] = React.useReducer(selectorReducer, {
79 | theme: selector.themes[0],
80 | animation: false,
81 | event: selector.events[0],
82 | hideItems: false,
83 | customPosition: false,
84 | disableEnterAnimation: false,
85 | disableExitAnimation: false,
86 | kbdShortcut: '',
87 | });
88 | const [payload, setPayload] = React.useState({
89 | x: 0,
90 | y: 0,
91 | data: null,
92 | props: null,
93 | });
94 | const { show } = useContextMenu({
95 | id: MENU_ID,
96 | });
97 |
98 | function handleSelector({
99 | target: { name, value },
100 | }: React.ChangeEvent) {
101 | setState({
102 | [singularize(name)]: value === 'none' ? false : value,
103 | });
104 | }
105 |
106 | function handleCheckboxes(e: React.ChangeEvent) {
107 | setState({
108 | [e.target.name]: !state[e.target.name],
109 | });
110 | }
111 |
112 | function handleContextMenu(event: React.MouseEvent) {
113 | show({
114 | event,
115 | props: {
116 | key: 'value',
117 | },
118 | position: state.customPosition
119 | ? {
120 | x: 0,
121 | y: 0,
122 | }
123 | : null,
124 | });
125 | }
126 |
127 | function handleItemClick(params: ItemParams) {
128 | console.log(params.triggerEvent);
129 |
130 | setPayload({
131 | x: params.triggerEvent.clientX,
132 | y: params.triggerEvent.clientY,
133 | data: params.data,
134 | props: params.props,
135 | });
136 | }
137 |
138 | function getAnimation() {
139 | const { disableEnterAnimation, disableExitAnimation, animation } = state;
140 | if (!animation) {
141 | return false;
142 | } else if (disableEnterAnimation || disableExitAnimation) {
143 | return {
144 | enter: disableEnterAnimation ? false : animation,
145 | exit: disableExitAnimation ? false : animation,
146 | };
147 | }
148 |
149 | return animation;
150 | }
151 |
152 | return (
153 |
154 |
155 | Settings
156 |
217 |
218 |
219 | Item payload
220 |
221 | On click payload
222 |
223 | {JSON.stringify(payload, null, 2)}
224 |
225 |
226 |
227 |
228 | Keyboard shortcut
229 |
230 | Shortcut triggered:
231 | {state.kbdShortcut}
232 |
233 |
234 |
235 |
240 | event is triggered everywhere in the box
241 |
242 |
243 |
312 |
313 |
314 | );
315 | }
316 |
--------------------------------------------------------------------------------
/example/components/Select.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 |
3 | export interface SelectProps extends React.HTMLAttributes {
4 | name: string;
5 | value: string;
6 | data: string[];
7 | onChange: (e: React.ChangeEvent) => void;
8 | }
9 |
10 | export function Select({ name, value, data, onChange, ...rest }: SelectProps) {
11 | return (
12 |
13 | {data.map(item => (
14 |
15 | {item}
16 |
17 | ))}
18 |
19 | );
20 | }
21 |
--------------------------------------------------------------------------------
/example/constants.ts:
--------------------------------------------------------------------------------
1 | export const MENU_ID = '🦄';
2 |
3 | export const enum DATA_TEST {
4 | MOUNT_NODE = 'mount-node',
5 | TOGGLE_CUSTOM_POSITION = 'toggle-custom-position',
6 | CONTEXT_MENU_TRIGGER = 'trigger',
7 | CONTEXT_MENU = 'context-menu',
8 | THEME_SELECTOR = 'theme-selector',
9 | ANIMATION_SELECTOR = 'animation-selector',
10 | EVENT_SELECTOR = 'event-selector',
11 | TOGGLE_HIDE_ITEMS = 'hide-items',
12 | TOGGLE_DISABLE_ENTER_ANIMATION = 'disable-enter-animation',
13 | TOGGLE_DISABLE_EXIT_ANIMATION = 'disable-exit-animation',
14 | DISABLED_ITEM_VIA_BOOLEAN = 'disabled-item-boolean',
15 | DISABLED_ITEM_VIA_FUNCTION = 'disabled-item-function',
16 | SUBMENU = 'submenu',
17 | NESTED_SUBMENU = 'nested-submenu',
18 | MENU_FIRST_ITEM = 'menu-firt-item',
19 | MENU_SECOND_ITEM = 'menu-second-item',
20 | MENU_LAST_ITEM = 'menu-last-item',
21 | SUBMENU_FIRST_ITEM = 'submenu-firt-item',
22 | NESTED_SUBMENU_FIRST_ITEM = 'nested-submenu-firt-item',
23 | ONCLICK_PAYLOAD = 'item-payload',
24 | KDB_SHORTCUT = "kbd-shortcut"
25 | }
26 |
--------------------------------------------------------------------------------
/example/index.css:
--------------------------------------------------------------------------------
1 | :root {
2 | --display-border: 1px solid red;
3 | }
4 |
5 | body {
6 | font-family: 'Inter', sans-serif;
7 | }
8 |
9 | * {
10 | box-sizing: border-box;
11 | }
12 |
13 | canvas {
14 | border: var(--display-border);
15 | }
16 |
17 | table.grid {
18 | width: 200px;
19 | border: var(--display-border);
20 | }
21 |
22 | table.grid tr {
23 | height: 15px;
24 | }
25 |
26 | table.grid td {
27 | border: 1px solid #000000;
28 | }
29 |
30 | table.grid td:hover {
31 | background: red;
32 | }
33 |
34 | main {
35 | max-width: 1180px;
36 | margin: auto;
37 | }
38 |
39 | .boxes-container{
40 | display: flex;
41 | }
42 |
43 | .box {
44 | border: var(--display-border);
45 | background-color: blue;
46 | width: 200px;
47 | height: 200px;
48 | color: white;
49 | text-align: center;
50 | }
--------------------------------------------------------------------------------
/example/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Playground
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/example/index.tsx:
--------------------------------------------------------------------------------
1 | import { createRoot } from 'react-dom/client';
2 | import * as React from 'react';
3 | import { App } from './components/App';
4 |
5 | import './index.css';
6 | import '../scss/main.scss';
7 |
8 | const root = createRoot(document.getElementById('root')!);
9 |
10 | root.render(
11 |
12 |
13 |
14 | );
15 |
--------------------------------------------------------------------------------
/example/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "example",
3 | "version": "1.0.0",
4 | "main": "index.js",
5 | "license": "MIT",
6 | "scripts": {
7 | "start": "parcel --no-cache index.html",
8 | "build": "parcel build index.html"
9 | },
10 | "dependencies": {
11 | "react-app-polyfill": "^3.0.0"
12 | },
13 | "alias": {
14 | "react": "../node_modules/react",
15 | "react-dom": "../node_modules/react-dom"
16 | },
17 | "devDependencies": {
18 | "@parcel/transformer-sass": "2.7.0",
19 | "@types/react": "^18.0.24",
20 | "@types/react-dom": "^18.0.8",
21 | "parcel": "^2.7.0",
22 | "typescript": "^4.8.4"
23 | }
24 | }
--------------------------------------------------------------------------------
/example/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "allowSyntheticDefaultImports": false,
4 | "target": "ESNext",
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.10.4"
7 | resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.10.4.tgz#168da1a36e90da68ae8d49c0f1b48c7c6249213a"
8 | integrity sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==
9 | dependencies:
10 | "@babel/highlight" "^7.10.4"
11 |
12 | "@babel/helper-validator-identifier@^7.10.4":
13 | version "7.10.4"
14 | resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz#a78c7a7251e01f616512d31b10adcf52ada5e0d2"
15 | integrity sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==
16 |
17 | "@babel/highlight@^7.10.4":
18 | version "7.10.4"
19 | resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.10.4.tgz#7d1bdfd65753538fabe6c38596cdb76d9ac60143"
20 | integrity sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==
21 | dependencies:
22 | "@babel/helper-validator-identifier" "^7.10.4"
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.1.0":
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.14", "@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.17"
60 | resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz#793041277af9073b0951a7fe0f0d8c4c98c36985"
61 | integrity sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==
62 | dependencies:
63 | "@jridgewell/resolve-uri" "3.1.0"
64 | "@jridgewell/sourcemap-codec" "1.4.14"
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@^1.12.2":
249 | version "1.14.0"
250 | resolved "https://registry.yarnpkg.com/@parcel/css/-/css-1.14.0.tgz#233750a1e3648b3746f27c2d8f3fd85a2290e512"
251 | integrity sha512-r5tJWe6NF6lesfPw1N3g7N7WUKpHqi2ONnw9wl5ccSGGIxkmgcPaPQxfvmhdjXvQnktSuIOR0HjQXVXu+/en/w==
252 | dependencies:
253 | lightningcss "^1.14.0"
254 |
255 | "@parcel/diagnostic@2.7.0":
256 | version "2.7.0"
257 | resolved "https://registry.yarnpkg.com/@parcel/diagnostic/-/diagnostic-2.7.0.tgz#cf2596a20ce9277334616e12bbdac98490189e99"
258 | integrity sha512-pdq/cTwVoL0n8yuDCRXFRSQHVWdmmIXPt3R3iT4KtYDYvOrMT2dLPT79IMqQkhYPANW8GuL15n/WxRngfRdkug==
259 | dependencies:
260 | "@mischnic/json-sourcemap" "^0.1.0"
261 | nullthrows "^1.1.1"
262 |
263 | "@parcel/events@2.7.0":
264 | version "2.7.0"
265 | resolved "https://registry.yarnpkg.com/@parcel/events/-/events-2.7.0.tgz#b6db8464d45626686134d412d3a36d024ffb1482"
266 | integrity sha512-kQDwMKgZ1U4M/G17qeDYF6bW5kybluN6ajYPc7mZcrWg+trEI/oXi81GMFaMX0BSUhwhbiN5+/Vb2wiG/Sn6ig==
267 |
268 | "@parcel/fs-search@2.7.0":
269 | version "2.7.0"
270 | resolved "https://registry.yarnpkg.com/@parcel/fs-search/-/fs-search-2.7.0.tgz#15e658006039ddc7b92528df5266ee2b9c47b6a4"
271 | integrity sha512-K1Hv25bnRpwQVA15RvcRuB8ZhfclnCHA8N8L6w7Ul1ncSJDxCIkIAc5hAubYNNYW3kWjCC2SOaEgFKnbvMllEQ==
272 | dependencies:
273 | detect-libc "^1.0.3"
274 |
275 | "@parcel/fs@2.7.0":
276 | version "2.7.0"
277 | resolved "https://registry.yarnpkg.com/@parcel/fs/-/fs-2.7.0.tgz#c9a0c60bdbef7101ff47f2db6b23814c3db06007"
278 | integrity sha512-PU5fo4Hh8y03LZgemgVREttc0wyHQUNmsJCybxTB7EjJie2CqJRumo+DFppArlvdchLwJdc9em03yQV/GNWrEg==
279 | dependencies:
280 | "@parcel/fs-search" "2.7.0"
281 | "@parcel/types" "2.7.0"
282 | "@parcel/utils" "2.7.0"
283 | "@parcel/watcher" "^2.0.0"
284 | "@parcel/workers" "2.7.0"
285 |
286 | "@parcel/graph@2.7.0":
287 | version "2.7.0"
288 | resolved "https://registry.yarnpkg.com/@parcel/graph/-/graph-2.7.0.tgz#2ae326c62764aaa53324b89d9c83ec0bc6ad55bf"
289 | integrity sha512-Q6E94GS6q45PtsZh+m+gvFRp/N1Qopxhu2sxjcWsGs5iBd6IWn2oYLWOH5iVzEjWuYpW2HkB08lH6J50O63uOA==
290 | dependencies:
291 | "@parcel/utils" "2.7.0"
292 | nullthrows "^1.1.1"
293 |
294 | "@parcel/hash@2.7.0":
295 | version "2.7.0"
296 | resolved "https://registry.yarnpkg.com/@parcel/hash/-/hash-2.7.0.tgz#8825cff69a0bc4816737415e6e2aa29e8671c0b1"
297 | integrity sha512-k6bSKnIlPJMPU3yjQzfgfvF9zuJZGOAlJgzpL4BbWvdbE8BTdjzLcFn0Ujrtud94EgIkiXd22sC2HpCUWoHGdA==
298 | dependencies:
299 | detect-libc "^1.0.3"
300 | xxhash-wasm "^0.4.2"
301 |
302 | "@parcel/logger@2.7.0":
303 | version "2.7.0"
304 | resolved "https://registry.yarnpkg.com/@parcel/logger/-/logger-2.7.0.tgz#1aa1de0458bdd613714ce4031134d92135aec590"
305 | integrity sha512-qjMY/bYo38+o+OiIrTRldU9CwL1E7J72t+xkTP8QIcUxLWz5LYR0YbynZUVulmBSfqsykjjxCy4a+8siVr+lPw==
306 | dependencies:
307 | "@parcel/diagnostic" "2.7.0"
308 | "@parcel/events" "2.7.0"
309 |
310 | "@parcel/markdown-ansi@2.7.0":
311 | version "2.7.0"
312 | resolved "https://registry.yarnpkg.com/@parcel/markdown-ansi/-/markdown-ansi-2.7.0.tgz#4ba70e3661ce06cd8fd2eb3f7b84028853a586e4"
313 | integrity sha512-ipOX0D6FVZFEXeb/z8MnTMq2RQEIuaILY90olVIuHEFLHHfOPEn+RK3u13HA1ChF5/9E3cMD79tu6x9JL9Kqag==
314 | dependencies:
315 | chalk "^4.1.0"
316 |
317 | "@parcel/namer-default@2.7.0":
318 | version "2.7.0"
319 | resolved "https://registry.yarnpkg.com/@parcel/namer-default/-/namer-default-2.7.0.tgz#e008097586016f16509834db11985dcc772c314c"
320 | integrity sha512-lIKMdsmi//7fepecNDYmJYzBlL91HifPsX03lJCdu1dC6q5fBs+gG0XjKKG7yPnSCw1qH/4m7drzt9+dRZYAHQ==
321 | dependencies:
322 | "@parcel/diagnostic" "2.7.0"
323 | "@parcel/plugin" "2.7.0"
324 | nullthrows "^1.1.1"
325 |
326 | "@parcel/node-resolver-core@2.7.0":
327 | version "2.7.0"
328 | resolved "https://registry.yarnpkg.com/@parcel/node-resolver-core/-/node-resolver-core-2.7.0.tgz#468074aa58a2f0026a492607153079ebb16308e3"
329 | integrity sha512-5UJQHalqMxdhJIs2hhqQzFfQpF7+NAowsRq064lYtiRvcD8wMr3OOQ9wd1iazGpFSl4JKdT7BwDU9/miDJmanQ==
330 | dependencies:
331 | "@parcel/diagnostic" "2.7.0"
332 | "@parcel/utils" "2.7.0"
333 | nullthrows "^1.1.1"
334 | semver "^5.7.1"
335 |
336 | "@parcel/optimizer-css@2.7.0":
337 | version "2.7.0"
338 | resolved "https://registry.yarnpkg.com/@parcel/optimizer-css/-/optimizer-css-2.7.0.tgz#460cde19b9ee61efed577473cb0822796b6e8b1a"
339 | integrity sha512-IfnOMACqhcAclKyOW9X9JpsknB6OShk9OVvb8EvbDTKHJhQHNNmzE88OkSI/pS3ZVZP9Zj+nWcVHguV+kvDeiQ==
340 | dependencies:
341 | "@parcel/css" "^1.12.2"
342 | "@parcel/diagnostic" "2.7.0"
343 | "@parcel/plugin" "2.7.0"
344 | "@parcel/source-map" "^2.0.0"
345 | "@parcel/utils" "2.7.0"
346 | browserslist "^4.6.6"
347 | nullthrows "^1.1.1"
348 |
349 | "@parcel/optimizer-htmlnano@2.7.0":
350 | version "2.7.0"
351 | resolved "https://registry.yarnpkg.com/@parcel/optimizer-htmlnano/-/optimizer-htmlnano-2.7.0.tgz#d2e843b539a430fcca723f08efcee26f98b3d40b"
352 | integrity sha512-5QrGdWS5Hi4VXE3nQNrGqugmSXt68YIsWwKRAdarOxzyULSJS3gbCiQOXqIPRJobfZjnSIcdtkyxSiCUe1inIA==
353 | dependencies:
354 | "@parcel/plugin" "2.7.0"
355 | htmlnano "^2.0.0"
356 | nullthrows "^1.1.1"
357 | posthtml "^0.16.5"
358 | svgo "^2.4.0"
359 |
360 | "@parcel/optimizer-image@2.7.0":
361 | version "2.7.0"
362 | resolved "https://registry.yarnpkg.com/@parcel/optimizer-image/-/optimizer-image-2.7.0.tgz#180d7709e6268e0634967eb265bf901aba2471ce"
363 | integrity sha512-EnaXz5UjR67FUu0BEcqZTT9LsbB/iFAkkghCotbnbOuC5QQsloq6tw54TKU3y+R3qsjgUoMtGxPcGfVoXxZXYw==
364 | dependencies:
365 | "@parcel/diagnostic" "2.7.0"
366 | "@parcel/plugin" "2.7.0"
367 | "@parcel/utils" "2.7.0"
368 | "@parcel/workers" "2.7.0"
369 | detect-libc "^1.0.3"
370 |
371 | "@parcel/optimizer-svgo@2.7.0":
372 | version "2.7.0"
373 | resolved "https://registry.yarnpkg.com/@parcel/optimizer-svgo/-/optimizer-svgo-2.7.0.tgz#9b4ab38a9d3c99504cf399a5c7709e5d2a615e71"
374 | integrity sha512-IO1JV4NpfP3V7FrhsqCcV8pDQIHraFi1/ZvEJyssITxjH49Im/txKlwMiQuZZryAPn8Xb8g395Muawuk6AK6sg==
375 | dependencies:
376 | "@parcel/diagnostic" "2.7.0"
377 | "@parcel/plugin" "2.7.0"
378 | "@parcel/utils" "2.7.0"
379 | svgo "^2.4.0"
380 |
381 | "@parcel/optimizer-terser@2.7.0":
382 | version "2.7.0"
383 | resolved "https://registry.yarnpkg.com/@parcel/optimizer-terser/-/optimizer-terser-2.7.0.tgz#b9ef408f45714952d1502940b6a63e5ebd3f0940"
384 | integrity sha512-07VZjIO8xsl2/WmS/qHI8lI/cpu47iS9eRpqwfZEEsdk1cfz50jhWkmFudHBxiHGMfcZ//1+DdaPg9RDBWZtZA==
385 | dependencies:
386 | "@parcel/diagnostic" "2.7.0"
387 | "@parcel/plugin" "2.7.0"
388 | "@parcel/source-map" "^2.0.0"
389 | "@parcel/utils" "2.7.0"
390 | nullthrows "^1.1.1"
391 | terser "^5.2.0"
392 |
393 | "@parcel/package-manager@2.7.0":
394 | version "2.7.0"
395 | resolved "https://registry.yarnpkg.com/@parcel/package-manager/-/package-manager-2.7.0.tgz#5de1bf5c94d95330e98dffb2a66c22d1f20c4c8a"
396 | integrity sha512-wmfSX1mRrTi8MeA4KrnPk/x7zGUsILCQmTo6lA4gygzAxDbM1pGuyFN8/Kt0y0SFO2lbljARtD/4an5qdotH+Q==
397 | dependencies:
398 | "@parcel/diagnostic" "2.7.0"
399 | "@parcel/fs" "2.7.0"
400 | "@parcel/logger" "2.7.0"
401 | "@parcel/types" "2.7.0"
402 | "@parcel/utils" "2.7.0"
403 | "@parcel/workers" "2.7.0"
404 | semver "^5.7.1"
405 |
406 | "@parcel/packager-css@2.7.0":
407 | version "2.7.0"
408 | resolved "https://registry.yarnpkg.com/@parcel/packager-css/-/packager-css-2.7.0.tgz#060af8b96e5ad53620b4021610364804e26d69b2"
409 | integrity sha512-44nzZwu+ssGuiFmYM6cf/Y4iChiUZ4DUzzpegnGlhXtKJKe4NHntxThJynuRZWKN2AAf48avApDpimg2jW0KDw==
410 | dependencies:
411 | "@parcel/plugin" "2.7.0"
412 | "@parcel/source-map" "^2.0.0"
413 | "@parcel/utils" "2.7.0"
414 | nullthrows "^1.1.1"
415 |
416 | "@parcel/packager-html@2.7.0":
417 | version "2.7.0"
418 | resolved "https://registry.yarnpkg.com/@parcel/packager-html/-/packager-html-2.7.0.tgz#4f86698d05f5ec5c3ebc8b46102a6ae42c58a24a"
419 | integrity sha512-Zgqd7sdcY/UnR370GR0q2ilmEohUDXsO8A1F28QCJzIsR1iCB6KRUT74+pawfQ1IhXZLaaFLLYe0UWcfm0JeXg==
420 | dependencies:
421 | "@parcel/plugin" "2.7.0"
422 | "@parcel/types" "2.7.0"
423 | "@parcel/utils" "2.7.0"
424 | nullthrows "^1.1.1"
425 | posthtml "^0.16.5"
426 |
427 | "@parcel/packager-js@2.7.0":
428 | version "2.7.0"
429 | resolved "https://registry.yarnpkg.com/@parcel/packager-js/-/packager-js-2.7.0.tgz#e694cc731d75697e63d3d4be0bdbbe4a2ae8f1fc"
430 | integrity sha512-wTRdM81PgRVDzWGXdWmqLwguWnTYWzhEDdjXpW2n8uMOu/CjHhMtogk65aaYk3GOnq6OBL/NsrmBiV/zKPj1vA==
431 | dependencies:
432 | "@parcel/diagnostic" "2.7.0"
433 | "@parcel/hash" "2.7.0"
434 | "@parcel/plugin" "2.7.0"
435 | "@parcel/source-map" "^2.0.0"
436 | "@parcel/utils" "2.7.0"
437 | globals "^13.2.0"
438 | nullthrows "^1.1.1"
439 |
440 | "@parcel/packager-raw@2.7.0":
441 | version "2.7.0"
442 | resolved "https://registry.yarnpkg.com/@parcel/packager-raw/-/packager-raw-2.7.0.tgz#5b68de05c19bbcf438f40b4ae9f45411ba9739bd"
443 | integrity sha512-jg2Zp8dI5VpIQlaeahXDCfrPN9m/DKht1NkR9P2CylMAwqCcc1Xc1RRiF0wfwcPZpPMpq1265n+4qnB7rjGBlA==
444 | dependencies:
445 | "@parcel/plugin" "2.7.0"
446 |
447 | "@parcel/packager-svg@2.7.0":
448 | version "2.7.0"
449 | resolved "https://registry.yarnpkg.com/@parcel/packager-svg/-/packager-svg-2.7.0.tgz#e7e96503c86815eca285b9cc8908105075d9ab38"
450 | integrity sha512-EmJg3HpD6/xxKBjir/CdCKJZwI24iVfBuxRS9LUp3xHAIebOzVh1z6IN+i2Di5+NyRwfOFaLliL4uMa1zwbyCA==
451 | dependencies:
452 | "@parcel/plugin" "2.7.0"
453 | "@parcel/types" "2.7.0"
454 | "@parcel/utils" "2.7.0"
455 | posthtml "^0.16.4"
456 |
457 | "@parcel/plugin@2.7.0":
458 | version "2.7.0"
459 | resolved "https://registry.yarnpkg.com/@parcel/plugin/-/plugin-2.7.0.tgz#0211281025d02afbc5a23fba237b7aae02e34e51"
460 | integrity sha512-qqgx+nnMn6/0lRc4lKbLGmhNtBiT93S2gFNB4Eb4Pfz/SxVYoW+fmml+KdfOSiZffWOAH5L6NwhyD7N8aSikzw==
461 | dependencies:
462 | "@parcel/types" "2.7.0"
463 |
464 | "@parcel/reporter-cli@2.7.0":
465 | version "2.7.0"
466 | resolved "https://registry.yarnpkg.com/@parcel/reporter-cli/-/reporter-cli-2.7.0.tgz#86499624e258034001b64c10b14e23ae4b92f44b"
467 | integrity sha512-80gEODg8cnAmnxGVuaSVDo8JJ54P9AA2bHwSs1cIkHWlJ3BjDQb83H31bBHncJ5Kn5kQ/j+7WjlqHpTCiOR9PA==
468 | dependencies:
469 | "@parcel/plugin" "2.7.0"
470 | "@parcel/types" "2.7.0"
471 | "@parcel/utils" "2.7.0"
472 | chalk "^4.1.0"
473 | term-size "^2.2.1"
474 |
475 | "@parcel/reporter-dev-server@2.7.0":
476 | version "2.7.0"
477 | resolved "https://registry.yarnpkg.com/@parcel/reporter-dev-server/-/reporter-dev-server-2.7.0.tgz#9bd3d10f745e0cbc9ab983ec046953c2c564dcb2"
478 | integrity sha512-ySuou5addK8fGue8aXzo536BaEjMujDrEc1xkp4TasInXHVcA98b+SYX5NAZTGob5CxKvZQ5ylhg77zW30B+iA==
479 | dependencies:
480 | "@parcel/plugin" "2.7.0"
481 | "@parcel/utils" "2.7.0"
482 |
483 | "@parcel/resolver-default@2.7.0":
484 | version "2.7.0"
485 | resolved "https://registry.yarnpkg.com/@parcel/resolver-default/-/resolver-default-2.7.0.tgz#648a257b81abe2eda09700d8f36348a88ea0442e"
486 | integrity sha512-v8TvWsbLK7/q7n4gv6OrYNbW18xUx4zKbVMGZb1u4yMhzEH4HFr1D9OeoTq3jk+ximAigds8B6triQbL5exF7A==
487 | dependencies:
488 | "@parcel/node-resolver-core" "2.7.0"
489 | "@parcel/plugin" "2.7.0"
490 |
491 | "@parcel/runtime-browser-hmr@2.7.0":
492 | version "2.7.0"
493 | resolved "https://registry.yarnpkg.com/@parcel/runtime-browser-hmr/-/runtime-browser-hmr-2.7.0.tgz#aed79b96c0d97021f56f2b7e35bc2d4f70869e26"
494 | integrity sha512-PLbMLdclQeYsi2LkilZVGFV1n3y55G1jaBvby4ekedUZjMw3SWdMY2tDxgSDdFWfLCnYHJXdGUQSzGGi1kPzjA==
495 | dependencies:
496 | "@parcel/plugin" "2.7.0"
497 | "@parcel/utils" "2.7.0"
498 |
499 | "@parcel/runtime-js@2.7.0":
500 | version "2.7.0"
501 | resolved "https://registry.yarnpkg.com/@parcel/runtime-js/-/runtime-js-2.7.0.tgz#63dd744e96c3554ac86778ffce1c8055e7653fce"
502 | integrity sha512-9/YUZTBNrSN2H6rbz/o1EOM0O7I3ZR/x9IDzxjJBD6Mi+0uCgCD02aedare/SNr1qgnbZZWmhpOzC+YgREcfLA==
503 | dependencies:
504 | "@parcel/plugin" "2.7.0"
505 | "@parcel/utils" "2.7.0"
506 | nullthrows "^1.1.1"
507 |
508 | "@parcel/runtime-react-refresh@2.7.0":
509 | version "2.7.0"
510 | resolved "https://registry.yarnpkg.com/@parcel/runtime-react-refresh/-/runtime-react-refresh-2.7.0.tgz#c56b847ef1144264e918339381e040ffe811efc5"
511 | integrity sha512-vDKO0rWqRzEpmvoZ4kkYUiSsTxT5NnH904BFPFxKI0wJCl6yEmPuEifmATo73OuYhP6jIP3Qfl1R4TtiDFPJ1Q==
512 | dependencies:
513 | "@parcel/plugin" "2.7.0"
514 | "@parcel/utils" "2.7.0"
515 | react-error-overlay "6.0.9"
516 | react-refresh "^0.9.0"
517 |
518 | "@parcel/runtime-service-worker@2.7.0":
519 | version "2.7.0"
520 | resolved "https://registry.yarnpkg.com/@parcel/runtime-service-worker/-/runtime-service-worker-2.7.0.tgz#352c3722ec635eee2898d9698541e3c1f53e8906"
521 | integrity sha512-uD2pAV0yV6+e7JaWH4KVPbG+zRCrxr/OACyS9tIh+Q/R1vRmh8zGM3yhdrcoiZ7tFOnM72vd6xY11eTrUsSVig==
522 | dependencies:
523 | "@parcel/plugin" "2.7.0"
524 | "@parcel/utils" "2.7.0"
525 | nullthrows "^1.1.1"
526 |
527 | "@parcel/source-map@^2.0.0":
528 | version "2.1.1"
529 | resolved "https://registry.yarnpkg.com/@parcel/source-map/-/source-map-2.1.1.tgz#fb193b82dba6dd62cc7a76b326f57bb35000a782"
530 | integrity sha512-Ejx1P/mj+kMjQb8/y5XxDUn4reGdr+WyKYloBljpppUy8gs42T+BNoEOuRYqDVdgPc6NxduzIDoJS9pOFfV5Ew==
531 | dependencies:
532 | detect-libc "^1.0.3"
533 |
534 | "@parcel/transformer-babel@2.7.0":
535 | version "2.7.0"
536 | resolved "https://registry.yarnpkg.com/@parcel/transformer-babel/-/transformer-babel-2.7.0.tgz#eae98d50a99cd722c3146cd57c479bfb86f537b2"
537 | integrity sha512-7iklDXXnKH1530+QbI+e4kIJ+Q1puA1ulRS10db3aUJMj5GnvXGDFwhSZ7+T1ps66QHO7cVO29VlbqiRDarH1Q==
538 | dependencies:
539 | "@parcel/diagnostic" "2.7.0"
540 | "@parcel/plugin" "2.7.0"
541 | "@parcel/source-map" "^2.0.0"
542 | "@parcel/utils" "2.7.0"
543 | browserslist "^4.6.6"
544 | json5 "^2.2.0"
545 | nullthrows "^1.1.1"
546 | semver "^5.7.0"
547 |
548 | "@parcel/transformer-css@2.7.0":
549 | version "2.7.0"
550 | resolved "https://registry.yarnpkg.com/@parcel/transformer-css/-/transformer-css-2.7.0.tgz#d0879ec04191e5ba3eadb6fc06b7ec0db3f5c3f6"
551 | integrity sha512-J4EpWK9spQpXyNCmKK8Xnane0xW/1B/EAmfp7Fiv7g+5yUjY4ODf4KUugvE+Eb2gekPkhOKNHermO2KrX0/PFA==
552 | dependencies:
553 | "@parcel/css" "^1.12.2"
554 | "@parcel/diagnostic" "2.7.0"
555 | "@parcel/plugin" "2.7.0"
556 | "@parcel/source-map" "^2.0.0"
557 | "@parcel/utils" "2.7.0"
558 | browserslist "^4.6.6"
559 | nullthrows "^1.1.1"
560 |
561 | "@parcel/transformer-html@2.7.0":
562 | version "2.7.0"
563 | resolved "https://registry.yarnpkg.com/@parcel/transformer-html/-/transformer-html-2.7.0.tgz#5397a924fea683ef2c345f36f99f67f0181d6967"
564 | integrity sha512-wYJl5rn81W+Rlk9oQwDJcjoVsWVDKyeri84FzmlGXOsg0EYgnqOiG+3MDM8GeZjfuGe5fuoum4eqZeS0WdUHXw==
565 | dependencies:
566 | "@parcel/diagnostic" "2.7.0"
567 | "@parcel/hash" "2.7.0"
568 | "@parcel/plugin" "2.7.0"
569 | nullthrows "^1.1.1"
570 | posthtml "^0.16.5"
571 | posthtml-parser "^0.10.1"
572 | posthtml-render "^3.0.0"
573 | semver "^5.7.1"
574 |
575 | "@parcel/transformer-image@2.7.0":
576 | version "2.7.0"
577 | resolved "https://registry.yarnpkg.com/@parcel/transformer-image/-/transformer-image-2.7.0.tgz#e569ffc426c6060bc4dcccc0347c526930abfba4"
578 | integrity sha512-mhi9/R5/ULhCkL2COVIKhNFoLDiZwQgprdaTJr5fnODggVxEX5o7ebFV6KNLMTEkwZUJWoB1hL0ziI0++DtoFA==
579 | dependencies:
580 | "@parcel/plugin" "2.7.0"
581 | "@parcel/utils" "2.7.0"
582 | "@parcel/workers" "2.7.0"
583 | nullthrows "^1.1.1"
584 |
585 | "@parcel/transformer-js@2.7.0":
586 | version "2.7.0"
587 | resolved "https://registry.yarnpkg.com/@parcel/transformer-js/-/transformer-js-2.7.0.tgz#1e69295a11bf70d880cdd3846cf89016a74aac50"
588 | integrity sha512-mzerR+D4rDomUSIk5RSTa2w+DXBdXUeQrpDO74WCDdpDi1lIl8ppFpqtmU7O6y6p8QsgkmS9b0g/vhcry6CJTA==
589 | dependencies:
590 | "@parcel/diagnostic" "2.7.0"
591 | "@parcel/plugin" "2.7.0"
592 | "@parcel/source-map" "^2.0.0"
593 | "@parcel/utils" "2.7.0"
594 | "@parcel/workers" "2.7.0"
595 | "@swc/helpers" "^0.4.2"
596 | browserslist "^4.6.6"
597 | detect-libc "^1.0.3"
598 | nullthrows "^1.1.1"
599 | regenerator-runtime "^0.13.7"
600 | semver "^5.7.1"
601 |
602 | "@parcel/transformer-json@2.7.0":
603 | version "2.7.0"
604 | resolved "https://registry.yarnpkg.com/@parcel/transformer-json/-/transformer-json-2.7.0.tgz#c203f74cd445ce93eb833dd88be8127d1eadc6c3"
605 | integrity sha512-RQjuxBpYOch+kr4a0zi77KJtOLTPYRM7iq4NN80zKnA0r0dwDUCxZBtaj2l0O0o3R4MMJnm+ncP+cB7XR7dZYA==
606 | dependencies:
607 | "@parcel/plugin" "2.7.0"
608 | json5 "^2.2.0"
609 |
610 | "@parcel/transformer-postcss@2.7.0":
611 | version "2.7.0"
612 | resolved "https://registry.yarnpkg.com/@parcel/transformer-postcss/-/transformer-postcss-2.7.0.tgz#66be4469ae9186c89638ff67ec5808139caaeb8e"
613 | integrity sha512-b6RskXBWf0MjpC9qjR2dQ1ZdRnlOiKYseG5CEovWCqM218RtdydFKz7jS+5Gxkb6qBtOG7zGPONXdPe+gTILcA==
614 | dependencies:
615 | "@parcel/diagnostic" "2.7.0"
616 | "@parcel/hash" "2.7.0"
617 | "@parcel/plugin" "2.7.0"
618 | "@parcel/utils" "2.7.0"
619 | clone "^2.1.1"
620 | nullthrows "^1.1.1"
621 | postcss-value-parser "^4.2.0"
622 | semver "^5.7.1"
623 |
624 | "@parcel/transformer-posthtml@2.7.0":
625 | version "2.7.0"
626 | resolved "https://registry.yarnpkg.com/@parcel/transformer-posthtml/-/transformer-posthtml-2.7.0.tgz#67d5761b895574edb771f7ab1b24ec80775f58bd"
627 | integrity sha512-cP8YOiSynWJ1ycmBlhnnHeuQb2cwmklZ+BNyLUktj5p78kDy2de7VjX+dRNRHoW4H9OgEcSF4UEfDVVz5RYIhw==
628 | dependencies:
629 | "@parcel/plugin" "2.7.0"
630 | "@parcel/utils" "2.7.0"
631 | nullthrows "^1.1.1"
632 | posthtml "^0.16.5"
633 | posthtml-parser "^0.10.1"
634 | posthtml-render "^3.0.0"
635 | semver "^5.7.1"
636 |
637 | "@parcel/transformer-raw@2.7.0":
638 | version "2.7.0"
639 | resolved "https://registry.yarnpkg.com/@parcel/transformer-raw/-/transformer-raw-2.7.0.tgz#d6d8b94d1b33efc3dbf748ec1954c8917a2e1566"
640 | integrity sha512-sDnItWCFSDez0izK1i5cgv+kXzZTbcJh4rNpVIgmE1kBLvAz608sqgcCkavb2wVJIvLesxYM+5G4p1CwkDlZ1g==
641 | dependencies:
642 | "@parcel/plugin" "2.7.0"
643 |
644 | "@parcel/transformer-react-refresh-wrap@2.7.0":
645 | version "2.7.0"
646 | resolved "https://registry.yarnpkg.com/@parcel/transformer-react-refresh-wrap/-/transformer-react-refresh-wrap-2.7.0.tgz#e206b529d4a3444e14ba329d3323c5be3ded25d2"
647 | integrity sha512-1vRmIJzyBA1nIiXTAU6tZExq2FvJj/2F0ft6KDw8GYPv0KjmdiPo/PmaZ7JeSVOM6SdXQIQCbTmp1vkMP7DtkA==
648 | dependencies:
649 | "@parcel/plugin" "2.7.0"
650 | "@parcel/utils" "2.7.0"
651 | react-refresh "^0.9.0"
652 |
653 | "@parcel/transformer-sass@2.7.0":
654 | version "2.7.0"
655 | resolved "https://registry.yarnpkg.com/@parcel/transformer-sass/-/transformer-sass-2.7.0.tgz#651b7a88bbc1ef452ace90ccb0883c1ad8cff721"
656 | integrity sha512-6m2T6Y5eQLX7ckIeuOjXXIZbzhyovnl69AvJ2FujoWb2nA55H/kg6ZdbKjo3CfXkOfg9LyG3nVnOE5PMgMpRFQ==
657 | dependencies:
658 | "@parcel/plugin" "2.7.0"
659 | "@parcel/source-map" "^2.0.0"
660 | sass "^1.38.0"
661 |
662 | "@parcel/transformer-svg@2.7.0":
663 | version "2.7.0"
664 | resolved "https://registry.yarnpkg.com/@parcel/transformer-svg/-/transformer-svg-2.7.0.tgz#c2a7d10bdbc6aeb2ae7ef85db5b583574807071c"
665 | integrity sha512-ioER37zceuuE+K6ZrnjCyMUWEnv+63hIAFResc1OXxRhyt+7kzMz9ZqK0Mt6QMLwl1dxhkLmrU41n9IxzKZuSQ==
666 | dependencies:
667 | "@parcel/diagnostic" "2.7.0"
668 | "@parcel/hash" "2.7.0"
669 | "@parcel/plugin" "2.7.0"
670 | nullthrows "^1.1.1"
671 | posthtml "^0.16.5"
672 | posthtml-parser "^0.10.1"
673 | posthtml-render "^3.0.0"
674 | semver "^5.7.1"
675 |
676 | "@parcel/types@2.7.0":
677 | version "2.7.0"
678 | resolved "https://registry.yarnpkg.com/@parcel/types/-/types-2.7.0.tgz#c89e95964339324c1931ef7a17906a72291d6b73"
679 | integrity sha512-+dhXVUnseTCpJvBTGMp0V6X13z6O/A/+CUtwEpMGZ8XSmZ4Gk44GvaTiBOp0bJpWG4fvCKp+UmC8PYbrDiiziw==
680 | dependencies:
681 | "@parcel/cache" "2.7.0"
682 | "@parcel/diagnostic" "2.7.0"
683 | "@parcel/fs" "2.7.0"
684 | "@parcel/package-manager" "2.7.0"
685 | "@parcel/source-map" "^2.0.0"
686 | "@parcel/workers" "2.7.0"
687 | utility-types "^3.10.0"
688 |
689 | "@parcel/utils@2.7.0":
690 | version "2.7.0"
691 | resolved "https://registry.yarnpkg.com/@parcel/utils/-/utils-2.7.0.tgz#f795d0f43efdd449ab0bbfac3632cd7f3ec0e4dd"
692 | integrity sha512-jNZ5bIGg1r1RDRKi562o4kuVwnz+XJ2Ie3b0Zwrqwvgfj6AbRFIKzDd+h85dWWmcDYzKUbHp11u6VJl1u8Vapg==
693 | dependencies:
694 | "@parcel/codeframe" "2.7.0"
695 | "@parcel/diagnostic" "2.7.0"
696 | "@parcel/hash" "2.7.0"
697 | "@parcel/logger" "2.7.0"
698 | "@parcel/markdown-ansi" "2.7.0"
699 | "@parcel/source-map" "^2.0.0"
700 | chalk "^4.1.0"
701 |
702 | "@parcel/watcher@^2.0.0":
703 | version "2.0.6"
704 | resolved "https://registry.yarnpkg.com/@parcel/watcher/-/watcher-2.0.6.tgz#9087e44ea93b2d7e901d479bb9b0578f25b2173a"
705 | integrity sha512-6CaHXp6BNrFY5375OGQLSeaxfO8csgGWbO1U2nUqufDtUks7ZIG5wAyj/wR1zkOxRrhN0EaZWvlgSKYqo7a9lg==
706 | dependencies:
707 | node-addon-api "^3.2.1"
708 | node-gyp-build "^4.3.0"
709 |
710 | "@parcel/workers@2.7.0":
711 | version "2.7.0"
712 | resolved "https://registry.yarnpkg.com/@parcel/workers/-/workers-2.7.0.tgz#d74955d361337127227912a5ab26cb3079ebfc78"
713 | integrity sha512-99VfaOX+89+RaoTSyH9ZQtkMBFZBFMvJmVJ/GeJT6QCd2wtKBStTHlaSnQOkLD/iRjJCNwV2xpZmm8YkTwV+hg==
714 | dependencies:
715 | "@parcel/diagnostic" "2.7.0"
716 | "@parcel/logger" "2.7.0"
717 | "@parcel/types" "2.7.0"
718 | "@parcel/utils" "2.7.0"
719 | chrome-trace-event "^1.0.2"
720 | nullthrows "^1.1.1"
721 |
722 | "@swc/helpers@^0.4.2":
723 | version "0.4.12"
724 | resolved "https://registry.yarnpkg.com/@swc/helpers/-/helpers-0.4.12.tgz#203243e78cff3c87c081c97ae548ab33e2503573"
725 | integrity sha512-R6RmwS9Dld5lNvwKlPn62+piU+WDG1sMfsnfJioXCciyko/gZ0DQ4Mqglhq1iGU1nQ/RcGkAwfMH+elMSkJH3Q==
726 | dependencies:
727 | tslib "^2.4.0"
728 |
729 | "@trysound/sax@0.2.0":
730 | version "0.2.0"
731 | resolved "https://registry.yarnpkg.com/@trysound/sax/-/sax-0.2.0.tgz#cccaab758af56761eb7bf37af6f03f326dd798ad"
732 | integrity sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==
733 |
734 | "@types/parse-json@^4.0.0":
735 | version "4.0.0"
736 | resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0"
737 | integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==
738 |
739 | "@types/prop-types@*":
740 | version "15.7.3"
741 | resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.3.tgz#2ab0d5da2e5815f94b0b9d4b95d1e5f243ab2ca7"
742 | integrity sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw==
743 |
744 | "@types/react-dom@^18.0.8":
745 | version "18.0.8"
746 | resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.0.8.tgz#d2606d855186cd42cc1b11e63a71c39525441685"
747 | integrity sha512-C3GYO0HLaOkk9dDAz3Dl4sbe4AKUGTCfFIZsz3n/82dPNN8Du533HzKatDxeUYWu24wJgMP1xICqkWk1YOLOIw==
748 | dependencies:
749 | "@types/react" "*"
750 |
751 | "@types/react@*":
752 | version "16.9.51"
753 | resolved "https://registry.yarnpkg.com/@types/react/-/react-16.9.51.tgz#f8aa51ffa9996f1387f63686696d9b59713d2b60"
754 | integrity sha512-lQa12IyO+DMlnSZ3+AGHRUiUcpK47aakMMoBG8f7HGxJT8Yfe+WE128HIXaHOHVPReAW0oDS3KAI0JI2DDe1PQ==
755 | dependencies:
756 | "@types/prop-types" "*"
757 | csstype "^3.0.2"
758 |
759 | "@types/react@^18.0.24":
760 | version "18.0.24"
761 | resolved "https://registry.yarnpkg.com/@types/react/-/react-18.0.24.tgz#2f79ed5b27f08d05107aab45c17919754cc44c20"
762 | integrity sha512-wRJWT6ouziGUy+9uX0aW4YOJxAY0bG6/AOk5AW5QSvZqI7dk6VBIbXvcVgIw/W5Jrl24f77df98GEKTJGOLx7Q==
763 | dependencies:
764 | "@types/prop-types" "*"
765 | "@types/scheduler" "*"
766 | csstype "^3.0.2"
767 |
768 | "@types/scheduler@*":
769 | version "0.16.2"
770 | resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.2.tgz#1a62f89525723dde24ba1b01b092bf5df8ad4d39"
771 | integrity sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==
772 |
773 | abortcontroller-polyfill@^1.1.9:
774 | version "1.7.5"
775 | resolved "https://registry.yarnpkg.com/abortcontroller-polyfill/-/abortcontroller-polyfill-1.7.5.tgz#6738495f4e901fbb57b6c0611d0c75f76c485bed"
776 | integrity sha512-JMJ5soJWP18htbbxJjG7bG6yuI6pRhgJ0scHHTfkUjf6wjP912xZWvM+A4sJK3gqd9E8fcPbDnOefbA9Th/FIQ==
777 |
778 | acorn@^8.5.0:
779 | version "8.8.1"
780 | resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.1.tgz#0a3f9cbecc4ec3bea6f0a80b66ae8dd2da250b73"
781 | integrity sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==
782 |
783 | ansi-styles@^3.2.1:
784 | version "3.2.1"
785 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
786 | integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==
787 | dependencies:
788 | color-convert "^1.9.0"
789 |
790 | ansi-styles@^4.1.0:
791 | version "4.3.0"
792 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937"
793 | integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==
794 | dependencies:
795 | color-convert "^2.0.1"
796 |
797 | anymatch@~3.1.2:
798 | version "3.1.2"
799 | resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716"
800 | integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==
801 | dependencies:
802 | normalize-path "^3.0.0"
803 | picomatch "^2.0.4"
804 |
805 | asap@~2.0.6:
806 | version "2.0.6"
807 | resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46"
808 | integrity sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=
809 |
810 | base-x@^3.0.8:
811 | version "3.0.9"
812 | resolved "https://registry.yarnpkg.com/base-x/-/base-x-3.0.9.tgz#6349aaabb58526332de9f60995e548a53fe21320"
813 | integrity sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ==
814 | dependencies:
815 | safe-buffer "^5.0.1"
816 |
817 | binary-extensions@^2.0.0:
818 | version "2.2.0"
819 | resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d"
820 | integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==
821 |
822 | boolbase@^1.0.0:
823 | version "1.0.0"
824 | resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e"
825 | integrity sha1-aN/1++YMUes3cl6p4+0xDcwed24=
826 |
827 | braces@~3.0.2:
828 | version "3.0.2"
829 | resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107"
830 | integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==
831 | dependencies:
832 | fill-range "^7.0.1"
833 |
834 | browserslist@^4.6.6:
835 | version "4.21.4"
836 | resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.4.tgz#e7496bbc67b9e39dd0f98565feccdcb0d4ff6987"
837 | integrity sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==
838 | dependencies:
839 | caniuse-lite "^1.0.30001400"
840 | electron-to-chromium "^1.4.251"
841 | node-releases "^2.0.6"
842 | update-browserslist-db "^1.0.9"
843 |
844 | buffer-from@^1.0.0:
845 | version "1.1.1"
846 | resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef"
847 | integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==
848 |
849 | callsites@^3.0.0:
850 | version "3.1.0"
851 | resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73"
852 | integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==
853 |
854 | caniuse-lite@^1.0.30001400:
855 | version "1.0.30001429"
856 | resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001429.tgz#70cdae959096756a85713b36dd9cb82e62325639"
857 | integrity sha512-511ThLu1hF+5RRRt0zYCf2U2yRr9GPF6m5y90SBCWsvSoYoW7yAGlv/elyPaNfvGCkp6kj/KFZWU0BMA69Prsg==
858 |
859 | chalk@^2.0.0:
860 | version "2.4.2"
861 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
862 | integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
863 | dependencies:
864 | ansi-styles "^3.2.1"
865 | escape-string-regexp "^1.0.5"
866 | supports-color "^5.3.0"
867 |
868 | chalk@^4.1.0:
869 | version "4.1.2"
870 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01"
871 | integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==
872 | dependencies:
873 | ansi-styles "^4.1.0"
874 | supports-color "^7.1.0"
875 |
876 | "chokidar@>=3.0.0 <4.0.0":
877 | version "3.5.3"
878 | resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd"
879 | integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==
880 | dependencies:
881 | anymatch "~3.1.2"
882 | braces "~3.0.2"
883 | glob-parent "~5.1.2"
884 | is-binary-path "~2.1.0"
885 | is-glob "~4.0.1"
886 | normalize-path "~3.0.0"
887 | readdirp "~3.6.0"
888 | optionalDependencies:
889 | fsevents "~2.3.2"
890 |
891 | chrome-trace-event@^1.0.2:
892 | version "1.0.3"
893 | resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz#1015eced4741e15d06664a957dbbf50d041e26ac"
894 | integrity sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==
895 |
896 | clone@^2.1.1:
897 | version "2.1.2"
898 | resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f"
899 | integrity sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=
900 |
901 | color-convert@^1.9.0:
902 | version "1.9.3"
903 | resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
904 | integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==
905 | dependencies:
906 | color-name "1.1.3"
907 |
908 | color-convert@^2.0.1:
909 | version "2.0.1"
910 | resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3"
911 | integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==
912 | dependencies:
913 | color-name "~1.1.4"
914 |
915 | color-name@1.1.3:
916 | version "1.1.3"
917 | resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
918 | integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=
919 |
920 | color-name@~1.1.4:
921 | version "1.1.4"
922 | resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
923 | integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
924 |
925 | commander@^2.20.0:
926 | version "2.20.3"
927 | resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
928 | integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
929 |
930 | commander@^7.0.0, commander@^7.2.0:
931 | version "7.2.0"
932 | resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7"
933 | integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==
934 |
935 | core-js@^3.19.2:
936 | version "3.26.0"
937 | resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.26.0.tgz#a516db0ed0811be10eac5d94f3b8463d03faccfe"
938 | integrity sha512-+DkDrhoR4Y0PxDz6rurahuB+I45OsEUv8E1maPTB6OuHRohMMcznBq9TMpdpDMm/hUPob/mJJS3PqgbHpMTQgw==
939 |
940 | cosmiconfig@^7.0.1:
941 | version "7.0.1"
942 | resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.0.1.tgz#714d756522cace867867ccb4474c5d01bbae5d6d"
943 | integrity sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ==
944 | dependencies:
945 | "@types/parse-json" "^4.0.0"
946 | import-fresh "^3.2.1"
947 | parse-json "^5.0.0"
948 | path-type "^4.0.0"
949 | yaml "^1.10.0"
950 |
951 | css-select@^4.1.3:
952 | version "4.3.0"
953 | resolved "https://registry.yarnpkg.com/css-select/-/css-select-4.3.0.tgz#db7129b2846662fd8628cfc496abb2b59e41529b"
954 | integrity sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==
955 | dependencies:
956 | boolbase "^1.0.0"
957 | css-what "^6.0.1"
958 | domhandler "^4.3.1"
959 | domutils "^2.8.0"
960 | nth-check "^2.0.1"
961 |
962 | css-tree@^1.1.2, css-tree@^1.1.3:
963 | version "1.1.3"
964 | resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.1.3.tgz#eb4870fb6fd7707327ec95c2ff2ab09b5e8db91d"
965 | integrity sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==
966 | dependencies:
967 | mdn-data "2.0.14"
968 | source-map "^0.6.1"
969 |
970 | css-what@^6.0.1:
971 | version "6.1.0"
972 | resolved "https://registry.yarnpkg.com/css-what/-/css-what-6.1.0.tgz#fb5effcf76f1ddea2c81bdfaa4de44e79bac70f4"
973 | integrity sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==
974 |
975 | csso@^4.2.0:
976 | version "4.2.0"
977 | resolved "https://registry.yarnpkg.com/csso/-/csso-4.2.0.tgz#ea3a561346e8dc9f546d6febedd50187cf389529"
978 | integrity sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==
979 | dependencies:
980 | css-tree "^1.1.2"
981 |
982 | csstype@^3.0.2:
983 | version "3.0.3"
984 | resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.3.tgz#2b410bbeba38ba9633353aff34b05d9755d065f8"
985 | integrity sha512-jPl+wbWPOWJ7SXsWyqGRk3lGecbar0Cb0OvZF/r/ZU011R4YqiRehgkQ9p4eQfo9DSDLqLL3wHwfxeJiuIsNag==
986 |
987 | detect-libc@^1.0.3:
988 | version "1.0.3"
989 | resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b"
990 | integrity sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==
991 |
992 | dom-serializer@^1.0.1:
993 | version "1.4.1"
994 | resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-1.4.1.tgz#de5d41b1aea290215dc45a6dae8adcf1d32e2d30"
995 | integrity sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==
996 | dependencies:
997 | domelementtype "^2.0.1"
998 | domhandler "^4.2.0"
999 | entities "^2.0.0"
1000 |
1001 | domelementtype@^2.0.1:
1002 | version "2.0.2"
1003 | resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.0.2.tgz#f3b6e549201e46f588b59463dd77187131fe6971"
1004 | integrity sha512-wFwTwCVebUrMgGeAwRL/NhZtHAUyT9n9yg4IMDwf10+6iCMxSkVq9MGCVEH+QZWo1nNidy8kNvwmv4zWHDTqvA==
1005 |
1006 | domelementtype@^2.2.0:
1007 | version "2.3.0"
1008 | resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.3.0.tgz#5c45e8e869952626331d7aab326d01daf65d589d"
1009 | integrity sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==
1010 |
1011 | domhandler@^4.2.0, domhandler@^4.2.2, domhandler@^4.3.1:
1012 | version "4.3.1"
1013 | resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-4.3.1.tgz#8d792033416f59d68bc03a5aa7b018c1ca89279c"
1014 | integrity sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==
1015 | dependencies:
1016 | domelementtype "^2.2.0"
1017 |
1018 | domutils@^2.8.0:
1019 | version "2.8.0"
1020 | resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.8.0.tgz#4437def5db6e2d1f5d6ee859bd95ca7d02048135"
1021 | integrity sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==
1022 | dependencies:
1023 | dom-serializer "^1.0.1"
1024 | domelementtype "^2.2.0"
1025 | domhandler "^4.2.0"
1026 |
1027 | dotenv-expand@^5.1.0:
1028 | version "5.1.0"
1029 | resolved "https://registry.yarnpkg.com/dotenv-expand/-/dotenv-expand-5.1.0.tgz#3fbaf020bfd794884072ea26b1e9791d45a629f0"
1030 | integrity sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==
1031 |
1032 | dotenv@^7.0.0:
1033 | version "7.0.0"
1034 | resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-7.0.0.tgz#a2be3cd52736673206e8a85fb5210eea29628e7c"
1035 | integrity sha512-M3NhsLbV1i6HuGzBUH8vXrtxOk+tWmzWKDMbAVSUp3Zsjm7ywFeuwrUXhmhQyRK1q5B5GGy7hcXPbj3bnfZg2g==
1036 |
1037 | electron-to-chromium@^1.4.251:
1038 | version "1.4.284"
1039 | resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz#61046d1e4cab3a25238f6bf7413795270f125592"
1040 | integrity sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==
1041 |
1042 | entities@^2.0.0:
1043 | version "2.0.3"
1044 | resolved "https://registry.yarnpkg.com/entities/-/entities-2.0.3.tgz#5c487e5742ab93c15abb5da22759b8590ec03b7f"
1045 | integrity sha512-MyoZ0jgnLvB2X3Lg5HqpFmn1kybDiIfEQmKzTb5apr51Rb+T3KdmMiqa70T+bhGnyv7bQ6WMj2QMHpGMmlrUYQ==
1046 |
1047 | entities@^3.0.1:
1048 | version "3.0.1"
1049 | resolved "https://registry.yarnpkg.com/entities/-/entities-3.0.1.tgz#2b887ca62585e96db3903482d336c1006c3001d4"
1050 | integrity sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==
1051 |
1052 | error-ex@^1.3.1:
1053 | version "1.3.2"
1054 | resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf"
1055 | integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==
1056 | dependencies:
1057 | is-arrayish "^0.2.1"
1058 |
1059 | escalade@^3.1.1:
1060 | version "3.1.1"
1061 | resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40"
1062 | integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==
1063 |
1064 | escape-string-regexp@^1.0.5:
1065 | version "1.0.5"
1066 | resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
1067 | integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=
1068 |
1069 | fill-range@^7.0.1:
1070 | version "7.0.1"
1071 | resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40"
1072 | integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==
1073 | dependencies:
1074 | to-regex-range "^5.0.1"
1075 |
1076 | fsevents@~2.3.2:
1077 | version "2.3.2"
1078 | resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a"
1079 | integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==
1080 |
1081 | get-port@^4.2.0:
1082 | version "4.2.0"
1083 | resolved "https://registry.yarnpkg.com/get-port/-/get-port-4.2.0.tgz#e37368b1e863b7629c43c5a323625f95cf24b119"
1084 | integrity sha512-/b3jarXkH8KJoOMQc3uVGHASwGLPq3gSFJ7tgJm2diza+bydJPTGOibin2steecKeOylE8oY2JERlVWkAJO6yw==
1085 |
1086 | glob-parent@~5.1.2:
1087 | version "5.1.2"
1088 | resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4"
1089 | integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==
1090 | dependencies:
1091 | is-glob "^4.0.1"
1092 |
1093 | globals@^13.2.0:
1094 | version "13.17.0"
1095 | resolved "https://registry.yarnpkg.com/globals/-/globals-13.17.0.tgz#902eb1e680a41da93945adbdcb5a9f361ba69bd4"
1096 | integrity sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==
1097 | dependencies:
1098 | type-fest "^0.20.2"
1099 |
1100 | has-flag@^3.0.0:
1101 | version "3.0.0"
1102 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
1103 | integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0=
1104 |
1105 | has-flag@^4.0.0:
1106 | version "4.0.0"
1107 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b"
1108 | integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==
1109 |
1110 | htmlnano@^2.0.0:
1111 | version "2.0.2"
1112 | resolved "https://registry.yarnpkg.com/htmlnano/-/htmlnano-2.0.2.tgz#3e3170941e2446a86211196d740272ebca78f878"
1113 | integrity sha512-+ZrQFS4Ub+zd+/fWwfvoYCEGNEa0/zrpys6CyXxvZDwtL7Pl+pOtRkiujyvBQ7Lmfp7/iEPxtOFgxWA16Gkj3w==
1114 | dependencies:
1115 | cosmiconfig "^7.0.1"
1116 | posthtml "^0.16.5"
1117 | timsort "^0.3.0"
1118 |
1119 | htmlparser2@^7.1.1:
1120 | version "7.2.0"
1121 | resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-7.2.0.tgz#8817cdea38bbc324392a90b1990908e81a65f5a5"
1122 | integrity sha512-H7MImA4MS6cw7nbyURtLPO1Tms7C5H602LRETv95z1MxO/7CP7rDVROehUYeYBUYEON94NXXDEPmZuq+hX4sog==
1123 | dependencies:
1124 | domelementtype "^2.0.1"
1125 | domhandler "^4.2.2"
1126 | domutils "^2.8.0"
1127 | entities "^3.0.1"
1128 |
1129 | immutable@^4.0.0:
1130 | version "4.1.0"
1131 | resolved "https://registry.yarnpkg.com/immutable/-/immutable-4.1.0.tgz#f795787f0db780183307b9eb2091fcac1f6fafef"
1132 | integrity sha512-oNkuqVTA8jqG1Q6c+UglTOD1xhC1BtjKI7XkCXRkZHrN5m18/XsnUp8Q89GkQO/z+0WjonSvl0FLhDYftp46nQ==
1133 |
1134 | import-fresh@^3.2.1:
1135 | version "3.3.0"
1136 | resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b"
1137 | integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==
1138 | dependencies:
1139 | parent-module "^1.0.0"
1140 | resolve-from "^4.0.0"
1141 |
1142 | is-arrayish@^0.2.1:
1143 | version "0.2.1"
1144 | resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d"
1145 | integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=
1146 |
1147 | is-binary-path@~2.1.0:
1148 | version "2.1.0"
1149 | resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09"
1150 | integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==
1151 | dependencies:
1152 | binary-extensions "^2.0.0"
1153 |
1154 | is-extglob@^2.1.1:
1155 | version "2.1.1"
1156 | resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
1157 | integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==
1158 |
1159 | is-glob@^4.0.1, is-glob@~4.0.1:
1160 | version "4.0.3"
1161 | resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084"
1162 | integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==
1163 | dependencies:
1164 | is-extglob "^2.1.1"
1165 |
1166 | is-json@^2.0.1:
1167 | version "2.0.1"
1168 | resolved "https://registry.yarnpkg.com/is-json/-/is-json-2.0.1.tgz#6be166d144828a131d686891b983df62c39491ff"
1169 | integrity sha512-6BEnpVn1rcf3ngfmViLM6vjUjGErbdrL4rwlv+u1NO1XO8kqT4YGL8+19Q+Z/bas8tY90BTWMk2+fW1g6hQjbA==
1170 |
1171 | is-number@^7.0.0:
1172 | version "7.0.0"
1173 | resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b"
1174 | integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==
1175 |
1176 | js-tokens@^4.0.0:
1177 | version "4.0.0"
1178 | resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
1179 | integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
1180 |
1181 | json-parse-even-better-errors@^2.3.0:
1182 | version "2.3.1"
1183 | resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d"
1184 | integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==
1185 |
1186 | json5@^2.2.0, json5@^2.2.1:
1187 | version "2.2.1"
1188 | resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.1.tgz#655d50ed1e6f95ad1a3caababd2b0efda10b395c"
1189 | integrity sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==
1190 |
1191 | lightningcss-darwin-arm64@1.16.0:
1192 | version "1.16.0"
1193 | resolved "https://registry.yarnpkg.com/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.16.0.tgz#f3318a2e64ca160610977675ee1a7e611f4a3617"
1194 | integrity sha512-gIhz6eZFwsC4oVMjBGQ3QWDdLQY7vcXFyM/x91PilgHqu63B9uBa10EZA75YoTEkbKhoz0uDCqyHh/EoF1GrkQ==
1195 |
1196 | lightningcss-darwin-x64@1.16.0:
1197 | version "1.16.0"
1198 | resolved "https://registry.yarnpkg.com/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.16.0.tgz#46361b701b572ce9ec29730624000b439c2184bb"
1199 | integrity sha512-kLPi+OEpDj3UGY6DC8TfjbcULJDKMP+TVKSlrEkNGn8t1YRzi2g4oy7UVTSB5AnSbT0CusUItzdVjHQ49EdoNA==
1200 |
1201 | lightningcss-linux-arm-gnueabihf@1.16.0:
1202 | version "1.16.0"
1203 | resolved "https://registry.yarnpkg.com/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.16.0.tgz#5da29f465dd44d98434b00b424cc4b445ea49eff"
1204 | integrity sha512-oSwEbvXUPr//H/ainBRJXTxHerlheee/KgkTTmAQWiVnt8HV+bRohTBWWPBy5ZArgiGLwj7ogv45istgljPN2Q==
1205 |
1206 | lightningcss-linux-arm64-gnu@1.16.0:
1207 | version "1.16.0"
1208 | resolved "https://registry.yarnpkg.com/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.16.0.tgz#21d139f5201c9b8bb3972c24116a5bcbb7e2c3b5"
1209 | integrity sha512-Drq9BSVIvmV9zsDJbCZWCulMvKMQWFIlYXPCKV/iwRj+ZAJ1BRngma0cNHB6uW7Wac8Jg04CJN5IA4ELE3J+cQ==
1210 |
1211 | lightningcss-linux-arm64-musl@1.16.0:
1212 | version "1.16.0"
1213 | resolved "https://registry.yarnpkg.com/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.16.0.tgz#d06936e0570fb51d58cc18ef2fb8858aeecd1979"
1214 | integrity sha512-1QXWStnTEo4RFQf0mfGhRyNUeEHilCZ0NA97XgwKwrYr/M7sYKU/1HWY00dPxFJ6GITR2pfJGo9xi3ScSSBxbA==
1215 |
1216 | lightningcss-linux-x64-gnu@1.16.0:
1217 | version "1.16.0"
1218 | resolved "https://registry.yarnpkg.com/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.16.0.tgz#fd9881cd839cac4676a01b713b06b0b178743f87"
1219 | integrity sha512-gD2eQYD5OFs1p83R0TcMCEc5HRyJES4lR4THmclv7khm3dc9vc+2VT0kFBPxO1L2AwlZuvXaaMan7X1Ul7uSfA==
1220 |
1221 | lightningcss-linux-x64-musl@1.16.0:
1222 | version "1.16.0"
1223 | resolved "https://registry.yarnpkg.com/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.16.0.tgz#697d87448e0f6445b6fc3cf8529d89709f3bfacc"
1224 | integrity sha512-HJsKeYxloEvg2WCQhtYPqzZUliLu9JBJNeI5y9cPQeDR/7ayGGLbVhJaotPtzJkElOFL/SaXsS+FRuH4w+yafg==
1225 |
1226 | lightningcss-win32-x64-msvc@1.16.0:
1227 | version "1.16.0"
1228 | resolved "https://registry.yarnpkg.com/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.16.0.tgz#e4a09c12a48534121ecd03ef0be8dadbbbbb63b6"
1229 | integrity sha512-h4ayyAlOMLUHV9NdofcIu79aEjmly93adVxcg5wDJpkvMiwDTufEN30M8G4gGcjo1JE5jFjAcyQcRpXYkYcemA==
1230 |
1231 | lightningcss@^1.14.0:
1232 | version "1.16.0"
1233 | resolved "https://registry.yarnpkg.com/lightningcss/-/lightningcss-1.16.0.tgz#4c8e4ef8133d54488d1482a115d3758259191c52"
1234 | integrity sha512-5+ZS9h+xeADcJTF2oRCT3yNZBlDYyOgQSdrWNBCqsIwm8ucKbF061OBVv/WHP4Zk8FToNhwFklk/hMuOngqsIg==
1235 | dependencies:
1236 | detect-libc "^1.0.3"
1237 | optionalDependencies:
1238 | lightningcss-darwin-arm64 "1.16.0"
1239 | lightningcss-darwin-x64 "1.16.0"
1240 | lightningcss-linux-arm-gnueabihf "1.16.0"
1241 | lightningcss-linux-arm64-gnu "1.16.0"
1242 | lightningcss-linux-arm64-musl "1.16.0"
1243 | lightningcss-linux-x64-gnu "1.16.0"
1244 | lightningcss-linux-x64-musl "1.16.0"
1245 | lightningcss-win32-x64-msvc "1.16.0"
1246 |
1247 | lines-and-columns@^1.1.6:
1248 | version "1.2.4"
1249 | resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632"
1250 | integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==
1251 |
1252 | lmdb@2.5.2:
1253 | version "2.5.2"
1254 | resolved "https://registry.yarnpkg.com/lmdb/-/lmdb-2.5.2.tgz#37e28a9fb43405f4dc48c44cec0e13a14c4a6ff1"
1255 | integrity sha512-V5V5Xa2Hp9i2XsbDALkBTeHXnBXh/lEmk9p22zdr7jtuOIY9TGhjK6vAvTpOOx9IKU4hJkRWZxn/HsvR1ELLtA==
1256 | dependencies:
1257 | msgpackr "^1.5.4"
1258 | node-addon-api "^4.3.0"
1259 | node-gyp-build-optional-packages "5.0.3"
1260 | ordered-binary "^1.2.4"
1261 | weak-lru-cache "^1.2.2"
1262 | optionalDependencies:
1263 | "@lmdb/lmdb-darwin-arm64" "2.5.2"
1264 | "@lmdb/lmdb-darwin-x64" "2.5.2"
1265 | "@lmdb/lmdb-linux-arm" "2.5.2"
1266 | "@lmdb/lmdb-linux-arm64" "2.5.2"
1267 | "@lmdb/lmdb-linux-x64" "2.5.2"
1268 | "@lmdb/lmdb-win32-x64" "2.5.2"
1269 |
1270 | mdn-data@2.0.14:
1271 | version "2.0.14"
1272 | resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.14.tgz#7113fc4281917d63ce29b43446f701e68c25ba50"
1273 | integrity sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==
1274 |
1275 | msgpackr-extract@^2.1.2:
1276 | version "2.1.2"
1277 | resolved "https://registry.yarnpkg.com/msgpackr-extract/-/msgpackr-extract-2.1.2.tgz#56272030f3e163e1b51964ef8b1cd5e7240c03ed"
1278 | integrity sha512-cmrmERQFb19NX2JABOGtrKdHMyI6RUyceaPBQ2iRz9GnDkjBWFjNJC0jyyoOfZl2U/LZE3tQCCQc4dlRyA8mcA==
1279 | dependencies:
1280 | node-gyp-build-optional-packages "5.0.3"
1281 | optionalDependencies:
1282 | "@msgpackr-extract/msgpackr-extract-darwin-arm64" "2.1.2"
1283 | "@msgpackr-extract/msgpackr-extract-darwin-x64" "2.1.2"
1284 | "@msgpackr-extract/msgpackr-extract-linux-arm" "2.1.2"
1285 | "@msgpackr-extract/msgpackr-extract-linux-arm64" "2.1.2"
1286 | "@msgpackr-extract/msgpackr-extract-linux-x64" "2.1.2"
1287 | "@msgpackr-extract/msgpackr-extract-win32-x64" "2.1.2"
1288 |
1289 | msgpackr@^1.5.4:
1290 | version "1.7.2"
1291 | resolved "https://registry.yarnpkg.com/msgpackr/-/msgpackr-1.7.2.tgz#68d6debf5999d6b61abb6e7046a689991ebf7261"
1292 | integrity sha512-mWScyHTtG6TjivXX9vfIy2nBtRupaiAj0HQ2mtmpmYujAmqZmaaEVPaSZ1NKLMvicaMLFzEaMk0ManxMRg8rMQ==
1293 | optionalDependencies:
1294 | msgpackr-extract "^2.1.2"
1295 |
1296 | node-addon-api@^3.2.1:
1297 | version "3.2.1"
1298 | resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-3.2.1.tgz#81325e0a2117789c0128dab65e7e38f07ceba161"
1299 | integrity sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==
1300 |
1301 | node-addon-api@^4.3.0:
1302 | version "4.3.0"
1303 | resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-4.3.0.tgz#52a1a0b475193e0928e98e0426a0d1254782b77f"
1304 | integrity sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==
1305 |
1306 | node-gyp-build-optional-packages@5.0.3:
1307 | version "5.0.3"
1308 | resolved "https://registry.yarnpkg.com/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.0.3.tgz#92a89d400352c44ad3975010368072b41ad66c17"
1309 | integrity sha512-k75jcVzk5wnnc/FMxsf4udAoTEUv2jY3ycfdSd3yWu6Cnd1oee6/CfZJApyscA4FJOmdoixWwiwOyf16RzD5JA==
1310 |
1311 | node-gyp-build@^4.3.0:
1312 | version "4.5.0"
1313 | resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.5.0.tgz#7a64eefa0b21112f89f58379da128ac177f20e40"
1314 | integrity sha512-2iGbaQBV+ITgCz76ZEjmhUKAKVf7xfY1sRl4UiKQspfZMH2h06SyhNsnSVy50cwkFQDGLyif6m/6uFXHkOZ6rg==
1315 |
1316 | node-releases@^2.0.6:
1317 | version "2.0.6"
1318 | resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.6.tgz#8a7088c63a55e493845683ebf3c828d8c51c5503"
1319 | integrity sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==
1320 |
1321 | normalize-path@^3.0.0, normalize-path@~3.0.0:
1322 | version "3.0.0"
1323 | resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
1324 | integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==
1325 |
1326 | nth-check@^2.0.1:
1327 | version "2.1.1"
1328 | resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-2.1.1.tgz#c9eab428effce36cd6b92c924bdb000ef1f1ed1d"
1329 | integrity sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==
1330 | dependencies:
1331 | boolbase "^1.0.0"
1332 |
1333 | nullthrows@^1.1.1:
1334 | version "1.1.1"
1335 | resolved "https://registry.yarnpkg.com/nullthrows/-/nullthrows-1.1.1.tgz#7818258843856ae971eae4208ad7d7eb19a431b1"
1336 | integrity sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw==
1337 |
1338 | object-assign@^4.1.1:
1339 | version "4.1.1"
1340 | resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
1341 | integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=
1342 |
1343 | ordered-binary@^1.2.4:
1344 | version "1.4.0"
1345 | resolved "https://registry.yarnpkg.com/ordered-binary/-/ordered-binary-1.4.0.tgz#6bb53d44925f3b8afc33d1eed0fa15693b211389"
1346 | integrity sha512-EHQ/jk4/a9hLupIKxTfUsQRej1Yd/0QLQs3vGvIqg5ZtCYSzNhkzHoZc7Zf4e4kUlDaC3Uw8Q/1opOLNN2OKRQ==
1347 |
1348 | parcel@^2.7.0:
1349 | version "2.7.0"
1350 | resolved "https://registry.yarnpkg.com/parcel/-/parcel-2.7.0.tgz#41fdd3e5c7144d4cf7f1fa3ab8d0ea0d47d31f77"
1351 | integrity sha512-pRYwnivwtNP0tip8xYSo4zCB0XhLt7/gJzP1p8OovCqkmFjG9VG+GW9TcAKqMIo0ovEa9tT+/s6gY1Qy+BONGQ==
1352 | dependencies:
1353 | "@parcel/config-default" "2.7.0"
1354 | "@parcel/core" "2.7.0"
1355 | "@parcel/diagnostic" "2.7.0"
1356 | "@parcel/events" "2.7.0"
1357 | "@parcel/fs" "2.7.0"
1358 | "@parcel/logger" "2.7.0"
1359 | "@parcel/package-manager" "2.7.0"
1360 | "@parcel/reporter-cli" "2.7.0"
1361 | "@parcel/reporter-dev-server" "2.7.0"
1362 | "@parcel/utils" "2.7.0"
1363 | chalk "^4.1.0"
1364 | commander "^7.0.0"
1365 | get-port "^4.2.0"
1366 | v8-compile-cache "^2.0.0"
1367 |
1368 | parent-module@^1.0.0:
1369 | version "1.0.1"
1370 | resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2"
1371 | integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==
1372 | dependencies:
1373 | callsites "^3.0.0"
1374 |
1375 | parse-json@^5.0.0:
1376 | version "5.2.0"
1377 | resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd"
1378 | integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==
1379 | dependencies:
1380 | "@babel/code-frame" "^7.0.0"
1381 | error-ex "^1.3.1"
1382 | json-parse-even-better-errors "^2.3.0"
1383 | lines-and-columns "^1.1.6"
1384 |
1385 | path-type@^4.0.0:
1386 | version "4.0.0"
1387 | resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b"
1388 | integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==
1389 |
1390 | performance-now@^2.1.0:
1391 | version "2.1.0"
1392 | resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b"
1393 | integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=
1394 |
1395 | picocolors@^1.0.0:
1396 | version "1.0.0"
1397 | resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c"
1398 | integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==
1399 |
1400 | picomatch@^2.0.4, picomatch@^2.2.1:
1401 | version "2.3.1"
1402 | resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42"
1403 | integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
1404 |
1405 | postcss-value-parser@^4.2.0:
1406 | version "4.2.0"
1407 | resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514"
1408 | integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==
1409 |
1410 | posthtml-parser@^0.10.1:
1411 | version "0.10.2"
1412 | resolved "https://registry.yarnpkg.com/posthtml-parser/-/posthtml-parser-0.10.2.tgz#df364d7b179f2a6bf0466b56be7b98fd4e97c573"
1413 | integrity sha512-PId6zZ/2lyJi9LiKfe+i2xv57oEjJgWbsHGGANwos5AvdQp98i6AtamAl8gzSVFGfQ43Glb5D614cvZf012VKg==
1414 | dependencies:
1415 | htmlparser2 "^7.1.1"
1416 |
1417 | posthtml-parser@^0.11.0:
1418 | version "0.11.0"
1419 | resolved "https://registry.yarnpkg.com/posthtml-parser/-/posthtml-parser-0.11.0.tgz#25d1c7bf811ea83559bc4c21c189a29747a24b7a"
1420 | integrity sha512-QecJtfLekJbWVo/dMAA+OSwY79wpRmbqS5TeXvXSX+f0c6pW4/SE6inzZ2qkU7oAMCPqIDkZDvd/bQsSFUnKyw==
1421 | dependencies:
1422 | htmlparser2 "^7.1.1"
1423 |
1424 | posthtml-render@^3.0.0:
1425 | version "3.0.0"
1426 | resolved "https://registry.yarnpkg.com/posthtml-render/-/posthtml-render-3.0.0.tgz#97be44931496f495b4f07b99e903cc70ad6a3205"
1427 | integrity sha512-z+16RoxK3fUPgwaIgH9NGnK1HKY9XIDpydky5eQGgAFVXTCSezalv9U2jQuNV+Z9qV1fDWNzldcw4eK0SSbqKA==
1428 | dependencies:
1429 | is-json "^2.0.1"
1430 |
1431 | posthtml@^0.16.4, posthtml@^0.16.5:
1432 | version "0.16.6"
1433 | resolved "https://registry.yarnpkg.com/posthtml/-/posthtml-0.16.6.tgz#e2fc407f67a64d2fa3567afe770409ffdadafe59"
1434 | integrity sha512-JcEmHlyLK/o0uGAlj65vgg+7LIms0xKXe60lcDOTU7oVX/3LuEuLwrQpW3VJ7de5TaFKiW4kWkaIpJL42FEgxQ==
1435 | dependencies:
1436 | posthtml-parser "^0.11.0"
1437 | posthtml-render "^3.0.0"
1438 |
1439 | promise@^8.1.0:
1440 | version "8.3.0"
1441 | resolved "https://registry.yarnpkg.com/promise/-/promise-8.3.0.tgz#8cb333d1edeb61ef23869fbb8a4ea0279ab60e0a"
1442 | integrity sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg==
1443 | dependencies:
1444 | asap "~2.0.6"
1445 |
1446 | raf@^3.4.1:
1447 | version "3.4.1"
1448 | resolved "https://registry.yarnpkg.com/raf/-/raf-3.4.1.tgz#0742e99a4a6552f445d73e3ee0328af0ff1ede39"
1449 | integrity sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==
1450 | dependencies:
1451 | performance-now "^2.1.0"
1452 |
1453 | react-app-polyfill@^3.0.0:
1454 | version "3.0.0"
1455 | resolved "https://registry.yarnpkg.com/react-app-polyfill/-/react-app-polyfill-3.0.0.tgz#95221e0a9bd259e5ca6b177c7bb1cb6768f68fd7"
1456 | integrity sha512-sZ41cxiU5llIB003yxxQBYrARBqe0repqPTTYBTmMqTz9szeBbE37BehCE891NZsmdZqqP+xWKdT3eo3vOzN8w==
1457 | dependencies:
1458 | core-js "^3.19.2"
1459 | object-assign "^4.1.1"
1460 | promise "^8.1.0"
1461 | raf "^3.4.1"
1462 | regenerator-runtime "^0.13.9"
1463 | whatwg-fetch "^3.6.2"
1464 |
1465 | react-error-overlay@6.0.9:
1466 | version "6.0.9"
1467 | resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.9.tgz#3c743010c9359608c375ecd6bc76f35d93995b0a"
1468 | integrity sha512-nQTTcUu+ATDbrSD1BZHr5kgSD4oF8OFjxun8uAaL8RwPBacGBNPf/yAuVVdx17N8XNzRDMrZ9XcKZHCjPW+9ew==
1469 |
1470 | react-refresh@^0.9.0:
1471 | version "0.9.0"
1472 | resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.9.0.tgz#71863337adc3e5c2f8a6bfddd12ae3bfe32aafbf"
1473 | integrity sha512-Gvzk7OZpiqKSkxsQvO/mbTN1poglhmAV7gR/DdIrRrSMXraRQQlfikRJOr3Nb9GTMPC5kof948Zy6jJZIFtDvQ==
1474 |
1475 | readdirp@~3.6.0:
1476 | version "3.6.0"
1477 | resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7"
1478 | integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==
1479 | dependencies:
1480 | picomatch "^2.2.1"
1481 |
1482 | regenerator-runtime@^0.13.7, regenerator-runtime@^0.13.9:
1483 | version "0.13.10"
1484 | resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.10.tgz#ed07b19616bcbec5da6274ebc75ae95634bfc2ee"
1485 | integrity sha512-KepLsg4dU12hryUO7bp/axHAKvwGOCV0sGloQtpagJ12ai+ojVDqkeGSiRX1zlq+kjIMZ1t7gpze+26QqtdGqw==
1486 |
1487 | resolve-from@^4.0.0:
1488 | version "4.0.0"
1489 | resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6"
1490 | integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==
1491 |
1492 | safe-buffer@^5.0.1:
1493 | version "5.2.1"
1494 | resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
1495 | integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
1496 |
1497 | sass@^1.38.0:
1498 | version "1.55.0"
1499 | resolved "https://registry.yarnpkg.com/sass/-/sass-1.55.0.tgz#0c4d3c293cfe8f8a2e8d3b666e1cf1bff8065d1c"
1500 | integrity sha512-Pk+PMy7OGLs9WaxZGJMn7S96dvlyVBwwtToX895WmCpAOr5YiJYEUJfiJidMuKb613z2xNWcXCHEuOvjZbqC6A==
1501 | dependencies:
1502 | chokidar ">=3.0.0 <4.0.0"
1503 | immutable "^4.0.0"
1504 | source-map-js ">=0.6.2 <2.0.0"
1505 |
1506 | semver@^5.7.0, semver@^5.7.1:
1507 | version "5.7.1"
1508 | resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
1509 | integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
1510 |
1511 | "source-map-js@>=0.6.2 <2.0.0":
1512 | version "1.0.2"
1513 | resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c"
1514 | integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==
1515 |
1516 | source-map-support@~0.5.20:
1517 | version "0.5.21"
1518 | resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f"
1519 | integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==
1520 | dependencies:
1521 | buffer-from "^1.0.0"
1522 | source-map "^0.6.0"
1523 |
1524 | source-map@^0.6.0, source-map@^0.6.1:
1525 | version "0.6.1"
1526 | resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
1527 | integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
1528 |
1529 | stable@^0.1.8:
1530 | version "0.1.8"
1531 | resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf"
1532 | integrity sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==
1533 |
1534 | supports-color@^5.3.0:
1535 | version "5.5.0"
1536 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
1537 | integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==
1538 | dependencies:
1539 | has-flag "^3.0.0"
1540 |
1541 | supports-color@^7.1.0:
1542 | version "7.2.0"
1543 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da"
1544 | integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==
1545 | dependencies:
1546 | has-flag "^4.0.0"
1547 |
1548 | svgo@^2.4.0:
1549 | version "2.8.0"
1550 | resolved "https://registry.yarnpkg.com/svgo/-/svgo-2.8.0.tgz#4ff80cce6710dc2795f0c7c74101e6764cfccd24"
1551 | integrity sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg==
1552 | dependencies:
1553 | "@trysound/sax" "0.2.0"
1554 | commander "^7.2.0"
1555 | css-select "^4.1.3"
1556 | css-tree "^1.1.3"
1557 | csso "^4.2.0"
1558 | picocolors "^1.0.0"
1559 | stable "^0.1.8"
1560 |
1561 | term-size@^2.2.1:
1562 | version "2.2.1"
1563 | resolved "https://registry.yarnpkg.com/term-size/-/term-size-2.2.1.tgz#2a6a54840432c2fb6320fea0f415531e90189f54"
1564 | integrity sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==
1565 |
1566 | terser@^5.2.0:
1567 | version "5.15.1"
1568 | resolved "https://registry.yarnpkg.com/terser/-/terser-5.15.1.tgz#8561af6e0fd6d839669c73b92bdd5777d870ed6c"
1569 | integrity sha512-K1faMUvpm/FBxjBXud0LWVAGxmvoPbZbfTCYbSgaaYQaIXI3/TdI7a7ZGA73Zrou6Q8Zmz3oeUTsp/dj+ag2Xw==
1570 | dependencies:
1571 | "@jridgewell/source-map" "^0.3.2"
1572 | acorn "^8.5.0"
1573 | commander "^2.20.0"
1574 | source-map-support "~0.5.20"
1575 |
1576 | timsort@^0.3.0:
1577 | version "0.3.0"
1578 | resolved "https://registry.yarnpkg.com/timsort/-/timsort-0.3.0.tgz#405411a8e7e6339fe64db9a234de11dc31e02bd4"
1579 | integrity sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=
1580 |
1581 | to-regex-range@^5.0.1:
1582 | version "5.0.1"
1583 | resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4"
1584 | integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==
1585 | dependencies:
1586 | is-number "^7.0.0"
1587 |
1588 | tslib@^2.4.0:
1589 | version "2.4.1"
1590 | resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.1.tgz#0d0bfbaac2880b91e22df0768e55be9753a5b17e"
1591 | integrity sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==
1592 |
1593 | type-fest@^0.20.2:
1594 | version "0.20.2"
1595 | resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4"
1596 | integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==
1597 |
1598 | typescript@^4.8.4:
1599 | version "4.8.4"
1600 | resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.8.4.tgz#c464abca159669597be5f96b8943500b238e60e6"
1601 | integrity sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==
1602 |
1603 | update-browserslist-db@^1.0.9:
1604 | version "1.0.10"
1605 | resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz#0f54b876545726f17d00cd9a2561e6dade943ff3"
1606 | integrity sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==
1607 | dependencies:
1608 | escalade "^3.1.1"
1609 | picocolors "^1.0.0"
1610 |
1611 | utility-types@^3.10.0:
1612 | version "3.10.0"
1613 | resolved "https://registry.yarnpkg.com/utility-types/-/utility-types-3.10.0.tgz#ea4148f9a741015f05ed74fd615e1d20e6bed82b"
1614 | integrity sha512-O11mqxmi7wMKCo6HKFt5AhO4BwY3VV68YU07tgxfz8zJTIxr4BpsezN49Ffwy9j3ZpwwJp4fkRwjRzq3uWE6Rg==
1615 |
1616 | v8-compile-cache@^2.0.0:
1617 | version "2.1.1"
1618 | resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.1.1.tgz#54bc3cdd43317bca91e35dcaf305b1a7237de745"
1619 | integrity sha512-8OQ9CL+VWyt3JStj7HX7/ciTL2V3Rl1Wf5OL+SNTm0yK1KvtReVulksyeRnCANHHuUxHlQig+JJDlUhBt1NQDQ==
1620 |
1621 | weak-lru-cache@^1.2.2:
1622 | version "1.2.2"
1623 | resolved "https://registry.yarnpkg.com/weak-lru-cache/-/weak-lru-cache-1.2.2.tgz#fdbb6741f36bae9540d12f480ce8254060dccd19"
1624 | integrity sha512-DEAoo25RfSYMuTGc9vPJzZcZullwIqRDSI9LOy+fkCJPi6hykCnfKaXTuPBDuXAUcqHXyOgFtHNp/kB2FjYHbw==
1625 |
1626 | whatwg-fetch@^3.6.2:
1627 | version "3.6.2"
1628 | resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.6.2.tgz#dced24f37f2624ed0281725d51d0e2e3fe677f8c"
1629 | integrity sha512-bJlen0FcuU/0EMLrdbJ7zOnW6ITZLrZMIarMUVmdKtsGvZna8vxKYaexICWPfZ8qwf9fzNq+UEIZrnSaApt6RA==
1630 |
1631 | xxhash-wasm@^0.4.2:
1632 | version "0.4.2"
1633 | resolved "https://registry.yarnpkg.com/xxhash-wasm/-/xxhash-wasm-0.4.2.tgz#752398c131a4dd407b5132ba62ad372029be6f79"
1634 | integrity sha512-/eyHVRJQCirEkSZ1agRSCwriMhwlyUcFkXD5TPVSLP+IPzjsqMVzZwdoczLp1SoQU0R3dxz1RpIK+4YNQbCVOA==
1635 |
1636 | yaml@^1.10.0:
1637 | version "1.10.2"
1638 | resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b"
1639 | integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==
1640 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "6.0.0",
3 | "license": "MIT",
4 | "main": "dist/index.js",
5 | "module": "dist/index.mjs",
6 | "types": "dist/index.d.ts",
7 | "exports": {
8 | "./package.json": "./package.json",
9 | ".": {
10 | "types": "./dist/index.d.ts",
11 | "import": "./dist/index.mjs",
12 | "require": "./dist/index.js"
13 | },
14 | "./scss/": "./scss/",
15 | "./inject-style": {
16 | "types": "./dist/inject-style.d.ts",
17 | "require": "./dist/inject-style.js",
18 | "import": "./dist/inject-style.esm.mjs"
19 | },
20 | "./dist/ReactContexify.css": "./dist/ReactContexify.min.css",
21 | "./dist/ReactContexify.css.map": "./dist/ReactContexify.css.map",
22 | "./ReactContexify.css": "./dist/ReactContexify.min.css",
23 | "./ReactContexify.css.map": "./dist/ReactContexify.css.map"
24 | },
25 | "files": [
26 | "dist",
27 | "scss"
28 | ],
29 | "scripts": {
30 | "start": "cd example && yarn start",
31 | "build": "tsup && yarn run build:style",
32 | "test": "cypress run",
33 | "cypress:open": "cypress open",
34 | "sass": "sass scss/main.scss dist/ReactContexify.css",
35 | "postsass": "postcss dist/ReactContexify.css --use autoprefixer -m -o dist/ReactContexify.css",
36 | "build:style": "yarn run sass && cssnano dist/ReactContexify.css dist/ReactContexify.min.css --no-zindex --no-reduceIdents && yarn run style2js",
37 | "style2js": "style2js --out-dir dist dist/ReactContexify.min.css"
38 | },
39 | "peerDependencies": {
40 | "react": ">=16",
41 | "react-dom": ">=16"
42 | },
43 | "prettier": {
44 | "printWidth": 80,
45 | "semi": true,
46 | "singleQuote": true,
47 | "trailingComma": "es5"
48 | },
49 | "name": "react-contexify",
50 | "author": "Fadi Khadra (https://github.com/fkhadra)",
51 | "repository": {
52 | "type": "git",
53 | "url": "git+https://github.com/fkhadra/react-contexify.git"
54 | },
55 | "bugs": {
56 | "url": "https://github.com/fkhadra/react-contexify/issues"
57 | },
58 | "description": "Add contextmenu to your react component with ease",
59 | "keywords": [
60 | "react",
61 | "context menu",
62 | "react-component",
63 | "menu",
64 | "react-contextmenu",
65 | "react-contexify",
66 | "popup"
67 | ],
68 | "devDependencies": {
69 | "@types/react": "^18.0.25",
70 | "@types/react-dom": "^18.0.8",
71 | "cssnano": "^5.1.14",
72 | "cssnano-cli": "^1.0.5",
73 | "cypress": "^11.0.1",
74 | "postcss": "^8.4.18",
75 | "postcss-cli": "^10.0.0",
76 | "react": "^18.2.0",
77 | "react-dom": "^18.2.0",
78 | "sass": "^1.56.1",
79 | "style2js": "^1.0.1",
80 | "tsup": "^6.4.0",
81 | "typescript": "^4.8.4"
82 | },
83 | "dependencies": {
84 | "clsx": "^1.2.1"
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/scss/_menu.scss:
--------------------------------------------------------------------------------
1 | :root{
2 | --contexify-zIndex: 666;
3 | --contexify-menu-minWidth: 220px;
4 | --contexify-menu-padding: 6px;
5 | --contexify-menu-radius: 6px;
6 | --contexify-menu-bgColor: #fff;
7 | --contexify-menu-shadow: 1px 2px 2px rgba(0, 0, 0, 0.1),
8 | 2px 4px 4px rgba(0, 0, 0, 0.1),
9 | 3px 6px 6px rgba(0, 0, 0, 0.1);
10 | --contexify-menu-negatePadding: var(--contexify-menu-padding);
11 |
12 | --contexify-separator-color: rgba(0, 0, 0, 0.2);
13 | --contexify-separator-margin: 5px;
14 | --contexify-itemContent-padding: 6px;
15 | --contexify-activeItem-radius: 4px;
16 | --contexify-item-color: #333;
17 | --contexify-activeItem-color: #fff;
18 | --contexify-activeItem-bgColor: #3498db;
19 | --contexify-rightSlot-color: #6f6e77;
20 | --contexify-activeRightSlot-color: #fff;
21 | --contexify-arrow-color: #6f6e77;
22 | --contexify-activeArrow-color: #fff;
23 | }
24 |
25 |
26 | @mixin focus-swag {
27 | color: var(--contexify-activeItem-color);
28 | background-color: var(--contexify-activeItem-bgColor);
29 | border-radius: var(--contexify-activeItem-radius);
30 | }
31 |
32 | @function negateMenuPadding() {
33 | @return calc(-1 * var(--contexify-menu-negatePadding));
34 | }
35 |
36 | // triggered when user select item from the context menu
37 | @keyframes contexify_feedback {
38 | from {
39 | opacity: .4;
40 | }
41 | to {
42 | opacity: 1;
43 | }
44 | }
45 |
46 |
47 | .contexify {
48 | position: fixed;
49 | opacity: 0;
50 | user-select: none;
51 | background-color: var(--contexify-menu-bgColor);
52 | box-sizing: border-box;
53 | box-shadow:var(--contexify-menu-shadow);
54 | border-radius: var(--contexify-menu-radius);
55 | padding: var(--contexify-menu-padding);
56 | min-width: var(--contexify-menu-minWidth);
57 | z-index: var(--contexify-zIndex);
58 |
59 | &_submenu-isOpen,
60 | &_submenu-isOpen > &_itemContent {
61 | @include focus-swag;
62 | }
63 |
64 | // target submenu arrow
65 | &_submenu-isOpen > &_itemContent &_rightSlot {
66 | color: var(--contexify-activeArrow-color)
67 | }
68 |
69 |
70 | &_submenu-isOpen > &_submenu {
71 | pointer-events: initial;
72 | opacity: 1;
73 | }
74 |
75 | & &_submenu {
76 | position: absolute;
77 | pointer-events: none;
78 | transition: opacity .265s;
79 |
80 | /* Initial submenu position */
81 | top: negateMenuPadding();
82 | left: 100%;
83 |
84 | &-bottom{
85 | bottom: negateMenuPadding();
86 | top: unset;
87 | }
88 |
89 | &-right {
90 | right: 100%;
91 | left: unset;
92 | }
93 | }
94 |
95 | &_rightSlot {
96 | margin-left: auto;
97 | display: flex;
98 | color: var(--contexify-rightSlot-color)
99 | }
100 |
101 | &_separator {
102 | height: 1px;
103 | cursor: default;
104 | margin: var(--contexify-separator-margin);
105 | background-color: var(--contexify-separator-color);
106 | }
107 |
108 | &_willLeave-disabled {
109 | pointer-events: none;
110 | }
111 |
112 | &_item {
113 | cursor: pointer;
114 | position: relative;
115 |
116 | &:focus{
117 | outline: 0;
118 | }
119 |
120 | &:not(&-disabled):hover > .contexify_itemContent .contexify_rightSlot,
121 | &:focus .contexify_rightSlot{
122 | color: var(--contexify-activeRightSlot-color);
123 | }
124 |
125 | &:not(&-disabled)[aria-haspopup] > .contexify_itemContent .contexify_rightSlot {
126 | color: var(--contexify-arrow-color);
127 | }
128 |
129 | // triggered by keyboard navigation
130 | &[aria-haspopup]:focus > .contexify_itemContent .contexify_rightSlot,
131 | &:not(&-disabled)[aria-haspopup].contexify_submenu-isOpen > .contexify_itemContent .contexify_rightSlot,
132 |
133 | &:not(&-disabled)[aria-haspopup]:hover > .contexify_itemContent .contexify_rightSlot {
134 | color: var(--contexify-activeArrow-color);
135 | }
136 |
137 | &:not(&-disabled):hover > &Content,
138 | &:not(&-disabled):focus > &Content {
139 | @include focus-swag;
140 | }
141 |
142 | &:not(&-disabled):hover > .contexify_submenu {
143 | pointer-events: initial;
144 | opacity: 1;
145 | }
146 |
147 | &-disabled {
148 | cursor: default;
149 | opacity: .5;
150 | }
151 | &Content {
152 | padding: var(--contexify-itemContent-padding);
153 | display: flex;
154 | align-items: center;
155 | white-space: nowrap;
156 | color: var(--contexify-item-color);
157 | position: relative;
158 | }
159 |
160 | &-feedback{
161 | animation: contexify_feedback 0.12s both;
162 | }
163 | }
164 | }
165 |
--------------------------------------------------------------------------------
/scss/_themes.scss:
--------------------------------------------------------------------------------
1 | .contexify_theme-dark {
2 | --contexify-menu-bgColor: rgba(40, 40, 40, 0.98);
3 | --contexify-separator-color: #4c4c4c;
4 | --contexify-item-color: #fff;
5 | // --contexify-activeItem-bgColor: #bb86fc;
6 | }
7 |
8 | .contexify_theme-light {
9 | --contexify-separator-color: #eee;
10 | --contexify-item-color: #666;
11 | --contexify-activeItem-color: #3498db;
12 | --contexify-activeItem-bgColor: #e0eefd;
13 | --contexify-activeRightSlot-color: #3498db;
14 | --contexify-active-arrow-color: #3498db;
15 | }
16 |
--------------------------------------------------------------------------------
/scss/animations/_fade.scss:
--------------------------------------------------------------------------------
1 | $delay: 0.3s;
2 |
3 | @keyframes contexify_fadeIn {
4 | from {
5 | opacity: 0;
6 | transform: translateY(10px);
7 | }
8 | to {
9 | opacity: 1;
10 | transform: translateY(0);
11 | }
12 | }
13 |
14 | @keyframes contexify_fadeOut {
15 | from {
16 | opacity: 1;
17 | transform: translateY(0);
18 | }
19 | to {
20 | opacity: 0;
21 | transform: translateY(10px);
22 | }
23 | }
24 |
25 | .contexify_willEnter-fade {
26 | animation: contexify_fadeIn $delay ease;
27 | }
28 |
29 | .contexify_willLeave-fade {
30 | animation: contexify_fadeOut $delay ease;
31 | }
32 |
--------------------------------------------------------------------------------
/scss/animations/_flip.scss:
--------------------------------------------------------------------------------
1 | $delay: 0.3s;
2 |
3 | @keyframes contexify_flipInX {
4 | from {
5 | transform: perspective(800px) rotate3d(1, 0, 0, 45deg);
6 | }
7 |
8 | to {
9 | transform: perspective(800px);
10 | }
11 | }
12 |
13 | @keyframes contexify_flipOutX {
14 | from {
15 | transform: perspective(800px);
16 | }
17 |
18 | to {
19 | transform: perspective(800px) rotate3d(1, 0, 0, 45deg);
20 | opacity: 0;
21 | }
22 | }
23 |
24 | .contexify_willEnter-flip {
25 | backface-visibility: visible !important;
26 | transform-origin: top center;
27 | animation: contexify_flipInX $delay;
28 | }
29 |
30 | .contexify_willLeave-flip {
31 | transform-origin: top center;
32 | animation: contexify_flipOutX $delay;
33 | backface-visibility: visible !important;
34 | }
35 |
--------------------------------------------------------------------------------
/scss/animations/_scale.scss:
--------------------------------------------------------------------------------
1 | $delay: 0.3s;
2 |
3 | @keyframes contexify_scaleIn {
4 | from {
5 | opacity: 0;
6 | transform: scale3d(0.3, 0.3, 0.3);
7 | }
8 |
9 | to {
10 | opacity: 1;
11 | }
12 | }
13 |
14 | @keyframes contexify_scaleOut {
15 | from {
16 | opacity: 1;
17 | }
18 |
19 | to {
20 | opacity: 0;
21 | transform: scale3d(0.3, 0.3, 0.3);
22 | }
23 | }
24 |
25 | .contexify_willEnter-scale {
26 | transform-origin: top left;
27 | animation: contexify_scaleIn $delay;
28 | }
29 |
30 | .contexify_willLeave-scale {
31 | transform-origin: top left;
32 | animation: contexify_scaleOut $delay;
33 | }
34 |
--------------------------------------------------------------------------------
/scss/animations/_slide.scss:
--------------------------------------------------------------------------------
1 | $delay: 0.3s;
2 |
3 | @keyframes contexify_slideIn {
4 | from {
5 | opacity: 0;
6 | transform: scale3d(1, 0.3, 1);
7 | }
8 |
9 | to {
10 | opacity: 1;
11 | }
12 | }
13 |
14 | @keyframes contexify_slideOut {
15 | from {
16 | opacity: 1;
17 | }
18 |
19 | to {
20 | opacity: 0;
21 | transform: scale3d(1, 0.3, 1);
22 | }
23 | }
24 |
25 | .contexify_willEnter-slide {
26 | transform-origin: top center;
27 | animation: contexify_slideIn $delay;
28 | }
29 |
30 | .contexify_willLeave-slide {
31 | transform-origin: top center;
32 | animation: contexify_slideOut $delay;
33 | }
34 |
--------------------------------------------------------------------------------
/scss/main.scss:
--------------------------------------------------------------------------------
1 | @charset "UTF-8";
2 |
3 | //ContextMenu,Separator,Item------------------------------------------ //
4 | @import 'menu';
5 |
6 | //Themes ------------------------------------------------------------ //
7 | @import 'themes';
8 |
9 | //Animations -------------------------------------------------------- //
10 | @import 'animations/scale';
11 | @import 'animations/fade';
12 | @import 'animations/flip';
13 | @import 'animations/slide';
14 |
--------------------------------------------------------------------------------
/src/components/Arrow.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | export const Arrow = () => (
4 |
15 |
16 |
17 | );
18 |
--------------------------------------------------------------------------------
/src/components/Item.tsx:
--------------------------------------------------------------------------------
1 | import React, { ReactNode, useRef } from 'react';
2 | import cx from 'clsx';
3 |
4 | import {
5 | ItemParams,
6 | InternalProps,
7 | BooleanPredicate,
8 | HandlerParamsEvent,
9 | BuiltInOrString,
10 | } from '../types';
11 | import { useItemTrackerContext } from './ItemTrackerProvider';
12 | import { NOOP, CssClass } from '../constants';
13 | import { getPredicateValue, isFn } from './utils';
14 | import { contextMenu } from '../core';
15 |
16 | export interface ItemProps
17 | extends InternalProps,
18 | Omit, 'hidden' | 'disabled' | 'onClick'> {
19 | /**
20 | * Any valid node that can be rendered
21 | */
22 | children: ReactNode;
23 |
24 | /**
25 | * Passed to the `Item` onClick callback. Accessible via `data`
26 | */
27 | data?: any;
28 |
29 | /**
30 | * Disable `Item`. If a function is used, a boolean must be returned
31 | *
32 | * @param id The item id, when defined
33 | * @param props The props passed when you called `show(e, {props: yourProps})`
34 | * @param data The data defined on the `Item`
35 | * @param triggerEvent The event that triggered the context menu
36 | *
37 | *
38 | * ```
39 | * function isItemDisabled({ triggerEvent, props, data }: PredicateParams): boolean
40 | * - content
41 | * ```
42 | */
43 | disabled?: BooleanPredicate;
44 |
45 | /**
46 | * Hide the `Item`. If a function is used, a boolean must be returned
47 | *
48 | * @param id The item id, when defined
49 | * @param props The props passed when you called `show(e, {props: yourProps})`
50 | * @param data The data defined on the `Item`
51 | * @param triggerEvent The event that triggered the context menu
52 | *
53 | *
54 | * ```
55 | * function isItemHidden({ triggerEvent, props, data }: PredicateParams): boolean
56 | * - content
57 | * ```
58 | */
59 | hidden?: BooleanPredicate;
60 |
61 | /**
62 | * Callback when the `Item` is clicked.
63 | *
64 | * @param id The item id, when defined
65 | * @param event The event that occured on the Item node
66 | * @param props The props passed when you called `show(e, {props: yourProps})`
67 | * @param data The data defined on the `Item`
68 | * @param triggerEvent The event that triggered the context menu
69 | *
70 | * ```
71 | * function handleItemClick({ id, triggerEvent, event, props, data }: ItemParams){
72 | * // retrieve the id of the Item
73 | * console.log(id) // item-id
74 | *
75 | * // access any other dom attribute
76 | * console.log(event.currentTarget.dataset.foo) // 123
77 | *
78 | * // access the props and the data
79 | * console.log(props, data);
80 | *
81 | * // access the coordinate of the mouse when the menu has been displayed
82 | * const { clientX, clientY } = triggerEvent;
83 | * }
84 | *
85 | * - Something
86 | * ```
87 | */
88 | onClick?: (args: ItemParams) => void;
89 |
90 | /**
91 | * Let you implement keyboard shortcut for the menu item. It will trigger the
92 | * `onClick` hander if the given callback returns `true`
93 | *
94 | * example:
95 | *
96 | * ```
97 | * function handleShortcut(e: React.KeyboardEvent){
98 | * // let's say we want to match ⌘ + c
99 | * return e.metaKey && e.key === "c";
100 | * }
101 | *
102 | * - Copy
⌘ C
103 | * ```
104 | */
105 | keyMatcher?: (e: KeyboardEvent) => boolean;
106 |
107 | /**
108 | * Useful when using form input inside the Menu
109 | *
110 | * default: `true`
111 | */
112 | closeOnClick?: boolean;
113 |
114 | /**
115 | * Let you specify another event for the `onClick` handler
116 | *
117 | * default: `onClick`
118 | */
119 | handlerEvent?: BuiltInOrString<'onClick' | 'onMouseDown' | 'onMouseUp'>;
120 | }
121 |
122 | export const Item: React.FC = ({
123 | id,
124 | children,
125 | className,
126 | style,
127 | triggerEvent,
128 | data,
129 | propsFromTrigger,
130 | keyMatcher,
131 | onClick = NOOP,
132 | disabled = false,
133 | hidden = false,
134 | closeOnClick = true,
135 | handlerEvent = 'onClick',
136 | ...rest
137 | }) => {
138 | const itemNode = useRef();
139 | const itemTracker = useItemTrackerContext();
140 | const handlerParams = {
141 | id,
142 | data,
143 | triggerEvent: triggerEvent as HandlerParamsEvent,
144 | props: propsFromTrigger,
145 | } as ItemParams;
146 | const isDisabled = getPredicateValue(disabled, handlerParams);
147 | const isHidden = getPredicateValue(hidden, handlerParams);
148 |
149 | function handleClick(e: React.MouseEvent) {
150 | handlerParams.event = e;
151 | e.stopPropagation();
152 |
153 | if (!isDisabled) {
154 | !closeOnClick ? onClick(handlerParams) : dispatchUserHanlder();
155 | }
156 | }
157 |
158 | // provide a feedback to the user that the item has been clicked before closing the menu
159 | function dispatchUserHanlder() {
160 | const node = itemNode.current!;
161 | node.focus();
162 | node.addEventListener(
163 | 'animationend',
164 | // defer, required for react 17
165 | () => setTimeout(contextMenu.hideAll),
166 | { once: true }
167 | );
168 | node.classList.add(CssClass.itemClickedFeedback);
169 | onClick(handlerParams);
170 | }
171 |
172 | function registerItem(node: HTMLElement | null) {
173 | if (node && !isDisabled) {
174 | itemNode.current = node;
175 | itemTracker.set(node, {
176 | node,
177 | isSubmenu: false,
178 | keyMatcher:
179 | !isDisabled &&
180 | isFn(keyMatcher) &&
181 | ((e: KeyboardEvent) => {
182 | if (keyMatcher(e)) {
183 | e.stopPropagation();
184 | e.preventDefault();
185 | handlerParams.event = e;
186 | dispatchUserHanlder();
187 | }
188 | }),
189 | });
190 | }
191 | }
192 |
193 | function handleKeyDown(e: React.KeyboardEvent) {
194 | if (e.key === 'Enter' || e.key === ' ') {
195 | e.stopPropagation();
196 | handlerParams.event = e;
197 | dispatchUserHanlder();
198 | }
199 | }
200 |
201 | if (isHidden) return null;
202 |
203 | return (
204 |
218 | );
219 | };
220 |
--------------------------------------------------------------------------------
/src/components/ItemTrackerProvider.tsx:
--------------------------------------------------------------------------------
1 | import React, { useContext, createContext } from 'react';
2 | import { ItemTracker } from '../hooks';
3 |
4 | const Context = createContext({} as ItemTracker);
5 |
6 | export const useItemTrackerContext = () => useContext(Context);
7 |
8 | export interface ItemTrackerProviderProps {
9 | value: ItemTracker;
10 | children?: React.ReactNode;
11 | }
12 |
13 | export const ItemTrackerProvider: React.FC = (
14 | props
15 | ) => ;
16 |
--------------------------------------------------------------------------------
/src/components/Menu.tsx:
--------------------------------------------------------------------------------
1 | import React, {
2 | ReactNode,
3 | useEffect,
4 | useReducer,
5 | useRef,
6 | useState,
7 | } from 'react';
8 | import cx from 'clsx';
9 |
10 | import { ItemTrackerProvider } from './ItemTrackerProvider';
11 |
12 | import { eventManager } from '../core/eventManager';
13 | import { TriggerEvent, MenuId, MenuAnimation, Theme } from '../types';
14 | import { useItemTracker } from '../hooks';
15 | import { createKeyboardController } from './keyboardController';
16 | import { CssClass, EVENT, hideOnEvents } from '../constants';
17 | import { cloneItems, getMousePosition, isFn, isStr } from './utils';
18 | import { flushSync } from 'react-dom';
19 | import { ShowContextMenuParams } from '../core';
20 |
21 | export interface MenuProps
22 | extends Omit, 'id'> {
23 | /**
24 | * Unique id to identify the menu. Use to Trigger the corresponding menu
25 | */
26 | id: MenuId;
27 |
28 | /**
29 | * Any valid node that can be rendered
30 | */
31 | children: ReactNode;
32 |
33 | /**
34 | * Theme is appended to `contexify_theme-${given theme}`.
35 | *
36 | * Built-in theme are `light` and `dark`
37 | */
38 | theme?: Theme;
39 |
40 | /**
41 | * Animation is appended to
42 | * - `.contexify_willEnter-${given animation}`
43 | * - `.contexify_willLeave-${given animation}`
44 | *
45 | * - To disable all animations you can pass `false`
46 | * - To disable only the enter or the exit animation you can provide an object `{enter: false, exit: 'exitAnimation'}`
47 | *
48 | * - default is set to `fade`
49 | */
50 | animation?: MenuAnimation;
51 |
52 | /**
53 | * Disables menu repositioning if outside screen.
54 | * This may be neeeded in some cases when using custom position.
55 | */
56 | disableBoundariesCheck?: boolean;
57 |
58 | /**
59 | * Prevents scrolling the window on when typing. Defaults to true.
60 | */
61 | preventDefaultOnKeydown?: boolean;
62 |
63 | /**
64 | * Used to track menu visibility
65 | */
66 | onVisibilityChange?: (isVisible: boolean) => void;
67 | }
68 |
69 | interface MenuState {
70 | x: number;
71 | y: number;
72 | visible: boolean;
73 | triggerEvent: TriggerEvent;
74 | propsFromTrigger: any;
75 | willLeave: boolean;
76 | }
77 |
78 | function reducer(
79 | state: MenuState,
80 | payload: Partial | ((state: MenuState) => Partial)
81 | ) {
82 | return { ...state, ...(isFn(payload) ? payload(state) : payload) };
83 | }
84 |
85 | export const Menu: React.FC = ({
86 | id,
87 | theme,
88 | style,
89 | className,
90 | children,
91 | animation = 'fade',
92 | preventDefaultOnKeydown = true,
93 | disableBoundariesCheck = false,
94 | onVisibilityChange,
95 | ...rest
96 | }) => {
97 | const [state, setState] = useReducer(reducer, {
98 | x: 0,
99 | y: 0,
100 | visible: false,
101 | triggerEvent: {} as TriggerEvent,
102 | propsFromTrigger: null,
103 | willLeave: false,
104 | });
105 | const nodeRef = useRef(null);
106 | const itemTracker = useItemTracker();
107 | const [menuController] = useState(() => createKeyboardController());
108 | const wasVisible = useRef();
109 | const visibilityId = useRef();
110 |
111 | // subscribe event manager
112 | useEffect(() => {
113 | eventManager.on(id, show).on(EVENT.HIDE_ALL, hide);
114 |
115 | return () => {
116 | eventManager.off(id, show).off(EVENT.HIDE_ALL, hide);
117 | };
118 | // hide rely on setState(dispatch), which is guaranted to be the same across render
119 | }, [id, animation, disableBoundariesCheck]);
120 |
121 | // collect menu items for keyboard navigation
122 | useEffect(() => {
123 | !state.visible ? itemTracker.clear() : menuController.init(itemTracker);
124 | }, [state.visible, menuController, itemTracker]);
125 |
126 | function checkBoundaries(x: number, y: number) {
127 | if (nodeRef.current && !disableBoundariesCheck) {
128 | const { innerWidth, innerHeight } = window;
129 | const { offsetWidth, offsetHeight } = nodeRef.current;
130 |
131 | if (x + offsetWidth > innerWidth) x -= x + offsetWidth - innerWidth;
132 |
133 | if (y + offsetHeight > innerHeight) y -= y + offsetHeight - innerHeight;
134 | }
135 |
136 | return { x, y };
137 | }
138 |
139 | // when the menu is transitioning from not visible to visible,
140 | // the nodeRef is attached to the dom element this let us check the boundaries
141 | useEffect(() => {
142 | // state.visible and state{x,y} are updated together
143 | if (state.visible) setState(checkBoundaries(state.x, state.y));
144 | }, [state.visible]);
145 |
146 | // subscribe dom events
147 | useEffect(() => {
148 | function preventDefault(e: KeyboardEvent) {
149 | if (preventDefaultOnKeydown) e.preventDefault();
150 | }
151 |
152 | function handleKeyboard(e: KeyboardEvent) {
153 | switch (e.key) {
154 | case 'Enter':
155 | case ' ':
156 | if (!menuController.openSubmenu()) hide();
157 | break;
158 | case 'Escape':
159 | hide();
160 | break;
161 | case 'ArrowUp':
162 | preventDefault(e);
163 | menuController.moveUp();
164 | break;
165 | case 'ArrowDown':
166 | preventDefault(e);
167 | menuController.moveDown();
168 | break;
169 | case 'ArrowRight':
170 | preventDefault(e);
171 | menuController.openSubmenu();
172 | break;
173 | case 'ArrowLeft':
174 | preventDefault(e);
175 | menuController.closeSubmenu();
176 | break;
177 | default:
178 | menuController.matchKeys(e);
179 | break;
180 | }
181 | }
182 |
183 | if (state.visible) {
184 | window.addEventListener('keydown', handleKeyboard);
185 |
186 | for (const ev of hideOnEvents) window.addEventListener(ev, hide);
187 | }
188 |
189 | return () => {
190 | window.removeEventListener('keydown', handleKeyboard);
191 |
192 | for (const ev of hideOnEvents) window.removeEventListener(ev, hide);
193 | };
194 | }, [state.visible, menuController, preventDefaultOnKeydown]);
195 |
196 | function show({ event, props, position }: ShowContextMenuParams) {
197 | event.stopPropagation();
198 | const p = position || getMousePosition(event);
199 | // check boundaries when the menu is already visible
200 | const { x, y } = checkBoundaries(p.x, p.y);
201 |
202 | flushSync(() => {
203 | setState({
204 | visible: true,
205 | willLeave: false,
206 | x,
207 | y,
208 | triggerEvent: event,
209 | propsFromTrigger: props,
210 | });
211 | });
212 |
213 | clearTimeout(visibilityId.current);
214 | if (!wasVisible.current && isFn(onVisibilityChange)) {
215 | onVisibilityChange(true);
216 | wasVisible.current = true;
217 | }
218 | }
219 |
220 | function hide(e?: Event) {
221 | type SafariEvent = KeyboardEvent & MouseEvent;
222 |
223 | if (
224 | e != null &&
225 | // Safari trigger a click event when you ctrl + trackpad
226 | ((e as SafariEvent).button === 2 || (e as SafariEvent).ctrlKey) &&
227 | // Firefox trigger a click event when right click occur
228 | e.type !== 'contextmenu'
229 | )
230 | return;
231 |
232 | animation && (isStr(animation) || ('exit' in animation && animation.exit))
233 | ? setState((state) => ({ willLeave: state.visible }))
234 | : setState((state) => ({
235 | visible: state.visible ? false : state.visible,
236 | }));
237 |
238 | visibilityId.current = setTimeout(() => {
239 | isFn(onVisibilityChange) && onVisibilityChange(false);
240 | wasVisible.current = false;
241 | });
242 | }
243 |
244 | function handleAnimationEnd() {
245 | if (state.willLeave && state.visible) {
246 | flushSync(() => setState({ visible: false, willLeave: false }));
247 | }
248 | }
249 |
250 | function computeAnimationClasses() {
251 | if (isStr(animation)) {
252 | return cx({
253 | [`${CssClass.animationWillEnter}${animation}`]: visible && !willLeave,
254 | [`${CssClass.animationWillLeave}${animation} ${CssClass.animationWillLeave}'disabled'`]:
255 | visible && willLeave,
256 | });
257 | } else if (animation && 'enter' in animation && 'exit' in animation) {
258 | return cx({
259 | [`${CssClass.animationWillEnter}${animation.enter}`]:
260 | animation.enter && visible && !willLeave,
261 | [`${CssClass.animationWillLeave}${animation.exit} ${CssClass.animationWillLeave}'disabled'`]:
262 | animation.exit && visible && willLeave,
263 | });
264 | }
265 |
266 | return null;
267 | }
268 |
269 | const { visible, triggerEvent, propsFromTrigger, x, y, willLeave } = state;
270 | const cssClasses = cx(
271 | CssClass.menu,
272 | className,
273 | { [`${CssClass.theme}${theme}`]: theme },
274 | computeAnimationClasses()
275 | );
276 |
277 | // TODO: switch to translate instead of top left
278 | // requires an additional dom element around the menu
279 | return (
280 |
281 | {visible && (
282 |
295 | {cloneItems(children, {
296 | propsFromTrigger,
297 | triggerEvent,
298 | })}
299 |
300 | )}
301 |
302 | );
303 | };
304 |
--------------------------------------------------------------------------------
/src/components/RightSlot.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import cx from 'clsx';
3 |
4 | import { CssClass } from '../constants';
5 |
6 | export interface RightSlotProps extends React.HTMLAttributes {
7 | children: React.ReactNode;
8 | }
9 |
10 | export const RightSlot: React.FC = ({ className, ...rest }) => (
11 |
12 | );
13 |
--------------------------------------------------------------------------------
/src/components/Separator.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import { BooleanPredicate, HandlerParamsEvent, InternalProps } from '../types';
4 | import { getPredicateValue } from './utils';
5 |
6 | import { CssClass } from '../constants';
7 |
8 | export interface SeparatorProps extends InternalProps {
9 | /**
10 | * Passed to the `Separator` hidden predicate. Accessible via `data`
11 | */
12 | data?: any;
13 |
14 | /**
15 | * Hide the `Separator`. If a function is used, a boolean must be returned
16 | *
17 | * @param props The props passed when you called `show(e, {props: yourProps})`
18 | * @param data The data defined on the `Separator`
19 | * @param triggerEvent The event that triggered the context menu
20 | *
21 | *
22 | * ```
23 | * function isSeparatorHidden({ triggerEvent, props, data }: PredicateParams): boolean
24 | *
25 | * ```
26 | */
27 | hidden?: BooleanPredicate;
28 | }
29 |
30 | export const Separator: React.FC = ({
31 | triggerEvent,
32 | data,
33 | propsFromTrigger,
34 | hidden = false,
35 | }) =>
36 | getPredicateValue(hidden, {
37 | data,
38 | triggerEvent: triggerEvent as HandlerParamsEvent,
39 | props: propsFromTrigger,
40 | }) ? null : (
41 |
42 | );
43 |
--------------------------------------------------------------------------------
/src/components/Submenu.tsx:
--------------------------------------------------------------------------------
1 | import React, { ReactNode, useRef } from 'react';
2 | import cx from 'clsx';
3 |
4 | import { InternalProps, BooleanPredicate, HandlerParamsEvent } from '../types';
5 | import {
6 | ItemTrackerProvider,
7 | useItemTrackerContext,
8 | } from './ItemTrackerProvider';
9 | import { useItemTracker } from '../hooks';
10 | import { CssClass } from '../constants';
11 | import { cloneItems, getPredicateValue } from './utils';
12 | import { Arrow } from './Arrow';
13 | import { RightSlot } from './RightSlot';
14 |
15 | export interface SubMenuProps
16 | extends InternalProps,
17 | Omit, 'hidden'> {
18 | /**
19 | * Any valid node that can be rendered
20 | */
21 | label: ReactNode;
22 |
23 | /**
24 | * Any valid node that can be rendered
25 | */
26 | children: ReactNode;
27 |
28 | /**
29 | * Render a custom arrow
30 | */
31 | arrow?: ReactNode;
32 |
33 | /**
34 | * Disable the `Submenu`. If a function is used, a boolean must be returned
35 | */
36 | disabled?: BooleanPredicate;
37 |
38 | /**
39 | * Hide the `Submenu` and his children. If a function is used, a boolean must be returned
40 | */
41 | hidden?: BooleanPredicate;
42 | }
43 |
44 | export const Submenu: React.FC = ({
45 | arrow,
46 | children,
47 | disabled = false,
48 | hidden = false,
49 | label,
50 | className,
51 | triggerEvent,
52 | propsFromTrigger,
53 | style,
54 | ...rest
55 | }) => {
56 | const parentItemTracker = useItemTrackerContext();
57 | const itemTracker = useItemTracker();
58 | const submenuNode = useRef(null);
59 | const handlerParams = {
60 | triggerEvent: triggerEvent as HandlerParamsEvent,
61 | props: propsFromTrigger,
62 | };
63 | const isDisabled = getPredicateValue(disabled, handlerParams);
64 | const isHidden = getPredicateValue(hidden, handlerParams);
65 |
66 | function setPosition() {
67 | const node = submenuNode.current;
68 | if (node) {
69 | const bottom = `${CssClass.submenu}-bottom`;
70 | const right = `${CssClass.submenu}-right`;
71 |
72 | // reset to default position before computing position
73 | node.classList.remove(bottom, right);
74 |
75 | const rect = node.getBoundingClientRect();
76 |
77 | if (rect.right > window.innerWidth) node.classList.add(right);
78 |
79 | if (rect.bottom > window.innerHeight) node.classList.add(bottom);
80 | }
81 | }
82 |
83 | function trackRef(node: HTMLElement | null) {
84 | if (node && !isDisabled)
85 | parentItemTracker.set(node, {
86 | node,
87 | isSubmenu: true,
88 | submenuRefTracker: itemTracker,
89 | setSubmenuPosition: setPosition,
90 | });
91 | }
92 |
93 | if (isHidden) return null;
94 |
95 | const cssClasses = cx(CssClass.item, className, {
96 | [`${CssClass.itemDisabled}`]: isDisabled,
97 | });
98 |
99 | return (
100 |
101 |
112 |
e.stopPropagation()}
115 | >
116 | {label}
117 |
{arrow || }
118 |
119 |
124 | {cloneItems(children, {
125 | propsFromTrigger,
126 | // @ts-ignore: injected by the parent
127 | triggerEvent,
128 | })}
129 |
130 |
131 |
132 | );
133 | };
134 |
--------------------------------------------------------------------------------
/src/components/keyboardController.ts:
--------------------------------------------------------------------------------
1 | import { ItemTracker, ItemTrackerRecord } from '../hooks';
2 | import { CssClass } from '../constants';
3 |
4 | interface Menu {
5 | items: T[];
6 | isRoot: boolean;
7 | focusedIndex: number;
8 | parentNode: HTMLElement;
9 | }
10 |
11 | export function createKeyboardController() {
12 | const menuList = new Map();
13 | let focusedIndex: number;
14 | let parentNode: HTMLElement;
15 | let isRoot: boolean;
16 | let currentItems: ItemTrackerRecord[];
17 | let forceCloseSubmenu = false;
18 |
19 | function init(rootMenu: ItemTracker) {
20 | currentItems = Array.from(rootMenu.values());
21 | focusedIndex = -1;
22 | isRoot = true;
23 | }
24 |
25 | function focusSelectedItem() {
26 | currentItems[focusedIndex].node.focus();
27 | }
28 |
29 | const isSubmenuFocused = () =>
30 | focusedIndex >= 0 && currentItems[focusedIndex].isSubmenu;
31 |
32 | const getSubmenuItems = () =>
33 | Array.from(currentItems[focusedIndex].submenuRefTracker!.values());
34 |
35 | function isFocused() {
36 | if (focusedIndex === -1) {
37 | // focus first item
38 | moveDown();
39 | return false;
40 | }
41 |
42 | return true;
43 | }
44 |
45 | function moveDown() {
46 | if (focusedIndex + 1 < currentItems.length) {
47 | focusedIndex++;
48 | } else if (focusedIndex + 1 === currentItems.length) {
49 | focusedIndex = 0;
50 | }
51 |
52 | if (forceCloseSubmenu) closeSubmenu();
53 |
54 | focusSelectedItem();
55 | }
56 |
57 | function moveUp() {
58 | if (focusedIndex === -1 || focusedIndex === 0) {
59 | focusedIndex = currentItems.length - 1;
60 | } else if (focusedIndex - 1 < currentItems.length) {
61 | focusedIndex--;
62 | }
63 |
64 | if (forceCloseSubmenu) closeSubmenu();
65 |
66 | focusSelectedItem();
67 | }
68 |
69 | function openSubmenu() {
70 | if (isFocused() && isSubmenuFocused()) {
71 | const submenuItems = getSubmenuItems();
72 | const { node, setSubmenuPosition } = currentItems[focusedIndex];
73 |
74 | menuList.set(node, {
75 | isRoot,
76 | focusedIndex,
77 | parentNode: parentNode || node,
78 | items: currentItems,
79 | });
80 |
81 | setSubmenuPosition!();
82 | node.classList.add(CssClass.submenuOpen);
83 | parentNode = node;
84 |
85 | if (submenuItems.length > 0) {
86 | focusedIndex = 0;
87 | currentItems = submenuItems;
88 | } else {
89 | forceCloseSubmenu = true;
90 | }
91 |
92 | isRoot = false;
93 |
94 | focusSelectedItem();
95 | return true;
96 | }
97 | return false;
98 | }
99 |
100 | function closeSubmenu() {
101 | if (isFocused() && !isRoot) {
102 | const parent = menuList.get(parentNode)!;
103 |
104 | parentNode!.classList.remove(CssClass.submenuOpen);
105 | currentItems = parent.items;
106 | parentNode = parent.parentNode;
107 |
108 | if (parent.isRoot) {
109 | isRoot = true;
110 | menuList.clear();
111 | }
112 |
113 | if (!forceCloseSubmenu) {
114 | focusedIndex = parent.focusedIndex;
115 | focusSelectedItem();
116 | }
117 | }
118 | }
119 |
120 | function matchKeys(e: KeyboardEvent) {
121 | // matches shortcut inside submenu as well even when submenu is not open
122 | // it matches native menu behavior
123 | function walkAndMatch(items: ItemTrackerRecord[]) {
124 | for (const item of items) {
125 | if (item.isSubmenu && item.submenuRefTracker)
126 | walkAndMatch(Array.from(item.submenuRefTracker.values()));
127 |
128 | item.keyMatcher && item.keyMatcher(e);
129 | }
130 | }
131 | walkAndMatch(currentItems);
132 | }
133 |
134 | return {
135 | init,
136 | moveDown,
137 | moveUp,
138 | openSubmenu,
139 | closeSubmenu,
140 | matchKeys,
141 | };
142 | }
143 |
--------------------------------------------------------------------------------
/src/components/utils.ts:
--------------------------------------------------------------------------------
1 | import { Children, cloneElement, ReactNode, ReactElement } from 'react';
2 |
3 | import { BooleanPredicate, PredicateParams, TriggerEvent } from '../types';
4 |
5 | export function isFn(v: any): v is Function {
6 | return typeof v === 'function';
7 | }
8 |
9 | export function isStr(v: any): v is String {
10 | return typeof v === 'string';
11 | }
12 |
13 | export function cloneItems(
14 | children: ReactNode,
15 | props: { triggerEvent: TriggerEvent; propsFromTrigger?: object }
16 | ) {
17 | return Children.map(
18 | // remove null item
19 | Children.toArray(children).filter(Boolean),
20 | (item) => cloneElement(item as ReactElement, props)
21 | );
22 | }
23 |
24 | export function getMousePosition(e: TriggerEvent) {
25 | const pos = {
26 | x: (e as MouseEvent).clientX,
27 | y: (e as MouseEvent).clientY,
28 | };
29 |
30 | const touch = (e as TouchEvent).changedTouches;
31 |
32 | if (touch) {
33 | pos.x = touch[0].clientX;
34 | pos.y = touch[0].clientY;
35 | }
36 |
37 | if (!pos.x || pos.x < 0) pos.x = 0;
38 |
39 | if (!pos.y || pos.y < 0) pos.y = 0;
40 |
41 | return pos;
42 | }
43 |
44 | export function getPredicateValue(
45 | predicate: BooleanPredicate,
46 | payload: PredicateParams
47 | ) {
48 | return isFn(predicate) ? predicate(payload) : predicate;
49 | }
50 |
--------------------------------------------------------------------------------
/src/constants.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * css classes mapping
3 | * */
4 | export const enum CssClass {
5 | menu = 'contexify',
6 | submenu = 'contexify_submenu',
7 | submenuOpen = 'contexify_submenu-isOpen',
8 | rightSlot = 'contexify_rightSlot',
9 | separator = 'contexify_separator',
10 | item = 'contexify_item',
11 | itemDisabled = 'contexify_item-disabled',
12 | itemContent = 'contexify_itemContent',
13 | itemClickedFeedback = 'contexify_item-feedback',
14 | theme = 'contexify_theme-',
15 | animationWillEnter = 'contexify_willEnter-',
16 | animationWillLeave = 'contexify_willLeave-',
17 | }
18 |
19 | export const enum EVENT {
20 | HIDE_ALL,
21 | }
22 |
23 | export const NOOP = () => {};
24 |
25 | export const hideOnEvents: (keyof GlobalEventHandlersEventMap)[] = [
26 | 'resize',
27 | 'contextmenu',
28 | 'click',
29 | 'scroll',
30 |
31 | // comment blur in dev so you can toggle console without closing the menu
32 | 'blur',
33 | ];
34 |
--------------------------------------------------------------------------------
/src/core/contextMenu.ts:
--------------------------------------------------------------------------------
1 | import { eventManager } from './eventManager';
2 | import { MenuId, TriggerEvent } from '../types';
3 | import { SyntheticEvent } from 'react';
4 |
5 | import { EVENT } from '../constants';
6 |
7 | export interface ContextMenu {
8 | show: (params: ShowContextMenuParams) => void;
9 | hideAll: () => void;
10 | }
11 |
12 | export interface ShowContextMenuParams {
13 | id: MenuId;
14 | event: TriggerEvent;
15 | props?: TProps;
16 | position?: {
17 | x: number;
18 | y: number;
19 | } | null;
20 | }
21 |
22 | const contextMenu: ContextMenu = {
23 | show({ event, id, props, position }) {
24 | if (event.preventDefault) event.preventDefault();
25 |
26 | eventManager.emit(EVENT.HIDE_ALL).emit(id, {
27 | event: (event as SyntheticEvent).nativeEvent || event,
28 | props,
29 | position,
30 | });
31 | },
32 | hideAll() {
33 | eventManager.emit(EVENT.HIDE_ALL);
34 | },
35 | };
36 |
37 | export { contextMenu };
38 |
--------------------------------------------------------------------------------
/src/core/eventManager.ts:
--------------------------------------------------------------------------------
1 | export type EventType = string | number | symbol;
2 | export type Handler = (args: T) => void;
3 |
4 | export interface EventManager {
5 | on(event: E, handler: Handler): EventManager;
6 | off(event: E, handler?: Handler): EventManager;
7 | emit(event: E, args?: T): EventManager;
8 | }
9 |
10 | function createEventManager(): EventManager {
11 | const eventList = new Map>();
12 |
13 | return {
14 | on(event: E, handler: Handler) {
15 | eventList.has(event)
16 | ? eventList.get(event)!.add(handler)
17 | : eventList.set(event, new Set([handler]));
18 | return this;
19 | },
20 | off(event: E, handler: Handler) {
21 | eventList.has(event) && eventList.get(event)!.delete(handler);
22 | return this;
23 | },
24 | emit(event: E, args: T) {
25 | eventList.has(event) &&
26 | eventList.get(event)!.forEach((handler: Handler) => {
27 | handler(args);
28 | });
29 | return this;
30 | },
31 | };
32 | }
33 |
34 | export const eventManager = createEventManager();
35 |
--------------------------------------------------------------------------------
/src/core/index.ts:
--------------------------------------------------------------------------------
1 | export * from './eventManager';
2 | export * from './contextMenu';
3 |
--------------------------------------------------------------------------------
/src/hooks/index.ts:
--------------------------------------------------------------------------------
1 | export * from './useItemTracker';
2 | export * from './useContextMenu';
3 |
--------------------------------------------------------------------------------
/src/hooks/useContextMenu.ts:
--------------------------------------------------------------------------------
1 | import { contextMenu, ShowContextMenuParams } from '../core';
2 | import { MenuId } from '../types';
3 |
4 | export interface UseContextMenuParams {
5 | id: MenuId;
6 | props?: TProps;
7 | }
8 |
9 | type MakeOptional = Omit &
10 | Partial>;
11 |
12 | export function useContextMenu(
13 | params: UseContextMenuParams
14 | ): {
15 | show: (params: MakeOptional) => void;
16 | hideAll: () => void;
17 | };
18 |
19 | export function useContextMenu(
20 | params?: Partial>
21 | ): {
22 | show: (params: ShowContextMenuParams) => void;
23 | hideAll: () => void;
24 | };
25 |
26 | export function useContextMenu(
27 | props?: UseContextMenuParams | Partial
28 | ) {
29 | return {
30 | show(params: ShowContextMenuParams) {
31 | contextMenu.show({
32 | ...props,
33 | ...params,
34 | });
35 | },
36 | hideAll() {
37 | contextMenu.hideAll();
38 | },
39 | };
40 | }
41 |
--------------------------------------------------------------------------------
/src/hooks/useItemTracker.ts:
--------------------------------------------------------------------------------
1 | import { useRef } from 'react';
2 |
3 | export interface ItemTrackerRecord {
4 | node: HTMLElement;
5 | isSubmenu: boolean;
6 | submenuRefTracker?: ItemTracker;
7 | setSubmenuPosition?: () => void;
8 | keyMatcher?: false | ((e: KeyboardEvent) => void);
9 | }
10 |
11 | export type ItemTracker = ReturnType;
12 |
13 | export const useItemTracker = () =>
14 | useRef>(new Map()).current;
15 |
--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
1 | export * from './components/Menu';
2 | export * from './components/Item';
3 | export * from './components/Separator';
4 | export * from './components/Submenu';
5 | export * from './components/RightSlot';
6 | export * from './core/contextMenu';
7 | export * from './hooks/useContextMenu';
8 | export * from './types';
9 |
--------------------------------------------------------------------------------
/src/types/index.ts:
--------------------------------------------------------------------------------
1 | export type BuiltInOrString = T | (string & {});
2 |
3 | /**
4 | * The event that triggered the context menu
5 | */
6 | export type HandlerParamsEvent = MouseEvent & TouchEvent & KeyboardEvent;
7 |
8 | /**
9 | * Pass the event handler. It's used to determine the position of the cursor
10 | */
11 | export type TriggerEvent =
12 | | MouseEvent
13 | | TouchEvent
14 | | KeyboardEvent
15 | | React.MouseEvent
16 | | React.TouchEvent
17 | | React.KeyboardEvent;
18 |
19 | export type BooleanPredicate = boolean | ((args: HandlerParams) => boolean);
20 |
21 | /**
22 | * Unique id to identify the menu. Use to Trigger the corresponding menu
23 | */
24 | export type MenuId = string | number;
25 |
26 | /**
27 | * Used both by `PredicatParams` and `ItemParams`
28 | */
29 | interface HandlerParams {
30 | /**
31 | * The id of the item when provided
32 | */
33 | id?: string;
34 |
35 | /**
36 | * The event that triggered the context menu
37 | */
38 | triggerEvent: HandlerParamsEvent;
39 |
40 | /**
41 | * Any props supplied when triggering the menu
42 | */
43 | props?: Props;
44 |
45 | /**
46 | * Data object provided to item
47 | */
48 | data?: Data;
49 | }
50 |
51 | /**
52 | * Used in 2 cases:
53 | * - When passing a boolean predicate to `disabled`
54 | * - When passing a boolean predicate to `hidden`
55 | *
56 | * @param props The props passed when you called `show(e, {props: yourProps})`
57 | * @param data The data defined on the `Item`
58 | * @param triggerEvent The event that triggered the context menu
59 | *
60 | * ```
61 | * function isItemDisabled({ triggerEvent, props, data }: PredicateParams): boolean
62 | * - content
63 | * ```
64 | */
65 | export type PredicateParams = HandlerParams<
66 | Props,
67 | Data
68 | >;
69 |
70 | /**
71 | * Callback when the `Item` is clicked.
72 | *
73 | * @param id The item id, when defined
74 | * @param event The event that occured on the Item node
75 | * @param props The props passed when you called `show(e, {props: yourProps})`
76 | * @param data The data defined on the `Item`
77 | * @param triggerEvent The event that triggered the context menu
78 | *
79 | * ```
80 | * function handleItemClick({ id, triggerEvent, event, props, data }: ItemParams){
81 | * // retrieve the id of the Item
82 | * console.log(id) // item-id
83 | *
84 | * // access any other dom attribute
85 | * console.log(event.currentTarget.dataset.foo) // 123
86 | *
87 | * // access the props and the data
88 | * console.log(props, data);
89 | *
90 | * // access the coordinate of the mouse when the menu has been displayed
91 | * const { clientX, clientY } = triggerEvent;
92 | * }
93 | *
94 | * - Something
95 | * ```
96 | */
97 | export interface ItemParams
98 | extends HandlerParams {
99 | event:
100 | | React.MouseEvent
101 | | React.TouchEvent
102 | | React.KeyboardEvent
103 | | KeyboardEvent;
104 | }
105 |
106 | export interface InternalProps {
107 | /**
108 | * INTERNAL USE ONLY: The event that triggered the context menu
109 | */
110 | triggerEvent?: TriggerEvent;
111 |
112 | /**
113 | * INTERNAL USE ONLY: Passed to the Item onClick callback. Accessible via `props`
114 | */
115 | propsFromTrigger?: any;
116 | }
117 |
118 | /**
119 | * Theme is appended to `react-contexify__theme--${given theme}`.
120 | *
121 | * Built-in theme are `light` and `dark`
122 | */
123 | export type Theme = BuiltInOrString<'light' | 'dark'>;
124 |
125 | /**
126 | * Animation is appended to
127 | * - `.react-contexify__will-enter--${given animation}`
128 | * - `.react-contexify__will-leave--${given animation}`
129 | *
130 | * - To disable all animations you can pass `false`
131 | * - To disable only the enter or the exit animation you can provide an object `{enter: false, exit: 'exitAnimation'}`
132 | * - default is set to `fade`
133 | *
134 | * Built-in animations are `fade`, `scale`, `flip`, `slide`
135 | */
136 | export type MenuAnimation =
137 | | Animation
138 | | false
139 | | { enter: Animation | false; exit: Animation | false };
140 |
141 | type Animation = BuiltInOrString<'fade' | 'scale' | 'flip' | 'slide'>;
142 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | // see https://www.typescriptlang.org/tsconfig to better understand tsconfigs
3 | "include": ["src", "types"],
4 | "compilerOptions": {
5 | "target": "ES2020",
6 | "module": "esnext",
7 | "lib": ["dom", "esnext"],
8 | "importHelpers": true,
9 | // output .d.ts declaration files for consumers
10 | "declaration": true,
11 | // output .js.map sourcemap files for consumers
12 | "sourceMap": true,
13 | // match output dir to input dir. e.g. dist/index instead of dist/src/index
14 | "rootDir": "./src",
15 | // stricter type-checking for stronger correctness. Recommended by TS
16 | "strict": true,
17 | // linter checks for common issues
18 | "noImplicitReturns": true,
19 | "noFallthroughCasesInSwitch": true,
20 | // noUnused* overlap with @typescript-eslint/no-unused-vars, can disable if duplicative
21 | "noUnusedLocals": true,
22 | "noUnusedParameters": true,
23 | // use Node's module resolution algorithm, instead of the legacy TS one
24 | "moduleResolution": "node",
25 | // transpile JSX to React.createElement
26 | "jsx": "react",
27 | // interop between ESM and CJS modules. Recommended by TS
28 | "esModuleInterop": true,
29 | // significant perf increase by skipping checking .d.ts files, particularly those in node_modules. Recommended by TS
30 | "skipLibCheck": true,
31 | // error out if import and file system have a casing mismatch. Recommended by TS
32 | "forceConsistentCasingInFileNames": true,
33 | // `tsdx build` ignores this option, but it is commonly used when type-checking separately with `tsc`
34 | "noEmit": true,
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/tsup.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'tsup';
2 |
3 | export default defineConfig({
4 | entry: ['src/index.ts'],
5 | clean: true,
6 | dts: true,
7 | format: ['esm', 'cjs'],
8 | sourcemap: true,
9 | minify: true,
10 | treeshake: true
11 | });
12 |
--------------------------------------------------------------------------------