├── .babelrc
├── .eslintignore
├── .eslintrc.js
├── .github
├── dependabot.yml
└── workflows
│ └── deploy-website.yml
├── .gitignore
├── .npmignore
├── .prettierignore
├── .prettierrc
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── docs
├── .gitignore
├── README.md
├── babel.config.js
├── blog
│ └── .gitkeep
├── docs
│ ├── installation.md
│ ├── introduction.md
│ ├── playground.md
│ ├── theming.md
│ └── usage.md
├── docusaurus.config.js
├── package-lock.json
├── package.json
├── sidebars.js
├── src
│ ├── components
│ │ ├── DemoCodes
│ │ │ ├── AnchorTag.js
│ │ │ ├── Colors.js
│ │ │ ├── Size.js
│ │ │ ├── Style.js
│ │ │ ├── Theming.js
│ │ │ └── UsingIcons.js
│ │ ├── Example
│ │ │ ├── Example.js
│ │ │ ├── Example.scss
│ │ │ ├── Example1.js
│ │ │ ├── Example2.js
│ │ │ ├── Example3.js
│ │ │ └── Example4.js
│ │ └── Playground
│ │ │ ├── EditorPlayground.js
│ │ │ ├── EditorPlayground.scss
│ │ │ ├── InteractivePlayground.js
│ │ │ ├── InteractivePlayground.scss
│ │ │ └── Playground.js
│ ├── css
│ │ ├── bootstrap.scss
│ │ └── custom.css
│ └── pages
│ │ ├── index.js
│ │ └── index.module.css
└── static
│ ├── .nojekyll
│ └── img
│ ├── dependencies.svg
│ ├── favicon.ico
│ ├── logo
│ ├── android-chrome-192x192.png
│ ├── android-chrome-512x512.png
│ ├── apple-touch-icon.png
│ ├── favicon-16x16.png
│ ├── favicon-32x32.png
│ └── logo.png
│ ├── preview.gif
│ └── social_preview.png
├── package-lock.json
├── package.json
├── rollup.config.js
├── src
├── css
│ └── index.css
└── index.js
└── types
└── index.d.ts
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["@babel/env", "@babel/preset-react"]
3 | }
4 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | # dependencies
2 | /node_modules
3 | /.pnp
4 | .pnp.js
5 |
6 | # testing
7 | /coverage
8 |
9 | # production
10 | /build
11 | /dist
12 |
13 | # misc
14 | .DS_Store
15 | .env.local
16 | .env.development.local
17 | .env.test.local
18 | .env.production.local
19 |
20 | npm-debug.log*
21 | yarn-debug.log*
22 | yarn-error.log*
23 | stats.html
24 |
25 | # docs
26 |
27 | # Dependencies
28 | /docs/node_modules
29 |
30 | # Production
31 | /docs/build
32 |
33 | # Generated files
34 | /docs/.docusaurus
35 | /docs/.cache-loader
36 |
37 | # Misc
38 | /docs/.DS_Store
39 | /docs/.env.local
40 | /docs/.env.development.local
41 | /docs/.env.test.local
42 | /docs/.env.production.local
43 |
44 | /docs/npm-debug.log*
45 | /docs/yarn-debug.log*
46 | /docs/yarn-error.log*
47 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | // .eslintrc.js
2 | module.exports = {
3 | env: {
4 | browser: true,
5 | es2021: true,
6 | node: true,
7 | },
8 | extends: [
9 | 'eslint:recommended',
10 | 'plugin:react/recommended',
11 | 'plugin:prettier/recommended',
12 | ],
13 | settings: {
14 | react: {
15 | version: 'detect',
16 | },
17 | },
18 | parserOptions: {
19 | ecmaFeatures: {
20 | jsx: true,
21 | },
22 | ecmaVersion: 'latest',
23 | sourceType: 'module',
24 | },
25 | plugins: ['react'],
26 | rules: {
27 | 'react/react-in-jsx-scope': 'off',
28 | },
29 | };
30 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | - package-ecosystem: 'npm'
4 | directory: '/'
5 | schedule:
6 | interval: 'monthly'
7 |
8 |
--------------------------------------------------------------------------------
/.github/workflows/deploy-website.yml:
--------------------------------------------------------------------------------
1 | name: Deploy docs to GitHub Pages
2 |
3 | on:
4 | push:
5 | branches:
6 | - main
7 |
8 | paths:
9 | - docs/**
10 |
11 | workflow_dispatch:
12 |
13 | permissions:
14 | contents: read
15 | pages: write
16 | id-token: write
17 |
18 | concurrency:
19 | group: ${{ github.workflow }}-${{ github.ref }}
20 | cancel-in-progress: true
21 |
22 | defaults:
23 | run:
24 | working-directory: ./docs
25 |
26 | jobs:
27 | build:
28 | runs-on: ubuntu-latest
29 | steps:
30 | - uses: actions/checkout@v3
31 |
32 | - uses: actions/setup-node@v3
33 | with:
34 | node-version: 16.x
35 | cache: 'npm'
36 | cache-dependency-path: docs/package-lock.json
37 |
38 | - name: Setup Pages
39 | uses: actions/configure-pages@v1
40 |
41 | - name: Restore cache
42 | uses: actions/cache@v3
43 | with:
44 | path: |
45 | **/node_modules
46 | key: ${{ runner.os }}-${{ hashFiles('**/package-lock.json') }}
47 |
48 | - name: Install dependencies
49 | run: npm ci --legacy-peer-deps
50 |
51 | - name: Build with docusaurus
52 | run: npm run build
53 |
54 | - name: Upload artifact
55 | uses: actions/upload-pages-artifact@v1
56 | with:
57 | path: ./docs/build
58 |
59 | deploy:
60 | environment:
61 | name: github-pages
62 | url: ${{ steps.deployment.outputs.page_url }}
63 | runs-on: ubuntu-latest
64 | needs: build
65 | steps:
66 | - name: Deploy to GitHub Pages
67 | id: deployment
68 | uses: actions/deploy-pages@v1
69 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # dependencies
2 | /node_modules
3 | /.pnp
4 | .pnp.js
5 |
6 | # testing
7 | /coverage
8 |
9 | # production
10 | /build
11 | /dist
12 |
13 | # misc
14 | .DS_Store
15 | .env.local
16 | .env.development.local
17 | .env.test.local
18 | .env.production.local
19 |
20 | npm-debug.log*
21 | yarn-debug.log*
22 | yarn-error.log*
23 | stats.html
24 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | /src
2 | /docs
3 | /.github
4 | .babelrc
5 | .eslintignore
6 | .eslintrc.js
7 | .prettierignore
8 | .prettierrc
9 | webpack.config.js
10 | CODE_OF_CONDUCT.md
11 | CONTRIBUTING.md
12 | rollup.config.js
13 | stats.html
14 |
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | # dependencies
2 | /node_modules
3 | /.pnp
4 | .pnp.js
5 |
6 | # testing
7 | /coverage
8 |
9 | # production
10 | /build
11 | /dist
12 |
13 | # misc
14 | .DS_Store
15 | .env.local
16 | .env.development.local
17 | .env.test.local
18 | .env.production.local
19 |
20 | npm-debug.log*
21 | yarn-debug.log*
22 | yarn-error.log*
23 | stats.html
24 |
25 | # docs
26 |
27 | # Dependencies
28 | /docs/node_modules
29 |
30 | # Production
31 | /docs/build
32 |
33 | # Generated files
34 | /docs/.docusaurus
35 | /docs/.cache-loader
36 |
37 | # Misc
38 | /docs/.DS_Store
39 | /docs/.env.local
40 | /docs/.env.development.local
41 | /docs/.env.test.local
42 | /docs/.env.production.local
43 |
44 | /docs/npm-debug.log*
45 | /docs/yarn-debug.log*
46 | /docs/yarn-error.log*
47 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "semi": true,
3 | "arrowParens": "always",
4 | "bracketSpacing": true,
5 | "printWidth": 80,
6 | "singleQuote": true,
7 | "tabWidth": 2
8 | }
9 |
--------------------------------------------------------------------------------
/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
77 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | 👍🎉 First off, thanks for taking the time to contribute! 🎉👍
4 |
5 | If you have found an issue or would like to request a new feature, simply create a new issue detailing the request. We also welcome pull requests. See below for information on getting started with development and submitting pull requests.
6 |
7 | Please note we have a [code of conduct](https://github.com/arifszn/reactive-button/blob/main/CODE_OF_CONDUCT.md), please follow it in all your interactions with the project.
8 |
9 | ## Found an Issue?
10 |
11 | If you find a bug in the source code or a mistake in the documentation, you can help us by
12 | submitting an issue to our [GitHub Repository](https://github.com/arifszn/reactive-button/issues/new). Even better you can submit a Pull Request
13 | with a fix.
14 |
15 | ## Submitting a Pull Request
16 |
17 | - If applicable, update the `readme`
18 | - Use `npm run lint` and `npm run prettier` before committing
19 | - Example for a commit message
20 |
21 | ```
22 | Fix type validation for typescript
23 | ```
24 |
25 | ### Developing
26 |
27 | Fork, then clone the repo:
28 |
29 | ```sh
30 | git clone https://github.com/your-username/reactive-button.git
31 | cd reactive-button
32 | ```
33 |
34 | Install dependencies:
35 |
36 | ```sh
37 | npm install
38 | ```
39 |
40 | ### Building
41 |
42 | Running the `build` task will create the `dist` version of the project.
43 |
44 | ```sh
45 | npm run build
46 | ```
47 |
48 | ### Project Structure
49 |
50 | ```text
51 | root
52 | ├── dist
53 | └── src
54 | └── css
55 | └── types
56 | ```
57 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 Ariful Alam
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
3D animated react button component with progress bar.
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 | Documentation
45 | ·
46 | Report Bug
47 | ·
48 | Request Feature
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 | **Reactive Button** is a 3D animated react component to replace the traditional boring buttons. Change your button style without adding any UI framework. Comes with progress bar and the goal is to let the users visualize what is happening after a button click.
59 |
60 | - 3D
61 | - Animated
62 | - Supports icons
63 | - Zero dependency
64 | - Progress indicator
65 | - Notification message
66 | - Supports TypeScript
67 | - Super easy to setup
68 | - Extremely lightweight
69 | - Super easy to customize
70 | - And much more !
71 |
72 | ## Resources
73 |
74 | - [Documentation](https://arifszn.github.io/reactive-button)
75 | - [Playground](https://arifszn.github.io/reactive-button/docs/playground)
76 | - [StackBlitz](https://stackblitz.com/edit/reactive-button)
77 |
78 | ## Installation
79 |
80 | Install via NPM .
81 |
82 | ```sh
83 | npm install reactive-button
84 | ```
85 |
86 | Or via Yarn .
87 |
88 | ```sh
89 | yarn add reactive-button
90 | ```
91 |
92 | ## Usage
93 |
94 | The targets of the below example:
95 |
96 | - Show a button showing the text '_Submit_'.
97 | - After clicking the button, change the button text to '_Loading_' and send an HTTP request.
98 | - Upon successful request, change the button text to '_Done_' as success notification.
99 |
100 | ```jsx
101 | import { useState } from 'react';
102 | import ReactiveButton from 'reactive-button';
103 |
104 | function App() {
105 | const [state, setState] = useState('idle');
106 |
107 | const onClickHandler = () => {
108 | setState('loading');
109 |
110 | // send an HTTP request
111 | setTimeout(() => {
112 | setState('success');
113 | }, 2000);
114 | };
115 |
116 | return (
117 |
124 | );
125 | }
126 |
127 | export default App;
128 | ```
129 |
130 | ### Other Usage
131 |
132 | Reactive Button has all the functionalities of a normal button.
133 |
134 | #### Color
135 |
136 | It comes with 10 default color options.
137 |
138 | ```jsx
139 | return (
140 | <>
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 | >
152 | );
153 | ```
154 |
155 | #### Size
156 |
157 | There are 4 sizes available.
158 |
159 | ```jsx
160 | return (
161 | <>
162 |
163 |
164 |
165 |
166 | >
167 | );
168 | ```
169 |
170 | #### Style
171 |
172 | Make the buttons more beautiful with these customization options.
173 |
174 | ```jsx
175 | return (
176 | <>
177 |
178 |
179 |
180 | >
181 | );
182 | ```
183 |
184 | #### Existing State
185 |
186 | In your project, There might be existing state for loading indicator which accepts boolean value only. If you don't want to define new state for Reactive Button, then utilize the existing state.
187 |
188 | ```jsx
189 | const [loading, setLoading] = useState(false);
190 |
191 | return (
192 |
197 | );
198 | ```
199 |
200 | #### Without State
201 |
202 | `state` is not mandatory.
203 |
204 | ```jsx
205 | return ;
206 | ```
207 |
208 | #### Using Icons
209 |
210 | You can use your own icons. Don't forget to wrap them with a parent element.
211 |
212 | ```jsx
213 | return (
214 |
217 | Send
218 |
219 | }
220 | />
221 | );
222 | ```
223 |
224 | #### Form Submit
225 |
226 | If you need to submit form by button clicking, set the type
prop as 'submit '.
227 |
228 | ```jsx
229 | return (
230 |
235 | );
236 | ```
237 |
238 | #### Anchor Tag
239 |
240 | To use Reactive button as anchor tag, simply wrap it with an anchor tag.
241 |
242 | ```jsx
243 | return (
244 |
245 |
246 |
247 | );
248 | ```
249 |
250 | ## Available Props
251 |
252 | | Props | Type | Description | Default |
253 | | :-------------: | :---------------------: | :-------------------------------------------------------------------------------------------------------------------------------: | :----------: |
254 | | buttonState | `string` | `'idle'` \| `'loading'` \| `'success'` \| `'error'` | `'idle'` |
255 | | onClick | `function` | Callback function when clicking button | `() => {}` |
256 | | color | `string` | `'primary'` \| `'secondary'` \| `'dark'` \| `'light'` \| `'green'` \| `'red'` \| `'yellow'` \| `'teal'` \| `'violet'` \| `'blue'` | `'primary'` |
257 | | idleText | `string` \| `ReactNode` | Button text when idle | `'Click Me'` |
258 | | loadingText | `string` \| `ReactNode` | Button text when loading | `'Loading'` |
259 | | successText | `string` \| `ReactNode` | Button text when loading successful | `'Success'` |
260 | | errorText | `string` \| `ReactNode` | Button text when loading failed | `'Error'` |
261 | | type | `string` | `'button'` \| `'submit'` \| `'reset'` | `'button'` |
262 | | className | `string` | Button classnames | `''` |
263 | | style | `React.CSSProperties` | Custom style | `{}` |
264 | | outline | `boolean` | Enable outline effect | `false` |
265 | | shadow | `boolean` | Enable shadow effect | `false` |
266 | | rounded | `boolean` | Enable rounded button | `false` |
267 | | size | `string` | `'tiny'` \| `'small'` \| `'normal'` \| `'large'` | `'normal'` |
268 | | block | `boolean` | Block Button | `false` |
269 | | messageDuration | `number` | Success/Error message duration in millisecond | `2000` |
270 | | disabled | `boolean` | Disable button | `false` |
271 | | buttonRef | `React.Ref` \| `null` | Button reference | `null` |
272 | | width | `string` \| `null` | Override button width | `null` |
273 | | height | `string` \| `null` | Override button height | `null` |
274 | | animation | `boolean` | Button hover and click animation | `true` |
275 |
276 | ## Support
277 |
278 | You can show your support by starring this project.
279 |
280 |
281 |
282 |
283 | ## Contribute
284 |
285 | To contribute, see the [contributing guide](https://github.com/arifszn/reactive-button/blob/main/CONTRIBUTING.md).
286 |
287 | ## License
288 |
289 | [MIT License](https://github.com/arifszn/reactive-button/blob/main/LICENSE)
290 |
--------------------------------------------------------------------------------
/docs/.gitignore:
--------------------------------------------------------------------------------
1 | # Dependencies
2 | /node_modules
3 |
4 | # Production
5 | /build
6 |
7 | # Generated files
8 | .docusaurus
9 | .cache-loader
10 |
11 | # Misc
12 | .DS_Store
13 | .env.local
14 | .env.development.local
15 | .env.test.local
16 | .env.production.local
17 |
18 | npm-debug.log*
19 | yarn-debug.log*
20 | yarn-error.log*
21 |
--------------------------------------------------------------------------------
/docs/README.md:
--------------------------------------------------------------------------------
1 | # Reactive Button Doc
2 |
3 | This website is built using [Docusaurus 2](https://docusaurus.io/), a modern static website generator.
4 |
5 | ## Installation
6 |
7 | ```console
8 | yarn install
9 | ```
10 |
11 | ## Local Development
12 |
13 | ```console
14 | yarn start
15 | ```
16 |
17 | This command starts a local development server and opens up a browser window. Most changes are reflected live without having to restart the server.
18 |
19 | ## Build
20 |
21 | ```console
22 | yarn build
23 | ```
24 |
25 | This command generates static content into the `build` directory and can be served using any static contents hosting service.
26 |
27 | ## Deployment
28 |
29 | ```console
30 | GIT_USER= USE_SSH=true yarn deploy
31 | ```
32 |
33 | If you are using GitHub pages for hosting, this command is a convenient way to build the website and push to the `gh-pages` branch.
34 |
--------------------------------------------------------------------------------
/docs/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [require.resolve('@docusaurus/core/lib/babel/preset')],
3 | };
4 |
--------------------------------------------------------------------------------
/docs/blog/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arifszn/reactive-button/b1c129b39c3ddbba0cf6f2399c18964046f4cfaf/docs/blog/.gitkeep
--------------------------------------------------------------------------------
/docs/docs/installation.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: installation
3 | title: Installation
4 | ---
5 |
6 | ## Requirements
7 |
8 | - React version >= `16.8 or above`
9 |
10 | ## Installation
11 |
12 | Install via NPM
13 |
14 | ```sh
15 | npm install reactive-button
16 | ```
17 |
18 | Install via Yarn
19 |
20 | ```sh
21 | yarn add reactive-button
22 | ```
23 |
--------------------------------------------------------------------------------
/docs/docs/introduction.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: introduction
3 | title: Introduction
4 | sidebar_label: Introduction
5 | hide_title: true
6 | ---
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 | **Reactive Button** is a 3D animated react component to replace the traditional boring buttons. Change your button style without adding any UI framework. Comes with progress bar and the goal is to let the users visualize what is happening after a button click.
55 |
56 | ## Example
57 |
58 | import Example from '../src/components/Example/Example';
59 |
60 |
61 |
62 | ## Features
63 |
64 | - 3D
65 | - Animated
66 | - Supports icons
67 | - Zero dependency
68 | - Progress indicator
69 | - Notification message
70 | - Supports TypeScript
71 | - Super easy to setup
72 | - Extremely lightweight
73 | - Super easy to customize
74 | - And much more !
75 |
76 | ## Support
77 |
78 | You can show your support by starring this project.
79 |
80 |
81 |
82 |
83 | ## Contribute
84 |
85 | To contribute, see the [contributing guide](https://github.com/arifszn/reactive-button/blob/main/CONTRIBUTING.md).
86 |
87 | ## License
88 |
89 | [MIT License](https://github.com/arifszn/reactive-button/blob/main/LICENSE)
90 |
--------------------------------------------------------------------------------
/docs/docs/playground.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: playground
3 | title: Playground
4 | ---
5 |
6 | Playground for Reactive Button.
7 |
8 | ## Interactive Playground
9 |
10 | Toggle or change the props to see changes.
11 |
12 | import InteractivePlayground from '../src/components/Playground/InteractivePlayground';
13 |
14 |
15 |
16 | ## Editor Playground
17 |
18 | Edit code to see changes.
19 |
20 | import EditorPlayground from '../src/components/Playground/EditorPlayground';
21 |
22 |
23 |
--------------------------------------------------------------------------------
/docs/docs/theming.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: theming
3 | title: Theming
4 | ---
5 |
6 | Reactive Button provides flexible styling option. Most of the common style changes can be achieved by using the style
prop.
7 |
8 | import Playground from '../src/components/Playground/Playground'
9 | import Theming from '../src/components/DemoCodes/Theming'
10 | import ReactiveButton from 'reactive-button'
11 |
12 |
19 |
20 | However, you are free to create your own theme.
21 |
22 | ## Custom Theme
23 |
24 | Modify the values how you prefer and use it in your existing css file.
25 |
26 |
27 |
28 | ```css
29 | .reactive-btn-wrapper,
30 | .reactive-btn {
31 | --reactive-button-min-width: 100px !important;
32 | --reactive-button-min-height: 35px !important;
33 | --reactive-button-font-size: 14px !important;
34 | --reactive-button-font-weight: 400 !important;
35 | --reactive-button-border-radius: 0px !important;
36 | --reactive-button-text-color: #ffffff !important;
37 | --reactive-progress-color: rgba(0, 0, 0, 0.15) !important;
38 |
39 | --reactive-button-primary-color: rgba(88, 103, 221, 1) !important;
40 | --reactive-button-secondary-color: rgba(108, 117, 125, 1) !important;
41 | --reactive-button-dark-color: rgba(66, 78, 106, 1) !important;
42 | --reactive-button-light-color: rgba(183, 186, 191, 1) !important;
43 | --reactive-button-green-color: rgba(37, 162, 51, 1) !important;
44 | --reactive-button-red-color: rgba(244, 81, 108, 1) !important;
45 | --reactive-button-yellow-color: rgba(255, 193, 7, 1) !important;
46 | --reactive-button-teal-color: rgba(0, 181, 173, 1) !important;
47 | --reactive-button-violet-color: rgba(100, 53, 201, 1) !important;
48 | --reactive-button-blue-color: rgba(66, 153, 225, 1) !important;
49 |
50 | --reactive-progress-outline-primary-color: rgba(88, 103, 221, 0.3) !important;
51 | --reactive-progress-outline-secondary-color: rgba(108, 117, 125, 0.3) !important;
52 | --reactive-progress-outline-dark-color: rgba(66, 78, 106, 0.3) !important;
53 | --reactive-progress-outline-light-color: rgba(214, 212, 212, 0.3) !important;
54 | --reactive-progress-outline-green-color: rgba(37, 162, 51, 0.3) !important;
55 | --reactive-progress-outline-red-color: rgba(244, 81, 108, 0.3) !important;
56 | --reactive-progress-outline-yellow-color: rgba(255, 193, 7, 0.3) !important;
57 | --reactive-progress-outline-teal-color: rgba(0, 181, 173, 0.3) !important;
58 | --reactive-progress-outline-violet-color: rgba(100, 53, 201, 0.3) !important;
59 | --reactive-progress-outline-blue-color: rgba(66, 153, 225, 0.3) !important;
60 | }
61 | ```
62 |
63 |
--------------------------------------------------------------------------------
/docs/docs/usage.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: usage
3 | title: Usage
4 | ---
5 |
6 | import Playground from '../src/components/Playground/Playground'
7 | import UsingIcons from '../src/components/DemoCodes/UsingIcons'
8 | import AnchorTag from '../src/components/DemoCodes/AnchorTag'
9 | import Colors from '../src/components/DemoCodes/Colors'
10 | import Size from '../src/components/DemoCodes/Size'
11 | import Style from '../src/components/DemoCodes/Style'
12 | import ReactiveButton from 'reactive-button'
13 | import { faReply } from '@fortawesome/free-solid-svg-icons';
14 | import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
15 |
16 | The targets of the below example:
17 |
18 | - Show a button showing the text '_Submit_'.
19 | - After clicking the button, change the button text to '_Loading_' and send an HTTP request.
20 | - Upon successful request, change the button text to '_Done_' as success notification.
21 |
22 | ```jsx
23 | import { useState } from 'react';
24 | import ReactiveButton from 'reactive-button';
25 |
26 | function App() {
27 | const [state, setState] = useState('idle');
28 |
29 | const onClickHandler = () => {
30 | setState('loading');
31 |
32 | // send an HTTP request
33 | setTimeout(() => {
34 | setState('success');
35 | }, 2000);
36 | };
37 |
38 | return (
39 |
46 | );
47 | }
48 |
49 | export default App;
50 | ```
51 |
52 | ## Other Usage
53 |
54 | Reactive Button has all the functionalities of a normal button.
55 |
56 | ### Color
57 |
58 | Reactive Button comes with 10 default color options.
59 |
60 |
67 |
68 | ```jsx
69 | return (
70 | <>
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 | >
82 | );
83 | ```
84 |
85 | ### Size
86 |
87 | There are 4 sizes available.
88 |
89 |
96 |
97 | ```jsx
98 | return (
99 | <>
100 |
101 |
102 |
103 |
104 | >
105 | );
106 | ```
107 |
108 | ### Style
109 |
110 | Make the buttons more beautiful with these customization options.
111 |
112 |
119 |
120 | ```jsx
121 | return (
122 | <>
123 |
124 |
125 |
126 | >
127 | );
128 | ```
129 |
130 | ### Existing State
131 |
132 | In your project, There might be existing state for loading indicator which accepts boolean value only. If you don't want to define new state for Reactive Button, then utilize the existing state.
133 |
134 | ```jsx
135 | const [loading, setLoading] = useState(false);
136 |
137 | return (
138 |
143 | );
144 | ```
145 |
146 | ### Without State
147 |
148 | `state` is not mandatory.
149 |
150 | ```jsx
151 | return ;
152 | ```
153 |
154 | ### Using Icons
155 |
156 | You can use your own icons. Don't forget to wrap them with a parent element.
157 |
158 |
165 |
166 | ```jsx
167 | return (
168 |
171 | Send
172 |
173 | }
174 | />
175 | );
176 | ```
177 |
178 | ### Form Submit
179 |
180 | If you need to submit form by button clicking, set the type
prop as 'submit '.
181 |
182 | ```jsx
183 | return (
184 |
189 | );
190 | ```
191 |
192 | ### Anchor Tag
193 |
194 | To use Reactive button as anchor tag, simply wrap it with an anchor tag.
195 |
196 |
203 |
204 | ```jsx
205 | return (
206 |
207 |
208 |
209 | );
210 | ```
211 |
212 | import Link from '@docusaurus/Link';
213 |
214 | Note: For more usage, visit Playground.
215 |
216 | ## Available Props
217 |
218 | | Props | Type | Description | Default |
219 | | :-------------: | :---------------------: | :-------------------------------------------------------------------------------------------------------------------------------: | :----------: |
220 | | buttonState | `string` | `'idle'` \| `'loading'` \| `'success'` \| `'error'` | `'idle'` |
221 | | onClick | `function` | Callback function when clicking button | `() => {}` |
222 | | color | `string` | `'primary'` \| `'secondary'` \| `'dark'` \| `'light'` \| `'green'` \| `'red'` \| `'yellow'` \| `'teal'` \| `'violet'` \| `'blue'` | `'primary'` |
223 | | idleText | `string` \| `ReactNode` | Button text when idle | `'Click Me'` |
224 | | loadingText | `string` \| `ReactNode` | Button text when loading | `'Loading'` |
225 | | successText | `string` \| `ReactNode` | Button text when loading successful | `'Success'` |
226 | | errorText | `string` \| `ReactNode` | Button text when loading failed | `'Error'` |
227 | | type | `string` | `'button'` \| `'submit'` \| `'reset'` | `'button'` |
228 | | className | `string` | Button classnames | `''` |
229 | | style | `React.CSSProperties` | Custom style | `{}` |
230 | | outline | `boolean` | Enable outline effect | `false` |
231 | | shadow | `boolean` | Enable shadow effect | `false` |
232 | | rounded | `boolean` | Enable rounded button | `false` |
233 | | size | `string` | `'tiny'` \| `'small'` \| `'normal'` \| `'large'` | `'normal'` |
234 | | block | `boolean` | Block Button | `false` |
235 | | messageDuration | `number` | Success/Error message duration in millisecond | `2000` |
236 | | disabled | `boolean` | Disable button | `false` |
237 | | buttonRef | `React.Ref` \| `null` | Button reference | `null` |
238 | | width | `string` \| `null` | Override button width | `null` |
239 | | height | `string` \| `null` | Override button height | `null` |
240 | | animation | `boolean` | Button hover and click animation | `true` |
241 |
--------------------------------------------------------------------------------
/docs/docusaurus.config.js:
--------------------------------------------------------------------------------
1 | // @ts-check
2 | // Note: type annotations allow type checking and IDEs autocompletion
3 |
4 | const lightCodeTheme = require('prism-react-renderer/themes/palenight');
5 | const darkCodeTheme = require('prism-react-renderer/themes/palenight');
6 |
7 | /** @type {import('@docusaurus/types').DocusaurusConfig} */
8 | module.exports = {
9 | title: 'Reactive Button',
10 | tagline: '3D animated react button component with progress bar',
11 | url: 'https://arifszn.github.io',
12 | baseUrl: '/reactive-button/',
13 | onBrokenLinks: 'throw',
14 | onBrokenMarkdownLinks: 'warn',
15 | favicon: 'img/favicon.ico',
16 | organizationName: 'arifszn',
17 | projectName: 'reactive-button',
18 | trailingSlash: false,
19 | customFields: {
20 | description:
21 | 'Reactive Button is a 3D animated react component to replace the traditional boring buttons. Change your button style without adding any UI framework. Comes with progress bar and the goal is to let the users visualize what is happening after a button click.',
22 | },
23 | themeConfig: {
24 | navbar: {
25 | title: 'Reactive Button',
26 | hideOnScroll: false,
27 | logo: {
28 | alt: 'Logo',
29 | src: 'img/logo/logo.png',
30 | },
31 | items: [
32 | {
33 | type: 'doc',
34 | docId: 'introduction',
35 | position: 'left',
36 | label: 'Docs',
37 | },
38 | {
39 | href: 'https://github.com/arifszn/reactive-button',
40 | position: 'right',
41 | 'aria-label': 'GitHub repository',
42 | className: 'header-github-link',
43 | },
44 | ],
45 | },
46 | footer: {
47 | style: 'light',
48 | copyright: `Copyright © ${new Date().getFullYear()} Ariful Alam `,
49 | },
50 | metadata: [
51 | {
52 | name: 'Reactive Button',
53 | content: '3D animated react button component with progress bar.',
54 | },
55 | ],
56 | image: 'img/logo/logo.png',
57 | announcementBar: {
58 | id: 'reactive_button_support_us',
59 | content:
60 | '⭐️ If you like this project, give it a star on GitHub ⭐️',
61 | // backgroundColor: "#fafbfc", // Defaults to `#fff`.
62 | // textColor: "#091E42", // Defaults to `#000`.
63 | // isCloseable: true, // Defaults to `true`.
64 | },
65 | colorMode: {
66 | defaultMode: 'light',
67 | disableSwitch: false,
68 | respectPrefersColorScheme: true,
69 | },
70 | prism: {
71 | theme: lightCodeTheme,
72 | darkTheme: darkCodeTheme,
73 | },
74 | },
75 | presets: [
76 | [
77 | '@docusaurus/preset-classic',
78 | {
79 | docs: {
80 | sidebarPath: require.resolve('./sidebars.js'),
81 | },
82 | theme: {
83 | customCss: require.resolve('./src/css/custom.css'),
84 | },
85 | blog: false,
86 | sitemap: {
87 | changefreq: 'weekly',
88 | priority: 0.5,
89 | },
90 | gtag: {
91 | trackingID: '2EH3VSS6EB',
92 | },
93 | },
94 | ],
95 | ],
96 | plugins: [
97 | require.resolve('docusaurus-plugin-sass'),
98 | [
99 | '@docusaurus/plugin-client-redirects',
100 | {
101 | redirects: [
102 | {
103 | from: '/docs',
104 | to: '/docs/introduction',
105 | },
106 | ],
107 | },
108 | ],
109 | ],
110 | themes: [
111 | [
112 | require.resolve('@easyops-cn/docusaurus-search-local'),
113 | {
114 | hashed: true,
115 | highlightSearchTermsOnTargetPage: true,
116 | explicitSearchResultPath: true,
117 | },
118 | ],
119 | ],
120 | };
121 |
--------------------------------------------------------------------------------
/docs/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "reactive-button-doc",
3 | "private": true,
4 | "scripts": {
5 | "docusaurus": "docusaurus",
6 | "start": "docusaurus start",
7 | "build": "docusaurus build",
8 | "swizzle": "docusaurus swizzle",
9 | "deploy": "docusaurus deploy",
10 | "clear": "docusaurus clear",
11 | "serve": "docusaurus serve",
12 | "write-translations": "docusaurus write-translations",
13 | "write-heading-ids": "docusaurus write-heading-ids"
14 | },
15 | "dependencies": {
16 | "@docusaurus/core": "^2.0.1",
17 | "@docusaurus/plugin-client-redirects": "^2.1.0",
18 | "@docusaurus/preset-classic": "^2.0.1",
19 | "@easyops-cn/docusaurus-search-local": "^0.31.0",
20 | "@fortawesome/free-solid-svg-icons": "^6.2.0",
21 | "@fortawesome/react-fontawesome": "^0.2.0",
22 | "@mdx-js/react": "1.6.22",
23 | "@svgr/webpack": "^6.3.1",
24 | "clsx": "^1.1.1",
25 | "docusaurus-plugin-sass": "^0.2.2",
26 | "file-loader": "^6.2.0",
27 | "react": "^17.0.2",
28 | "react-dom": "^17.0.2",
29 | "react-icons": "^4.2.0",
30 | "react-live": "2.4.1",
31 | "reactive-button": "^1.3.13",
32 | "sass": "^1.54.5",
33 | "styled-components": "^5.3.0",
34 | "url-loader": "^4.1.1"
35 | },
36 | "browserslist": {
37 | "production": [
38 | ">0.5%",
39 | "not dead",
40 | "not op_mini all"
41 | ],
42 | "development": [
43 | "last 1 chrome version",
44 | "last 1 firefox version",
45 | "last 1 safari version"
46 | ]
47 | },
48 | "devDependencies": {
49 | "eslint": "^8.25.0",
50 | "eslint-config-prettier": "^8.5.0",
51 | "eslint-plugin-prettier": "^4.0.0",
52 | "eslint-plugin-react": "^7.29.4",
53 | "prettier": "^2.5.1",
54 | "prop-types": "^15.8.1"
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/docs/sidebars.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | docs: ['introduction', 'installation', 'usage', 'playground', 'theming'],
3 | };
4 |
--------------------------------------------------------------------------------
/docs/src/components/DemoCodes/AnchorTag.js:
--------------------------------------------------------------------------------
1 | const AnchorTag = `
2 |
3 |
4 |
5 | `;
6 |
7 | export default AnchorTag;
8 |
--------------------------------------------------------------------------------
/docs/src/components/DemoCodes/Colors.js:
--------------------------------------------------------------------------------
1 | const Colors = `
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 | `;
39 |
40 | export default Colors;
41 |
--------------------------------------------------------------------------------
/docs/src/components/DemoCodes/Size.js:
--------------------------------------------------------------------------------
1 | const Size = `
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | `;
19 |
20 | export default Size;
21 |
--------------------------------------------------------------------------------
/docs/src/components/DemoCodes/Style.js:
--------------------------------------------------------------------------------
1 | const Style = `
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | `;
16 |
17 | export default Style;
18 |
--------------------------------------------------------------------------------
/docs/src/components/DemoCodes/Theming.js:
--------------------------------------------------------------------------------
1 | const Theming = `
2 |
8 | `;
9 |
10 | export default Theming;
11 |
--------------------------------------------------------------------------------
/docs/src/components/DemoCodes/UsingIcons.js:
--------------------------------------------------------------------------------
1 | const UsingIcons = `
2 |
5 | Send
6 |
7 | }
8 | />
9 | `;
10 |
11 | export default UsingIcons;
12 |
--------------------------------------------------------------------------------
/docs/src/components/Example/Example.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Example1 from './Example1';
3 | import Example2 from './Example2';
4 | import Example3 from './Example3';
5 | import Example4 from './Example4';
6 | import './Example.scss';
7 |
8 | const Example = () => {
9 | return (
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | );
19 | };
20 |
21 | export default Example;
22 |
--------------------------------------------------------------------------------
/docs/src/components/Example/Example.scss:
--------------------------------------------------------------------------------
1 | .example-component-wrapper {
2 | .reactive-btn-wrapper,
3 | .reactive-btn {
4 | --reactive-button-font-size: 13px !important;
5 | }
6 | .flex-section {
7 | padding-bottom: 6px;
8 | padding-top: 6px;
9 | }
10 | .flex-section .item {
11 | padding: 10px;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/docs/src/components/Example/Example1.js:
--------------------------------------------------------------------------------
1 | import React, { useRef, useState } from 'react';
2 | import ReactiveButton from 'reactive-button';
3 |
4 | const Example1 = () => {
5 | const [button1, setButton1] = useState({
6 | ref: useRef(),
7 | color: 'primary',
8 | idleText: 'Primary',
9 | loadingText: 'Loading',
10 | successText: 'Success',
11 | errorText: 'Error',
12 | buttonState: 'idle',
13 | endState: 'success',
14 | });
15 |
16 | const [button2, setButton2] = useState({
17 | ref: useRef(),
18 | color: 'secondary',
19 | idleText: 'Secondary',
20 | loadingText: 'Loading',
21 | successText: 'Success',
22 | errorText: 'Error',
23 | buttonState: 'idle',
24 | endState: 'success',
25 | });
26 |
27 | const [button3, setButton3] = useState({
28 | ref: useRef(),
29 | color: 'teal',
30 | idleText: 'Teal',
31 | loadingText: 'Loading',
32 | successText: 'Success',
33 | errorText: 'Error',
34 | buttonState: 'idle',
35 | endState: 'success',
36 | });
37 |
38 | const [button4, setButton4] = useState({
39 | ref: useRef(),
40 | color: 'green',
41 | idleText: 'Green',
42 | loadingText: 'Loading',
43 | successText: 'Success',
44 | errorText: 'Error',
45 | buttonState: 'idle',
46 | endState: 'success',
47 | });
48 |
49 | const [button5, setButton5] = useState({
50 | ref: useRef(),
51 | color: 'red',
52 | idleText: 'Red',
53 | loadingText: 'Loading',
54 | successText: 'Success',
55 | errorText: 'Error',
56 | buttonState: 'idle',
57 | endState: 'success',
58 | });
59 |
60 | const buttons = [
61 | [button1, setButton1],
62 | [button2, setButton2],
63 | [button3, setButton3],
64 | [button4, setButton4],
65 | [button5, setButton5],
66 | ];
67 |
68 | const onClickHandler = (index) => {
69 | buttons[index][1]({
70 | ...buttons[index][0],
71 | buttonState: 'loading',
72 | });
73 | setTimeout(() => {
74 | buttons[index][1]({
75 | ...buttons[index][0],
76 | buttonState: buttons[index][0].endState,
77 | });
78 | }, 2000);
79 | };
80 |
81 | return (
82 |
83 |
84 | {buttons.map((button, index) => (
85 |
86 | {
95 | onClickHandler(index);
96 | }}
97 | />
98 |
99 | ))}
100 |
101 |
102 | );
103 | };
104 |
105 | export default Example1;
106 |
--------------------------------------------------------------------------------
/docs/src/components/Example/Example2.js:
--------------------------------------------------------------------------------
1 | import {
2 | faCalendarCheck,
3 | faCheck,
4 | faCheckCircle,
5 | faSpinner,
6 | faThumbsUp,
7 | faTimes,
8 | faUserCheck,
9 | } from '@fortawesome/free-solid-svg-icons';
10 | import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
11 | import React, { useEffect, useRef, useState } from 'react';
12 | import ReactiveButton from 'reactive-button';
13 |
14 | const Example2 = () => {
15 | const [button1, setButton1] = useState({
16 | ref: useRef(),
17 | color: 'violet',
18 | idleText: 'Violet',
19 | loadingText: (
20 |
21 | Loading
22 |
23 | ),
24 | successText: (
25 |
26 | Success
27 |
28 | ),
29 | errorText: (
30 |
31 | Error
32 |
33 | ),
34 | buttonState: 'idle',
35 | endState: 'success',
36 | });
37 |
38 | const [button2, setButton2] = useState({
39 | ref: useRef(),
40 | color: 'blue',
41 | idleText: 'Blue',
42 | loadingText: (
43 |
44 | Loading
45 |
46 | ),
47 | successText: (
48 |
49 | Success
50 |
51 | ),
52 | errorText: (
53 |
54 | Error
55 |
56 | ),
57 | buttonState: 'idle',
58 | endState: 'success',
59 | });
60 |
61 | const [button3, setButton3] = useState({
62 | ref: useRef(),
63 | color: 'yellow',
64 | idleText: 'Yellow',
65 | loadingText: (
66 |
67 | Loading
68 |
69 | ),
70 | successText: (
71 |
72 | Success
73 |
74 | ),
75 | errorText: (
76 |
77 | Error
78 |
79 | ),
80 | buttonState: 'idle',
81 | endState: 'success',
82 | });
83 |
84 | const [button4, setButton4] = useState({
85 | ref: useRef(),
86 | color: 'dark',
87 | idleText: 'Dark',
88 | loadingText: (
89 |
90 | Loading
91 |
92 | ),
93 | successText: (
94 |
95 | Success
96 |
97 | ),
98 | errorText: (
99 |
100 | Error
101 |
102 | ),
103 | buttonState: 'idle',
104 | endState: 'success',
105 | });
106 |
107 | const [button5, setButton5] = useState({
108 | ref: useRef(),
109 | color: 'light',
110 | idleText: 'Light',
111 | loadingText: (
112 |
113 | Loading
114 |
115 | ),
116 | successText: (
117 |
118 | Success
119 |
120 | ),
121 | errorText: (
122 |
123 | Error
124 |
125 | ),
126 | buttonState: 'idle',
127 | endState: 'success',
128 | });
129 |
130 | const buttons = [
131 | [button1, setButton1],
132 | [button2, setButton2],
133 | [button3, setButton3],
134 | [button4, setButton4],
135 | [button5, setButton5],
136 | ];
137 |
138 | const onClickHandler = (index) => {
139 | buttons[index][1]({
140 | ...buttons[index][0],
141 | buttonState: 'loading',
142 | });
143 | setTimeout(() => {
144 | buttons[index][1]({
145 | ...buttons[index][0],
146 | buttonState: buttons[index][0].endState,
147 | });
148 | }, 2000);
149 | };
150 |
151 | useEffect(() => {
152 | const timer = buttons.map((button) => {
153 | button[0].ref.current.click();
154 | });
155 | return () => {
156 | //un-mounting
157 | clearTimeout(timer);
158 | };
159 | }, []);
160 |
161 | return (
162 |
163 |
164 | {buttons.map((button, index) => (
165 |
166 | onClickHandler(index)}
175 | />
176 |
177 | ))}
178 |
179 |
180 | );
181 | };
182 |
183 | export default Example2;
184 |
--------------------------------------------------------------------------------
/docs/src/components/Example/Example3.js:
--------------------------------------------------------------------------------
1 | import { faCheck, faTimes } from '@fortawesome/free-solid-svg-icons';
2 | import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
3 | import React, { useEffect, useRef, useState } from 'react';
4 | import ReactiveButton from 'reactive-button';
5 | import { BiLoader } from 'react-icons/bi';
6 | import { ImSpinner8 } from 'react-icons/im';
7 | import { SiSpinrilla } from 'react-icons/si';
8 | import { ImSpinner9 } from 'react-icons/im';
9 |
10 | const Example3 = () => {
11 | const [button1, setButton1] = useState({
12 | ref: useRef(),
13 | color: 'violet',
14 | idleText: 'Violet',
15 | loadingText: 'Loading',
16 | successText: (
17 |
18 | Success
19 |
20 | ),
21 | errorText: (
22 |
23 | {' '}
24 |
25 |
26 | {' '}
27 | Error
28 |
29 | ),
30 | buttonState: 'loading',
31 | endState: 'success',
32 | });
33 |
34 | const [button2, setButton2] = useState({
35 | ref: useRef(),
36 | color: 'blue',
37 | idleText: 'Blue',
38 | loadingText: (
39 |
40 | Loading
41 |
42 | ),
43 | successText: (
44 |
45 | {' '}
46 |
47 |
48 | {' '}
49 | Success
50 |
51 | ),
52 | errorText: (
53 |
54 | {' '}
55 |
56 |
57 | {' '}
58 | Error
59 |
60 | ),
61 | buttonState: 'loading',
62 | endState: 'success',
63 | });
64 |
65 | const [button3, setButton3] = useState({
66 | ref: useRef(),
67 | color: 'yellow',
68 | idleText: 'Yellow',
69 | loadingText: (
70 |
71 | Loading
72 |
73 | ),
74 | successText: (
75 |
76 | {' '}
77 |
78 |
79 | {' '}
80 | Success
81 |
82 | ),
83 | errorText: (
84 |
85 | {' '}
86 |
87 |
88 | {' '}
89 | Error
90 |
91 | ),
92 | buttonState: 'loading',
93 | endState: 'success',
94 | });
95 |
96 | const [button4, setButton4] = useState({
97 | ref: useRef(),
98 | color: 'dark',
99 | idleText: 'Dark',
100 | loadingText: (
101 |
102 | Loading
103 |
104 | ),
105 | successText: (
106 |
107 | {' '}
108 |
109 |
110 | {' '}
111 | Success
112 |
113 | ),
114 | errorText: (
115 |
116 | {' '}
117 |
118 |
119 | {' '}
120 | Error
121 |
122 | ),
123 | buttonState: 'loading',
124 | endState: 'success',
125 | });
126 |
127 | const [button5, setButton5] = useState({
128 | ref: useRef(),
129 | color: 'light',
130 | idleText: 'Light',
131 | loadingText: (
132 |
133 | Loading
134 |
135 | ),
136 | successText: (
137 |
138 | {' '}
139 |
140 |
141 | {' '}
142 | Success
143 |
144 | ),
145 | errorText: (
146 |
147 | {' '}
148 |
149 |
150 | {' '}
151 | Error
152 |
153 | ),
154 | buttonState: 'loading',
155 | endState: 'success',
156 | });
157 |
158 | const buttons = [
159 | [button1, setButton1],
160 | [button2, setButton2],
161 | [button3, setButton3],
162 | [button4, setButton4],
163 | [button5, setButton5],
164 | ];
165 |
166 | const onClickHandler = (index) => {
167 | buttons[index][1]({
168 | ...buttons[index][0],
169 | buttonState: 'loading',
170 | });
171 | setTimeout(() => {
172 | buttons[index][1]({
173 | ...buttons[index][0],
174 | buttonState: buttons[index][0].endState,
175 | });
176 | }, 2000);
177 | };
178 |
179 | useEffect(() => {
180 | setTimeout(() => {
181 | buttons.map((button) => {
182 | if (button[0].autoStart) {
183 | button[0].ref.current.click();
184 | }
185 | });
186 | }, 1000);
187 | }, []);
188 |
189 | return (
190 |
191 |
192 | {buttons.map((button, index) => (
193 |
194 | onClickHandler(index)}
206 | />
207 |
208 | ))}
209 |
210 |
211 | );
212 | };
213 |
214 | export default Example3;
215 |
--------------------------------------------------------------------------------
/docs/src/components/Example/Example4.js:
--------------------------------------------------------------------------------
1 | import {
2 | faCheck,
3 | faExclamationCircle,
4 | faRadiation,
5 | faSpinner,
6 | faThumbsDown,
7 | faTimes,
8 | faUserTimes,
9 | } from '@fortawesome/free-solid-svg-icons';
10 | import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
11 | import React, { useEffect, useRef, useState } from 'react';
12 | import ReactiveButton from 'reactive-button';
13 |
14 | const Example4 = () => {
15 | const [button1, setButton1] = useState({
16 | ref: useRef(),
17 | color: 'primary',
18 | idleText: 'Primary',
19 | loadingText: (
20 |
21 | Loading
22 |
23 | ),
24 | successText: (
25 |
26 | Success
27 |
28 | ),
29 | errorText: (
30 |
31 | Error
32 |
33 | ),
34 | buttonState: 'idle',
35 | endState: 'error',
36 | });
37 |
38 | const [button2, setButton2] = useState({
39 | ref: useRef(),
40 | color: 'secondary',
41 | idleText: 'Secondary',
42 | loadingText: (
43 |
44 | Loading
45 |
46 | ),
47 | successText: (
48 |
49 | Success
50 |
51 | ),
52 | errorText: (
53 |
54 | Error
55 |
56 | ),
57 | buttonState: 'idle',
58 | endState: 'error',
59 | });
60 |
61 | const [button3, setButton3] = useState({
62 | ref: useRef(),
63 | color: 'teal',
64 | idleText: 'Teal',
65 | loadingText: (
66 |
67 | Loading
68 |
69 | ),
70 | successText: (
71 |
72 | Success
73 |
74 | ),
75 | errorText: (
76 |
77 | Error
78 |
79 | ),
80 | buttonState: 'idle',
81 | endState: 'error',
82 | });
83 |
84 | const [button4, setButton4] = useState({
85 | ref: useRef(),
86 | color: 'green',
87 | idleText: 'Green',
88 | loadingText: (
89 |
90 | {' '}
91 |
92 |
93 | {' '}
94 | Loading
95 |
96 | ),
97 | successText: (
98 |
99 | {' '}
100 |
101 |
102 | {' '}
103 | Success
104 |
105 | ),
106 | errorText: (
107 |
108 | {' '}
109 |
110 |
111 | {' '}
112 | Error
113 |
114 | ),
115 | buttonState: 'idle',
116 | endState: 'error',
117 | });
118 |
119 | const [button5, setButton5] = useState({
120 | ref: useRef(),
121 | color: 'red',
122 | idleText: 'Red',
123 | loadingText: (
124 |
125 | {' '}
126 |
127 |
128 | {' '}
129 | Loading
130 |
131 | ),
132 | successText: (
133 |
134 | {' '}
135 |
136 |
137 | {' '}
138 | Success
139 |
140 | ),
141 | errorText: (
142 |
143 | {' '}
144 |
145 |
146 | {' '}
147 | Error
148 |
149 | ),
150 | buttonState: 'idle',
151 | endState: 'error',
152 | });
153 |
154 | const buttons = [
155 | [button1, setButton1],
156 | [button2, setButton2],
157 | [button3, setButton3],
158 | [button4, setButton4],
159 | [button5, setButton5],
160 | ];
161 |
162 | const onClickHandler = (index) => {
163 | buttons[index][1]({
164 | ...buttons[index][0],
165 | buttonState: 'loading',
166 | });
167 | setTimeout(() => {
168 | buttons[index][1]({
169 | ...buttons[index][0],
170 | buttonState: buttons[index][0].endState,
171 | });
172 | }, 2000);
173 | };
174 |
175 | useEffect(() => {
176 | const timer = buttons.map((button) => {
177 | button[0].ref.current.click();
178 | });
179 |
180 | return () => {
181 | //un-mounting
182 | clearTimeout(timer);
183 | };
184 | }, []);
185 |
186 | return (
187 |
188 |
189 | {buttons.map((button, index) => (
190 |
191 | onClickHandler(index)}
203 | />
204 |
205 | ))}
206 |
207 |
208 | );
209 | };
210 |
211 | export default Example4;
212 |
--------------------------------------------------------------------------------
/docs/src/components/Playground/EditorPlayground.js:
--------------------------------------------------------------------------------
1 | import React, { Fragment, useState } from 'react';
2 | import ReactiveButton from 'reactive-button';
3 | import './EditorPlayground.scss';
4 | import palenight from 'prism-react-renderer/themes/palenight';
5 | import { LiveProvider, LiveEditor, LiveError, LivePreview } from 'react-live';
6 | import {
7 | faCheck,
8 | faSpinner,
9 | faTimes,
10 | faCircleNotch,
11 | faThumbsUp,
12 | faBomb,
13 | } from '@fortawesome/free-solid-svg-icons';
14 | import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
15 |
16 | const EditorPlayground = () => {
17 | const code = `
18 | function App() {
19 | const [state, setState] = useState('idle');
20 |
21 | const onClickHandler = () => {
22 | setState('loading');
23 | setTimeout(() => {
24 | setState('success');
25 | }, 2000);
26 | };
27 |
28 | return (
29 |
36 | Loading
37 | >
38 | }
39 | successText={
40 | <>
41 | Success
42 | >
43 | }
44 | errorText={
45 | <>
46 | Error
47 | >
48 | }
49 | type={'button'}
50 | className={'class1 class2'}
51 | style={{
52 | borderRadius: '5px',
53 | }}
54 | outline={false}
55 | shadow={false}
56 | rounded={false}
57 | size={'normal'}
58 | block={false}
59 | messageDuration={2000}
60 | disabled={false}
61 | buttonRef={null}
62 | width={null}
63 | height={null}
64 | animation={true}
65 | />
66 | );
67 | }
68 | `;
69 |
70 | return (
71 |
72 |
88 |
96 |
101 |
102 |
103 | );
104 | };
105 |
106 | export default EditorPlayground;
107 |
--------------------------------------------------------------------------------
/docs/src/components/Playground/EditorPlayground.scss:
--------------------------------------------------------------------------------
1 | .editor-playground-component-wrapper {
2 | .playground__card {
3 | min-height: 120px;
4 | }
5 | .editor__card__body {
6 | padding: 0;
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/docs/src/components/Playground/InteractivePlayground.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState } from 'react';
2 | import ReactiveButton from 'reactive-button';
3 | import './InteractivePlayground.scss';
4 | import '../../css/bootstrap.scss';
5 |
6 | const InteractivePlayground = () => {
7 | const defaultValues = {
8 | buttonState: 'idle',
9 | color: 'primary',
10 | idleText: 'Click Me',
11 | loadingText: 'Loading',
12 | successText: 'Success',
13 | errorText: 'Error',
14 | className: '',
15 | outline: false,
16 | shadow: false,
17 | rounded: false,
18 | size: 'normal',
19 | messageDuration: 2000,
20 | block: false,
21 | disabled: false,
22 | width: '',
23 | height: '',
24 | animation: true,
25 | };
26 | const [buttonState, setButtonState] = useState(defaultValues.buttonState);
27 | const [color, setColor] = useState(defaultValues.color);
28 | const [idleText, setIdleText] = useState(defaultValues.idleText);
29 | const [loadingText, setLoadingText] = useState(defaultValues.loadingText);
30 | const [successText, setSuccessText] = useState(defaultValues.successText);
31 | const [errorText, setErrorText] = useState(defaultValues.errorText);
32 | const [className, setClassName] = useState(defaultValues.className);
33 | const [outline, setOutline] = useState(defaultValues.outline);
34 | const [shadow, setShadow] = useState(defaultValues.shadow);
35 | const [rounded, setRounded] = useState(defaultValues.rounded);
36 | const [size, setSize] = useState(defaultValues.size);
37 | const [messageDuration, setMessageDuration] = useState(
38 | defaultValues.messageDuration
39 | );
40 | const [block, setBlock] = useState(defaultValues.block);
41 | const [disabled, setDisabled] = useState(defaultValues.disabled);
42 | const [width, setWidth] = useState(defaultValues.width);
43 | const [height, setHeight] = useState(defaultValues.height);
44 | const [animation, setAnimation] = useState(defaultValues.animation);
45 |
46 | const [resetButtonState, setResetButtonState] = useState('idle');
47 | const [disableButtonStateProp, setDisableButtonStateProp] = useState(false);
48 |
49 | const buttonOnClickHandler = () => {
50 | setDisableButtonStateProp(true);
51 | setButtonState('loading');
52 | setTimeout(() => {
53 | setButtonState('success');
54 | setDisableButtonStateProp(false);
55 | }, 2000);
56 | };
57 |
58 | useEffect(() => {
59 | if (buttonState === 'success' || buttonState === 'error') {
60 | setDisableButtonStateProp(true);
61 | setTimeout(() => {
62 | setDisableButtonStateProp(false);
63 | setButtonState('idle');
64 | }, messageDuration);
65 | }
66 | }, [buttonState]);
67 |
68 | const buttonStateOnChangeHandler = (e) => {
69 | setButtonState(e.target.value);
70 | };
71 |
72 | const colorOnChangeHandler = (e) => {
73 | setColor(e.target.value);
74 | };
75 |
76 | const idleTextOnChangeHandler = (e) => {
77 | setIdleText(e.target.value);
78 | };
79 |
80 | const loadingTextOnChangeHandler = (e) => {
81 | setLoadingText(e.target.value);
82 | };
83 |
84 | const successTextOnChangeHandler = (e) => {
85 | setSuccessText(e.target.value);
86 | };
87 |
88 | const errorTextOnChangeHandler = (e) => {
89 | setErrorText(e.target.value);
90 | };
91 |
92 | const classNameOnChangeHandler = (e) => {
93 | setClassName(e.target.value);
94 | };
95 |
96 | const outlineOnChangeHandler = (e) => {
97 | setOutline(e.target.checked === true ? true : false);
98 | };
99 |
100 | const shadowOnChangeHandler = (e) => {
101 | setShadow(e.target.checked === true ? true : false);
102 | };
103 |
104 | const roundedOnChangeHandler = (e) => {
105 | setRounded(e.target.checked === true ? true : false);
106 | };
107 |
108 | const sizeOnChangeHandler = (e) => {
109 | setSize(e.target.value);
110 | };
111 |
112 | const blockOnChangeHandler = (e) => {
113 | setBlock(e.target.checked === true ? true : false);
114 | };
115 |
116 | const messageDurationOnChangeHandler = (e) => {
117 | if (parseInt(e.target.value) >= 0) {
118 | setMessageDuration(e.target.value);
119 | }
120 | };
121 |
122 | const disabledChangeHandler = (e) => {
123 | setDisabled(e.target.checked === true ? true : false);
124 | };
125 |
126 | const widthOnChangeHandler = (e) => {
127 | setWidth(e.target.value);
128 | };
129 |
130 | const heightOnChangeHandler = (e) => {
131 | setHeight(e.target.value);
132 | };
133 |
134 | const animationOnChangeHandler = (e) => {
135 | setAnimation(e.target.checked === true ? true : false);
136 | };
137 |
138 | const resetAll = () => {
139 | setResetButtonState('loading');
140 |
141 | setTimeout(() => {
142 | setButtonState(defaultValues.buttonState);
143 | setColor(defaultValues.buttonState);
144 | setIdleText(defaultValues.idleText);
145 | setLoadingText(defaultValues.loadingText);
146 | setSuccessText(defaultValues.successText);
147 | setErrorText(defaultValues.errorText);
148 | setClassName(defaultValues.className);
149 | setSize(defaultValues.size);
150 | setShadow(defaultValues.shadow);
151 | setRounded(defaultValues.rounded);
152 | setOutline(defaultValues.outline);
153 | setBlock(defaultValues.block);
154 | setMessageDuration(defaultValues.messageDuration);
155 | setDisabled(defaultValues.disabled);
156 | setWidth(defaultValues.width);
157 | setHeight(defaultValues.height);
158 | setAnimation(defaultValues.animation);
159 |
160 | setResetButtonState('success');
161 | }, 1000);
162 | };
163 |
164 | return (
165 |
166 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
210 | buttonState
211 |
212 |
213 |
220 | idle
221 | loading
222 | success
223 | error
224 |
225 |
226 |
227 |
228 |
232 | idleText
233 |
234 |
235 |
243 |
244 |
245 |
246 |
250 | successText
251 |
252 |
253 |
261 |
262 |
263 |
264 |
268 | shadow
269 |
270 |
271 |
278 |
279 |
280 |
281 |
285 | outline
286 |
287 |
288 |
295 |
296 |
297 |
298 |
302 | animation
303 |
304 |
305 |
312 |
313 |
314 |
315 |
319 | className
320 |
321 |
322 |
330 |
331 |
332 |
333 |
337 | size
338 |
339 |
340 |
346 | tiny
347 | small
348 | normal
349 | large
350 |
351 |
352 |
353 |
354 |
358 | messageDuration
359 |
360 |
361 |
369 |
370 |
371 |
372 |
373 |
374 |
375 |
376 |
380 | color
381 |
382 |
383 |
389 | primary
390 | Secondary
391 | dark
392 | light
393 | green
394 | red
395 | yellow
396 | teal
397 | violet
398 | blue
399 |
400 |
401 |
402 |
403 |
407 | loadingText
408 |
409 |
410 |
418 |
419 |
420 |
421 |
425 | errorText
426 |
427 |
428 |
436 |
437 |
438 |
439 |
443 | rounded
444 |
445 |
446 |
453 |
454 |
455 |
456 |
460 | block
461 |
462 |
463 |
470 |
471 |
472 |
473 |
477 | disabled
478 |
479 |
480 |
487 |
488 |
489 |
490 |
494 | width
495 |
496 |
497 |
498 |
506 |
507 | px
508 |
509 |
510 |
511 |
512 |
513 |
517 | height
518 |
519 |
520 |
521 |
529 |
530 | px
531 |
532 |
533 |
534 |
535 |
536 |
537 |
538 |
539 |
540 |
541 |
551 |
552 |
553 |
554 | );
555 | };
556 |
557 | export default InteractivePlayground;
558 |
--------------------------------------------------------------------------------
/docs/src/components/Playground/InteractivePlayground.scss:
--------------------------------------------------------------------------------
1 | .interactive-playground-component-wrapper {
2 | .playground__card {
3 | min-height: 120px;
4 | }
5 |
6 | .props__container .flex-section {
7 | justify-content: left;
8 | }
9 |
10 | .form-control,
11 | .input-group-text {
12 | font-size: inherit !important;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/docs/src/components/Playground/Playground.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import styled, { css } from 'styled-components';
3 | import { LiveProvider, LiveEditor, LiveError, LivePreview } from 'react-live';
4 | import palenight from 'prism-react-renderer/themes/palenight';
5 | import PropTypes from 'prop-types';
6 |
7 | const foreground = '#f8f8f2';
8 | const red = '#ff5555';
9 |
10 | const StyledProvider = styled(LiveProvider)`
11 | border-radius: 3px;
12 | box-shadow: 1px 1px 20px rgba(20, 20, 20, 0.27);
13 | overflow: hidden;
14 | margin-bottom: 100px;
15 | `;
16 |
17 | const LiveWrapper = styled.div`
18 | display: flex;
19 | flex-direction: row;
20 | justify-content: stretch;
21 | align-items: stretch;
22 | @media (max-width: 600px) {
23 | flex-direction: column;
24 | }
25 | `;
26 |
27 | const Column = css`
28 | flex-basis: ${(props) => (props.previewOnly ? '100%' : '50%')};
29 | width: ${(props) => (props.previewOnly ? '100%' : '50%')};
30 | max-width: ${(props) => (props.previewOnly ? '100%' : '50%')};
31 | @media (max-width: 600px) {
32 | flex-basis: auto;
33 | width: 100%;
34 | max-width: 100%;
35 | height: ${(props) => props.height};
36 | max-height: ${(props) => props.height};
37 | }
38 | `;
39 |
40 | const StyledEditor = styled.div`
41 | font-family: 'Source Code Pro', monospace;
42 | font-size: 14px;
43 | height: ${(props) => props.height};
44 | max-height: ${(props) => props.height};
45 | overflow: auto;
46 | ${Column};
47 | * > textarea:focus {
48 | outline: none;
49 | }
50 | `;
51 |
52 | const StyledPreview = styled(LivePreview)`
53 | position: relative;
54 | padding: 1.5rem;
55 | color: black;
56 | height: auto;
57 | overflow: hidden;
58 | display: flex;
59 | justify-content: center;
60 | flex-direction: row;
61 | align-items: center;
62 | flex-wrap: wrap;
63 | ${Column};
64 | `;
65 |
66 | const StyledError = styled(LiveError)`
67 | display: block;
68 | padding: 0.5rem;
69 | background: ${red};
70 | color: ${foreground};
71 | white-space: pre-wrap;
72 | text-align: left;
73 | font-size: 0.9em;
74 | font-family: 'Source Code Pro', monospace;
75 | `;
76 |
77 | const Playground = ({ noInline, code, scope, height, previewOnly = false }) => {
78 | return (
79 |
85 |
86 | {!previewOnly && (
87 |
88 |
89 |
90 | )}
91 |
96 |
97 |
98 |
99 | );
100 | };
101 |
102 | Playground.propTypes = {
103 | noInline: PropTypes.bool,
104 | code: PropTypes.string,
105 | scope: PropTypes.object,
106 | height: PropTypes.string,
107 | previewOnly: PropTypes.bool,
108 | };
109 |
110 | export default Playground;
111 |
--------------------------------------------------------------------------------
/docs/src/css/custom.css:
--------------------------------------------------------------------------------
1 | /* stylelint-disable docusaurus/copyright-header */
2 | /**
3 | * Any CSS included here will be global. The classic template
4 | * bundles Infima by default. Infima is a CSS framework designed to
5 | * work well for content-centric websites.
6 | */
7 |
8 | /* You can override the default Infima variables here. */
9 | :root {
10 | --ifm-color-primary: #5867dd;
11 | --ifm-color-primary-dark: #3e50d8;
12 | --ifm-color-primary-darker: #3144d5;
13 | --ifm-color-primary-darkest: #2535b4;
14 | --ifm-color-primary-light: #727ee2;
15 | --ifm-color-primary-lighter: #7f8ae5;
16 | --ifm-color-primary-lightest: #a5aded;
17 | --ifm-code-font-size: 95%;
18 | --ifm-navbar-item-padding-horizontal: 16px;
19 | }
20 |
21 | ::-webkit-scrollbar-track {
22 | /* border-radius: 0px; */
23 | box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3);
24 | -webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3);
25 | -moz-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3);
26 | }
27 |
28 | * {
29 | scrollbar-width: thin;
30 | /* scrollbar-color: darkgrey #F5F5F5; */
31 | }
32 |
33 | @media screen and (min-width: 966px) {
34 | ::-webkit-scrollbar,
35 | .scroller {
36 | width: 8px;
37 | height: 8px;
38 | background-color: #f1f1f1;
39 | }
40 | }
41 |
42 | ::-webkit-scrollbar-thumb {
43 | /* border-radius: 0px;
44 | box-shadow: inset 0 0 6px rgba(0,0,0,0.5);
45 | -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.5);
46 | -moz-box-shadow: inset 0 0 6px rgba(0,0,0,0.5); */
47 | background-color: #888;
48 | border-radius: 10px;
49 | }
50 |
51 | .navbar__title {
52 | color: var(--ifm-color-primary);
53 | }
54 |
55 | .header-github-link:before {
56 | background: url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12'/%3E%3C/svg%3E")
57 | no-repeat;
58 | content: '';
59 | display: flex;
60 | height: 24px;
61 | width: 24px;
62 | }
63 |
64 | html[data-theme='dark'] .header-github-link:before {
65 | background: url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill='%23fff' d='M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12'/%3E%3C/svg%3E")
66 | no-repeat;
67 | }
68 |
69 | .z-styled-preview {
70 | background-color: #e3eaea;
71 | }
72 |
73 | html[data-theme='dark'] .z-styled-preview {
74 | background-color: #232525;
75 | }
76 |
77 | .header-github-link:hover {
78 | opacity: 0.6;
79 | }
80 |
81 | .docusaurus-highlight-code-line {
82 | background-color: rgb(72, 77, 91);
83 | display: block;
84 | margin: 0 calc(-1 * var(--ifm-pre-padding));
85 | padding: 0 var(--ifm-pre-padding);
86 | }
87 |
88 | .flex-section {
89 | align-items: center;
90 | display: flex;
91 | justify-content: center;
92 | flex-direction: row;
93 | flex-wrap: wrap;
94 | }
95 |
96 | /* ----------- z-table starts ----------- */
97 | .z-table-wrapper {
98 | border: 1px solid #e0e0e0;
99 | }
100 |
101 | .z-table-wrapper table {
102 | width: 100%;
103 | color: #8a8f94;
104 | margin-bottom: 0;
105 | border-collapse: unset;
106 | }
107 |
108 | .z-table-wrapper table tr {
109 | background: var(--ifm-table-background);
110 | line-height: 30px;
111 | }
112 |
113 | .z-table-wrapper table th {
114 | background-color: #e2e4e4;
115 | color: #adacac;
116 | text-align: center;
117 | text-transform: uppercase;
118 | letter-spacing: 0.05em;
119 | }
120 |
121 | html[data-theme='dark'] .z-table-wrapper table th {
122 | background-color: #1d1f1f;
123 | }
124 |
125 | .z-table-wrapper table th:nth-child(3) {
126 | width: 20px;
127 | }
128 |
129 | .z-table-wrapper table td:first-child {
130 | font-weight: 600;
131 | color: #777;
132 | }
133 |
134 | .z-table-wrapper table td:nth-child(2) {
135 | color: cadetblue;
136 | }
137 |
138 | .z-table-wrapper table tr:nth-child(2n) {
139 | background-color: var(--ifm-table-stripe-background);
140 | }
141 |
142 | .z-table-wrapper table td,
143 | .z-table-wrapper table th {
144 | border: none;
145 | font-size: 13px;
146 | white-space: nowrap !important;
147 | }
148 |
149 | /* ----------- z-table ends ----------- */
150 |
151 | /* bootstrap custom starts */
152 |
153 | .border {
154 | border: 1px solid #dee2e6 !important;
155 | }
156 |
157 | .w-25 {
158 | width: 25% !important;
159 | }
160 |
161 | .w-50 {
162 | width: 50% !important;
163 | }
164 |
165 | .w-75 {
166 | width: 75% !important;
167 | }
168 |
169 | .w-100 {
170 | width: 100% !important;
171 | }
172 |
173 | .w-auto {
174 | width: auto !important;
175 | }
176 |
177 | .h-25 {
178 | height: 25% !important;
179 | }
180 |
181 | .h-50 {
182 | height: 50% !important;
183 | }
184 |
185 | .h-75 {
186 | height: 75% !important;
187 | }
188 |
189 | .h-100 {
190 | height: 100% !important;
191 | }
192 |
193 | .h-auto {
194 | height: auto !important;
195 | }
196 |
197 | .float-left {
198 | float: left !important;
199 | }
200 |
201 | .float-right {
202 | float: right !important;
203 | }
204 |
205 | .float-none {
206 | float: none !important;
207 | }
208 |
209 | .justify-content-center {
210 | -ms-flex-pack: center !important;
211 | justify-content: center !important;
212 | }
213 |
214 | .m-auto {
215 | margin: auto !important;
216 | }
217 |
218 | .mt-auto,
219 | .my-auto {
220 | margin-top: auto !important;
221 | }
222 |
223 | .mr-auto,
224 | .mx-auto {
225 | margin-right: auto !important;
226 | }
227 |
228 | .mb-auto,
229 | .my-auto {
230 | margin-bottom: auto !important;
231 | }
232 |
233 | .ml-auto,
234 | .mx-auto {
235 | margin-left: auto !important;
236 | }
237 |
238 | .text-left {
239 | text-align: left !important;
240 | }
241 |
242 | .text-right {
243 | text-align: right !important;
244 | }
245 |
246 | .text-center {
247 | text-align: center !important;
248 | }
249 |
250 | .mt-0,
251 | .my-0 {
252 | margin-top: 0 !important;
253 | }
254 |
255 | .mr-0,
256 | .mx-0 {
257 | margin-right: 0 !important;
258 | }
259 |
260 | .mb-0,
261 | .my-0 {
262 | margin-bottom: 0 !important;
263 | }
264 |
265 | .ml-0,
266 | .mx-0 {
267 | margin-left: 0 !important;
268 | }
269 |
270 | .m-1 {
271 | margin: 0.25rem !important;
272 | }
273 |
274 | .mt-1,
275 | .my-1 {
276 | margin-top: 0.25rem !important;
277 | }
278 |
279 | .mr-1,
280 | .mx-1 {
281 | margin-right: 0.25rem !important;
282 | }
283 |
284 | .mb-1,
285 | .my-1 {
286 | margin-bottom: 0.25rem !important;
287 | }
288 |
289 | .ml-1,
290 | .mx-1 {
291 | margin-left: 0.25rem !important;
292 | }
293 |
294 | .m-2 {
295 | margin: 0.5rem !important;
296 | }
297 |
298 | .mt-2,
299 | .my-2 {
300 | margin-top: 0.5rem !important;
301 | }
302 |
303 | .mr-2,
304 | .mx-2 {
305 | margin-right: 0.5rem !important;
306 | }
307 |
308 | .mb-2,
309 | .my-2 {
310 | margin-bottom: 0.5rem !important;
311 | }
312 |
313 | .ml-2,
314 | .mx-2 {
315 | margin-left: 0.5rem !important;
316 | }
317 |
318 | .m-3 {
319 | margin: 1rem !important;
320 | }
321 |
322 | .mt-3,
323 | .my-3 {
324 | margin-top: 1rem !important;
325 | }
326 |
327 | .mr-3,
328 | .mx-3 {
329 | margin-right: 1rem !important;
330 | }
331 |
332 | .mb-3,
333 | .my-3 {
334 | margin-bottom: 1rem !important;
335 | }
336 |
337 | .ml-3,
338 | .mx-3 {
339 | margin-left: 1rem !important;
340 | }
341 |
342 | .m-4 {
343 | margin: 1.5rem !important;
344 | }
345 |
346 | .mt-4,
347 | .my-4 {
348 | margin-top: 1.5rem !important;
349 | }
350 |
351 | .mr-4,
352 | .mx-4 {
353 | margin-right: 1.5rem !important;
354 | }
355 |
356 | .mb-4,
357 | .my-4 {
358 | margin-bottom: 1.5rem !important;
359 | }
360 |
361 | .ml-4,
362 | .mx-4 {
363 | margin-left: 1.5rem !important;
364 | }
365 |
366 | .m-5 {
367 | margin: 3rem !important;
368 | }
369 |
370 | .mt-5,
371 | .my-5 {
372 | margin-top: 3rem !important;
373 | }
374 |
375 | .mr-5,
376 | .mx-5 {
377 | margin-right: 3rem !important;
378 | }
379 |
380 | .mb-5,
381 | .my-5 {
382 | margin-bottom: 3rem !important;
383 | }
384 |
385 | .ml-5,
386 | .mx-5 {
387 | margin-left: 3rem !important;
388 | }
389 |
390 | .p-0 {
391 | padding: 0 !important;
392 | }
393 |
394 | .pt-0,
395 | .py-0 {
396 | padding-top: 0 !important;
397 | }
398 |
399 | .pr-0,
400 | .px-0 {
401 | padding-right: 0 !important;
402 | }
403 |
404 | .pb-0,
405 | .py-0 {
406 | padding-bottom: 0 !important;
407 | }
408 |
409 | .pl-0,
410 | .px-0 {
411 | padding-left: 0 !important;
412 | }
413 |
414 | .p-1 {
415 | padding: 0.25rem !important;
416 | }
417 |
418 | .pt-1,
419 | .py-1 {
420 | padding-top: 0.25rem !important;
421 | }
422 |
423 | .pr-1,
424 | .px-1 {
425 | padding-right: 0.25rem !important;
426 | }
427 |
428 | .pb-1,
429 | .py-1 {
430 | padding-bottom: 0.25rem !important;
431 | }
432 |
433 | .pl-1,
434 | .px-1 {
435 | padding-left: 0.25rem !important;
436 | }
437 |
438 | .p-2 {
439 | padding: 0.5rem !important;
440 | }
441 |
442 | .pt-2,
443 | .py-2 {
444 | padding-top: 0.5rem !important;
445 | }
446 |
447 | .pr-2,
448 | .px-2 {
449 | padding-right: 0.5rem !important;
450 | }
451 |
452 | .pb-2,
453 | .py-2 {
454 | padding-bottom: 0.5rem !important;
455 | }
456 |
457 | .pl-2,
458 | .px-2 {
459 | padding-left: 0.5rem !important;
460 | }
461 |
462 | .p-3 {
463 | padding: 1rem !important;
464 | }
465 |
466 | .pt-3,
467 | .py-3 {
468 | padding-top: 1rem !important;
469 | }
470 |
471 | .pr-3,
472 | .px-3 {
473 | padding-right: 1rem !important;
474 | }
475 |
476 | .pb-3,
477 | .py-3 {
478 | padding-bottom: 1rem !important;
479 | }
480 |
481 | .pl-3,
482 | .px-3 {
483 | padding-left: 1rem !important;
484 | }
485 |
486 | .p-4 {
487 | padding: 1.5rem !important;
488 | }
489 |
490 | .pt-4,
491 | .py-4 {
492 | padding-top: 1.5rem !important;
493 | }
494 |
495 | .pr-4,
496 | .px-4 {
497 | padding-right: 1.5rem !important;
498 | }
499 |
500 | .pb-4,
501 | .py-4 {
502 | padding-bottom: 1.5rem !important;
503 | }
504 |
505 | .pl-4,
506 | .px-4 {
507 | padding-left: 1.5rem !important;
508 | }
509 |
510 | .p-5 {
511 | padding: 3rem !important;
512 | }
513 |
514 | .pt-5,
515 | .py-5 {
516 | padding-top: 3rem !important;
517 | }
518 |
519 | .pr-5,
520 | .px-5 {
521 | padding-right: 3rem !important;
522 | }
523 |
524 | .pb-5,
525 | .py-5 {
526 | padding-bottom: 3rem !important;
527 | }
528 |
529 | .pl-5,
530 | .px-5 {
531 | padding-left: 3rem !important;
532 | }
533 |
534 | /* bootstrap custom ends */
535 |
536 | /* **************************** z-switch starts **************************** */
537 |
538 | .z-switch {
539 | --z-switch-ball-bg: var(--ifm-color-primary);
540 | --z-switch-checked-bg: var(--ifm-color-primary);
541 | --z-switch-border-color: var(--ifm-color-primary);
542 | --z-switch-hover-border-color: transparent;
543 | --z-switch-disabled-checked-bg: transparent;
544 | --z-switch-width: 41px;
545 | --z-switch-height: 21px;
546 | --z-switch-bg: var(--ifm-background-color);
547 | --z-switch-radius: 12px;
548 | --z-switch-ball-width: 15px;
549 | --z-switch-ball-bg: #d7d7f4;
550 | --z-switch-checked-ball-bg: white;
551 | --z-switch-border-color: #d7d7f4;
552 | --z-switch-hover-border-color: #d7d7f4;
553 | --z-switch-checked-bg: var(--ifm-color-primary);
554 | --z-switch-disabled-bg: var(--ifm-color-primary-light);
555 | --z-switch-disabled-checked-bg: var(--ifm-color-primary-dark);
556 | position: relative;
557 | width: var(--z-switch-width);
558 | height: var(--z-switch-height);
559 | background: var(--z-switch-bg);
560 | border: 1px solid var(--z-switch-border-color);
561 | border-radius: var(--z-switch-radius);
562 | cursor: pointer;
563 | transition: 0.3s;
564 | appearance: none;
565 | -moz-appearance: none;
566 | -webkit-appearance: none;
567 | }
568 |
569 | .z-switch:focus {
570 | outline: none;
571 | }
572 |
573 | .z-switch:checked {
574 | --z-switch-border-color: var(--ifm-color-primary);
575 | background: var(--ifm-color-primary);
576 | }
577 |
578 | .z-switch:checked::before {
579 | --z-switch-ball-bg: var(--z-switch-checked-ball-bg);
580 | transform: translateX(20px);
581 | }
582 |
583 | .z-switch::before {
584 | position: absolute;
585 | content: '';
586 | top: 2px;
587 | left: 2px;
588 | width: var(--z-switch-ball-width);
589 | height: var(--z-switch-ball-width);
590 | background: var(--z-switch-ball-bg);
591 | border-radius: 50%;
592 | transition: 0.3s;
593 | }
594 |
595 | .z-switch:disabled {
596 | --z-switch-bg: var(--z-switch-disabled-bg);
597 | --z-switch-checked-bg: var(--z-switch-disabled-checked-bg);
598 | }
599 |
600 | .z-switch:disabled:checked {
601 | --z-switch-border-color: #d7d7f4;
602 | background: #d7d7f4;
603 | }
604 | /* **************************** z-switch ends **************************** */
605 | .z-center {
606 | align-items: center;
607 | -webkit-box-pack: center;
608 | justify-content: center;
609 | -webkit-box-align: center;
610 | display: flex;
611 | }
612 |
613 | .vertical-align {
614 | vertical-align: middle;
615 | }
616 |
617 | .keyword {
618 | color: var(--ifm-color-primary);
619 | }
620 |
621 | .reactive-button-badges a,
622 | .reactive-button-badges img {
623 | padding-left: 2px;
624 | padding-right: 2px;
625 | }
626 |
627 | .shadow-dim {
628 | box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15) !important;
629 | }
630 |
631 | svg.react-icon {
632 | vertical-align: middle;
633 | }
634 |
635 | .footer__logo {
636 | max-width: 80px;
637 | }
638 |
639 | .fadeIn {
640 | opacity: 1;
641 | animation-name: fadeIn;
642 | animation-iteration-count: 1;
643 | animation-timing-function: ease-in;
644 | animation-duration: 1s;
645 | }
646 |
647 | @keyframes fadeIn {
648 | 0% {
649 | opacity: 0;
650 | }
651 | 100% {
652 | opacity: 1;
653 | }
654 | }
655 |
656 | @-webkit-keyframes fadeIn {
657 | from {
658 | opacity: 0;
659 | }
660 | to {
661 | opacity: 1;
662 | }
663 | }
664 |
665 | .icon-spin {
666 | -webkit-animation: icon-spin 2s infinite linear;
667 | animation: icon-spin 2s infinite linear;
668 | }
669 |
670 | @-webkit-keyframes icon-spin {
671 | 0% {
672 | -webkit-transform: rotate(0deg);
673 | transform: rotate(0deg);
674 | }
675 | 100% {
676 | -webkit-transform: rotate(359deg);
677 | transform: rotate(359deg);
678 | }
679 | }
680 |
681 | @keyframes icon-spin {
682 | 0% {
683 | -webkit-transform: rotate(0deg);
684 | transform: rotate(0deg);
685 | }
686 | 100% {
687 | -webkit-transform: rotate(359deg);
688 | transform: rotate(359deg);
689 | }
690 | }
691 |
--------------------------------------------------------------------------------
/docs/src/pages/index.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState } from 'react';
2 | import clsx from 'clsx';
3 | import Layout from '@theme/Layout';
4 | import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
5 | import useBaseUrl from '@docusaurus/useBaseUrl';
6 | import styles from './index.module.css';
7 | import ReactiveButton from 'reactive-button';
8 | import { FaArrowRight } from 'react-icons/fa';
9 | import { useHistory } from '@docusaurus/router';
10 | import Playground from '../components/Playground/Playground';
11 | import PropTypes from 'prop-types';
12 |
13 | const showcaseCode = `
14 | function App() {
15 | const [state, setState] = useState('idle');
16 |
17 | return (
18 | {
21 | setState('loading');
22 | setTimeout(() => {
23 | setState('success');
24 | }, 2000);
25 | }}
26 | />
27 | );
28 | }
29 | `.trim();
30 |
31 | const showcaseScope = { ReactiveButton, useState };
32 |
33 | const features = [
34 | {
35 | title: 'Progress Indicator',
36 | description: (
37 | <>
38 | Don't just click button. See what is happening behind your button
39 | click.
40 | >
41 | ),
42 | },
43 | {
44 | title: 'Animated',
45 | description: (
46 | <>
47 | The 3D animated buttons replace the traditional buttons with reactive
48 | behavior.
49 | >
50 | ),
51 | },
52 | {
53 | title: 'Customizable',
54 | description: (
55 | <>
56 | Comes with proper customization. Use the beautiful default themes or
57 | create your own.
58 | >
59 | ),
60 | },
61 | {
62 | title: 'Simple',
63 | description: (
64 | <>
65 | You know button? Use it just like a button. It's super easy and
66 | simple.
67 | >
68 | ),
69 | },
70 | {
71 | title: 'Lightweight',
72 | description: (
73 | <>Extremely small in size. Less than 20 KB with zero dependency.>
74 | ),
75 | },
76 | {
77 | title: 'Flexible',
78 | description: (
79 | <>Reactive button is an isolated component. Use it with any UI library.>
80 | ),
81 | },
82 | ];
83 |
84 | function Feature({ title, description }) {
85 | return (
86 |
87 |
{title}
88 |
{description}
89 |
90 | );
91 | }
92 |
93 | function Home() {
94 | const {
95 | siteConfig: { title, customFields, tagline },
96 | } = useDocusaurusContext();
97 |
98 | const { description } = customFields;
99 |
100 | const [showGetStartedButton, setShowGetStartedButton] = useState(false);
101 | const docLink = useBaseUrl('docs/introduction');
102 | const history = useHistory();
103 |
104 | useEffect(() => {
105 | setShowGetStartedButton(true);
106 | }, []);
107 |
108 | const buttonOnClickHandler = () => {
109 | history.push(docLink);
110 | };
111 |
112 | return (
113 |
114 |
115 |
150 | {showGetStartedButton && (
151 |
152 |
167 |
168 | )}
169 |
170 | {features && features.length > 0 && (
171 |
172 |
173 |
174 | {features.map((props, idx) => (
175 |
176 | ))}
177 |
178 |
179 |
180 | )}
181 |
182 |
183 |
184 | );
185 | }
186 |
187 | Feature.propTypes = {
188 | title: PropTypes.string,
189 | description: PropTypes.node,
190 | };
191 |
192 | export default Home;
193 |
--------------------------------------------------------------------------------
/docs/src/pages/index.module.css:
--------------------------------------------------------------------------------
1 | /* stylelint-disable docusaurus/copyright-header */
2 |
3 | /**
4 | * CSS files with the .module.css suffix will be treated as CSS modules
5 | * and scoped locally.
6 | */
7 |
8 | .heroBanner {
9 | padding: 4rem 0;
10 | text-align: center;
11 | position: relative;
12 | overflow: hidden;
13 | }
14 |
15 | @media screen and (max-width: 966px) {
16 | .heroBanner {
17 | padding: 2rem;
18 | }
19 | }
20 |
21 | .buttons {
22 | display: flex;
23 | align-items: center;
24 | justify-content: center;
25 | }
26 |
27 | .features {
28 | display: flex;
29 | align-items: center;
30 | padding: 2rem 0;
31 | width: 100%;
32 | }
33 |
34 | .featureImage {
35 | height: 200px;
36 | width: 200px;
37 | padding-bottom: 20px;
38 | }
39 |
40 | html[data-theme='dark'] .features {
41 | background-color: #33363b;
42 | }
43 |
44 | .exampleComponent {
45 | display: flex;
46 | align-items: center;
47 | padding: 3rem 0;
48 | width: 100%;
49 | background-color: #f7f7f7;
50 | }
51 |
52 | html[data-theme='dark'] .exampleComponent {
53 | background-color: #18191a;
54 | }
55 |
56 | .exampleComponent__container {
57 | margin-left: auto;
58 | margin-right: auto;
59 | padding-left: var(--ifm-spacing-horizontal);
60 | padding-right: var(--ifm-spacing-horizontal);
61 | width: 100%;
62 | }
63 |
64 | .exampleComponent__item {
65 | padding: 50px 100px;
66 | }
67 |
68 | @media screen and (max-width: 966px) {
69 | .exampleComponent__item {
70 | padding: unset;
71 | }
72 | }
73 |
74 | .logo {
75 | animation-duration: 2s;
76 | animation-name: jackInTheBox;
77 | width: 80px;
78 | }
79 |
80 | .heroProjectKeywords {
81 | color: var(--ifm-color-primary);
82 | }
83 |
84 | .heroProjectKeywordsSecondary {
85 | color: var(--ifm-color-primary-lighter);
86 | }
87 |
88 | .root {
89 | opacity: 1;
90 | animation-name: fadeIn;
91 | animation-iteration-count: 1;
92 | animation-timing-function: ease-in;
93 | animation-duration: 1s;
94 | }
95 |
96 | /* animations */
97 | @keyframes jackInTheBox {
98 | from {
99 | opacity: 0;
100 | transform: scale(0.1) rotate(30deg);
101 | transform-origin: center bottom;
102 | }
103 |
104 | 50% {
105 | transform: rotate(-10deg);
106 | }
107 |
108 | 70% {
109 | transform: rotate(3deg);
110 | }
111 |
112 | to {
113 | opacity: 1;
114 | transform: scale(1);
115 | }
116 | }
117 |
118 | @keyframes fadeIn {
119 | 0% {
120 | opacity: 0;
121 | }
122 | 100% {
123 | opacity: 1;
124 | }
125 | }
126 |
127 | @-webkit-keyframes fadeIn {
128 | from {
129 | opacity: 0;
130 | }
131 | to {
132 | opacity: 1;
133 | }
134 | }
135 |
--------------------------------------------------------------------------------
/docs/static/.nojekyll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arifszn/reactive-button/b1c129b39c3ddbba0cf6f2399c18964046f4cfaf/docs/static/.nojekyll
--------------------------------------------------------------------------------
/docs/static/img/dependencies.svg:
--------------------------------------------------------------------------------
1 | dependencies dependencies none none
--------------------------------------------------------------------------------
/docs/static/img/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arifszn/reactive-button/b1c129b39c3ddbba0cf6f2399c18964046f4cfaf/docs/static/img/favicon.ico
--------------------------------------------------------------------------------
/docs/static/img/logo/android-chrome-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arifszn/reactive-button/b1c129b39c3ddbba0cf6f2399c18964046f4cfaf/docs/static/img/logo/android-chrome-192x192.png
--------------------------------------------------------------------------------
/docs/static/img/logo/android-chrome-512x512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arifszn/reactive-button/b1c129b39c3ddbba0cf6f2399c18964046f4cfaf/docs/static/img/logo/android-chrome-512x512.png
--------------------------------------------------------------------------------
/docs/static/img/logo/apple-touch-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arifszn/reactive-button/b1c129b39c3ddbba0cf6f2399c18964046f4cfaf/docs/static/img/logo/apple-touch-icon.png
--------------------------------------------------------------------------------
/docs/static/img/logo/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arifszn/reactive-button/b1c129b39c3ddbba0cf6f2399c18964046f4cfaf/docs/static/img/logo/favicon-16x16.png
--------------------------------------------------------------------------------
/docs/static/img/logo/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arifszn/reactive-button/b1c129b39c3ddbba0cf6f2399c18964046f4cfaf/docs/static/img/logo/favicon-32x32.png
--------------------------------------------------------------------------------
/docs/static/img/logo/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arifszn/reactive-button/b1c129b39c3ddbba0cf6f2399c18964046f4cfaf/docs/static/img/logo/logo.png
--------------------------------------------------------------------------------
/docs/static/img/preview.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arifszn/reactive-button/b1c129b39c3ddbba0cf6f2399c18964046f4cfaf/docs/static/img/preview.gif
--------------------------------------------------------------------------------
/docs/static/img/social_preview.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arifszn/reactive-button/b1c129b39c3ddbba0cf6f2399c18964046f4cfaf/docs/static/img/social_preview.png
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "reactive-button",
3 | "version": "1.3.15",
4 | "description": "3D animated react button component with progress bar",
5 | "private": false,
6 | "homepage": "https://github.com/arifszn/reactive-button#readme",
7 | "main": "./dist/index.cjs.js",
8 | "module": "./dist/index.esm.js",
9 | "typings": "./types/index.d.ts",
10 | "scripts": {
11 | "build": "rollup -c --bundleConfigAsCjs",
12 | "lint": "eslint --ext .js,.jsx .",
13 | "lint:fix": "eslint --ext .js,.jsx --fix .",
14 | "prettier": "prettier --check './**/*.{js,jsx,ts,tsx,css,md,json}'",
15 | "prettier:fix": "prettier --write './**/*.{js,jsx,ts,tsx,css,md,json}'"
16 | },
17 | "peerDependencies": {
18 | "react": ">=16.8.0",
19 | "react-dom": ">=16.8.0"
20 | },
21 | "devDependencies": {
22 | "@babel/cli": "^7.11.6",
23 | "@babel/core": "^7.11.6",
24 | "@babel/preset-env": "^7.11.5",
25 | "@babel/preset-react": "^7.10.4",
26 | "@rollup/plugin-babel": "^6.0.3",
27 | "@rollup/plugin-commonjs": "^25.0.2",
28 | "@rollup/plugin-image": "^3.0.2",
29 | "@rollup/plugin-node-resolve": "^15.1.0",
30 | "@rollup/plugin-terser": "^0.4.3",
31 | "@types/react": "^18.0.17",
32 | "eslint": "^8.11.0",
33 | "eslint-config-prettier": "^8.5.0",
34 | "eslint-plugin-prettier": "^4.0.0",
35 | "eslint-plugin-react": "^7.29.4",
36 | "prettier": "^2.5.1",
37 | "prop-types": "^15.8.1",
38 | "rollup": "^3.26.0",
39 | "rollup-plugin-peer-deps-external": "^2.2.3",
40 | "rollup-plugin-postcss": "^4.0.2"
41 | },
42 | "author": "arifszn",
43 | "license": "MIT",
44 | "repository": {
45 | "type": "git",
46 | "url": "https://github.com/arifszn/reactive-button.git"
47 | },
48 | "bugs": {
49 | "url": "https://github.com/arifszn/reactive-button/issues"
50 | },
51 | "keywords": [
52 | "react",
53 | "button",
54 | "react-button",
55 | "react-animated-button",
56 | "react-3d-button",
57 | "react-button-progress-bar",
58 | "react-component",
59 | "button-component",
60 | "button-progress",
61 | "button-ui",
62 | "simple-button",
63 | "progressbar",
64 | "animation",
65 | "reactjs",
66 | "reactive",
67 | "3d-button",
68 | "button-progress",
69 | "progress-bar",
70 | "component",
71 | "beautiful-button"
72 | ]
73 | }
74 |
--------------------------------------------------------------------------------
/rollup.config.js:
--------------------------------------------------------------------------------
1 | import babel from '@rollup/plugin-babel';
2 | import commonjs from '@rollup/plugin-commonjs';
3 | import external from 'rollup-plugin-peer-deps-external';
4 | import postcss from 'rollup-plugin-postcss';
5 | import resolve from '@rollup/plugin-node-resolve';
6 | import image from '@rollup/plugin-image';
7 | import pkg from './package.json';
8 | import terser from '@rollup/plugin-terser';
9 |
10 | export default {
11 | input: './src/index.js',
12 | output: [
13 | {
14 | file: pkg.main,
15 | format: 'cjs',
16 | exports: 'auto',
17 | },
18 | {
19 | file: pkg.module,
20 | format: 'esm',
21 | },
22 | ],
23 | plugins: [
24 | external(),
25 | terser(),
26 | postcss(),
27 | babel({
28 | exclude: 'node_modules/**',
29 | }),
30 | resolve(),
31 | commonjs(),
32 | image(),
33 | ],
34 | };
35 |
--------------------------------------------------------------------------------
/src/css/index.css:
--------------------------------------------------------------------------------
1 | .reactive-btn-wrapper,
2 | .reactive-btn {
3 | --reactive-button-min-width: 100px;
4 | --reactive-button-min-height: 35px;
5 | --reactive-button-font-size: 14px;
6 | --reactive-button-font-weight: 400;
7 | --reactive-button-border-radius: 0px;
8 | --reactive-button-text-color: #ffffff;
9 | --reactive-progress-color: rgba(0, 0, 0, 0.15);
10 |
11 | --reactive-button-primary-color: rgba(88, 103, 221, 1);
12 | --reactive-button-secondary-color: rgba(108, 117, 125, 1);
13 | --reactive-button-dark-color: rgba(66, 78, 106, 1);
14 | --reactive-button-light-color: rgba(183, 186, 191, 1);
15 | --reactive-button-green-color: rgba(37, 162, 51, 1);
16 | --reactive-button-red-color: rgba(244, 81, 108, 1);
17 | --reactive-button-yellow-color: rgba(255, 193, 7, 1);
18 | --reactive-button-teal-color: rgba(0, 181, 173, 1);
19 | --reactive-button-violet-color: rgba(100, 53, 201, 1);
20 | --reactive-button-blue-color: rgba(66, 153, 225, 1);
21 |
22 | --reactive-progress-outline-primary-color: rgba(88, 103, 221, 0.3);
23 | --reactive-progress-outline-secondary-color: rgba(108, 117, 125, 0.3);
24 | --reactive-progress-outline-dark-color: rgba(66, 78, 106, 0.3);
25 | --reactive-progress-outline-light-color: rgba(214, 212, 212, 0.3);
26 | --reactive-progress-outline-green-color: rgba(37, 162, 51, 0.3);
27 | --reactive-progress-outline-red-color: rgba(244, 81, 108, 0.3);
28 | --reactive-progress-outline-yellow-color: rgba(255, 193, 7, 0.3);
29 | --reactive-progress-outline-teal-color: rgba(0, 181, 173, 0.3);
30 | --reactive-progress-outline-violet-color: rgba(100, 53, 201, 0.3);
31 | --reactive-progress-outline-blue-color: rgba(66, 153, 225, 0.3);
32 | }
33 |
34 | .reactive-btn-wrapper {
35 | display: inline-block;
36 | min-width: var(--reactive-button-min-width);
37 | height: var(--reactive-button-min-height);
38 | }
39 |
40 | .reactive-btn-wrapper.tiny {
41 | min-width: calc(var(--reactive-button-min-width) - 35px);
42 | height: calc(var(--reactive-button-min-height) - 11px);
43 | }
44 |
45 | .reactive-btn-wrapper.small {
46 | min-width: calc(var(--reactive-button-min-width) - 25px);
47 | height: calc(var(--reactive-button-min-height) - 5px);
48 | }
49 |
50 | .reactive-btn-wrapper.large {
51 | min-width: calc(var(--reactive-button-min-width) + 25px);
52 | height: calc(var(--reactive-button-min-height) + 5px);
53 | }
54 |
55 | .reactive-btn-wrapper.block {
56 | width: 100%;
57 | }
58 |
59 | .reactive-btn {
60 | margin-bottom: 0;
61 | padding: 6px 14px 6px;
62 | font-size: var(--reactive-button-font-size);
63 | font-weight: var(--reactive-button-font-weight);
64 | width: 100%;
65 | min-height: 100%;
66 | color: var(--reactive-button-text-color);
67 | text-align: center;
68 | line-height: 1.5;
69 | text-decoration: none;
70 | user-select: none;
71 | -webkit-user-select: none;
72 | -moz-user-select: none;
73 | -ms-user-select: none;
74 | vertical-align: middle;
75 | cursor: pointer;
76 | background-color: var(--reactive-button-primary-color);
77 | border: none;
78 | -webkit-border-radius: var(--reactive-button-border-radius);
79 | -moz-border-radius: var(--reactive-button-border-radius);
80 | border-radius: var(--reactive-button-border-radius);
81 | -webkit-box-shadow: inset 0 -2px 0 rgba(0, 0, 0, 0.2);
82 | -moz-box-shadow: inset 0 -2px 0 rgba(0, 0, 0, 0.2);
83 | box-shadow: inset 0 -2px 0 rgba(0, 0, 0, 0.2);
84 | -webkit-transition: 0.1s;
85 | -moz-transition: 0.1s;
86 | transition: 0.1s;
87 | -webkit-box-sizing: border-box;
88 | -moz-box-sizing: border-box;
89 | box-sizing: border-box;
90 | position: relative;
91 | overflow: hidden;
92 | outline: none !important;
93 | align-items: center;
94 | -webkit-box-pack: center;
95 | -webkit-box-align: center;
96 | }
97 |
98 | .reactive-btn.outline {
99 | background-color: transparent !important;
100 | }
101 |
102 | .reactive-btn:disabled {
103 | cursor: default;
104 | }
105 |
106 | .reactive-btn:hover:not(:disabled):not(.disabled) {
107 | opacity: 0.85;
108 | }
109 |
110 | .reactive-btn:not(.no-animation):hover:not(:disabled):not(.disabled) {
111 | opacity: 0.85;
112 | -webkit-box-shadow: inset 0 -4px 0 rgba(0, 0, 0, 0.2);
113 | -moz-box-shadow: inset 0 -4px 0 rgba(0, 0, 0, 0.2);
114 | box-shadow: inset 0 -4px 0 rgba(0, 0, 0, 0.2);
115 | margin-top: -1px;
116 | padding: 6px 14px 8px;
117 | }
118 |
119 | .reactive-btn:not(.no-animation):active:not(:disabled):not(.disabled) {
120 | -webkit-box-shadow: none;
121 | -moz-box-shadow: none;
122 | box-shadow: none;
123 | margin-top: 1px;
124 | padding: 6px 14px 4px;
125 | }
126 |
127 | .reactive-btn:focus {
128 | outline: none !important;
129 | }
130 |
131 | .reactive-btn.rounded {
132 | border-radius: 50rem !important;
133 | -webkit-border-radius: 50rem !important;
134 | -moz-border-radius: 50rem !important;
135 | }
136 |
137 | .reactive-btn.disabled {
138 | opacity: 0.7;
139 | }
140 |
141 | .reactive-btn .content {
142 | position: relative;
143 | }
144 |
145 | .reactive-btn .progress {
146 | position: absolute;
147 | top: 0;
148 | left: 0;
149 | right: 0;
150 | bottom: 0;
151 | height: 100%;
152 | width: 100%;
153 | background-color: var(--reactive-progress-color);
154 | transform: translateX(-100%);
155 | transition: transform 0.2s ease;
156 | }
157 |
158 | .reactive-btn:not([data-button-state='idle']) .progress {
159 | transform: translateX(0%);
160 | transition: transform 3s cubic-bezier(0.59, 0.01, 0.41, 0.99);
161 | }
162 |
163 | .reactive-btn .drbll1:after {
164 | content: '.';
165 | animation: dots 1s steps(5, end) infinite;
166 | }
167 |
168 | .reactive-btn-wrapper.tiny .reactive-btn {
169 | font-size: calc(var(--reactive-button-font-size) - 4px);
170 | line-height: 1;
171 | }
172 |
173 | .reactive-btn-wrapper.small .reactive-btn {
174 | font-size: calc(var(--reactive-button-font-size) - 2px);
175 | }
176 |
177 | .reactive-btn-wrapper.large .reactive-btn {
178 | font-size: calc(var(--reactive-button-font-size) + 2px);
179 | }
180 |
181 | /* primary button starts */
182 | .reactive-btn.primary.outline {
183 | border-color: var(--reactive-button-primary-color);
184 | color: var(--reactive-button-primary-color);
185 | border: 1px solid var(--reactive-button-primary-color);
186 | box-shadow: inset 0 -1px 0 var(--reactive-button-primary-color);
187 | -webkit-box-shadow: inset 0 -1px 0 var(--reactive-button-primary-color);
188 | -moz-box-shadow: inset 0 -1px 0 var(--reactive-button-primary-color);
189 | }
190 |
191 | .reactive-btn.primary.outline .progress {
192 | background-color: var(--reactive-progress-outline-primary-color) !important;
193 | }
194 |
195 | .reactive-btn.primary.outline:hover:not(:disabled):not(.disabled) {
196 | box-shadow: inset 0 -3px 0 var(--reactive-button-primary-color);
197 | -webkit-box-shadow: inset 0 -3px 0 var(--reactive-button-primary-color);
198 | -moz-box-shadow: inset 0 -3px 0 var(--reactive-button-primary-color);
199 | }
200 |
201 | .reactive-btn.primary.shadow {
202 | box-shadow: 0px 5px 16px -3px var(--reactive-button-primary-color) !important;
203 | }
204 |
205 | /* primary button ends */
206 |
207 | /* secondary button starts */
208 | .reactive-btn.secondary {
209 | background: var(--reactive-button-secondary-color);
210 | }
211 |
212 | .reactive-btn.secondary.outline {
213 | border-color: var(--reactive-button-secondary-color);
214 | color: var(--reactive-button-secondary-color);
215 | border: 1px solid var(--reactive-button-secondary-color);
216 | box-shadow: inset 0 -1px 0 var(--reactive-button-secondary-color);
217 | -webkit-box-shadow: inset 0 -1px 0 var(--reactive-button-secondary-color);
218 | -moz-box-shadow: inset 0 -1px 0 var(--reactive-button-secondary-color);
219 | }
220 |
221 | .reactive-btn.secondary.outline .progress {
222 | background-color: var(--reactive-progress-outline-secondary-color) !important;
223 | }
224 |
225 | .reactive-btn.secondary.outline:hover:not(:disabled):not(.disabled) {
226 | box-shadow: inset 0 -3px 0 var(--reactive-button-secondary-color);
227 | -webkit-box-shadow: inset 0 -3px 0 var(--reactive-button-secondary-color);
228 | -moz-box-shadow: inset 0 -3px 0 var(--reactive-button-secondary-color);
229 | }
230 |
231 | .reactive-btn.secondary.shadow {
232 | box-shadow: 0px 5px 16px -3px var(--reactive-button-secondary-color) !important;
233 | }
234 |
235 | /* secondary button ends */
236 |
237 | /* dark button starts */
238 |
239 | .reactive-btn.dark {
240 | background: var(--reactive-button-dark-color);
241 | }
242 |
243 | .reactive-btn.dark.outline {
244 | border-color: var(--reactive-button-dark-color);
245 | color: var(--reactive-button-dark-color);
246 | border: 1px solid var(--reactive-button-dark-color);
247 | box-shadow: inset 0 -1px 0 var(--reactive-button-dark-color);
248 | -webkit-box-shadow: inset 0 -1px 0 var(--reactive-button-dark-color);
249 | -moz-box-shadow: inset 0 -1px 0 var(--reactive-button-dark-color);
250 | }
251 |
252 | .reactive-btn.dark.outline .progress {
253 | background-color: var(--reactive-progress-outline-dark-color) !important;
254 | }
255 |
256 | .reactive-btn.dark.outline:hover:not(:disabled):not(.disabled) {
257 | box-shadow: inset 0 -3px 0 var(--reactive-button-dark-color);
258 | -webkit-box-shadow: inset 0 -3px 0 var(--reactive-button-dark-color);
259 | -moz-box-shadow: inset 0 -3px 0 var(--reactive-button-dark-color);
260 | }
261 |
262 | .reactive-btn.dark.shadow {
263 | box-shadow: 0px 5px 16px -3px var(--reactive-button-dark-color) !important;
264 | }
265 |
266 | /* dark button ends */
267 |
268 | /* light button starts */
269 |
270 | .reactive-btn.light {
271 | background: var(--reactive-button-light-color);
272 | color: #000000;
273 | }
274 |
275 | .reactive-btn.light.outline {
276 | border-color: var(--reactive-button-light-color);
277 | color: var(--reactive-button-light-color);
278 | border: 1px solid var(--reactive-button-light-color);
279 | box-shadow: inset 0 -1px 0 var(--reactive-button-light-color);
280 | -webkit-box-shadow: inset 0 -1px 0 var(--reactive-button-light-color);
281 | -moz-box-shadow: inset 0 -1px 0 var(--reactive-button-light-color);
282 | }
283 |
284 | .reactive-btn.light.outline .progress {
285 | background-color: var(--reactive-progress-outline-light-color) !important;
286 | }
287 |
288 | .reactive-btn.light.outline:hover:not(:disabled):not(.disabled) {
289 | box-shadow: inset 0 -3px 0 var(--reactive-button-light-color);
290 | -webkit-box-shadow: inset 0 -3px 0 var(--reactive-button-light-color);
291 | -moz-box-shadow: inset 0 -3px 0 var(--reactive-button-light-color);
292 | }
293 |
294 | .reactive-btn.light.shadow {
295 | box-shadow: 0px 5px 16px -3px var(--reactive-button-light-color) !important;
296 | }
297 |
298 | /* light button ends */
299 |
300 | /* green button starts */
301 | .reactive-btn.green {
302 | background: var(--reactive-button-green-color);
303 | }
304 |
305 | .reactive-btn.green.outline {
306 | border-color: var(--reactive-button-green-color);
307 | color: var(--reactive-button-green-color);
308 | border: 1px solid var(--reactive-button-green-color);
309 | box-shadow: inset 0 -1px 0 var(--reactive-button-green-color);
310 | -webkit-box-shadow: inset 0 -1px 0 var(--reactive-button-green-color);
311 | -moz-box-shadow: inset 0 -1px 0 var(--reactive-button-green-color);
312 | }
313 |
314 | .reactive-btn.green.outline .progress {
315 | background-color: var(--reactive-progress-outline-green-color) !important;
316 | }
317 |
318 | .reactive-btn.green.outline:hover:not(:disabled):not(.disabled) {
319 | box-shadow: inset 0 -3px 0 var(--reactive-button-green-color);
320 | -webkit-box-shadow: inset 0 -3px 0 var(--reactive-button-green-color);
321 | -moz-box-shadow: inset 0 -3px 0 var(--reactive-button-green-color);
322 | }
323 |
324 | .reactive-btn.green.shadow {
325 | box-shadow: 0px 5px 16px -3px var(--reactive-button-green-color) !important;
326 | }
327 |
328 | /* green button ends */
329 |
330 | /* red button starts */
331 | .reactive-btn.red {
332 | background: var(--reactive-button-red-color);
333 | }
334 |
335 | .reactive-btn.red.outline {
336 | border-color: var(--reactive-button-red-color);
337 | color: var(--reactive-button-red-color);
338 | border: 1px solid var(--reactive-button-red-color);
339 | box-shadow: inset 0 -1px 0 var(--reactive-button-red-color);
340 | -webkit-box-shadow: inset 0 -1px 0 var(--reactive-button-red-color);
341 | -moz-box-shadow: inset 0 -1px 0 var(--reactive-button-red-color);
342 | }
343 |
344 | .reactive-btn.red.outline .progress {
345 | background-color: var(--reactive-progress-outline-red-color) !important;
346 | }
347 |
348 | .reactive-btn.red.outline:hover:not(:disabled):not(.disabled) {
349 | box-shadow: inset 0 -3px 0 var(--reactive-button-red-color);
350 | -webkit-box-shadow: inset 0 -3px 0 var(--reactive-button-red-color);
351 | -moz-box-shadow: inset 0 -3px 0 var(--reactive-button-red-color);
352 | }
353 |
354 | .reactive-btn.red.shadow {
355 | box-shadow: 0px 5px 16px -3px var(--reactive-button-red-color) !important;
356 | }
357 |
358 | /* red button ends */
359 |
360 | /* yellow button starts */
361 | .reactive-btn.yellow {
362 | background: var(--reactive-button-yellow-color);
363 | color: #000000;
364 | }
365 |
366 | .reactive-btn.yellow.outline {
367 | border-color: var(--reactive-button-yellow-color);
368 | color: var(--reactive-button-yellow-color);
369 | border: 1px solid var(--reactive-button-yellow-color);
370 | box-shadow: inset 0 -1px 0 var(--reactive-button-yellow-color);
371 | -webkit-box-shadow: inset 0 -1px 0 var(--reactive-button-yellow-color);
372 | -moz-box-shadow: inset 0 -1px 0 var(--reactive-button-yellow-color);
373 | }
374 |
375 | .reactive-btn.yellow.outline .progress {
376 | background-color: var(--reactive-progress-outline-yellow-color) !important;
377 | }
378 |
379 | .reactive-btn.yellow.outline:hover:not(:disabled):not(.disabled) {
380 | box-shadow: inset 0 -3px 0 var(--reactive-button-yellow-color);
381 | -webkit-box-shadow: inset 0 -3px 0 var(--reactive-button-yellow-color);
382 | -moz-box-shadow: inset 0 -3px 0 var(--reactive-button-yellow-color);
383 | }
384 |
385 | .reactive-btn.yellow.shadow {
386 | box-shadow: 0px 5px 16px -3px var(--reactive-button-yellow-color) !important;
387 | }
388 |
389 | /* yellow button ends */
390 |
391 | /* teal button starts */
392 | .reactive-btn.teal {
393 | background: var(--reactive-button-teal-color);
394 | }
395 |
396 | .reactive-btn.teal.outline {
397 | border-color: var(--reactive-button-teal-color);
398 | color: var(--reactive-button-teal-color);
399 | border: 1px solid var(--reactive-button-teal-color);
400 | box-shadow: inset 0 -1px 0 var(--reactive-button-teal-color);
401 | -webkit-box-shadow: inset 0 -1px 0 var(--reactive-button-teal-color);
402 | -moz-box-shadow: inset 0 -1px 0 var(--reactive-button-teal-color);
403 | }
404 |
405 | .reactive-btn.teal.outline .progress {
406 | background-color: var(--reactive-progress-outline-teal-color) !important;
407 | }
408 |
409 | .reactive-btn.teal.outline:hover:not(:disabled):not(.disabled) {
410 | box-shadow: inset 0 -3px 0 var(--reactive-button-teal-color);
411 | -webkit-box-shadow: inset 0 -3px 0 var(--reactive-button-teal-color);
412 | -moz-box-shadow: inset 0 -3px 0 var(--reactive-button-teal-color);
413 | }
414 |
415 | .reactive-btn.teal.shadow {
416 | box-shadow: 0px 5px 16px -3px var(--reactive-button-teal-color) !important;
417 | }
418 |
419 | /* teal button ends */
420 |
421 | /* violet button starts */
422 | .reactive-btn.violet {
423 | background: var(--reactive-button-violet-color);
424 | }
425 |
426 | .reactive-btn.violet.outline {
427 | border-color: var(--reactive-button-violet-color);
428 | color: var(--reactive-button-violet-color);
429 | border: 1px solid var(--reactive-button-violet-color);
430 | box-shadow: inset 0 -1px 0 var(--reactive-button-violet-color);
431 | -webkit-box-shadow: inset 0 -1px 0 var(--reactive-button-violet-color);
432 | -moz-box-shadow: inset 0 -1px 0 var(--reactive-button-violet-color);
433 | }
434 |
435 | .reactive-btn.violet.outline .progress {
436 | background-color: var(--reactive-progress-outline-violet-color) !important;
437 | }
438 |
439 | .reactive-btn.violet.outline:hover:not(:disabled):not(.disabled) {
440 | box-shadow: inset 0 -3px 0 var(--reactive-button-violet-color);
441 | -webkit-box-shadow: inset 0 -3px 0 var(--reactive-button-violet-color);
442 | -moz-box-shadow: inset 0 -3px 0 var(--reactive-button-violet-color);
443 | }
444 |
445 | .reactive-btn.violet.shadow {
446 | box-shadow: 0px 5px 16px -3px var(--reactive-button-violet-color) !important;
447 | }
448 |
449 | /* violet button ends */
450 |
451 | /* blue button starts */
452 | .reactive-btn.blue {
453 | background: var(--reactive-button-blue-color);
454 | }
455 |
456 | .reactive-btn.blue.outline {
457 | border-color: var(--reactive-button-blue-color);
458 | color: var(--reactive-button-blue-color);
459 | border: 1px solid var(--reactive-button-blue-color);
460 | box-shadow: inset 0 -1px 0 var(--reactive-button-blue-color);
461 | -webkit-box-shadow: inset 0 -1px 0 var(--reactive-button-blue-color);
462 | -moz-box-shadow: inset 0 -1px 0 var(--reactive-button-blue-color);
463 | }
464 |
465 | .reactive-btn.blue.outline .progress {
466 | background-color: var(--reactive-progress-outline-blue-color) !important;
467 | }
468 |
469 | .reactive-btn.blue.outline:hover:not(:disabled):not(.disabled) {
470 | box-shadow: inset 0 -3px 0 var(--reactive-button-blue-color);
471 | -webkit-box-shadow: inset 0 -3px 0 var(--reactive-button-blue-color);
472 | -moz-box-shadow: inset 0 -3px 0 var(--reactive-button-blue-color);
473 | }
474 |
475 | .reactive-btn.blue.shadow {
476 | box-shadow: 0px 5px 16px -3px var(--reactive-button-blue-color) !important;
477 | }
478 |
479 | /* blue button ends */
480 |
481 | .reactive-spin {
482 | animation: reactive-spin 2s infinite linear;
483 | }
484 | .reactive-btn-loading-svg,
485 | .reactive-btn-success-svg,
486 | .reactive-btn-error-svg {
487 | display: inline-block;
488 | font-size: inherit;
489 | height: 1em;
490 | overflow: visible;
491 | vertical-align: -0.125em;
492 | }
493 |
494 | @keyframes dots {
495 | 0%,
496 | 20% {
497 | color: rgba(0, 0, 0, 0);
498 | text-shadow: 0.25em 0 0 rgba(0, 0, 0, 0), 0.5em 0 0 rgba(0, 0, 0, 0);
499 | }
500 |
501 | 40% {
502 | color: white;
503 | text-shadow: 0.25em 0 0 rgba(0, 0, 0, 0), 0.5em 0 0 rgba(0, 0, 0, 0);
504 | }
505 |
506 | 60% {
507 | text-shadow: 0.25em 0 0 white, 0.5em 0 0 rgba(0, 0, 0, 0);
508 | }
509 |
510 | 80%,
511 | 100% {
512 | text-shadow: 0.25em 0 0 white, 0.5em 0 0 white;
513 | }
514 | }
515 |
516 | @keyframes reactive-spin {
517 | 0% {
518 | -webkit-transform: rotate(0deg);
519 | transform: rotate(0deg);
520 | }
521 | 100% {
522 | -webkit-transform: rotate(360deg);
523 | transform: rotate(360deg);
524 | }
525 | }
526 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState } from 'react';
2 | import './css/index.css';
3 | import PropTypes from 'prop-types';
4 |
5 | const loadingIcon = (
6 |
16 |
20 |
21 | );
22 |
23 | const successIcon = (
24 |
34 |
38 |
39 | );
40 |
41 | const errorIcon = (
42 |
52 |
56 |
57 | );
58 |
59 | const ReactiveButton = (props) => {
60 | const color = props.color ? props.color : 'primary';
61 |
62 | const idleText = props.idleText ? props.idleText : 'Click Me';
63 |
64 | const loadingText =
65 | props.loadingText && props.loadingText !== ''
66 | ? props.loadingText
67 | : 'Loading';
68 |
69 | const successText =
70 | props.successText && props.successText !== ''
71 | ? props.successText
72 | : 'Success';
73 |
74 | const errorText =
75 | props.errorText && props.errorText !== '' ? props.errorText : 'Error';
76 |
77 | const type = props.type ? props.type : 'button';
78 |
79 | const className = `reactive-btn${
80 | props.className ? ' ' + props.className : ''
81 | }`;
82 |
83 | const outline = props.outline ? true : false;
84 |
85 | const shadow = props.shadow ? true : false;
86 |
87 | const style = props.style ? props.style : {};
88 |
89 | const rounded = props.rounded ? true : false;
90 |
91 | const size = props.size ? props.size : 'normal';
92 |
93 | const animation =
94 | typeof props.animation !== 'undefined' && props.animation === false
95 | ? false
96 | : true;
97 |
98 | const [buttonState, setButtonState] = useState(
99 | props.buttonState ? props.buttonState : 'idle'
100 | );
101 |
102 | const onClickHandler = () => {
103 | if (typeof props.onClick !== 'undefined') {
104 | props.onClick();
105 | }
106 | };
107 |
108 | useEffect(() => {
109 | if (typeof props.buttonState !== 'undefined') {
110 | setButtonState(props.buttonState);
111 | if (props.buttonState === 'success' || props.buttonState === 'error') {
112 | setTimeout(
113 | () => {
114 | setButtonState('idle');
115 | },
116 | props.messageDuration ? props.messageDuration : 2000
117 | );
118 | }
119 | }
120 | }, [props.buttonState, props.messageDuration]);
121 |
122 | const getButtonText = (currentButtonState) => {
123 | if (currentButtonState === 'idle') {
124 | return idleText;
125 | } else if (currentButtonState === 'loading') {
126 | return loadingText === 'Loading' ? (
127 |
128 | {loadingIcon} {loadingText}
129 |
130 | ) : (
131 | loadingText
132 | );
133 | } else if (currentButtonState === 'success') {
134 | return successText === 'Success' ? (
135 |
136 | {successIcon} {successText}
137 |
138 | ) : (
139 | successText
140 | );
141 | } else if (currentButtonState === 'error') {
142 | return errorText === 'Error' ? (
143 |
144 | {errorIcon} {errorText}
145 |
146 | ) : (
147 | errorText
148 | );
149 | }
150 | };
151 |
152 | return (
153 |
154 |
158 |
171 |
172 |
173 | {getButtonText(buttonState)}
174 |
175 |
176 |
177 |
178 | );
179 | };
180 |
181 | ReactiveButton.propTypes = {
182 | color: PropTypes.string,
183 | idleText: PropTypes.oneOfType([PropTypes.string, PropTypes.node]),
184 | loadingText: PropTypes.oneOfType([PropTypes.string, PropTypes.node]),
185 | successText: PropTypes.oneOfType([PropTypes.string, PropTypes.node]),
186 | errorText: PropTypes.oneOfType([PropTypes.string, PropTypes.node]),
187 | type: PropTypes.string,
188 | className: PropTypes.string,
189 | outline: PropTypes.bool,
190 | shadow: PropTypes.bool,
191 | style: PropTypes.oneOfType([PropTypes.object, PropTypes.array]),
192 | rounded: PropTypes.bool,
193 | size: PropTypes.string,
194 | animation: PropTypes.bool,
195 | buttonState: PropTypes.string,
196 | onClick: PropTypes.func,
197 | messageDuration: PropTypes.number,
198 | block: PropTypes.bool,
199 | width: PropTypes.string,
200 | height: PropTypes.string,
201 | buttonRef: PropTypes.oneOfType([
202 | PropTypes.func,
203 | PropTypes.shape({ current: PropTypes.any }),
204 | ]),
205 | disabled: PropTypes.bool,
206 | };
207 |
208 | export default ReactiveButton;
209 |
--------------------------------------------------------------------------------
/types/index.d.ts:
--------------------------------------------------------------------------------
1 | // Type definitions for Reactive Button
2 | // Project https://github.com/arifszn/reactive-button
3 | // Author: Ariful Alam
4 |
5 | import {
6 | CSSProperties,
7 | Component,
8 | MouseEvent,
9 | MutableRefObject,
10 | ReactNode,
11 | } from 'react';
12 |
13 | export interface ReactiveButtonProps {
14 | /**
15 | * Current button state. Values: 'idle' | 'loading' | 'success' | 'error'
16 | *
17 | * Default: 'idle'.
18 | */
19 | buttonState?: string;
20 |
21 | /**
22 | * Callback function when clicking button.
23 | *
24 | * Default: () => {}
25 | */
26 | onClick?: (event: MouseEvent) => void;
27 |
28 | /**
29 | * Button color. values: 'primary' | 'secondary' | 'dark' | 'light' | 'green' | 'red' | 'yellow' | 'teal' | 'violet' | 'blue'
30 | *
31 | * Default: 'primary'
32 | */
33 | color?: string;
34 |
35 | /**
36 | * Button text when idle.
37 | *
38 | * Default: 'Click Me'
39 | */
40 | idleText?: string | ReactNode;
41 |
42 | /**
43 | * Button text when loading.
44 | *
45 | * Default: 'Loading'
46 | */
47 | loadingText?: string | ReactNode;
48 |
49 | /**
50 | * Button text when loading successful.
51 | *
52 | * Default: 'Success'
53 | */
54 | successText?: string | ReactNode;
55 |
56 | /**
57 | * Button text when loading failed.
58 | *
59 | * Default: 'Error'
60 | */
61 | errorText?: string | ReactNode;
62 |
63 | /**
64 | * Button type attribute. Values: 'button' | 'submit' | 'reset'
65 | *
66 | * Default: 'button'
67 | */
68 | type?: string;
69 |
70 | /**
71 | * Button classnames.
72 | *
73 | * Default: ''
74 | */
75 | className?: string;
76 |
77 | /**
78 | * Custom style.
79 | *
80 | * Default: {}
81 | */
82 | style?: CSSProperties;
83 |
84 | /**
85 | * Enable outline effect.
86 | *
87 | * Default: false
88 | */
89 | outline?: boolean;
90 |
91 | /**
92 | * Enable shadow effect.
93 | *
94 | * Default: false
95 | */
96 | shadow?: boolean;
97 |
98 | /**
99 | * Enable rounded button.
100 | *
101 | * Default: false
102 | */
103 | rounded?: boolean;
104 |
105 | /**
106 | * Button size. Values: 'tiny' | 'small' | 'normal' | 'large'
107 | *
108 | * Default: 'normal'
109 | */
110 | size?: string;
111 |
112 | /**
113 | * Block button.
114 | *
115 | * Default: false
116 | */
117 | block?: boolean;
118 |
119 | /**
120 | * Success/Error message duration in millisecond.
121 | *
122 | * Default: 2000
123 | */
124 | messageDuration?: number;
125 |
126 | /**
127 | * Disable button.
128 | *
129 | * Default: false
130 | */
131 | disabled?: boolean;
132 |
133 | /**
134 | * Button reference.
135 | *
136 | * Default null
137 | */
138 | buttonRef?: MutableRefObject | null;
139 |
140 | /**
141 | * Override button width.
142 | *
143 | * Default null
144 | */
145 | width?: string | null;
146 |
147 | /**
148 | * Override button height.
149 | *
150 | * Default null
151 | */
152 | height?: string | null;
153 |
154 | /**
155 | * Button hover and click animation.
156 | *
157 | * Default true
158 | */
159 | animation?: boolean;
160 | }
161 |
162 | declare class ReactiveButton extends Component {}
163 |
164 | export default ReactiveButton;
165 |
--------------------------------------------------------------------------------