├── .eslintrc.json ├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── add-my-logo.yml │ ├── bug-report.yml │ ├── config.yml │ └── feature-request.yml ├── PULL_REQUEST_TEMPLATE │ ├── bug-fix.md │ ├── documentation-update.md │ └── new-feature.md └── workflows │ └── tests.yml ├── .gitignore ├── .idea ├── .gitignore ├── codeStyles │ ├── Project.xml │ └── codeStyleConfig.xml ├── inspectionProfiles │ └── Project_Default.xml ├── modules.xml ├── react-idle-timer.iml ├── runConfigurations │ └── All_Tests.xml └── vcs.xml ├── .npmignore ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── docs ├── configs │ ├── docs.sidebar.json │ └── site.config.ts ├── contentlayer.config.ts ├── layouts │ ├── index.tsx │ └── mdx.tsx ├── next-env.d.ts ├── next.config.js ├── next.i18n.config.js ├── next.redirect.js ├── package-lock.json ├── package.json ├── pages │ ├── 404.tsx │ ├── _app.tsx │ ├── _document.tsx │ ├── demo.tsx │ ├── docs │ │ ├── [[...slug]].tsx │ │ ├── about │ │ │ ├── changelog.mdx │ │ │ ├── contributing.mdx │ │ │ └── license.mdx │ │ ├── api │ │ │ ├── idle-timer-provider.mdx │ │ │ ├── methods.mdx │ │ │ ├── props.mdx │ │ │ ├── types.mdx │ │ │ ├── use-idle-timer.mdx │ │ │ └── with-idle-timer.mdx │ │ ├── features │ │ │ ├── activity-detection.mdx │ │ │ ├── confirm-prompt.mdx │ │ │ ├── cross-tab.mdx │ │ │ └── idle-detection.mdx │ │ └── getting-started │ │ │ ├── installation.mdx │ │ │ ├── new.mdx │ │ │ └── testing.mdx │ └── index.tsx ├── public │ ├── favicon.png │ ├── fonts │ │ └── Inter.woff2 │ ├── locales │ │ └── en │ │ │ └── common.json │ ├── logos │ │ └── edgemesh-logo.png │ ├── og-image.png │ ├── robots.txt │ ├── square-logo.png │ └── twitter-og-image.png ├── sponsors.json ├── src │ ├── components │ │ ├── Announcer.tsx │ │ ├── ChakraNextImage.tsx │ │ ├── Container.tsx │ │ ├── ControlDrawer.tsx │ │ ├── Demo.tsx │ │ ├── DiscordBar.tsx │ │ ├── EditPageButton.tsx │ │ ├── Features.tsx │ │ ├── FontFace.tsx │ │ ├── Footer.tsx │ │ ├── Header.tsx │ │ ├── HeaderIconButtons.tsx │ │ ├── Hero.tsx │ │ ├── Logo.tsx │ │ ├── MobileNav.tsx │ │ ├── PageContainer.tsx │ │ ├── PageTransition.tsx │ │ ├── Pagination.tsx │ │ ├── SEO.tsx │ │ ├── Sidebar.tsx │ │ ├── SidebarCategory.tsx │ │ ├── SidebarLink.tsx │ │ ├── SponsorButton.tsx │ │ ├── Sponsors.tsx │ │ ├── Stats.tsx │ │ ├── TableOfContents.tsx │ │ ├── UsedBy.tsx │ │ ├── Window.tsx │ │ └── mdx │ │ │ ├── Anchor.tsx │ │ │ ├── CodeBlock.tsx │ │ │ ├── CodeBlockStyles.ts │ │ │ ├── CodeContainer.tsx │ │ │ ├── CodeSandbox.tsx │ │ │ ├── CodeSandboxButton.tsx │ │ │ ├── ComponentLinks.tsx │ │ │ ├── CopyButton.tsx │ │ │ ├── Highlight.tsx │ │ │ ├── InlineCode.tsx │ │ │ ├── LinkedHeading.tsx │ │ │ ├── Pre.tsx │ │ │ ├── Property.tsx │ │ │ ├── Table.tsx │ │ │ └── index.tsx │ ├── hooks │ │ ├── useRouteChanged.ts │ │ └── useScrollSpy.ts │ ├── theme │ │ ├── config.ts │ │ ├── index.ts │ │ ├── mdx.ts │ │ └── textStyles.ts │ └── utils │ │ ├── convertBackticks.tsx │ │ ├── debounce.ts │ │ ├── findRouteByPath.ts │ │ ├── ga.ts │ │ ├── getCodeQuality.ts │ │ ├── getDiscordMembers.ts │ │ ├── getGithubStars.ts │ │ ├── getNpmDownloads.ts │ │ ├── getRouteContext.ts │ │ ├── getSponsors.ts │ │ ├── getTestCoverage.ts │ │ ├── getUsedBy.ts │ │ ├── i18n.ts │ │ ├── mdx.ts │ │ ├── numberFormatter.ts │ │ ├── rehype.ts │ │ └── seo.ts ├── tsconfig.json └── usedby.json ├── jest.config.mjs ├── logo.svg ├── package-lock.json ├── package-scripts.js ├── package.json ├── scripts └── build.js ├── src ├── IdleTimerContext.tsx ├── TabManager │ ├── BroadcastChannel.ts │ ├── LeaderElector.ts │ └── index.ts ├── index.ts ├── types │ ├── EventType.ts │ ├── EventsType.ts │ ├── FnType.ts │ ├── IEventHandler.ts │ ├── IIdleTimer.ts │ ├── IIdleTimerContext.ts │ ├── IIdleTimerProps.ts │ ├── IMessageHandler.ts │ ├── IPresenceChangeHandler.ts │ ├── ITimers.ts │ ├── MessageActionType.ts │ ├── MessageType.ts │ └── PresenceType.ts ├── useIdleTimer.tsx ├── utils │ ├── debounce.ts │ ├── defaults.ts │ ├── isBrowser.ts │ ├── now.ts │ ├── sleep.ts │ ├── throttle.ts │ ├── timers.ts │ └── token.ts └── withIdleTimer.tsx ├── tests ├── BroadcastChannel.test.ts ├── IdleTimerProvider.test.tsx ├── LeaderElector.test.ts ├── SSR.test.tsx ├── TabManager.test.ts ├── bundle.test.tsx ├── index.d.ts ├── test.setup.ts ├── test.utils.ts ├── useIdleTimer.test.ts └── withIdleTimer.test.tsx ├── tsconfig.base.json ├── tsconfig.build.json └── tsconfig.json /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": true, 4 | "es2021": true, 5 | "jest/globals": true 6 | }, 7 | "extends": [ 8 | "plugin:react/recommended", 9 | "plugin:@next/next/recommended", 10 | "standard" 11 | ], 12 | "settings": { 13 | "react": { 14 | "version": "latest" 15 | } 16 | }, 17 | "parser": "@typescript-eslint/parser", 18 | "parserOptions": { 19 | "ecmaFeatures": { 20 | "jsx": true 21 | }, 22 | "ecmaVersion": "latest", 23 | "sourceType": "module" 24 | }, 25 | "plugins": [ 26 | "jest", 27 | "react", 28 | "@typescript-eslint" 29 | ], 30 | "rules": { 31 | "no-unused-vars": "off", 32 | "@typescript-eslint/no-unused-vars": "error", 33 | "react/react-in-jsx-scope": "off", 34 | "jest/no-disabled-tests": "warn", 35 | "jest/no-focused-tests": "warn", 36 | "jest/no-identical-title": "error", 37 | "jest/prefer-to-have-length": "warn", 38 | "jest/valid-expect": "error" 39 | }, 40 | "ignorePatterns": [ 41 | "**/dist/**", 42 | "**/out/**" 43 | ] 44 | } -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: SupremeTechnopriest 2 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/add-my-logo.yml: -------------------------------------------------------------------------------- 1 | name: 🎨 Add My Logo 2 | description: Add your logo to the Documentation Site. 3 | title: "🎨 " 4 | labels: ["triage", "docs"] 5 | assignees: 6 | - supremetechnopriest 7 | body: 8 | - type: markdown 9 | attributes: 10 | value: | 11 | Thank you for adding your logo to the Documentation Site! 12 | - type: input 13 | id: name 14 | attributes: 15 | label: What is your company name? 16 | description: "Your company name will be used for the tooltip when you hover over your logo." 17 | placeholder: "My Company" 18 | validations: 19 | required: true 20 | - type: input 21 | id: link 22 | attributes: 23 | label: What is your website? 24 | description: "Your website will be used as the href when your logo is clicked." 25 | placeholder: "https://my.co" 26 | value: "https://" 27 | validations: 28 | required: true 29 | - type: textarea 30 | id: logo 31 | attributes: 32 | label: Upload your logo. 33 | description: Your logo should be exactly 100px high. 34 | validations: 35 | required: true 36 | - type: checkboxes 37 | id: verified 38 | attributes: 39 | label: Sponsorship 40 | description: No worries if you are not. This is used for positioning of your logo. 41 | options: 42 | - label: Are you a sponsor of Idle Timer? 43 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug-report.yml: -------------------------------------------------------------------------------- 1 | name: 🐞 Bug Report 2 | description: Report a bug found in IdleTimer. 3 | title: "🐞 " 4 | labels: ["triage", "bug"] 5 | assignees: 6 | - supremetechnopriest 7 | body: 8 | - type: markdown 9 | attributes: 10 | value: | 11 | Thank you for taking the time to fill out this bug report! 12 | - type: textarea 13 | id: what-happened 14 | attributes: 15 | label: What happened? 16 | description: Also tell us, what did you expect to happen? 17 | placeholder: Tell us what you see! 18 | validations: 19 | required: true 20 | - type: textarea 21 | id: reproduction 22 | attributes: 23 | label: Reproduction Steps 24 | description: "How do you trigger this bug? Please walk us through it step by step." 25 | value: | 26 | 1. 27 | 2. 28 | 3. 29 | ... 30 | render: bash 31 | validations: 32 | required: true 33 | - type: textarea 34 | id: logs 35 | attributes: 36 | label: Relevant log output 37 | description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks. 38 | render: bash 39 | - type: textarea 40 | id: context 41 | attributes: 42 | label: Screenshots or Additional Context 43 | description: Add any screenshots or provide additional context that may be helpful in resolving the issue. 44 | - type: dropdown 45 | id: version 46 | attributes: 47 | label: Module Version 48 | description: Select the version you are running. 49 | options: 50 | - 5.7.2 51 | - 5.7.1 52 | - 5.7.0 53 | - 5.6.2 54 | - 5.6.1 55 | - 5.6.0 56 | - 5.5.3 57 | - 5.5.2 58 | - 5.5.1 59 | - 5.5.0 60 | - 5.4.2 61 | - 5.4.1 62 | - 5.4.0 63 | - 5.3.0 64 | - 5.2.0 65 | - 5.1.3 66 | - 5.1.2 67 | - 5.1.1 68 | - 5.1.0 69 | - 5.0.0 70 | - 4.*.* 71 | - 3.*.* 72 | - 2.*.* 73 | - 1.*.* 74 | - 0.*.* 75 | validations: 76 | required: true 77 | - type: dropdown 78 | id: browsers 79 | attributes: 80 | label: What browsers are you seeing the problem on? Select all that apply. 81 | multiple: true 82 | options: 83 | - Firefox 84 | - Chrome 85 | - Safari 86 | - Microsoft Edge 87 | - Other 88 | - type: dropdown 89 | id: devices 90 | attributes: 91 | label: What devices are you seeing the problem on? 92 | multiple: true 93 | options: 94 | - Desktop 95 | - Mobile 96 | - Tablet 97 | - Wearable 98 | - Other 99 | - type: checkboxes 100 | id: verify 101 | attributes: 102 | label: Verification 103 | description: Please check closed issues and discussions before opening a new issue. 104 | options: 105 | - label: I have checked for existing closed issues and discussions. 106 | required: true 107 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: ❓ Question or Other 4 | url: https://github.com/SupremeTechnopriest/react-idle-timer/discussions/new/choose 5 | about: Ask a question or start a discussion. 6 | - name: 📖 Documentation 7 | url: https://idletimer.dev/ 8 | about: Explore detailed documentation and examples. 9 | - name: 💬 Join the Community 10 | url: https://discord.gg/YPuxNdWA4D 11 | about: Join our discord community for announcements and support. 12 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature-request.yml: -------------------------------------------------------------------------------- 1 | name: ⚡️ Feature Request 2 | description: Suggest a feature you would like to see supported in IdleTimer. 3 | title: "⚡️ " 4 | labels: ["triage", "enhancement"] 5 | assignees: 6 | - supremetechnopriest 7 | body: 8 | - type: markdown 9 | attributes: 10 | value: | 11 | Thank you for taking the time to suggest this feature! 12 | - type: textarea 13 | id: problem 14 | attributes: 15 | label: What problem does your feature request solve? 16 | description: A clear and concise description of what the problem is. 17 | placeholder: Tell us the problem! 18 | validations: 19 | required: true 20 | - type: textarea 21 | id: solution 22 | attributes: 23 | label: Describe the solution you are proposing. 24 | description: A clear and concise description of what you would like to see implemented. 25 | placeholder: Tell us the solution! 26 | validations: 27 | required: true 28 | - type: textarea 29 | id: alternatives 30 | attributes: 31 | label: Describe alternatives you have considered. 32 | description: A clear and concise description of any alternative solutions or features you have considered. 33 | placeholder: Tell us about any alternatives! 34 | - type: dropdown 35 | id: importance 36 | attributes: 37 | label: Importance 38 | description: How important is this feature to you? 39 | options: 40 | - I Need It 41 | - Nice to Have 42 | - Could Live Without 43 | validations: 44 | required: true 45 | - type: checkboxes 46 | id: context 47 | attributes: 48 | label: Additional Context 49 | description: Help us understand the severity of this missing feature. Check all that apply. 50 | options: 51 | - label: This missing feature presents as a bug. 52 | - label: This missing feature is forcing me to consider alternatives. 53 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE/bug-fix.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 🐞 Bug Fix 3 | labels: triage, bug 4 | about: Fix a bug in the IdleTimer Source or Documentation. 5 | --- 6 | 7 | ## Pre Submission Checklist 8 | 9 | 10 | 11 | ### Type of Change 12 | - [x] Bug fix. 13 | - [ ] New feature. 14 | - [ ] Documentation update. 15 | 16 | ### Requirements 17 | - [ ] I have read the [**CONTRIBUTING**](CONTRIBUTING.md) document. 18 | - [ ] I have followed the [**Commit Message Guidelines**](CONTRIBUTING.md#git-commit-messages). 19 | - [ ] My code passes the eslint style. 20 | 21 | ### Documentation 22 | - [ ] My change requires a change to the documentation. 23 | - [ ] I have updated the documentation accordingly. 24 | 25 | ### Automated Tests 26 | - [ ] My change does not require any additional tests to maintain full coverage. 27 | - [ ] I have added tests to cover any critical components of my change. 28 | - [ ] The test suite is passing. 29 | 30 | ## Issues this Pull Request Resolves 31 | 32 | 33 | 34 | ## Additional Context 35 | 36 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE/documentation-update.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 📝 Documentation Update 3 | labels: triage, docs 4 | about: Update to Documentation or Examples. 5 | --- 6 | 7 | ## Pre Submission Checklist 8 | 9 | 10 | 11 | ### Type of Change 12 | - [ ] Bug fix. 13 | - [ ] New feature. 14 | - [x] Documentation update. 15 | 16 | ### Requirements 17 | - [ ] I have read the [**CONTRIBUTING**](CONTRIBUTING.md) document. 18 | - [ ] I have followed the [**Commit Message Guidelines**](CONTRIBUTING.md#git-commit-messages). 19 | - [ ] My code passes the eslint style. 20 | 21 | ### Documentation 22 | - [x] My change requires a change to the documentation. 23 | - [x] I have updated the documentation accordingly. 24 | 25 | ### Automated Tests 26 | - [x] My change does not require any additional tests to maintain full coverage. 27 | - [ ] I have added tests to cover any critical components of my change. 28 | - [x] The test suite is passing. 29 | 30 | ## Issues this Pull Request Resolves 31 | 32 | 33 | 34 | ## Additional Context 35 | 36 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE/new-feature.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: ⚡️ New Feature 3 | labels: triage, enhancement 4 | about: Implement a New Feature. 5 | --- 6 | 7 | ## Pre Submission Checklist 8 | 9 | 10 | 11 | ### Type of Change 12 | - [ ] Bug fix. 13 | - [x] New feature. 14 | - [ ] Documentation update. 15 | 16 | ### Requirements 17 | - [ ] I have read the [**CONTRIBUTING**](CONTRIBUTING.md) document. 18 | - [ ] I have followed the [**Commit Message Guidelines**](CONTRIBUTING.md#git-commit-messages). 19 | - [ ] My code passes the eslint style. 20 | 21 | ### Documentation 22 | - [ ] My change requires a change to the documentation. 23 | - [ ] I have updated the documentation accordingly. 24 | 25 | ### Automated Tests 26 | - [ ] My change does not require any additional tests to maintain full coverage. 27 | - [ ] I have added tests to cover any critical components of my change. 28 | - [ ] The test suite is passing. 29 | 30 | ## Issues this Pull Request Resolves 31 | 32 | 33 | 34 | ## Additional Context 35 | 36 | -------------------------------------------------------------------------------- /.github/workflows/tests.yml: -------------------------------------------------------------------------------- 1 | name: tests 2 | on: 3 | push: 4 | branches: 5 | - master 6 | tags: 7 | - '!*' 8 | paths: 9 | - .github/workflows/* 10 | - src/** 11 | - '*.json' 12 | - '!*.MD' 13 | - '!docs/**' 14 | pull_request: 15 | paths: 16 | - .github/workflows/* 17 | - src/** 18 | - '*.json' 19 | - '!*.MD' 20 | - '!docs/**' 21 | jobs: 22 | test: 23 | name: Test 24 | runs-on: ubuntu-latest 25 | steps: 26 | - uses: actions/checkout@master 27 | - uses: actions/setup-node@master 28 | with: 29 | node-version: '18' 30 | - name: Install Modules 31 | run: npm i 32 | - name: Build Package 33 | run: npm run build 34 | - name: Run Tests 35 | run: npm t 36 | - name: Upload Coverage 37 | uses: paambaati/codeclimate-action@v3.2.0 38 | env: 39 | CC_TEST_REPORTER_ID: fff55059c877f2d5091c8a89cb5bebd3bcf12811355ce9e109e35f78c4bef96c 40 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # OSX 2 | # 3 | .DS_Store 4 | 5 | # Node 6 | # 7 | node_modules 8 | npm-debug.log* 9 | 10 | # Next 11 | # 12 | .next 13 | .contentlayer 14 | 15 | # Application 16 | # 17 | dist 18 | out 19 | worker 20 | coverage 21 | 22 | # Environments 23 | # 24 | .env.local -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Editor-based HTTP Client requests 5 | /httpRequests/ 6 | -------------------------------------------------------------------------------- /.idea/codeStyles/Project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | 10 | 19 | 20 | 31 | 32 | 33 | 35 | 36 | 37 | 38 | 42 | 43 | 44 | 45 | 47 | 48 | 49 | 50 | 52 | 53 | 54 | 69 | 70 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /.idea/codeStyles/codeStyleConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/react-idle-timer.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/runConfigurations/All_Tests.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | # OSX 2 | # 3 | .DS_Store 4 | 5 | # node.js 6 | # 7 | node_modules/ 8 | npm-debug.log 9 | npm-debug.log.* 10 | 11 | # Config 12 | # 13 | .github 14 | .vscode 15 | .eslintrc.json 16 | .gitignore 17 | package-scripts.js 18 | jest.config.mjs 19 | tsconfig.json 20 | 21 | # Application 22 | # 23 | scripts 24 | docs 25 | src 26 | tests 27 | coverage 28 | CONTRIBUTING.md 29 | CHANGELOG.md 30 | logo.svg -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Randy Lebeau 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 |

React Idle Timer

7 | 8 |

9 | 10 | Version 11 | 12 | 13 | License 14 | 15 | 16 | Downloads 17 | 18 | 19 | GitHub Sponsors 20 | 21 | 22 | Tests 23 | 24 | 25 | Test Coverage 26 | 27 | 28 | Maintainability 29 | 30 | 31 | Discord 32 | 33 |

34 | 35 |
36 | 37 | Welcome to the all new IdleTimer! The documentation has moved to [https://idletimer.dev](https://idletimer.dev). There you can find everything you need to get started using and contributing to IdleTimer. 38 | 39 |
40 |
41 | 42 |

43 | 44 | Docs 45 | 46 | 47 | Discord 48 | 49 | 50 | Issues 51 | 52 |

53 | 54 |

55 | 56 | JavaScript Style Guide 57 | 58 |

59 | 60 | -------------------------------------------------------------------------------- /docs/configs/docs.sidebar.json: -------------------------------------------------------------------------------- 1 | { 2 | "routes": [ 3 | { 4 | "title": "Getting Started", 5 | "heading": true, 6 | "routes": [ 7 | { 8 | "title": "Installation", 9 | "path": "/docs/getting-started/installation" 10 | }, 11 | { 12 | "title": "What's New", 13 | "path": "/docs/getting-started/new" 14 | }, 15 | { 16 | "title": "Testing Considerations", 17 | "path": "/docs/getting-started/testing" 18 | } 19 | ] 20 | }, 21 | { 22 | "title": "Features", 23 | "heading": true, 24 | "routes": [ 25 | { 26 | "title": "Idle Detection", 27 | "path": "/docs/features/idle-detection" 28 | }, 29 | { 30 | "title": "Activity Detection", 31 | "path": "/docs/features/activity-detection" 32 | }, 33 | { 34 | "title": "Confirm Prompt", 35 | "path": "/docs/features/confirm-prompt" 36 | }, 37 | { 38 | "title": "Cross Tab Support", 39 | "path": "/docs/features/cross-tab" 40 | } 41 | ] 42 | }, 43 | { 44 | "title": "API", 45 | "heading": true, 46 | "sort": true, 47 | "routes": [ 48 | { 49 | "title": "Types", 50 | "path": "/docs/api/types" 51 | }, 52 | { 53 | "title": "Props", 54 | "path": "/docs/api/props" 55 | }, 56 | { 57 | "title": "Methods", 58 | "path": "/docs/api/methods" 59 | }, 60 | { 61 | "title": "useIdleTimer", 62 | "path": "/docs/api/use-idle-timer" 63 | }, 64 | { 65 | "title": "withIdleTimer", 66 | "path": "/docs/api/with-idle-timer" 67 | }, 68 | { 69 | "title": "IdleTimerProvider", 70 | "path": "/docs/api/idle-timer-provider" 71 | } 72 | ] 73 | }, 74 | { 75 | "title": "About", 76 | "heading": true, 77 | "sort": true, 78 | "routes": [ 79 | { 80 | "title": "Changelog", 81 | "path": "/docs/about/changelog" 82 | }, 83 | { 84 | "title": "Contributing", 85 | "path": "/docs/about/contributing" 86 | }, 87 | { 88 | "title": "License", 89 | "path": "/docs/about/license" 90 | } 91 | ] 92 | } 93 | ] 94 | } 95 | -------------------------------------------------------------------------------- /docs/configs/site.config.ts: -------------------------------------------------------------------------------- 1 | const baseUrl = 'https://github.com/SupremeTechnopriest/react-idle-timer' 2 | 3 | export default { 4 | copyright: `Copyright © ${new Date().getFullYear()} Randy Lebeau. All Rights Reserved.`, 5 | author: { 6 | name: 'Randy Lebeau', 7 | github: 'https://github.com/supremetechnopriest', 8 | linkedin: 'https://linkedin.com/in/randylebeau', 9 | email: 'randylebeau@gmail.com' 10 | }, 11 | repo: { 12 | url: baseUrl, 13 | editUrl: `${baseUrl}/edit/main/website/pages`, 14 | blobUrl: `${baseUrl}/blob/main` 15 | }, 16 | package: { 17 | url: 'https://npmjs.com/package/react-idle-timer' 18 | }, 19 | sponsor: { 20 | url: 'https://github.com/sponsors/SupremeTechnopriest' 21 | }, 22 | discord: { 23 | url: 'https://discord.gg/YPuxNdWA4D', 24 | invite: 'YPuxNdWA4D' 25 | }, 26 | seo: { 27 | title: 'IdleTimer', 28 | titleTemplate: 'IdleTimer - %s', 29 | description: 'Robust activity detection for your React applications.', 30 | siteUrl: 'https://idletimer.dev', 31 | openGraph: { 32 | type: 'website', 33 | locale: 'en_US', 34 | url: 'https://idletimer.dev', 35 | title: 'IdleTimer', 36 | description: 'Robust activity detection for your React applications.', 37 | site_name: 'https://idletimer.dev', 38 | images: [ 39 | { 40 | url: 'https://idletimer.dev/og-image.png', 41 | width: 1240, 42 | height: 480, 43 | alt: 'IdleTimer Logo' 44 | }, 45 | { 46 | url: 'https://idletimer.dev/twitter-og-image.png', 47 | width: 1012, 48 | height: 506, 49 | alt: 'IdleTimer Logo' 50 | } 51 | ] 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /docs/contentlayer.config.ts: -------------------------------------------------------------------------------- 1 | import { 2 | ComputedFields, 3 | defineDocumentType, 4 | makeSource 5 | } from 'contentlayer/source-files' 6 | 7 | import remarkEmoji from 'remark-emoji' 8 | import remarkGfm from 'remark-gfm' 9 | import remarkSlug from 'remark-slug' 10 | 11 | import siteConfig from './configs/site.config' 12 | import { getTableOfContents } from './src/utils/mdx' 13 | import { rehypeMdxCodeMeta } from './src/utils/rehype' 14 | 15 | const computedFields: ComputedFields = { 16 | slug: { 17 | type: 'string', 18 | resolve: (doc) => `/${doc._raw.flattenedPath}` 19 | }, 20 | editUrl: { 21 | type: 'string', 22 | resolve: (doc) => `${siteConfig.repo.editUrl}/${doc._id}` 23 | } 24 | } 25 | 26 | const Doc = defineDocumentType(() => ({ 27 | name: 'Doc', 28 | filePathPattern: 'docs/**/*.mdx', 29 | contentType: 'mdx', 30 | fields: { 31 | title: { type: 'string', required: true }, 32 | description: { type: 'string', required: true }, 33 | image: { type: 'string' } 34 | }, 35 | computedFields: { 36 | ...computedFields, 37 | frontMatter: { 38 | type: 'json', 39 | resolve: (doc) => ({ 40 | title: doc.title, 41 | description: doc.description, 42 | image: doc.image, 43 | slug: `/${doc._raw.flattenedPath}`, 44 | headings: getTableOfContents(doc.body.raw) 45 | }) 46 | } 47 | } 48 | })) 49 | 50 | export default makeSource({ 51 | contentDirPath: 'pages', 52 | documentTypes: [Doc], 53 | mdx: { 54 | rehypePlugins: [rehypeMdxCodeMeta], 55 | remarkPlugins: [remarkSlug, remarkGfm, remarkEmoji] 56 | } 57 | }) 58 | -------------------------------------------------------------------------------- /docs/layouts/index.tsx: -------------------------------------------------------------------------------- 1 | import { PageContainer } from '@components/PageContainer' 2 | import dynamic from 'next/dynamic' 3 | 4 | const MDXLayout = dynamic(() => import('layouts/mdx')) 5 | 6 | export default function DefaultLayout ({ children, frontMatter }) { 7 | const slug = frontMatter?.slug 8 | 9 | const layoutMap = { 10 | guides: {children}, 11 | docs: {children}, 12 | changelog: {children}, 13 | faq: {children}, 14 | default: ( 15 | {children} 16 | ) 17 | } 18 | 19 | const layout = Object.entries(layoutMap).find(([path]) => { 20 | return slug?.startsWith(`/${path}`) 21 | }) 22 | 23 | if (!layout) return layoutMap.default 24 | 25 | return layout[1] 26 | } 27 | -------------------------------------------------------------------------------- /docs/layouts/mdx.tsx: -------------------------------------------------------------------------------- 1 | import { ReactNode } from 'react' 2 | import docsSidebar from '@configs/docs.sidebar.json' 3 | import { PageContainer } from '@components/PageContainer' 4 | import { Pagination } from '@components/Pagination' 5 | import { Sidebar } from '@components/Sidebar' 6 | import { findRouteByPath, removeFromLast } from '@utils/findRouteByPath' 7 | import { getRouteContext } from '@utils/getRouteContext' 8 | 9 | export function getRoutes (slug: string) { 10 | const configMap = { 11 | '/': docsSidebar 12 | } 13 | 14 | const [, sidebar] = 15 | Object.entries(configMap).find(([path]) => slug.startsWith(path)) ?? [] 16 | 17 | return sidebar?.routes ?? [] 18 | } 19 | 20 | interface MDXLayoutProps { 21 | frontMatter: any 22 | children: ReactNode 23 | } 24 | 25 | export default function MDXLayout (props: MDXLayoutProps) { 26 | const { frontMatter, children } = props 27 | const routes = getRoutes(frontMatter.slug) 28 | 29 | const route = findRouteByPath(removeFromLast(frontMatter.slug, '#'), routes) 30 | const routeContext = getRouteContext(route, routes) 31 | 32 | return ( 33 | } 36 | pagination={ 37 | 41 | } 42 | > 43 | {children} 44 | 45 | ) 46 | } 47 | -------------------------------------------------------------------------------- /docs/next-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | // NOTE: This file should not be edited 5 | // see https://nextjs.org/docs/basic-features/typescript for more information. 6 | -------------------------------------------------------------------------------- /docs/next.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const { withContentlayer } = require('next-contentlayer') 3 | const redirects = require('./next.redirect') 4 | const { i18n } = require('./next.i18n.config') 5 | 6 | /** 7 | * @type {import('next').NextConfig} 8 | **/ 9 | module.exports = withContentlayer()({ 10 | redirects, 11 | i18n, 12 | images: { 13 | domains: ['avatars.githubusercontent.com'] 14 | }, 15 | eslint: { 16 | ignoreDuringBuilds: true 17 | }, 18 | webpack (config) { 19 | config.resolve.alias.react = path.resolve(__dirname, 'node_modules/react') 20 | return config 21 | } 22 | }) 23 | -------------------------------------------------------------------------------- /docs/next.i18n.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | i18n: { 3 | locales: ['en'], 4 | defaultLocale: 'en' 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /docs/next.redirect.js: -------------------------------------------------------------------------------- 1 | async function redirect () { 2 | return [ 3 | { 4 | source: '/docs', 5 | destination: '/docs/getting-started/installation', 6 | permanent: true 7 | }, 8 | { 9 | source: '/features', 10 | destination: '/docs/features/idle-detection', 11 | permanent: true 12 | }, 13 | { 14 | source: '/api', 15 | destination: '/docs/api/use-idle-timer', 16 | permanent: true 17 | }, 18 | { 19 | source: '/discord', 20 | destination: 'https://discord.gg/YPuxNdWA4D', 21 | permanent: true 22 | }, 23 | { 24 | source: '/github', 25 | destination: 'https://github.com/SupremeTechnopriest/react-idle-timer', 26 | permanent: true 27 | }, 28 | { 29 | source: '/npm', 30 | destination: 'https://npmjs.com/package/react-idle-timer', 31 | permanent: true 32 | }, 33 | { 34 | source: '/sponsor', 35 | destination: 'https://github.com/sponsors/SupremeTechnopriest', 36 | permanent: true 37 | }, 38 | { 39 | source: '/donate', 40 | destination: 'https://github.com/sponsors/SupremeTechnopriest', 41 | permanent: true 42 | }, 43 | { 44 | source: '/changelog', 45 | destination: '/docs/changelog', 46 | permanent: true 47 | }, 48 | { 49 | source: '/contributing', 50 | destination: '/docs/contributing', 51 | permanent: true 52 | }, 53 | { 54 | source: '/license', 55 | destination: '/docs/license', 56 | permanent: true 57 | } 58 | ] 59 | } 60 | 61 | module.exports = redirect 62 | -------------------------------------------------------------------------------- /docs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "scripts": { 4 | "dev": "next dev", 5 | "build": "next build" 6 | }, 7 | "dependencies": { 8 | "@apollo/client": "^3.5.10", 9 | "@chakra-ui/react": "^1.8.7", 10 | "@chakra-ui/skip-nav": "^1.2.6", 11 | "@octokit/rest": "^18.12.0", 12 | "contentlayer": "^0.1.2", 13 | "date-fns": "^2.28.0", 14 | "focus-visible": "^5.2.0", 15 | "framer-motion": "^6.2.8", 16 | "github-slugger": "^1.4.0", 17 | "graphql": "^16.3.0", 18 | "mdx-bundler": "^8.0.1", 19 | "next": "^12.1.1", 20 | "next-contentlayer": "^0.1.2", 21 | "next-i18next": "^10.5.0", 22 | "next-seo": "^5.3.0", 23 | "oneline": "^1.0.3", 24 | "prism-react-renderer": "^1.3.1", 25 | "react": "^17.0.2", 26 | "react-dom": "^17.0.2", 27 | "react-icons": "^4.3.1", 28 | "react-idle-timer": "^5.7.2", 29 | "remark": "^14.0.2", 30 | "remark-emoji": "^3.0.2", 31 | "remark-gfm": "^3.0.1", 32 | "remark-slug": "^7.0.1", 33 | "unified": "^10.1.2", 34 | "unist-util-visit": "^4.1.0" 35 | }, 36 | "devDependencies": { 37 | "typescript": "^4.6.3" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /docs/pages/404.tsx: -------------------------------------------------------------------------------- 1 | import NextLink from 'next/link' 2 | import { Button, Heading, Text, VStack } from '@chakra-ui/react' 3 | import { useTranslation } from 'next-i18next' 4 | 5 | import { translationProps } from '@utils/i18n' 6 | 7 | import { SEO } from '@components/SEO' 8 | import { Announcer } from '@components/Announcer' 9 | import { Header } from '@components/Header' 10 | 11 | export async function getStaticProps ({ locale }) { 12 | return { 13 | props: { 14 | ...(await translationProps(locale, ['common'])) 15 | } 16 | } 17 | } 18 | 19 | export default function NotFoundPage () { 20 | const { t } = useTranslation('common') 21 | return ( 22 | <> 23 | 27 | 32 |
33 | 40 | {t('notFound.heading')} 41 | {t('notFound.message')} 42 | 43 | 52 | 53 | 54 | 55 | ) 56 | } 57 | -------------------------------------------------------------------------------- /docs/pages/_app.tsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect } from 'react' 2 | import Head from 'next/head' 3 | import Script from 'next/script' 4 | import { AppProps } from 'next/app' 5 | import { useRouter } from 'next/router' 6 | import { DefaultSeo } from 'next-seo' 7 | import { appWithTranslation } from 'next-i18next' 8 | 9 | import { ChakraProvider, ColorModeScript } from '@chakra-ui/react' 10 | 11 | import { FontFace } from '@components/FontFace' 12 | 13 | import { useRouteChanged } from '@hooks/useRouteChanged' 14 | 15 | import { getSeo } from '@utils/seo' 16 | import { pageView } from '@utils/ga' 17 | import { theme } from '../src/theme' 18 | import 'focus-visible' 19 | 20 | React.useLayoutEffect = typeof window !== 'undefined' ? React.useLayoutEffect : React.useEffect 21 | 22 | function App ({ Component, pageProps }: AppProps) { 23 | const seo = getSeo() 24 | const router = useRouter() 25 | 26 | useRouteChanged(pageView) 27 | 28 | useEffect(() => { 29 | router.events.on('routeChangeComplete', pageView) 30 | return () => { 31 | router.events.off('routeChangeComplete', pageView) 32 | } 33 | }, [router.events]) 34 | 35 | return ( 36 | <> 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | ) 67 | } 68 | 69 | export default appWithTranslation(App) 70 | -------------------------------------------------------------------------------- /docs/pages/_document.tsx: -------------------------------------------------------------------------------- 1 | import NextDocument, { 2 | DocumentContext, 3 | Head, 4 | Html, 5 | Main, 6 | NextScript 7 | } from 'next/document' 8 | import { ColorModeScript } from '@chakra-ui/react' 9 | 10 | export default class Document extends NextDocument { 11 | static getInitialProps (ctx: DocumentContext) { 12 | return NextDocument.getInitialProps(ctx) 13 | } 14 | 15 | render () { 16 | return ( 17 | 18 | 19 | 26 | 27 | 28 | 29 |
30 | 31 | 32 | 33 | ) 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /docs/pages/docs/[[...slug]].tsx: -------------------------------------------------------------------------------- 1 | import Layout from 'layouts' 2 | import { GetStaticPaths, GetStaticProps } from 'next' 3 | import { useMDXComponent } from 'next-contentlayer/hooks' 4 | 5 | import { MDXComponents } from '@components/mdx' 6 | import { Announcer } from '@components/Announcer' 7 | import { Header } from '@components/Header' 8 | 9 | import { useTranslation } from 'next-i18next' 10 | import { translationProps } from '@utils/i18n' 11 | 12 | import { allDocs, Doc } from '@contentlayer/generated' 13 | 14 | export const getStaticPaths: GetStaticPaths = async () => { 15 | const docs = allDocs 16 | .map((t) => t._raw.flattenedPath.replace('docs/', '')) 17 | .map((id) => ({ params: { slug: id.split('/') } })) 18 | return { paths: docs, fallback: false } 19 | } 20 | 21 | export const getStaticProps: GetStaticProps = async (ctx) => { 22 | const params = Array.isArray(ctx.params.slug) 23 | ? ctx.params.slug 24 | : [ctx.params.slug] 25 | const doc = allDocs.find((doc) => doc._id.includes(params.join('/'))) 26 | return { 27 | props: { 28 | doc, 29 | ...(await translationProps(ctx.locale, ['common'])) 30 | } 31 | } 32 | } 33 | 34 | export default function Page ({ doc }: { doc: Doc }) { 35 | const Component = useMDXComponent(doc.body.code) 36 | const { t } = useTranslation('common') 37 | return ( 38 | <> 39 | 44 |
45 | 46 | 47 | 48 | 49 | ) 50 | } 51 | -------------------------------------------------------------------------------- /docs/pages/docs/about/license.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: License 3 | description: IdleTimer License 4 | --- 5 | 6 | ### MIT License 7 | 8 | __Copyright (c) 2022 Randy Lebeau__ 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy 11 | of this software and associated documentation files (the "Software"), to deal 12 | in the Software without restriction, including without limitation the rights 13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | copies of the Software, and to permit persons to whom the Software is 15 | furnished to do so, subject to the following conditions: 16 | 17 | The above copyright notice and this permission notice shall be included in all 18 | copies or substantial portions of the Software. 19 | 20 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 26 | SOFTWARE. 27 | -------------------------------------------------------------------------------- /docs/pages/docs/api/methods.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Methods 3 | description: IdleTimer methods 4 | --- 5 | 6 | Methods are the API that is returned by IdleTimer. You can interface 7 | with your IdleTimer instance by using the following functions. Examples of 8 | how to use them can be found in the [hook](/docs/api/use-idle-timer) 9 | and [higher order component](/docs/api/with-idle-timer) docs. 10 | 11 | ### start 12 | 16 | 17 | ### reset 18 | 22 | 23 | ### activate 24 | 28 | 29 | ### pause 30 | 34 | 35 | ### resume 36 | 40 | 41 | ### message 42 | 46 | 47 | ### isIdle 48 | 52 | 53 | ### isPrompted 54 | 58 | 59 | ### isLeader 60 | 64 | 65 | ### isLastActiveTab 66 | 70 | 71 | ### getTabId 72 | 76 | 77 | ### getRemainingTime 78 | 82 | 83 | ### getElapsedTime 84 | 88 | 89 | ### getTotalElapsedTime 90 | 94 | 95 | ### getLastIdleTime 96 | 100 | 101 | ### getLastActiveTime 102 | 106 | 107 | ### getIdleTime 108 | 112 | 113 | ### getTotalIdleTime 114 | 118 | 119 | ### getActiveTime 120 | 124 | 125 | ### getTotalActiveTime 126 | 130 | -------------------------------------------------------------------------------- /docs/pages/docs/api/types.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Types 3 | description: Typescript types included with IdleTimer package 4 | --- 5 | 6 | IdleTimer exports its internal types for working in Typescript projects. All the types you will need are outlined below. Examples of how to use them can be found in the [hook](/docs/api/use-idle-timer) and [higher order component](/docs/api/with-idle-timer) docs. 7 | 8 | ## IIdleTimerProps 9 | 10 | This is the interface of the available properties IdleTimer accepts. 11 | 12 | ```js 13 | import type { IIdleTimerProps } from 'react-idle-timer' 14 | ``` 15 | 16 | 17 | 18 | 19 | 20 | 21 | ## IIdleTimer 22 | 23 | This is the interface that IdleTimer exports. It consists of the methods that can be called after instantiating an IdleTimer instance. 24 | 25 | ```js 26 | import type { IIdleTimer } from 'react-idle-timer' 27 | ``` 28 | 29 | 30 | 31 | 32 | 33 | 34 | ## ITimers 35 | 36 | The interface that is accepted by the `timers` property. 37 | 38 | ```js 39 | import type { ITimers } from 'react-idle-timer' 40 | ``` 41 | 42 | 43 | 44 | 45 | 46 | 47 | ## EventsType 48 | 49 | The events type contains all the valid DOM Event values that can be passed to `events` and `immediateEvents`. 50 | 51 | ```js 52 | import type { EventsType } from 'react-idle-timer' 53 | ``` 54 | 55 | 56 | 57 | 58 | 59 | ## MessageType 60 | 61 | The type for messages sent through the `message()` method. 62 | 63 | 64 | 65 | 66 | 67 | 68 | ## PresenceType 69 | 70 | The type for `onPresenceChange` state changes. 71 | 72 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /docs/pages/docs/api/use-idle-timer.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: useIdleTimer 3 | description: React hook for functional React applications 4 | --- 5 | 6 | The `useIdleTimer` hook can be used with functional React components. It takes 7 | [IIdleTimerProps](/docs/api/props) as configuration options and returns 8 | [IIdleTimer](/docs/api/methods). 9 | 10 | ## Import 11 | ```js 12 | import { useIdleTimer } from 'react-idle-timer' 13 | ``` 14 | 15 | ## Usage 16 | 17 | A minimal example with the bare essential configuration. 18 | 19 | ```js 20 | import { useIdleTimer } from 'react-idle-timer' 21 | 22 | export const App = () => { 23 | const onPresenceChange = (presence) => { 24 | // Handle state changes in one function 25 | } 26 | 27 | const idleTimer = useIdleTimer({ onPresenceChange }) 28 | 29 | return ( 30 | 31 | ) 32 | } 33 | ``` 34 | 35 | A full example with all available props and methods. Props are set to their 36 | default value. 37 | 38 | ```js 39 | import { useIdleTimer } from 'react-idle-timer' 40 | 41 | export const App = () => { 42 | const onPresenceChange = (presence) => { 43 | // Handle state changes in one function 44 | } 45 | 46 | const onPrompt = () => { 47 | // Fire a Modal Prompt 48 | } 49 | 50 | const onIdle = () => { 51 | // Close Modal Prompt 52 | // Do some idle action like log out your user 53 | } 54 | 55 | const onActive = (event) => { 56 | // Close Modal Prompt 57 | // Do some active action 58 | } 59 | 60 | const onAction = (event) => { 61 | // Do something when a user triggers a watched event 62 | } 63 | 64 | const { 65 | start, 66 | reset, 67 | activate, 68 | pause, 69 | resume, 70 | isIdle, 71 | isPrompted, 72 | isLeader, 73 | isLastActiveTab, 74 | getTabId, 75 | getRemainingTime, 76 | getElapsedTime, 77 | getLastIdleTime, 78 | getLastActiveTime, 79 | getIdleTime, 80 | getTotalIdleTime, 81 | getActiveTime, 82 | getTotalActiveTime 83 | } = useIdleTimer({ 84 | onPresenceChange, 85 | onPrompt, 86 | onIdle, 87 | onActive, 88 | onAction, 89 | timeout: 1000 * 60 * 20, 90 | promptBeforeIdle: 0, 91 | events: [ 92 | 'mousemove', 93 | 'keydown', 94 | 'wheel', 95 | 'DOMMouseScroll', 96 | 'mousewheel', 97 | 'mousedown', 98 | 'touchstart', 99 | 'touchmove', 100 | 'MSPointerDown', 101 | 'MSPointerMove', 102 | 'visibilitychange', 103 | 'focus' 104 | ], 105 | immediateEvents: [], 106 | debounce: 0, 107 | throttle: 0, 108 | eventsThrottle: 200, 109 | element: document, 110 | startOnMount: true, 111 | startManually: false, 112 | stopOnIdle: false, 113 | crossTab: false, 114 | name: 'idle-timer', 115 | syncTimers: 0, 116 | leaderElection: false 117 | }) 118 | return ( 119 | 120 | ) 121 | } 122 | ``` 123 | 124 | ## Examples 125 | 126 | 127 | Idle Detection 128 | Activity Detection 129 | Cross Tab Support 130 | Confirm Prompt 131 | Presence Change Handler 132 | -------------------------------------------------------------------------------- /docs/pages/docs/features/activity-detection.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Activity Detection 3 | description: Activity Detection feature explanation and example 4 | --- 5 | 6 | The activity detection feature is responsible for notifying you when any of your 7 | watched events has been triggered, regardless of whether or not it will result in 8 | a change of idle state. 9 | 10 | ### Properties 11 | 12 | The properties associated with activity detection are: 13 | 14 | {/* cspell:disable */} 15 | - [events](/docs/api/props#events): The events to listen for activity on. 16 | - [element](/docs/api/props#element): The DOM element to bind event listeners to. 17 | - [onAction](/docs/api/props#onaction): Function called each time an event is triggered. 18 | - [throttle](/docs/api/props#throttle): Throttle the `onAction` callback in milliseconds. 19 | - [debounce](/docs/api/props#debounce): Debounce the `onAction` callback in milliseconds. 20 | - [startOnMount](/docs/api/props#startonmount): Bind the events when the host component mounts. Defaults to `true`. 21 | - [startManually](/docs/api/props#startmanually): Require a call to `start()` in order to bind the events initally. 22 | {/* cspell:enable */} 23 | 24 | ### Methods 25 | 26 | The methods associated with activity detection are: 27 | 28 | {/* cspell:disable */} 29 | - [start](/docs/api/methods#start): Binds the events. 30 | - [pause](/docs/api/methods#pause): Unbinds events. 31 | - [resume](/docs/api/methods#resume): Rebinds events. 32 | - [getElapsedTime](/docs/api/methods#getelapsedtime): Returns the ammount of milliseconds since the host component was mounted. 33 | {/* cspell:enable */} 34 | 35 | ### Example 36 | 37 | -------------------------------------------------------------------------------- /docs/pages/docs/features/confirm-prompt.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Confirm Prompt' 3 | description: Confirm Prompt feature explanation and example 4 | --- 5 | 6 | A common use case for IdleTimer is to detect when you user has gone idle and then 7 | prompt them to see if they are still there. Handling of this common use case is 8 | now built in to IdleTimer. 9 | 10 | ### Properties 11 | 12 | The properties associated with the confirm prompt feature are: 13 | 14 | {/* cspell:disable */} 15 | - [timeout](/docs/api/props#timeout): The time before the `onIdle` event will be emitted. 16 | - [promptBeforeIdle](/docs/api/props#promptbeforeidle): How long before idle to emit the `onPrompt` event. 17 | - [onPresenceChange](/docs/api/props#onpresencechange): Function called when a user's presence state changes. 18 | - [onPrompt](/docs/api/props#onprompt): Function called after the idle timeout is reached. 19 | {/* cspell:enable */} 20 | 21 | ### Methods 22 | 23 | The methods associated with the confirm prompt feature are: 24 | 25 | {/* cspell:disable */} 26 | - [isPrompted()](/docs/api/methods#isprompted): Returns true if the prompt is displayed. 27 | {/* cspell:enable */} 28 | 29 | ### Example 30 | -------------------------------------------------------------------------------- /docs/pages/docs/features/cross-tab.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Cross Tab 3 | description: Cross Tab Feature explanation and example 4 | --- 5 | 6 | The cross tab feature enables reconciliation of events and state across multiple 7 | tabs running your application. It also exposes the underlying messaging layer for 8 | your own use. You can broadcast arbitrary messages to all tabs, regardless of 9 | their idle state. 10 | 11 | ### Properties 12 | 13 | The properties associated with the cross tab feature are: 14 | 15 | {/* cspell:disable */} 16 | - [crossTab](/docs/api/props#crosstab): Enables the cross tab feature. 17 | - [syncTimers](/docs/api/props#synctimers): Syncs timeout durations between tabs when user activity is detected. 18 | - [name](/docs/api/props#name): Name of the idle timer instance. Set this if you are using crossTab with multiple instances on the same page. 19 | - [leaderElection](/docs/api/props#leaderelection): Enables the leader election feature. 20 | - [onMessage](/docs/api/props#onprompt): Function called when a message is received. 21 | {/* cspell:enable */} 22 | 23 | ### Methods 24 | 25 | The methods associated with the cross tab feature are: 26 | 27 | {/* cspell:disable */} 28 | - [message()](/docs/api/methods#message): Broadcast a message to all tabs. 29 | - [isLeader()](/docs/api/methods#isleader): Returns whether or not the current tab is the elected leader. 30 | - [isLastActiveTab()](/docs/api/methods#islastactivetab): Returns whether or not the current tab is the last active tab. 31 | - [getTabId()](/docs/api/methods#gettabid): Returns the current tab's id. 32 | {/* cspell:enable */} 33 | 34 | ### Example 35 | -------------------------------------------------------------------------------- /docs/pages/docs/features/idle-detection.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Idle Detection 3 | description: Idle Detection feature explanation and example 4 | --- 5 | 6 | As its namesake suggests, idle detection is the flagship feature of IdleTimer. 7 | The idle detection feature set is responsible for tracking your users activity 8 | based on the events you want to listen to and let you know when the user has 9 | not triggered those events in a given time period. 10 | 11 | ### Properties 12 | 13 | The properties associated with idle detection are: 14 | 15 | {/* cspell:disable */} 16 | - [timeout](/docs/api/props#timeout): The time before a user is considered idle. 17 | - [element](/docs/api/props#element): The DOM element to bind event listeners to. 18 | - [events](/docs/api/props#events): The events to listen for activity on. 19 | - [immediateEvents](/docs/api/props#immediateevents): The events that will immediately trigger an idle event (bypassing timeout). 20 | - [onPresenceChange](/docs/api/props#onpresencechange): Function called when a user's presence state changes. 21 | - [onIdle](/docs/api/props#onidle): Function called when a user becomes idle from an active state. 22 | - [onActive](/docs/api/props#onactive): Function called when a user becomes active from an idle state. 23 | - [eventsThrottle](/docs/api/props#eventsthrottle): Throttle for the events bound. Saves on CPU if you are using repeated events. 24 | - [startOnMount](/docs/api/props#startonmount): Starts the timer when the host component mounts. 25 | - [startManually](/docs/api/props#startmanually): Require a call to `start()` in order to start the timer. 26 | - [stopOnIdle](/docs/api/props#stoponidle): Require the timer to be manually reset after going idle by calling `start()` or `reset()`. 27 | {/* cspell:enable */} 28 | 29 | ### Methods 30 | 31 | The methods associated with idle detection are: 32 | 33 | {/* cspell:disable */} 34 | - [start](/docs/api/methods#start): Starts the timer. 35 | - [reset](/docs/api/methods#reset): Resets the timer to its initial state. 36 | - [activate](/docs/api/methods#activate): Resets the IdleTimer instance to its initial state, starts the timer and emits `onActive` if the user was idle. 37 | - [pause](/docs/api/methods#pause): Pauses a running timer. 38 | - [resume](/docs/api/methods#resume): Resumes a running timer. 39 | - [getElapsedTime](/docs/api/methods#getelapsedtime): Returns the time in milliseconds since the host component was mounted. 40 | - [getRemainingTime](/docs/api/methods#getremainingtime): Returns the time remaining in milliseconds until idle. 41 | - [getLastActiveTime](/docs/api/methods#getlastactivetime): Returns a Date of the last time the user was active. 42 | - [getActiveTime](/docs/api/methods#getactivetime): Returns time in milliseconds the user was active since the last reset. 43 | - [getTotalActiveTime](/docs/api/methods#gettotalactivetime): Returns time in milliseconds the user was active since the component mounted. 44 | - [getLastIdleTime](/docs/api/methods#getlastidletime): Returns a Date of the last time the user was idle. 45 | - [getIdleTime](/docs/api/methods#getidletime): Returns time in milliseconds the user was idle since the last reset. 46 | - [getTotalIdleTime](/docs/api/methods#gettotalidletime): Returns time in milliseconds the user was idle since the component mounted. 47 | {/* cspell:enable */} 48 | 49 | ### Example 50 | -------------------------------------------------------------------------------- /docs/pages/docs/getting-started/installation.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Installation 3 | description: How to install and set up IdleTimer 4 | --- 5 | 6 | ## Welcome 7 | 8 | Hello and welcome to IdleTimer. If you are new here, you can get a detailed 9 | overview of how to use IdleTimer on this page. Check out the examples in the 10 | [features](/docs/features/idle-detection) section. 11 | 12 | ### Installation 13 | 14 | Inside your React project directory, install IdleTimer by running either of the 15 | following: 16 | 17 | ```bash copy 18 | npm i react-idle-timer 19 | ``` 20 | 21 | ```bash copy 22 | yarn add react-idle-timer 23 | ``` 24 | 25 | ### Legacy Browser Support 26 | 27 | IdleTimer supports legacy browsers for both `esm` and `cjs` projects. With a modern node.js runtime you can import IdleTimer like this: 28 | 29 | ```ts 30 | import { useIdleTimer } from 'react-idle-timer/legacy' 31 | ``` 32 | 33 | For older versions of node which lack support for `package.json` exports, you will have to import the full path. 34 | 35 | For CommonJS: 36 | 37 | ```ts 38 | import { useIdleTimer } from 'react-idle-timer/dist/index.legacy.cjs.js' 39 | ``` 40 | 41 | For ECMAScript Modules: 42 | 43 | ```ts 44 | import { useIdleTimer } from 'react-idle-timer/dist/index.legacy.esm.js' 45 | ``` 46 | 47 | ## Changelog 48 | 49 | To see what has updated in a given version of IdleTimer, you can check the 50 | [changelog](/docs/about/changelog) or the 51 | [github releases](https://github.com/SupremeTechnopriest/react-idle-timer/releases). 52 | 53 | ## Contributing 54 | 55 | Please see our [contribution guidelines](/docs/about/contributing) to learn how you 56 | can contribute to this project. 57 | 58 | ## License 59 | 60 | IdleTimer is MIT Licensed. You can view the [license](/docs/about/license) here. 61 | A copy of the license is also shipped with every installation from NPM. 62 | -------------------------------------------------------------------------------- /docs/pages/docs/getting-started/testing.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Testing Considerations 3 | description: Testing considerations for IdleTimer 4 | --- 5 | 6 | In order to write tests that include IdleTimer, a few things will need to be mocked. 7 | Examples will be provided for the [jest](https://jestjs.io/) framework 8 | and the [testing-library](https://testing-library.com/docs/react-testing-library/intro) 9 | utilities, but the principles can be applied to any framework. 10 | 11 | To keep your tests clean and modular, you will want to create a startup script 12 | and add it to the `setupFilesAfterEnv` section of your `jest.config.js` or `package.json`. 13 | We will assume the setup file is called `test.setup.js` for the following implementation. 14 | 15 | ### Mock Timers 16 | If you are using worker thread timers, you can mock them for your testing 17 | environment. IdleTimer exposes a function to do this for you. 18 | 19 | In your `test.setup.js`, add the following: 20 | 21 | ```js 22 | import { createMocks } from 'react-idle-timer' 23 | beforeAll(createMocks) 24 | ``` 25 | 26 | This will have jest or your test runner of choice use the main thread timers 27 | for testing. 28 | 29 | ### Mock MessageChannel 30 | IdleTimer uses [MessageChannel](https://developer.mozilla.org/en-US/docs/Web/API/MessageChannel) 31 | for the cross tab messaging layer internally. This is not mocked by default 32 | in `js-dom`. If you are using the cross tab feature, you will need to mock the global. 33 | Add the following to your `test.setup.js`. 34 | 35 | ```js 36 | import { MessageChannel } from 'worker_threads' 37 | import { cleanup } from '@testing-library/react' 38 | 39 | beforeAll(() => { 40 | // @ts-ignore 41 | global.MessageChannel = MessageChannel 42 | }) 43 | 44 | afterAll(cleanup) 45 | ``` 46 | 47 | If you are using Typescript you will have to either ignore the global assignment 48 | or extend the global name space for your test runner. Since you are unlikely to 49 | need types for MessageChannel, `// @ts-ignore` will suffice. 50 | 51 | ### Full Mock 52 | 53 | Here is the full mock requirements to test with IdleTimer. 54 | 55 | ```js 56 | // 57 | // jest.config.js 58 | // 59 | 60 | export default { 61 | ...otherOptions, 62 | setupFilesAfterEnv: [ 63 | './test.setup.js' 64 | ] 65 | } 66 | ``` 67 | 68 | ```js 69 | // 70 | // test.setup.js 71 | // 72 | 73 | import { createMocks } from 'react-idle-timer' 74 | import { MessageChannel } from 'worker_threads' 75 | import { cleanup } from '@testing-library/react' 76 | 77 | beforeAll(() => { 78 | createMocks() 79 | global.MessageChannel = MessageChannel 80 | }) 81 | 82 | afterAll(cleanup) 83 | ``` 84 | 85 | 86 | 87 | With this setup script, you will be able to fully test your application 88 | with IdleTimer. If you need more examples, you can check out the 89 | [test suite](https://github.com/supremetechnopriest/react-idle-timer/tree/master/tests) 90 | for IdleTimer itself. 91 | -------------------------------------------------------------------------------- /docs/pages/index.tsx: -------------------------------------------------------------------------------- 1 | import { GetStaticProps } from 'next' 2 | import { useTranslation } from 'next-i18next' 3 | import { Box, Divider } from '@chakra-ui/react' 4 | 5 | import { translationProps } from '@utils/i18n' 6 | import { getGithubStars } from '@utils/getGithubStars' 7 | import { getDiscordMembers } from '@utils/getDiscordMembers' 8 | import { getTestCoverage } from '@utils/getTestCoverage' 9 | import { getCodeQuality } from '@utils/getCodeQuality' 10 | import { getUsedBy } from '@utils/getUsedBy' 11 | import { getSponsors } from '@utils/getSponsors' 12 | import { 13 | getTotalNpmDownloads, 14 | getMonthlyNpmDownloads 15 | } from '@utils/getNpmDownloads' 16 | 17 | import { SEO } from '@components/SEO' 18 | import { Announcer } from '@components/Announcer' 19 | import { Header } from '@components/Header' 20 | import { Hero } from '@components/Hero' 21 | import { Features } from '@components/Features' 22 | import { Stats } from '@components/Stats' 23 | import { Demo } from '@components/Demo' 24 | import { DiscordBar } from '@components/DiscordBar' 25 | import { ISponsor, Sponsors } from '@components/Sponsors' 26 | import { UsedBy } from '@components/UsedBy' 27 | import { Footer } from '@components/Footer' 28 | 29 | interface IHomeProps { 30 | githubStars: string 31 | totalDownloads: string 32 | monthlyDownloads: string 33 | discordMembers: string 34 | testCoverage: string 35 | codeQuality: string 36 | usedBy: { 37 | organizations: ISponsor[] 38 | } 39 | sponsors: { 40 | individuals: ISponsor[] 41 | organizations: ISponsor[] 42 | } 43 | } 44 | 45 | export const getStaticProps: GetStaticProps = async ({ locale }) => { 46 | const [ 47 | { prettyCount: githubStars }, 48 | { prettyCount: totalDownloads }, 49 | { prettyCount: monthlyDownloads }, 50 | { prettyCount: discordMembers }, 51 | { prettyCount: testCoverage }, 52 | { score: codeQuality } 53 | ] = await Promise.all([ 54 | getGithubStars(), 55 | getTotalNpmDownloads(), 56 | getMonthlyNpmDownloads(), 57 | getDiscordMembers(), 58 | getTestCoverage(), 59 | getCodeQuality() 60 | ]) 61 | 62 | const usedBy = await getUsedBy() 63 | const sponsors = await getSponsors() 64 | 65 | return { 66 | props: { 67 | ...(await translationProps(locale, ['common'])), 68 | githubStars, 69 | totalDownloads, 70 | monthlyDownloads, 71 | discordMembers, 72 | testCoverage, 73 | codeQuality, 74 | usedBy, 75 | sponsors 76 | }, 77 | revalidate: 60 78 | } 79 | } 80 | 81 | export default function IndexPage (props: IHomeProps) { 82 | const { t } = useTranslation('common') 83 | return ( 84 | <> 85 | 89 | 94 |
95 | 96 | 97 | 98 | 99 | 100 | 108 | 109 | 110 | 111 | 115 | 116 | 117 | 118 | 119 |