From add3ca76b9c2460a43b419b1ee99483120888650 Mon Sep 17 00:00:00 2001 From: Rogin Farrer Date: Sun, 22 Mar 2020 14:10:16 -0400 Subject: [PATCH] Merge v3 into master (#41) * Commit new version! * v3.0.0-2 * improve storybook * try to fix type exports * v3.0.0-3 * add missing warning dependency * v3.0.0-4 * adding cypress, removing some jest tests * update readme with directions to v2 docs Co-authored-by: Rogin Farrer --- .babelrc | 5 - .eslintrc | 17 - .gitignore | 7 +- .prettierignore | 4 - .size-snapshot.json | 12 - .storybook/config.js | 1 + .storybook/main.js | 29 + LICENSE | 2 +- README.md | 19 +- about.mdx | 8 - cypress.json | 3 + cypress/.eslintrc.json | 6 + cypress/fixtures/example.json | 5 + cypress/integration/example-spec.js | 49 + cypress/integration/examples/actions.spec.js | 298 + cypress/integration/examples/aliasing.spec.js | 42 + .../integration/examples/assertions.spec.js | 168 + .../integration/examples/connectors.spec.js | 97 + cypress/integration/examples/cookies.spec.js | 78 + .../integration/examples/cypress_api.spec.js | 222 + cypress/integration/examples/files.spec.js | 114 + .../examples/local_storage.spec.js | 52 + cypress/integration/examples/location.spec.js | 32 + cypress/integration/examples/misc.spec.js | 92 + .../integration/examples/navigation.spec.js | 56 + .../examples/network_requests.spec.js | 195 + cypress/integration/examples/querying.spec.js | 114 + .../examples/spies_stubs_clocks.spec.js | 95 + .../integration/examples/traversal.spec.js | 121 + .../integration/examples/utilities.spec.js | 133 + cypress/integration/examples/viewport.spec.js | 59 + cypress/integration/examples/waiting.spec.js | 34 + cypress/integration/examples/window.spec.js | 22 + cypress/plugins/index.js | 21 + cypress/support/commands.js | 25 + cypress/support/index.js | 20 + docs/_ui-components/ui-components.css | 35 - docs/_ui-components/ui-components.js | 17 - docs/basic/basic-demo.mdx | 39 - docs/basic/index.js | 27 - docs/controlled/controlled.mdx | 41 - docs/controlled/index.js | 30 - docs/nested/nested-demo.mdx | 91 - docs/transition-styles/index.js | 39 - .../transition-styles-demo.mdx | 49 - docs/unmount/unmounted-demo.mdx | 45 - doczrc.js | 10 - example/.npmignore | 3 + example/index.html | 14 + example/index.tsx | 45 + example/package.json | 24 + example/tsconfig.json | 19 + jest.config.js | 3 - package.json | 157 +- prettier.config.js | 5 - rollup.config.js | 85 - src/__tests__/.eslintrc | 8 - src/__tests__/collapse.controlled.jest.js | 42 - src/__tests__/collapse.unmount.jest.js | 44 - .../hooks.use-effect-after-mount.jest.js | 21 - src/__tests__/utils.getElementHeight.jest.js | 15 - .../utils.make-transitions-styles.jest.js | 49 - src/hooks.js | 33 - src/hooks.ts | 60 + src/index.ts | 178 + src/react-collapsed.js | 151 - src/types.ts | 57 + src/utils.js | 46 - src/utils.ts | 46 + stories/components.tsx | 55 + stories/controlled.tsx | 28 + stories/custom-transition-styles.tsx | 41 + stories/div.tsx | 27 + stories/index.stories.tsx | 13 + docs/nested/index.js => stories/nested.tsx | 27 +- stories/uncontrolled.tsx | 25 + docs/unmount/index.js => stories/unmount.tsx | 29 +- tests/hooks.test.ts | 54 + .../collapse.jest.js => tests/index.test.tsx | 105 +- tests/jest.setup.ts | 1 + {src/__mocks__ => tests/mocks}/utils.js | 0 tests/react-collapsed.test.tsx | 175 + .../utils.test.ts | 13 +- tsconfig.json | 32 + yarn.lock | 17216 ++++++++++++---- 85 files changed, 16061 insertions(+), 5565 deletions(-) delete mode 100644 .babelrc delete mode 100644 .eslintrc delete mode 100644 .prettierignore delete mode 100644 .size-snapshot.json create mode 100644 .storybook/config.js create mode 100644 .storybook/main.js delete mode 100644 about.mdx create mode 100644 cypress.json create mode 100644 cypress/.eslintrc.json create mode 100644 cypress/fixtures/example.json create mode 100644 cypress/integration/example-spec.js create mode 100644 cypress/integration/examples/actions.spec.js create mode 100644 cypress/integration/examples/aliasing.spec.js create mode 100644 cypress/integration/examples/assertions.spec.js create mode 100644 cypress/integration/examples/connectors.spec.js create mode 100644 cypress/integration/examples/cookies.spec.js create mode 100644 cypress/integration/examples/cypress_api.spec.js create mode 100644 cypress/integration/examples/files.spec.js create mode 100644 cypress/integration/examples/local_storage.spec.js create mode 100644 cypress/integration/examples/location.spec.js create mode 100644 cypress/integration/examples/misc.spec.js create mode 100644 cypress/integration/examples/navigation.spec.js create mode 100644 cypress/integration/examples/network_requests.spec.js create mode 100644 cypress/integration/examples/querying.spec.js create mode 100644 cypress/integration/examples/spies_stubs_clocks.spec.js create mode 100644 cypress/integration/examples/traversal.spec.js create mode 100644 cypress/integration/examples/utilities.spec.js create mode 100644 cypress/integration/examples/viewport.spec.js create mode 100644 cypress/integration/examples/waiting.spec.js create mode 100644 cypress/integration/examples/window.spec.js create mode 100644 cypress/plugins/index.js create mode 100644 cypress/support/commands.js create mode 100644 cypress/support/index.js delete mode 100644 docs/_ui-components/ui-components.css delete mode 100644 docs/_ui-components/ui-components.js delete mode 100644 docs/basic/basic-demo.mdx delete mode 100644 docs/basic/index.js delete mode 100644 docs/controlled/controlled.mdx delete mode 100644 docs/controlled/index.js delete mode 100644 docs/nested/nested-demo.mdx delete mode 100644 docs/transition-styles/index.js delete mode 100644 docs/transition-styles/transition-styles-demo.mdx delete mode 100644 docs/unmount/unmounted-demo.mdx delete mode 100644 doczrc.js create mode 100644 example/.npmignore create mode 100644 example/index.html create mode 100644 example/index.tsx create mode 100644 example/package.json create mode 100644 example/tsconfig.json delete mode 100644 jest.config.js delete mode 100644 prettier.config.js delete mode 100644 rollup.config.js delete mode 100644 src/__tests__/.eslintrc delete mode 100644 src/__tests__/collapse.controlled.jest.js delete mode 100644 src/__tests__/collapse.unmount.jest.js delete mode 100644 src/__tests__/hooks.use-effect-after-mount.jest.js delete mode 100644 src/__tests__/utils.getElementHeight.jest.js delete mode 100644 src/__tests__/utils.make-transitions-styles.jest.js delete mode 100644 src/hooks.js create mode 100644 src/hooks.ts create mode 100644 src/index.ts delete mode 100644 src/react-collapsed.js create mode 100644 src/types.ts delete mode 100644 src/utils.js create mode 100644 src/utils.ts create mode 100644 stories/components.tsx create mode 100644 stories/controlled.tsx create mode 100644 stories/custom-transition-styles.tsx create mode 100644 stories/div.tsx create mode 100644 stories/index.stories.tsx rename docs/nested/index.js => stories/nested.tsx (75%) create mode 100644 stories/uncontrolled.tsx rename docs/unmount/index.js => stories/unmount.tsx (65%) create mode 100644 tests/hooks.test.ts rename src/__tests__/collapse.jest.js => tests/index.test.tsx (58%) create mode 100644 tests/jest.setup.ts rename {src/__mocks__ => tests/mocks}/utils.js (100%) create mode 100644 tests/react-collapsed.test.tsx rename src/__tests__/utils.call-all.jest.js => tests/utils.test.ts (60%) create mode 100644 tsconfig.json diff --git a/.babelrc b/.babelrc deleted file mode 100644 index cebe7c5..0000000 --- a/.babelrc +++ /dev/null @@ -1,5 +0,0 @@ -{ - "presets": ["@babel/env", "@babel/preset-react"], - "plugins": ["@babel/plugin-syntax-object-rest-spread"], - "exclude": ["./node_modules/**"] -} diff --git a/.eslintrc b/.eslintrc deleted file mode 100644 index 18b87f2..0000000 --- a/.eslintrc +++ /dev/null @@ -1,17 +0,0 @@ -{ - "extends": ["./node_modules/rogin-scripts/eslint.js"], - "plugins": ["react-hooks"], - "settings": { - "react": { - "version": "detect" - } - }, - "rules": { - "react/prop-types": [1], - "no-negated-condition": [0], - "consistent-return": [0], - "jest/no-disabled-tests": [0], - "import/extensions": "off", - "jest/prefer-called-with": "off" - } -} diff --git a/.gitignore b/.gitignore index d982a49..d4de8fc 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,5 @@ +*.log +.DS_Store node_modules +.cache dist -.docz/ -.vscode/ -coverage -.eslintcache \ No newline at end of file diff --git a/.prettierignore b/.prettierignore deleted file mode 100644 index 879b392..0000000 --- a/.prettierignore +++ /dev/null @@ -1,4 +0,0 @@ -.docz -dist -coverage -.vscode \ No newline at end of file diff --git a/.size-snapshot.json b/.size-snapshot.json deleted file mode 100644 index b1d95e9..0000000 --- a/.size-snapshot.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "dist/react-collapsed.cjs.js": { - "bundled": 12405, - "minified": 5824, - "gzipped": 2005 - }, - "dist/react-collapsed.umd.js": { - "bundled": 13277, - "minified": 4781, - "gzipped": 1905 - } -} diff --git a/.storybook/config.js b/.storybook/config.js new file mode 100644 index 0000000..8fca887 --- /dev/null +++ b/.storybook/config.js @@ -0,0 +1 @@ +import 'cypress-storybook/react'; diff --git a/.storybook/main.js b/.storybook/main.js new file mode 100644 index 0000000..83dcb64 --- /dev/null +++ b/.storybook/main.js @@ -0,0 +1,29 @@ +module.exports = { + stories: ['../stories/**/*.stories.(ts|tsx)'], + addons: [ + '@storybook/addon-actions', + '@storybook/addon-links', + '@storybook/addon-a11y', + '@storybook/addon-storysource', + ], + webpackFinal: async config => { + config.module.rules.push({ + test: /\.(ts|tsx)$/, + use: [ + { + loader: require.resolve('ts-loader'), + options: { + transpileOnly: true, + }, + }, + { + loader: require.resolve('react-docgen-typescript-loader'), + }, + ], + }); + + config.resolve.extensions.push('.ts', '.tsx'); + + return config; + }, +}; diff --git a/LICENSE b/LICENSE index ddc1bef..fa36fcc 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2018 Rogin Farrer +Copyright (c) 2019-2020 Rogin Farrer Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index f2d2a39..91cc44e 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,16 @@ -# React-Collapsed (useCollapse) 🙈 +# react-collapsed (useCollapse) -A tiny (< 2kb) custom hook for creating flexible and accessible expand/collapse components in React. +A custom hook for creating flexible and accessible expand/collapse components in React. + +## v3 + +This master branch now reflects the development of the next major release of this library. If you're looking for the latest stable source code, [head over to the v2 branch](https://github.com/roginfarrer/react-collapsed/tree/v2). ## Features - Handles the height of animations of your elements, `auto` included! - You control the UI - `useCollapse` provides the necessary props, you control everything else. - Built with accessibility in mind - no need to worry if your collapse/expand component is accessible, since this takes care of it for you! -- Small footprint (< 2kb gzipped) - No animation framework required! Simply powered by CSS animations ## Demo @@ -17,9 +20,9 @@ A tiny (< 2kb) custom hook for creating flexible and accessible expand/collapse ## Installation ```bash -$ yarn add react-collapsed +$ yarn add react-collapsed@next # or -$ npm i react-collapsed +$ npm i react-collapsed@next ``` ## Usage @@ -31,7 +34,7 @@ import React from 'react'; import useCollapse from 'react-collapsed'; function Demo() { - const {getCollapseProps, getToggleProps, isOpen} = useCollapse(); + const { getCollapseProps, getToggleProps, isOpen } = useCollapse(); return ( @@ -45,12 +48,12 @@ function Demo() { ### Control it yourself ```js -import React, {useState} from 'react'; +import React, { useState } from 'react'; import useCollapse from 'react-collapsed'; function Demo() { const [isOpen, setOpen] = useState(false); - const {getCollapseProps, getToggleProps} = useCollapse({isOpen}); + const { getCollapseProps, getToggleProps } = useCollapse({ isOpen }); return ( diff --git a/about.mdx b/about.mdx deleted file mode 100644 index 245bf3c..0000000 --- a/about.mdx +++ /dev/null @@ -1,8 +0,0 @@ ---- -title: react-collapse -route: / ---- - -import README from './README.md'; - - \ No newline at end of file diff --git a/cypress.json b/cypress.json new file mode 100644 index 0000000..e426660 --- /dev/null +++ b/cypress.json @@ -0,0 +1,3 @@ +{ + "baseUrl": "http://localhost:6006" +} diff --git a/cypress/.eslintrc.json b/cypress/.eslintrc.json new file mode 100644 index 0000000..96a5a52 --- /dev/null +++ b/cypress/.eslintrc.json @@ -0,0 +1,6 @@ +{ + "plugins": ["cypress"], + "env": { + "cypress/globals": true + } +} diff --git a/cypress/fixtures/example.json b/cypress/fixtures/example.json new file mode 100644 index 0000000..da18d93 --- /dev/null +++ b/cypress/fixtures/example.json @@ -0,0 +1,5 @@ +{ + "name": "Using fixtures to represent data", + "email": "hello@cypress.io", + "body": "Fixtures are a great way to mock data for responses to routes" +} \ No newline at end of file diff --git a/cypress/integration/example-spec.js b/cypress/integration/example-spec.js new file mode 100644 index 0000000..0ee5c97 --- /dev/null +++ b/cypress/integration/example-spec.js @@ -0,0 +1,49 @@ +import 'cypress-storybook/cypress'; + +describe('My First Test', function() { + it('Does not do much!', function() { + expect(true).to.equal(true); + }); +}); + +describe('My First Test', function() { + it('Does not do much!', function() { + expect(true).to.equal(false); + }); +}); + +describe('My First Test', function() { + it('clicks the link "type"', function() { + cy.visit('https://example.cypress.io'); + + cy.contains('type').click(); + }); +}); + +describe('RC', () => { + // Note the use of `before` + before(() => { + // Visit the storybook iframe page once per file + cy.visitStorybook(); + }); + + // Note the use of `beforeEach` + beforeEach(() => { + // The first parameter is the category. This is the `title` in CSF or the value in `storiesOf` + // The second parameter is the name of the story. This is the name of the function in CSF or the value in the `add` + // This does not refresh the page, but will unmount any previous story and use the Storybook Router API to render a fresh new story + cy.loadStory('React-Collapsed', 'Uncontrolled'); + }); + + it('toggles open and close the panel', () => { + cy.contains('Close').should('exist'); + cy.contains('Open').should('not.exist'); + cy.contains('In the morning').should('be.visible'); + + cy.contains('Close').click(); + + cy.contains('Close').should('not.exist'); + cy.contains('Open').should('exist'); + cy.contains('In the morning').should('not.be.visible'); + }); +}); diff --git a/cypress/integration/examples/actions.spec.js b/cypress/integration/examples/actions.spec.js new file mode 100644 index 0000000..f26ba63 --- /dev/null +++ b/cypress/integration/examples/actions.spec.js @@ -0,0 +1,298 @@ +/// + +context('Actions', () => { + beforeEach(() => { + cy.visit('https://example.cypress.io/commands/actions') + }) + + // https://on.cypress.io/interacting-with-elements + + it('.type() - type into a DOM element', () => { + // https://on.cypress.io/type + cy.get('.action-email') + .type('fake@email.com').should('have.value', 'fake@email.com') + + // .type() with special character sequences + .type('{leftarrow}{rightarrow}{uparrow}{downarrow}') + .type('{del}{selectall}{backspace}') + + // .type() with key modifiers + .type('{alt}{option}') //these are equivalent + .type('{ctrl}{control}') //these are equivalent + .type('{meta}{command}{cmd}') //these are equivalent + .type('{shift}') + + // Delay each keypress by 0.1 sec + .type('slow.typing@email.com', { delay: 100 }) + .should('have.value', 'slow.typing@email.com') + + cy.get('.action-disabled') + // Ignore error checking prior to type + // like whether the input is visible or disabled + .type('disabled error checking', { force: true }) + .should('have.value', 'disabled error checking') + }) + + it('.focus() - focus on a DOM element', () => { + // https://on.cypress.io/focus + cy.get('.action-focus').focus() + .should('have.class', 'focus') + .prev().should('have.attr', 'style', 'color: orange;') + }) + + it('.blur() - blur off a DOM element', () => { + // https://on.cypress.io/blur + cy.get('.action-blur').type('About to blur').blur() + .should('have.class', 'error') + .prev().should('have.attr', 'style', 'color: red;') + }) + + it('.clear() - clears an input or textarea element', () => { + // https://on.cypress.io/clear + cy.get('.action-clear').type('Clear this text') + .should('have.value', 'Clear this text') + .clear() + .should('have.value', '') + }) + + it('.submit() - submit a form', () => { + // https://on.cypress.io/submit + cy.get('.action-form') + .find('[type="text"]').type('HALFOFF') + cy.get('.action-form').submit() + .next().should('contain', 'Your form has been submitted!') + }) + + it('.click() - click on a DOM element', () => { + // https://on.cypress.io/click + cy.get('.action-btn').click() + + // You can click on 9 specific positions of an element: + // ----------------------------------- + // | topLeft top topRight | + // | | + // | | + // | | + // | left center right | + // | | + // | | + // | | + // | bottomLeft bottom bottomRight | + // ----------------------------------- + + // clicking in the center of the element is the default + cy.get('#action-canvas').click() + + cy.get('#action-canvas').click('topLeft') + cy.get('#action-canvas').click('top') + cy.get('#action-canvas').click('topRight') + cy.get('#action-canvas').click('left') + cy.get('#action-canvas').click('right') + cy.get('#action-canvas').click('bottomLeft') + cy.get('#action-canvas').click('bottom') + cy.get('#action-canvas').click('bottomRight') + + // .click() accepts an x and y coordinate + // that controls where the click occurs :) + + cy.get('#action-canvas') + .click(80, 75) // click 80px on x coord and 75px on y coord + .click(170, 75) + .click(80, 165) + .click(100, 185) + .click(125, 190) + .click(150, 185) + .click(170, 165) + + // click multiple elements by passing multiple: true + cy.get('.action-labels>.label').click({ multiple: true }) + + // Ignore error checking prior to clicking + cy.get('.action-opacity>.btn').click({ force: true }) + }) + + it('.dblclick() - double click on a DOM element', () => { + // https://on.cypress.io/dblclick + + // Our app has a listener on 'dblclick' event in our 'scripts.js' + // that hides the div and shows an input on double click + cy.get('.action-div').dblclick().should('not.be.visible') + cy.get('.action-input-hidden').should('be.visible') + }) + + it('.rightclick() - right click on a DOM element', () => { + // https://on.cypress.io/rightclick + + // Our app has a listener on 'contextmenu' event in our 'scripts.js' + // that hides the div and shows an input on right click + cy.get('.rightclick-action-div').rightclick().should('not.be.visible') + cy.get('.rightclick-action-input-hidden').should('be.visible') + }) + + it('.check() - check a checkbox or radio element', () => { + // https://on.cypress.io/check + + // By default, .check() will check all + // matching checkbox or radio elements in succession, one after another + cy.get('.action-checkboxes [type="checkbox"]').not('[disabled]') + .check().should('be.checked') + + cy.get('.action-radios [type="radio"]').not('[disabled]') + .check().should('be.checked') + + // .check() accepts a value argument + cy.get('.action-radios [type="radio"]') + .check('radio1').should('be.checked') + + // .check() accepts an array of values + cy.get('.action-multiple-checkboxes [type="checkbox"]') + .check(['checkbox1', 'checkbox2']).should('be.checked') + + // Ignore error checking prior to checking + cy.get('.action-checkboxes [disabled]') + .check({ force: true }).should('be.checked') + + cy.get('.action-radios [type="radio"]') + .check('radio3', { force: true }).should('be.checked') + }) + + it('.uncheck() - uncheck a checkbox element', () => { + // https://on.cypress.io/uncheck + + // By default, .uncheck() will uncheck all matching + // checkbox elements in succession, one after another + cy.get('.action-check [type="checkbox"]') + .not('[disabled]') + .uncheck().should('not.be.checked') + + // .uncheck() accepts a value argument + cy.get('.action-check [type="checkbox"]') + .check('checkbox1') + .uncheck('checkbox1').should('not.be.checked') + + // .uncheck() accepts an array of values + cy.get('.action-check [type="checkbox"]') + .check(['checkbox1', 'checkbox3']) + .uncheck(['checkbox1', 'checkbox3']).should('not.be.checked') + + // Ignore error checking prior to unchecking + cy.get('.action-check [disabled]') + .uncheck({ force: true }).should('not.be.checked') + }) + + it('.select() - select an option in a