├── .github ├── FUNDING.yml └── workflows │ ├── ci.yml │ ├── close-stale-issues.yml │ └── publish.yml ├── .gitignore ├── .husky └── pre-commit ├── .vscode ├── extensions.json └── settings.json ├── .yarn └── plugins │ └── @yarnpkg │ └── plugin-nolyfill.cjs ├── .yarnrc.yml ├── LICENSE ├── README.md ├── biome.json ├── package.json ├── packages └── react-timerange-picker │ ├── LICENSE │ ├── README.md │ ├── package.json │ ├── src │ ├── TimeRangePicker.css │ ├── TimeRangePicker.spec.tsx │ ├── TimeRangePicker.tsx │ ├── index.ts │ └── shared │ │ └── types.ts │ ├── tsconfig.build.json │ ├── tsconfig.json │ ├── vitest.config.ts │ └── vitest.setup.ts ├── sample ├── .gitignore ├── Sample.css ├── Sample.tsx ├── index.html ├── index.tsx ├── package.json ├── tsconfig.json ├── vite.config.ts └── yarn.lock ├── test ├── .gitignore ├── LocaleOptions.tsx ├── MaxDetailOptions.tsx ├── Test.css ├── Test.tsx ├── ValidityOptions.tsx ├── ValueOptions.tsx ├── ViewOptions.tsx ├── index.html ├── index.tsx ├── package.json ├── shared │ └── types.ts ├── tsconfig.json └── vite.config.ts └── yarn.lock /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: wojtekmaj 2 | open_collective: react-date-picker 3 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: ['*'] 6 | pull_request: 7 | branches: [main] 8 | 9 | env: 10 | HUSKY: 0 11 | 12 | jobs: 13 | lint: 14 | name: Static code analysis 15 | runs-on: ubuntu-24.04-arm 16 | 17 | steps: 18 | - name: Checkout 19 | uses: actions/checkout@v4 20 | 21 | - name: Setup Biome 22 | uses: biomejs/setup-biome@v2 23 | 24 | - name: Run tests 25 | run: biome lint 26 | 27 | typescript: 28 | name: Type checking 29 | runs-on: ubuntu-24.04-arm 30 | 31 | steps: 32 | - name: Checkout 33 | uses: actions/checkout@v4 34 | 35 | - name: Cache Yarn cache 36 | uses: actions/cache@v4 37 | env: 38 | cache-name: yarn-cache 39 | with: 40 | path: ~/.yarn/berry/cache 41 | key: ${{ runner.os }}-${{ env.cache-name }}-${{ hashFiles('**/yarn.lock') }} 42 | restore-keys: | 43 | ${{ runner.os }}-${{ env.cache-name }} 44 | 45 | - name: Use Node.js 46 | uses: actions/setup-node@v4 47 | with: 48 | node-version: '22' 49 | 50 | - name: Enable Corepack 51 | run: corepack enable 52 | 53 | - name: Install dependencies 54 | run: yarn --immutable 55 | 56 | - name: Build package 57 | run: yarn build 58 | 59 | - name: Run type checking 60 | run: yarn tsc 61 | 62 | format: 63 | name: Formatting 64 | runs-on: ubuntu-24.04-arm 65 | 66 | steps: 67 | - name: Checkout 68 | uses: actions/checkout@v4 69 | 70 | - name: Setup Biome 71 | uses: biomejs/setup-biome@v2 72 | 73 | - name: Run formatting 74 | run: biome format 75 | 76 | unit: 77 | name: Unit tests 78 | runs-on: ubuntu-24.04-arm 79 | 80 | steps: 81 | - name: Checkout 82 | uses: actions/checkout@v4 83 | 84 | - name: Cache Yarn cache 85 | uses: actions/cache@v4 86 | env: 87 | cache-name: yarn-cache 88 | with: 89 | path: ~/.yarn/berry/cache 90 | key: ${{ runner.os }}-${{ env.cache-name }}-${{ hashFiles('**/yarn.lock') }} 91 | restore-keys: | 92 | ${{ runner.os }}-${{ env.cache-name }} 93 | 94 | - name: Use Node.js 95 | uses: actions/setup-node@v4 96 | with: 97 | node-version: '22' 98 | 99 | - name: Enable Corepack 100 | run: corepack enable 101 | 102 | - name: Install dependencies 103 | run: yarn --immutable 104 | 105 | - name: Run tests 106 | run: yarn unit 107 | -------------------------------------------------------------------------------- /.github/workflows/close-stale-issues.yml: -------------------------------------------------------------------------------- 1 | name: Close stale issues 2 | 3 | on: 4 | schedule: 5 | - cron: '0 0 * * 1' # Every Monday 6 | workflow_dispatch: 7 | 8 | jobs: 9 | close-issues: 10 | name: Close stale issues 11 | runs-on: ubuntu-24.04-arm 12 | 13 | steps: 14 | - name: Close stale issues 15 | uses: actions/stale@v8 16 | with: 17 | days-before-issue-stale: 90 18 | days-before-issue-close: 14 19 | stale-issue-label: 'stale' 20 | stale-issue-message: 'This issue is stale because it has been open 90 days with no activity. Remove stale label or comment or this issue will be closed in 14 days.' 21 | close-issue-message: 'This issue was closed because it has been stalled for 14 days with no activity.' 22 | exempt-issue-labels: 'fresh' 23 | remove-issue-stale-when-updated: true 24 | days-before-pr-stale: -1 25 | days-before-pr-close: -1 26 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish 2 | 3 | on: 4 | release: 5 | types: [published] 6 | 7 | env: 8 | HUSKY: 0 9 | 10 | permissions: 11 | id-token: write 12 | 13 | jobs: 14 | publish: 15 | name: Publish 16 | runs-on: ubuntu-24.04-arm 17 | 18 | steps: 19 | - name: Checkout 20 | uses: actions/checkout@v4 21 | 22 | - name: Cache Yarn cache 23 | uses: actions/cache@v4 24 | env: 25 | cache-name: yarn-cache 26 | with: 27 | path: ~/.yarn/berry/cache 28 | key: ${{ runner.os }}-${{ env.cache-name }}-${{ hashFiles('**/yarn.lock') }} 29 | restore-keys: | 30 | ${{ runner.os }}-${{ env.cache-name }} 31 | 32 | - name: Use Node.js 33 | uses: actions/setup-node@v4 34 | with: 35 | node-version: '22' 36 | registry-url: 'https://registry.npmjs.org' 37 | 38 | - name: Enable Corepack 39 | run: corepack enable 40 | 41 | - name: Install dependencies 42 | run: yarn --immutable 43 | 44 | - name: Publish with latest tag 45 | if: github.event.release.prelease == false 46 | run: yarn npm publish --tag latest --provenance 47 | working-directory: packages/react-timerange-picker 48 | env: 49 | YARN_NPM_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} 50 | 51 | - name: Publish with next tag 52 | if: github.event.release.prelease == true 53 | run: yarn npm publish --tag next --provenance 54 | working-directory: packages/react-timerange-picker 55 | env: 56 | YARN_NPM_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} 57 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # OS 2 | .DS_Store 3 | 4 | # Cache 5 | .cache 6 | .playwright 7 | .tmp 8 | *.tsbuildinfo 9 | .eslintcache 10 | 11 | # Yarn 12 | .pnp.* 13 | **/.yarn/* 14 | !**/.yarn/patches 15 | !**/.yarn/plugins 16 | !**/.yarn/releases 17 | !**/.yarn/sdks 18 | !**/.yarn/versions 19 | 20 | # Project-generated directories and files 21 | coverage 22 | dist 23 | node_modules 24 | playwright-report 25 | test-results 26 | package.tgz 27 | 28 | # Logs 29 | npm-debug.log 30 | yarn-error.log 31 | 32 | # .env files 33 | **/.env 34 | **/.env.* 35 | !**/.env.example 36 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | yarn format --staged --no-errors-on-unmatched --write 2 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": ["biomejs.biome"], 3 | "unwantedRecommendations": ["dbaeumer.jshint", "dbaeumer.vscode-eslint", "esbenp.prettier-vscode"] 4 | } 5 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.defaultFormatter": "biomejs.biome", 3 | "editor.formatOnSave": true, 4 | "search.exclude": { 5 | "**/.yarn": true 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /.yarn/plugins/@yarnpkg/plugin-nolyfill.cjs: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | //prettier-ignore 3 | module.exports = { 4 | name: "@yarnpkg/plugin-nolyfill", 5 | factory: function (require) { 6 | "use strict";var plugin=(()=>{var p=Object.defineProperty;var i=Object.getOwnPropertyDescriptor;var n=Object.getOwnPropertyNames;var y=Object.prototype.hasOwnProperty;var l=(t=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(t,{get:(r,e)=>(typeof require<"u"?require:r)[e]}):t)(function(t){if(typeof require<"u")return require.apply(this,arguments);throw new Error('Dynamic require of "'+t+'" is not supported')});var c=(t,r)=>{for(var e in r)p(t,e,{get:r[e],enumerable:!0})},g=(t,r,e,s)=>{if(r&&typeof r=="object"||typeof r=="function")for(let a of n(r))!y.call(t,a)&&a!==e&&p(t,a,{get:()=>r[a],enumerable:!(s=i(r,a))||s.enumerable});return t};var f=t=>g(p({},"__esModule",{value:!0}),t);var m={};c(m,{default:()=>h});var o=l("@yarnpkg/core"),d=["abab","array-buffer-byte-length","array-includes","array.from","array.of","array.prototype.at","array.prototype.every","array.prototype.find","array.prototype.findlast","array.prototype.findlastindex","array.prototype.flat","array.prototype.flatmap","array.prototype.flatmap","array.prototype.foreach","array.prototype.reduce","array.prototype.toreversed","array.prototype.tosorted","arraybuffer.prototype.slice","assert","asynciterator.prototype","available-typed-arrays","deep-equal","deep-equal-json","define-properties","es-aggregate-error","es-iterator-helpers","es-set-tostringtag","es6-object-assign","function-bind","function.prototype.name","get-symbol-description","globalthis","gopd","harmony-reflect","has","has-property-descriptors","has-proto","has-symbols","has-tostringtag","hasown","internal-slot","is-arguments","is-array-buffer","is-core-module","is-date-object","is-generator-function","is-nan","is-regex","is-shared-array-buffer","is-string","is-symbol","is-typed-array","is-weakref","isarray","iterator.prototype","json-stable-stringify","jsonify","object-is","object-keys","object.assign","object.entries","object.fromentries","object.getownpropertydescriptors","object.groupby","object.hasown","object.values","promise.allsettled","promise.any","reflect.getprototypeof","reflect.ownkeys","regexp.prototype.flags","safe-array-concat","safe-regex-test","set-function-length","side-channel","string.prototype.at","string.prototype.codepointat","string.prototype.includes","string.prototype.matchall","string.prototype.padend","string.prototype.padstart","string.prototype.repeat","string.prototype.replaceall","string.prototype.split","string.prototype.startswith","string.prototype.trim","string.prototype.trimend","string.prototype.trimleft","string.prototype.trimright","string.prototype.trimstart","typed-array-buffer","typed-array-byte-length","typed-array-byte-offset","typed-array-length","typedarray","unbox-primitive","util.promisify","which-boxed-primitive","which-typed-array"],u=new Map(d.map(t=>[o.structUtils.makeIdent(null,t).identHash,o.structUtils.makeIdent("nolyfill",t)])),b={hooks:{reduceDependency:async t=>{let r=u.get(t.identHash);if(r){let e=o.structUtils.makeDescriptor(r,"latest"),s=o.structUtils.makeRange({protocol:"npm:",source:null,selector:o.structUtils.stringifyDescriptor(e),params:null});return o.structUtils.makeDescriptor(t,s)}return t}}},h=b;return f(m);})(); 7 | return plugin; 8 | } 9 | }; 10 | -------------------------------------------------------------------------------- /.yarnrc.yml: -------------------------------------------------------------------------------- 1 | logFilters: 2 | - code: YN0076 3 | level: discard 4 | 5 | nodeLinker: node-modules 6 | 7 | plugins: 8 | - checksum: 9b6f8a34bda80f025c0b223fa80836f5e931cf5c8dd83e10ccfa9e677856cf1508b063d027060f74e3ce66ee1c8a936542e85db18a30584f9b88a50379b3f514 9 | path: .yarn/plugins/@yarnpkg/plugin-nolyfill.cjs 10 | spec: "https://raw.githubusercontent.com/wojtekmaj/yarn-plugin-nolyfill/v1.0.1/bundles/@yarnpkg/plugin-nolyfill.js" 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017–2024 Wojciech Maj 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 | packages/react-timerange-picker/README.md -------------------------------------------------------------------------------- /biome.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://biomejs.dev/schemas/1.9.0/schema.json", 3 | "files": { 4 | "ignore": [".tsimp", ".yarn", "coverage", "dist", ".pnp.cjs", ".pnp.loader.mjs"] 5 | }, 6 | "formatter": { 7 | "lineWidth": 100, 8 | "indentStyle": "space" 9 | }, 10 | "linter": { 11 | "rules": { 12 | "complexity": { 13 | "noUselessSwitchCase": "off" 14 | }, 15 | "correctness": { 16 | "noUnusedImports": "warn", 17 | "noUnusedVariables": "warn" 18 | }, 19 | "suspicious": { 20 | "noConsoleLog": "warn" 21 | } 22 | } 23 | }, 24 | "css": { 25 | "formatter": { 26 | "quoteStyle": "single" 27 | } 28 | }, 29 | "javascript": { 30 | "formatter": { 31 | "quoteStyle": "single" 32 | } 33 | }, 34 | "overrides": [ 35 | { 36 | "include": ["**/package.json"], 37 | "formatter": { 38 | "lineWidth": 1 39 | } 40 | }, 41 | { 42 | "include": ["**/vite.config.ts"], 43 | "linter": { 44 | "rules": { 45 | "suspicious": { 46 | "noConsoleLog": "off" 47 | } 48 | } 49 | } 50 | } 51 | ] 52 | } 53 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@wojtekmaj/react-timerange-picker-monorepo", 3 | "version": "1.0.0", 4 | "description": "@wojtekmaj/react-timerange-picker monorepo", 5 | "type": "module", 6 | "workspaces": [ 7 | "packages/*", 8 | "test" 9 | ], 10 | "scripts": { 11 | "build": "yarn workspace @wojtekmaj/react-timerange-picker build", 12 | "dev": "yarn workspace @wojtekmaj/react-timerange-picker watch & yarn workspace test dev", 13 | "format": "yarn workspaces foreach --all run format", 14 | "lint": "yarn workspaces foreach --all run lint", 15 | "postinstall": "husky", 16 | "test": "yarn workspaces foreach --all run test", 17 | "tsc": "yarn workspaces foreach --all run tsc", 18 | "unit": "yarn workspaces foreach --all run unit" 19 | }, 20 | "devDependencies": { 21 | "husky": "^9.0.0" 22 | }, 23 | "packageManager": "yarn@4.9.1" 24 | } 25 | -------------------------------------------------------------------------------- /packages/react-timerange-picker/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017–2024 Wojciech Maj 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 | -------------------------------------------------------------------------------- /packages/react-timerange-picker/README.md: -------------------------------------------------------------------------------- 1 | [![npm](https://img.shields.io/npm/v/@wojtekmaj/react-timerange-picker.svg)](https://www.npmjs.com/package/@wojtekmaj/react-timerange-picker) ![downloads](https://img.shields.io/npm/dt/@wojtekmaj/react-timerange-picker.svg) [![CI](https://github.com/wojtekmaj/react-timerange-picker/actions/workflows/ci.yml/badge.svg)](https://github.com/wojtekmaj/react-timerange-picker/actions) 2 | 3 | # React-TimeRange-Picker 4 | 5 | A time range picker for your React app. 6 | 7 | - Supports virtually any language 8 | - No moment.js needed 9 | 10 | ## tl;dr 11 | 12 | - Install by executing `npm install @wojtekmaj/react-timerange-picker` or `yarn add @wojtekmaj/react-timerange-picker`. 13 | - Import by adding `import TimeRangePicker from '@wojtekmaj/react-timerange-picker'`. 14 | - Use by adding ``. Use `onChange` prop for getting new values. 15 | 16 | ## Demo 17 | 18 | A minimal demo page can be found in `sample` directory. 19 | 20 | [Online demo](https://projects.wojtekmaj.pl/react-timerange-picker/) is also available! 21 | 22 | ## Consider native alternative 23 | 24 | If you don't need to support legacy browsers and don't need the advanced features this package provides, consider using native time input instead. It's more accessible, adds no extra weight to your bundle, and works better on mobile devices. 25 | 26 | ```tsx 27 | 28 | 29 | ``` 30 | 31 | ## Looking for a date range picker or a datetime range picker? 32 | 33 | React-TimeRange-Picker will play nicely with [React-DateRange-Picker](https://github.com/wojtekmaj/react-daterange-picker) and [React-DateTimeRange-Picker](https://github.com/wojtekmaj/react-datetimerange-picker). Check them out! 34 | 35 | ## Getting started 36 | 37 | ### Compatibility 38 | 39 | Your project needs to use React 16.3 or later. If you use an older version of React, please refer to the table below to find a suitable React-TimeRange-Picker version. 40 | 41 | | React version | Newest compatible React-TimeRange-Picker version | 42 | | ------------- | ------------------------------------------------ | 43 | | ≥16.8 | latest | 44 | | ≥16.3 | 4.x | 45 | | ≥16.0 | 2.x | 46 | 47 | ### Installation 48 | 49 | Add React-TimeRange-Picker to your project by executing `npm install @wojtekmaj/react-timerange-picker` or `yarn add @wojtekmaj/react-timerange-picker`. 50 | 51 | ### Usage 52 | 53 | Here's an example of basic usage: 54 | 55 | ```tsx 56 | import { useState } from 'react'; 57 | import TimeRangePicker from '@wojtekmaj/react-timerange-picker'; 58 | 59 | type ValuePiece = Date | string | null; 60 | 61 | type Value = ValuePiece | [ValuePiece, ValuePiece]; 62 | 63 | function MyApp() { 64 | const [value, onChange] = useState(['10:00', '11:00']); 65 | 66 | return ( 67 |
68 | 69 |
70 | ); 71 | } 72 | ``` 73 | 74 | ### Custom styling 75 | 76 | If you want to use default React-Date-Picker and React-Calendar styling to build upon it, you can import them by using: 77 | 78 | ```ts 79 | import '@wojtekmaj/react-timerange-picker/dist/TimeRangePicker.css'; 80 | import 'react-clock/dist/Clock.css'; 81 | ``` 82 | 83 | ## User guide 84 | 85 | ### TimeRangePicker 86 | 87 | Displays an input field complete with custom inputs, native input and a clock. 88 | 89 | #### Props 90 | 91 | | Prop name | Description | Default value | Example values | 92 | | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | 93 | | amPmAriaLabel | `aria-label` for the AM/PM select input. | n/a | `"Select AM/PM"` | 94 | | autoFocus | Automatically focuses the input on mount. | n/a | `true` | 95 | | className | Class name(s) that will be added along with `"react-timerange-picker"` to the main React-TimeRange-Picker `
` element. | n/a |
  • String: `"class1 class2"`
  • Array of strings: `["class1", "class2 class3"]`
| 96 | | clearAriaLabel | `aria-label` for the clear button. | n/a | `"Clear value"` | 97 | | clearIcon | Content of the clear button. Setting the value explicitly to `null` will hide the icon. | (default icon) |
  • String: `"Clear"`
  • React element: ``
  • React function: `ClearIcon`
| 98 | | clockAriaLabel | `aria-label` for the clock button. | n/a | `"Toggle clock"` | 99 | | clockProps | Props to pass to React-Clock component. | n/a | See [React-Clock documentation](https://github.com/wojtekmaj/react-clock) | 100 | | clockIcon | Content of the clock button. Setting the value explicitly to `null` will hide the icon. | (default icon) |
  • String: `"Clock"`
  • React element: ``
  • React function: `ClockIcon`
| 101 | | closeClock | Whether to close the clock on value selection. **Note**: It's recommended to use `shouldCloseClock` function instead. | `true` | `false` | 102 | | data-testid | `data-testid` attribute for the main React-TimeRange-Picker `
` element. | n/a | `"timerange-picker"` | 103 | | disableClock | When set to `true`, will remove the clock and the button toggling its visibility. | `false` | `true` | 104 | | disabled | Whether the time range picker should be disabled. | `false` | `true` | 105 | | format | Input format based on [Unicode Technical Standard #35](https://www.unicode.org/reports/tr35/tr35-dates.html#Date_Field_Symbol_Table). Supported values are: `H`, `HH`, `h`, `hh`, `m`, `mm`, `s`, `ss`, `a`. **Note**: When using SSR, setting this prop may help resolving hydration errors caused by locale mismatch between server and client. | n/a | `"h:m:s a"` | 106 | | hourAriaLabel | `aria-label` for the hour input. | n/a | `"Hour"` | 107 | | hourPlaceholder | `placeholder` for the hour input. | `"--"` | `"hh"` | 108 | | id | `id` attribute for the main React-TimeRange-Picker `
` element. | n/a | `"timerange-picker"` | 109 | | isOpen | Whether the clock should be opened. | `false` | `true` | 110 | | locale | Locale that should be used by the time range picker and the clock. Can be any [IETF language tag](https://en.wikipedia.org/wiki/IETF_language_tag). **Note**: When using SSR, setting this prop may help resolving hydration errors caused by locale mismatch between server and client. | Server locale/User's browser settings | `"hu-HU"` | 111 | | maxDetail | How detailed time picking shall be. Can be `"hour"`, `"minute"` or `"second"`. | `"minute"` | `"second"` | 112 | | maxTime | Maximum time that the user can select. | n/a |
  • Date: `new Date()`
  • String: `"22:15:00"`
| 113 | | minTime | Minimum date that the user can select. | n/a |
  • Date: `new Date()`
  • String: `"22:15:00"`
| 114 | | minuteAriaLabel | `aria-label` for the minute input. | n/a | `"Minute"` | 115 | | minutePlaceholder | `placeholder` for the minute input. | `"--"` | `"mm"` | 116 | | name | Input name prefix. Time from/Time to fields will be named `"yourprefix_from"` and `"yourprefix_to"` respectively. | `"timerange"` | `"myCustomName"` | 117 | | nativeInputAriaLabel | `aria-label` for the native time input. | n/a | `"Time"` | 118 | | onChange | Function called when the user picks a valid time. | n/a | `(value) => alert('New time is: ', value)` | 119 | | onClockClose | Function called when the clock closes. | n/a | `() => alert('Clock closed')` | 120 | | onClockOpen | Function called when the clock opens. | n/a | `() => alert('Clock opened')` | 121 | | onFocus | Function called when the user focuses an input. | n/a | `(event) => alert('Focused input: ', event.target.name)` | 122 | | onInvalidChange | Function called when the user picks an invalid time. | n/a | `() => alert('Invalid time')` | 123 | | openClockOnFocus | Whether to open the clock on input focus. **Note**: It's recommended to use `shouldOpenClock` function instead. | `true` | `false` | 124 | | portalContainer | Element to render the clock in using portal. | n/a | `document.getElementById('my-div')` | 125 | | rangeDivider | Divider between time inputs. | `"–"` | `" to "` | 126 | | required | Whether time input should be required. | `false` | `true` | 127 | | secondAriaLabel | `aria-label` for the second input. | n/a | `"Second"` | 128 | | secondPlaceholder | `placeholder` for the second input. | `"--"` | `"ss"` | 129 | | shouldCloseClock | Function called before the clock closes. `reason` can be `"buttonClick"`, `"escape"`, `"outsideAction"`, or `"select"`. If it returns `false`, the clock will not close. | n/a | `({ reason }) => reason !== 'outsideAction'` | 130 | | shouldOpenClock | Function called before the clock opens. `reason` can be `"buttonClick"` or `"focus"`. If it returns `false`, the clock will not open. | n/a | `({ reason }) => reason !== 'focus'` | 131 | | value | Input value. | n/a |
  • Date: `new Date(2017, 0, 1, 22, 15)`
  • String: `"22:15:00"`
  • An array of dates: `[new Date(2017, 0, 1, 22, 15), new Date(2017, 0, 1, 23, 45)]`
  • An array of strings: `["22:15:00", "23:45:00"]`
| 132 | 133 | ### Clock 134 | 135 | TimeRangePicker component passes all props to React-Clock, with the exception of `className` (you can use `clockClassName` for that instead). There are tons of customizations you can do! For more information, see [Clock component props](https://github.com/wojtekmaj/react-clock#props). 136 | 137 | ## License 138 | 139 | The MIT License. 140 | 141 | ## Author 142 | 143 | 144 | 145 | 148 | 151 | 152 |
146 | Wojciech Maj 147 | 149 | Wojciech Maj 150 |
153 | -------------------------------------------------------------------------------- /packages/react-timerange-picker/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@wojtekmaj/react-timerange-picker", 3 | "version": "6.0.0", 4 | "description": "A time range picker for your React app.", 5 | "type": "module", 6 | "sideEffects": [ 7 | "*.css" 8 | ], 9 | "main": "./dist/cjs/index.js", 10 | "module": "./dist/esm/index.js", 11 | "source": "./src/index.ts", 12 | "types": "./dist/cjs/index.d.ts", 13 | "exports": { 14 | ".": { 15 | "import": "./dist/esm/index.js", 16 | "require": "./dist/cjs/index.js" 17 | }, 18 | "./*": "./*" 19 | }, 20 | "scripts": { 21 | "build": "yarn build-js && yarn copy-styles", 22 | "build-js": "yarn build-js-esm && yarn build-js-cjs && yarn build-js-cjs-package && yarn build-js-cjs-replace", 23 | "build-js-esm": "tsc --project tsconfig.build.json --outDir dist/esm", 24 | "build-js-cjs": "tsc --project tsconfig.build.json --outDir dist/cjs --module commonjs --moduleResolution node --verbatimModuleSyntax false", 25 | "build-js-cjs-package": "echo '{\n \"type\": \"commonjs\"\n}' > dist/cjs/package.json", 26 | "build-js-cjs-replace": "replace-in-files --string='/dist/esm/' --replacement='/dist/cjs/' dist/cjs/**/*", 27 | "clean": "node -e \"fs.rmSync('./dist', { recursive: true, force: true })\"", 28 | "copy-styles": "cpy 'src/**/*.css' dist", 29 | "format": "biome format", 30 | "lint": "biome lint", 31 | "prepack": "yarn clean && yarn build", 32 | "test": "yarn lint && yarn tsc && yarn format && yarn unit", 33 | "tsc": "tsc", 34 | "unit": "vitest", 35 | "watch": "yarn build-js-esm --watch & yarn build-js-cjs --watch & node --eval \"fs.watch('src', () => child_process.exec('yarn copy-styles'))\"" 36 | }, 37 | "keywords": [ 38 | "react", 39 | "time", 40 | "time-picker", 41 | "time-range", 42 | "time-range-picker" 43 | ], 44 | "author": { 45 | "name": "Wojciech Maj", 46 | "email": "kontakt@wojtekmaj.pl" 47 | }, 48 | "license": "MIT", 49 | "dependencies": { 50 | "clsx": "^2.0.0", 51 | "make-event-props": "^1.6.0", 52 | "react-clock": "^5.0.0", 53 | "react-fit": "^2.0.0", 54 | "react-time-picker": "^7.0.0" 55 | }, 56 | "devDependencies": { 57 | "@biomejs/biome": "1.9.0", 58 | "@testing-library/dom": "^10.0.0", 59 | "@testing-library/jest-dom": "^6.0.0", 60 | "@testing-library/react": "^16.0.0", 61 | "@testing-library/user-event": "^14.5.0", 62 | "@types/node": "*", 63 | "@types/react": "*", 64 | "@types/react-dom": "*", 65 | "cpy-cli": "^5.0.0", 66 | "happy-dom": "^15.10.2", 67 | "react": "^18.2.0", 68 | "react-dom": "^18.2.0", 69 | "replace-in-files-cli": "^3.0.0", 70 | "typescript": "^5.5.2", 71 | "vitest": "^3.0.5", 72 | "vitest-canvas-mock": "^0.2.2" 73 | }, 74 | "peerDependencies": { 75 | "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", 76 | "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", 77 | "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" 78 | }, 79 | "peerDependenciesMeta": { 80 | "@types/react": { 81 | "optional": true 82 | } 83 | }, 84 | "publishConfig": { 85 | "access": "public", 86 | "provenance": true 87 | }, 88 | "files": [ 89 | "dist", 90 | "src" 91 | ], 92 | "repository": { 93 | "type": "git", 94 | "url": "git+https://github.com/wojtekmaj/react-timerange-picker.git", 95 | "directory": "packages/react-timerange-picker" 96 | }, 97 | "funding": "https://github.com/wojtekmaj/react-timerange-picker?sponsor=1" 98 | } 99 | -------------------------------------------------------------------------------- /packages/react-timerange-picker/src/TimeRangePicker.css: -------------------------------------------------------------------------------- 1 | .react-timerange-picker { 2 | display: inline-flex; 3 | position: relative; 4 | } 5 | 6 | .react-timerange-picker, 7 | .react-timerange-picker *, 8 | .react-timerange-picker *:before, 9 | .react-timerange-picker *:after { 10 | -moz-box-sizing: border-box; 11 | -webkit-box-sizing: border-box; 12 | box-sizing: border-box; 13 | } 14 | 15 | .react-timerange-picker--disabled { 16 | background-color: #f0f0f0; 17 | color: #6d6d6d; 18 | } 19 | 20 | .react-timerange-picker__wrapper { 21 | display: flex; 22 | flex-grow: 1; 23 | flex-shrink: 0; 24 | align-items: center; 25 | border: thin solid gray; 26 | } 27 | 28 | .react-timerange-picker__inputGroup { 29 | min-width: calc((4px * 3) + 0.54em * 6 + 0.217em * 2); 30 | height: 100%; 31 | flex-grow: 1; 32 | padding: 0 2px; 33 | box-sizing: content-box; 34 | } 35 | 36 | .react-timerange-picker__inputGroup__divider { 37 | padding: 1px 0; 38 | white-space: pre; 39 | } 40 | 41 | .react-timerange-picker__inputGroup__divider, 42 | .react-timerange-picker__inputGroup__leadingZero { 43 | display: inline-block; 44 | font: inherit; 45 | } 46 | 47 | .react-timerange-picker__inputGroup__input { 48 | min-width: 0.54em; 49 | height: 100%; 50 | position: relative; 51 | padding: 0 1px; 52 | border: 0; 53 | background: none; 54 | color: currentColor; 55 | font: inherit; 56 | box-sizing: content-box; 57 | -webkit-appearance: textfield; 58 | -moz-appearance: textfield; 59 | appearance: textfield; 60 | } 61 | 62 | .react-timerange-picker__inputGroup__input::-webkit-outer-spin-button, 63 | .react-timerange-picker__inputGroup__input::-webkit-inner-spin-button { 64 | -webkit-appearance: none; 65 | -moz-appearance: none; 66 | appearance: none; 67 | margin: 0; 68 | } 69 | 70 | .react-timerange-picker__inputGroup__input:invalid { 71 | background: rgba(255, 0, 0, 0.1); 72 | } 73 | 74 | .react-timerange-picker__inputGroup__input--hasLeadingZero { 75 | margin-left: -0.54em; 76 | padding-left: calc(1px + 0.54em); 77 | } 78 | 79 | .react-timerange-picker__inputGroup__amPm { 80 | font: inherit; 81 | -webkit-appearance: menulist; 82 | -moz-appearance: menulist; 83 | appearance: menulist; 84 | } 85 | 86 | .react-timerange-picker__button { 87 | border: 0; 88 | background: transparent; 89 | padding: 4px 6px; 90 | } 91 | 92 | .react-timerange-picker__button:enabled { 93 | cursor: pointer; 94 | } 95 | 96 | .react-timerange-picker__button:enabled:hover .react-timerange-picker__button__icon, 97 | .react-timerange-picker__button:enabled:focus .react-timerange-picker__button__icon { 98 | stroke: #0078d7; 99 | } 100 | 101 | .react-timerange-picker__button:disabled .react-timerange-picker__button__icon { 102 | stroke: #6d6d6d; 103 | } 104 | 105 | .react-timerange-picker__button svg { 106 | display: inherit; 107 | } 108 | 109 | .react-timerange-picker__clock { 110 | width: 200px; 111 | height: 200px; 112 | max-width: 100vw; 113 | padding: 25px; 114 | background-color: white; 115 | border: thin solid #a0a096; 116 | z-index: 1; 117 | } 118 | 119 | .react-timerange-picker__clock--closed { 120 | display: none; 121 | } 122 | -------------------------------------------------------------------------------- /packages/react-timerange-picker/src/TimeRangePicker.spec.tsx: -------------------------------------------------------------------------------- 1 | import { describe, expect, it, vi } from 'vitest'; 2 | import { act, fireEvent, render, waitFor, waitForElementToBeRemoved } from '@testing-library/react'; 3 | import { userEvent } from '@testing-library/user-event'; 4 | 5 | import TimeRangePicker from './TimeRangePicker.js'; 6 | 7 | async function waitForElementToBeRemovedOrHidden(callback: () => HTMLElement | null) { 8 | const element = callback(); 9 | 10 | if (element) { 11 | try { 12 | await waitFor(() => 13 | expect(element).toHaveAttribute('class', expect.stringContaining('--closed')), 14 | ); 15 | } catch { 16 | await waitForElementToBeRemoved(element); 17 | } 18 | } 19 | } 20 | 21 | describe('TimeRangePicker', () => { 22 | it('passes default name to TimeInput components', () => { 23 | const { container } = render(); 24 | 25 | const nativeInputs = container.querySelectorAll('input[type="time"]'); 26 | 27 | expect(nativeInputs[0]).toHaveAttribute('name', 'timerange_from'); 28 | expect(nativeInputs[1]).toHaveAttribute('name', 'timerange_to'); 29 | }); 30 | 31 | it('passes custom name to TimeInput components', () => { 32 | const name = 'testName'; 33 | 34 | const { container } = render(); 35 | 36 | const nativeInputs = container.querySelectorAll('input[type="time"]'); 37 | 38 | expect(nativeInputs[0]).toHaveAttribute('name', `${name}_from`); 39 | expect(nativeInputs[1]).toHaveAttribute('name', `${name}_to`); 40 | }); 41 | 42 | it('passes autoFocus flag to first TimeInput component', () => { 43 | const { container } = render(); 44 | 45 | const customInputs = container.querySelectorAll('input[data-input]'); 46 | 47 | expect(customInputs[0]).toHaveFocus(); 48 | }); 49 | 50 | it('passes disabled flag to TimeInput components', () => { 51 | const { container } = render(); 52 | 53 | const nativeInputs = container.querySelectorAll('input[type="time"]'); 54 | 55 | expect(nativeInputs[0]).toBeDisabled(); 56 | expect(nativeInputs[1]).toBeDisabled(); 57 | }); 58 | 59 | it('passes format to TimeInput components', () => { 60 | const { container } = render(); 61 | 62 | const customInputs = container.querySelectorAll('input[data-input]'); 63 | 64 | expect(customInputs).toHaveLength(2); 65 | expect(customInputs[0]).toHaveAttribute('name', 'second'); 66 | expect(customInputs[1]).toHaveAttribute('name', 'second'); 67 | }); 68 | 69 | it('passes aria-label props to TimeInput components', () => { 70 | const ariaLabelProps = { 71 | amPmAriaLabel: 'Select AM/PM', 72 | clearAriaLabel: 'Clear value', 73 | clockAriaLabel: 'Toggle clock', 74 | hourAriaLabel: 'Hour', 75 | minuteAriaLabel: 'Minute', 76 | nativeInputAriaLabel: 'Time', 77 | secondAriaLabel: 'Second', 78 | }; 79 | 80 | const { container } = render(); 81 | 82 | const clockButton = container.querySelector('button.react-timerange-picker__clock-button'); 83 | const clearButton = container.querySelector('button.react-timerange-picker__clear-button'); 84 | const timeInputs = container.querySelectorAll( 85 | '.react-timerange-picker__inputGroup', 86 | ) as unknown as [HTMLDivElement, HTMLDivElement]; 87 | 88 | const [timeFromInput, timeToInput] = timeInputs; 89 | 90 | const nativeFromInput = timeFromInput.querySelector('input[type="time"]'); 91 | const hourFromInput = timeFromInput.querySelector('input[name="hour12"]'); 92 | const minuteFromInput = timeFromInput.querySelector('input[name="minute"]'); 93 | const secondFromInput = timeFromInput.querySelector('input[name="second"]'); 94 | 95 | const nativeToInput = timeToInput.querySelector('input[type="time"]'); 96 | const hourToInput = timeToInput.querySelector('input[name="hour12"]'); 97 | const minuteToInput = timeToInput.querySelector('input[name="minute"]'); 98 | const secondToInput = timeToInput.querySelector('input[name="second"]'); 99 | 100 | expect(clockButton).toHaveAttribute('aria-label', ariaLabelProps.clockAriaLabel); 101 | expect(clearButton).toHaveAttribute('aria-label', ariaLabelProps.clearAriaLabel); 102 | 103 | expect(nativeFromInput).toHaveAttribute('aria-label', ariaLabelProps.nativeInputAriaLabel); 104 | expect(hourFromInput).toHaveAttribute('aria-label', ariaLabelProps.hourAriaLabel); 105 | expect(minuteFromInput).toHaveAttribute('aria-label', ariaLabelProps.minuteAriaLabel); 106 | expect(secondFromInput).toHaveAttribute('aria-label', ariaLabelProps.secondAriaLabel); 107 | 108 | expect(nativeToInput).toHaveAttribute('aria-label', ariaLabelProps.nativeInputAriaLabel); 109 | expect(hourToInput).toHaveAttribute('aria-label', ariaLabelProps.hourAriaLabel); 110 | expect(minuteToInput).toHaveAttribute('aria-label', ariaLabelProps.minuteAriaLabel); 111 | expect(secondToInput).toHaveAttribute('aria-label', ariaLabelProps.secondAriaLabel); 112 | }); 113 | 114 | it('passes placeholder props to TimeInput components', () => { 115 | const placeholderProps = { 116 | hourPlaceholder: 'hh', 117 | minutePlaceholder: 'mm', 118 | secondPlaceholder: 'ss', 119 | }; 120 | 121 | const { container } = render(); 122 | 123 | const timeInputs = container.querySelectorAll( 124 | '.react-timerange-picker__inputGroup', 125 | ) as unknown as [HTMLDivElement, HTMLDivElement]; 126 | 127 | const [timeFromInput, timeToInput] = timeInputs; 128 | 129 | const hourFromInput = timeFromInput.querySelector('input[name="hour12"]'); 130 | const minuteFromInput = timeFromInput.querySelector('input[name="minute"]'); 131 | const secondFromInput = timeFromInput.querySelector('input[name="second"]'); 132 | 133 | const hourToInput = timeToInput.querySelector('input[name="hour12"]'); 134 | const minuteToInput = timeToInput.querySelector('input[name="minute"]'); 135 | const secondToInput = timeToInput.querySelector('input[name="second"]'); 136 | 137 | expect(hourFromInput).toHaveAttribute('placeholder', placeholderProps.hourPlaceholder); 138 | expect(minuteFromInput).toHaveAttribute('placeholder', placeholderProps.minutePlaceholder); 139 | expect(secondFromInput).toHaveAttribute('placeholder', placeholderProps.secondPlaceholder); 140 | 141 | expect(hourToInput).toHaveAttribute('placeholder', placeholderProps.hourPlaceholder); 142 | expect(minuteToInput).toHaveAttribute('placeholder', placeholderProps.minutePlaceholder); 143 | expect(secondToInput).toHaveAttribute('placeholder', placeholderProps.secondPlaceholder); 144 | }); 145 | 146 | describe('passes value to TimeInput components', () => { 147 | it('passes single value to TimeInput components', () => { 148 | const value = new Date(2019, 0, 1); 149 | 150 | const { container } = render(); 151 | 152 | const nativeInputs = container.querySelectorAll('input[type="time"]'); 153 | 154 | expect(nativeInputs[0]).toHaveValue('00:00'); 155 | expect(nativeInputs[1]).toHaveValue(''); 156 | }); 157 | 158 | it('passes the first item of an array of values to TimeInput components', () => { 159 | const value1 = new Date(2019, 0, 1); 160 | const value2 = new Date(2019, 6, 1, 12, 30); 161 | 162 | const { container } = render(); 163 | 164 | const nativeInputs = container.querySelectorAll('input[type="time"]'); 165 | 166 | expect(nativeInputs[0]).toHaveValue('00:00'); 167 | expect(nativeInputs[1]).toHaveValue('12:30'); 168 | }); 169 | }); 170 | 171 | it('applies className to its wrapper when given a string', () => { 172 | const className = 'testClassName'; 173 | 174 | const { container } = render(); 175 | 176 | const wrapper = container.firstElementChild; 177 | 178 | expect(wrapper).toHaveClass(className); 179 | }); 180 | 181 | it('applies "--open" className to its wrapper when given isOpen flag', () => { 182 | const { container } = render(); 183 | 184 | const wrapper = container.firstElementChild; 185 | 186 | expect(wrapper).toHaveClass('react-timerange-picker--open'); 187 | }); 188 | 189 | it('applies clock className to the clock when given a string', () => { 190 | const clockClassName = 'testClassName'; 191 | 192 | const { container } = render( 193 | , 194 | ); 195 | 196 | const clock = container.querySelector('.react-clock'); 197 | 198 | expect(clock).toHaveClass(clockClassName); 199 | }); 200 | 201 | it('renders TimeInput components', () => { 202 | const { container } = render(); 203 | 204 | const nativeInputs = container.querySelectorAll('input[type="time"]'); 205 | 206 | expect(nativeInputs.length).toBe(2); 207 | }); 208 | 209 | it('renders range divider with default divider', () => { 210 | const { container } = render(); 211 | 212 | const rangeDivider = container.querySelector('.react-timerange-picker__range-divider'); 213 | 214 | expect(rangeDivider).toBeInTheDocument(); 215 | expect(rangeDivider).toHaveTextContent('–'); 216 | }); 217 | 218 | it('renders range divider with custom divider', () => { 219 | const { container } = render(); 220 | 221 | const rangeDivider = container.querySelector('.react-timerange-picker__range-divider'); 222 | 223 | expect(rangeDivider).toBeInTheDocument(); 224 | expect(rangeDivider).toHaveTextContent('to'); 225 | }); 226 | 227 | describe('renders clear button properly', () => { 228 | it('renders clear button', () => { 229 | const { container } = render(); 230 | 231 | const clearButton = container.querySelector('button.react-timerange-picker__clear-button'); 232 | 233 | expect(clearButton).toBeInTheDocument(); 234 | }); 235 | 236 | it('renders clear icon by default when clearIcon is not given', () => { 237 | const { container } = render(); 238 | 239 | const clearButton = container.querySelector( 240 | 'button.react-timerange-picker__clear-button', 241 | ) as HTMLButtonElement; 242 | 243 | const clearIcon = clearButton.querySelector('svg'); 244 | 245 | expect(clearIcon).toBeInTheDocument(); 246 | }); 247 | 248 | it('renders clear icon when given clearIcon as a string', () => { 249 | const { container } = render(); 250 | 251 | const clearButton = container.querySelector('button.react-timerange-picker__clear-button'); 252 | 253 | expect(clearButton).toHaveTextContent('❌'); 254 | }); 255 | 256 | it('renders clear icon when given clearIcon as a React element', () => { 257 | function ClearIcon() { 258 | return <>❌; 259 | } 260 | 261 | const { container } = render(} />); 262 | 263 | const clearButton = container.querySelector('button.react-timerange-picker__clear-button'); 264 | 265 | expect(clearButton).toHaveTextContent('❌'); 266 | }); 267 | 268 | it('renders clear icon when given clearIcon as a function', () => { 269 | function ClearIcon() { 270 | return <>❌; 271 | } 272 | 273 | const { container } = render(); 274 | 275 | const clearButton = container.querySelector('button.react-timerange-picker__clear-button'); 276 | 277 | expect(clearButton).toHaveTextContent('❌'); 278 | }); 279 | }); 280 | 281 | describe('renders clock button properly', () => { 282 | it('renders clock button', () => { 283 | const { container } = render(); 284 | 285 | const clockButton = container.querySelector('button.react-timerange-picker__clock-button'); 286 | 287 | expect(clockButton).toBeInTheDocument(); 288 | }); 289 | 290 | it('renders clock icon by default when clockIcon is not given', () => { 291 | const { container } = render(); 292 | 293 | const clockButton = container.querySelector( 294 | 'button.react-timerange-picker__clock-button', 295 | ) as HTMLButtonElement; 296 | 297 | const clockIcon = clockButton.querySelector('svg'); 298 | 299 | expect(clockIcon).toBeInTheDocument(); 300 | }); 301 | 302 | it('renders clock icon when given clockIcon as a string', () => { 303 | const { container } = render(); 304 | 305 | const clockButton = container.querySelector('button.react-timerange-picker__clock-button'); 306 | 307 | expect(clockButton).toHaveTextContent('🕒'); 308 | }); 309 | 310 | it('renders clock icon when given clockIcon as a React element', () => { 311 | function ClockIcon() { 312 | return <>🕒; 313 | } 314 | 315 | const { container } = render(} />); 316 | 317 | const clockButton = container.querySelector('button.react-timerange-picker__clock-button'); 318 | 319 | expect(clockButton).toHaveTextContent('🕒'); 320 | }); 321 | 322 | it('renders clock icon when given clockIcon as a function', () => { 323 | function ClockIcon() { 324 | return <>🕒; 325 | } 326 | 327 | const { container } = render(); 328 | 329 | const clockButton = container.querySelector('button.react-timerange-picker__clock-button'); 330 | 331 | expect(clockButton).toHaveTextContent('🕒'); 332 | }); 333 | }); 334 | 335 | it('renders Clock components when given isOpen flag', () => { 336 | const { container } = render(); 337 | 338 | const clock = container.querySelector('.react-clock'); 339 | 340 | expect(clock).toBeInTheDocument(); 341 | }); 342 | 343 | it('does not render Clock component when given disableClock & isOpen flags', () => { 344 | const { container } = render(); 345 | 346 | const clock = container.querySelector('.react-clock'); 347 | 348 | expect(clock).toBeFalsy(); 349 | }); 350 | 351 | it('opens Clock component when given isOpen flag by changing props', () => { 352 | const { container, rerender } = render(); 353 | 354 | const clock = container.querySelector('.react-clock'); 355 | 356 | expect(clock).toBeFalsy(); 357 | 358 | rerender(); 359 | 360 | const clock2 = container.querySelector('.react-clock'); 361 | 362 | expect(clock2).toBeInTheDocument(); 363 | }); 364 | 365 | it('opens Clock component when clicking on a button', () => { 366 | const { container } = render(); 367 | 368 | const clock = container.querySelector('.react-clock'); 369 | const button = container.querySelector( 370 | 'button.react-timerange-picker__clock-button', 371 | ) as HTMLButtonElement; 372 | 373 | expect(clock).toBeFalsy(); 374 | 375 | fireEvent.click(button); 376 | 377 | const clock2 = container.querySelector('.react-clock'); 378 | 379 | expect(clock2).toBeInTheDocument(); 380 | }); 381 | 382 | describe('handles opening Clock component when focusing on an input inside properly', () => { 383 | it('opens Clock component when focusing on an input inside by default', () => { 384 | const { container } = render(); 385 | 386 | const clock = container.querySelector('.react-clock'); 387 | const input = container.querySelector('input[name^="hour"]') as HTMLInputElement; 388 | 389 | expect(clock).toBeFalsy(); 390 | 391 | fireEvent.focus(input); 392 | 393 | const clock2 = container.querySelector('.react-clock'); 394 | 395 | expect(clock2).toBeInTheDocument(); 396 | }); 397 | 398 | it('opens Clock component when focusing on an input inside given openClockOnFocus = true', () => { 399 | const { container } = render(); 400 | 401 | const clock = container.querySelector('.react-clock'); 402 | const input = container.querySelector('input[name^="hour"]') as HTMLInputElement; 403 | 404 | expect(clock).toBeFalsy(); 405 | 406 | fireEvent.focus(input); 407 | 408 | const clock2 = container.querySelector('.react-clock'); 409 | 410 | expect(clock2).toBeInTheDocument(); 411 | }); 412 | 413 | it('does not open Clock component when focusing on an input inside given openClockOnFocus = false', () => { 414 | const { container } = render(); 415 | 416 | const clock = container.querySelector('.react-clock'); 417 | const input = container.querySelector('input[name^="hour"]') as HTMLInputElement; 418 | 419 | expect(clock).toBeFalsy(); 420 | 421 | fireEvent.focus(input); 422 | 423 | const clock2 = container.querySelector('.react-clock'); 424 | 425 | expect(clock2).toBeFalsy(); 426 | }); 427 | 428 | it('does not open Clock when focusing on an input inside given shouldOpenCalendar function returning false', () => { 429 | const shouldOpenClock = () => false; 430 | 431 | const { container } = render(); 432 | 433 | const clock = container.querySelector('.react-clock'); 434 | const input = container.querySelector('input[name^="hour"]') as HTMLInputElement; 435 | 436 | expect(clock).toBeFalsy(); 437 | 438 | fireEvent.focus(input); 439 | 440 | const clock2 = container.querySelector('.react-clock'); 441 | 442 | expect(clock2).toBeFalsy(); 443 | }); 444 | 445 | it('does not open Clock component when focusing on a select element', () => { 446 | const { container } = render(); 447 | 448 | const clock = container.querySelector('.react-clock'); 449 | const select = container.querySelector('select[name="amPm"]') as HTMLSelectElement; 450 | 451 | expect(clock).toBeFalsy(); 452 | 453 | fireEvent.focus(select); 454 | 455 | const clock2 = container.querySelector('.react-clock'); 456 | 457 | expect(clock2).toBeFalsy(); 458 | }); 459 | }); 460 | 461 | it('closes Clock component when clicked outside', async () => { 462 | const { container } = render(); 463 | 464 | userEvent.click(document.body); 465 | 466 | await waitForElementToBeRemovedOrHidden(() => 467 | container.querySelector('.react-timerange-picker__clock'), 468 | ); 469 | }); 470 | 471 | it('does not close Clock clicked outside with shouldCloseClock function returning false', () => { 472 | const shouldCloseClock = () => false; 473 | 474 | const { container } = render(); 475 | 476 | userEvent.click(document.body); 477 | 478 | const clock = container.querySelector('.react-clock'); 479 | 480 | expect(clock).toBeInTheDocument(); 481 | }); 482 | 483 | it('closes Clock component when focused outside', async () => { 484 | const { container } = render(); 485 | 486 | fireEvent.focusIn(document.body); 487 | 488 | await waitForElementToBeRemovedOrHidden(() => 489 | container.querySelector('.react-timerange-picker__clock'), 490 | ); 491 | }); 492 | 493 | it('closes Clock component when tapped outside', async () => { 494 | const { container } = render(); 495 | 496 | fireEvent.touchStart(document.body); 497 | 498 | await waitForElementToBeRemovedOrHidden(() => 499 | container.querySelector('.react-timerange-picker__clock'), 500 | ); 501 | }); 502 | 503 | it('does not close Clock component when clicked inside', () => { 504 | const { container } = render(); 505 | 506 | const customInputs = container.querySelectorAll('input[data-input]'); 507 | const hourInput = customInputs[0] as HTMLInputElement; 508 | const minuteInput = customInputs[1] as HTMLInputElement; 509 | 510 | fireEvent.blur(hourInput); 511 | fireEvent.focus(minuteInput); 512 | 513 | const clock = container.querySelector('.react-clock'); 514 | 515 | expect(clock).toBeInTheDocument(); 516 | }); 517 | 518 | it('does not close Clock when changing value', () => { 519 | const { container } = render(); 520 | 521 | const hourInput = container.querySelector('input[name="hour12"]') as HTMLInputElement; 522 | 523 | act(() => { 524 | fireEvent.change(hourInput, { target: { value: '9' } }); 525 | }); 526 | 527 | const clock = container.querySelector('.react-clock'); 528 | 529 | expect(clock).toBeInTheDocument(); 530 | }); 531 | 532 | it('calls onChange callback when changing value', () => { 533 | const value = '22:41:28'; 534 | const onChange = vi.fn(); 535 | 536 | const { container } = render( 537 | , 538 | ); 539 | 540 | const hourInput = container.querySelector('input[name="hour12"]') as HTMLInputElement; 541 | 542 | act(() => { 543 | fireEvent.change(hourInput, { target: { value: '9' } }); 544 | }); 545 | 546 | expect(onChange).toHaveBeenCalledWith(['21:41:28', null]); 547 | }); 548 | 549 | it('calls onInvalidChange callback when changing value to an invalid one', () => { 550 | const value = '22:41:28'; 551 | const onInvalidChange = vi.fn(); 552 | 553 | const { container } = render( 554 | , 555 | ); 556 | 557 | const hourInput = container.querySelector('input[name="hour12"]') as HTMLInputElement; 558 | 559 | act(() => { 560 | fireEvent.change(hourInput, { target: { value: '99' } }); 561 | }); 562 | 563 | expect(onInvalidChange).toHaveBeenCalled(); 564 | }); 565 | 566 | it('clears the value when clicking on a button', () => { 567 | const onChange = vi.fn(); 568 | 569 | const { container } = render(); 570 | 571 | const clock = container.querySelector('.react-clock'); 572 | 573 | expect(clock).toBeFalsy(); 574 | 575 | const button = container.querySelector( 576 | 'button.react-timerange-picker__clear-button', 577 | ) as HTMLButtonElement; 578 | 579 | fireEvent.click(button); 580 | 581 | expect(onChange).toHaveBeenCalledWith(null); 582 | }); 583 | 584 | describe('onChangeFrom', () => { 585 | it('calls onChange properly given no initial value', () => { 586 | const onChange = vi.fn(); 587 | 588 | const { container } = render( 589 | , 590 | ); 591 | 592 | const nextValueFrom = '16:00:00'; 593 | 594 | const customInputs = container.querySelectorAll('input[data-input]'); 595 | const hourInput = customInputs[0] as HTMLInputElement; 596 | const minuteInput = customInputs[1] as HTMLInputElement; 597 | const secondInput = customInputs[2] as HTMLInputElement; 598 | 599 | act(() => { 600 | fireEvent.change(hourInput, { target: { value: '16' } }); 601 | }); 602 | 603 | act(() => { 604 | fireEvent.change(minuteInput, { target: { value: '0' } }); 605 | }); 606 | 607 | act(() => { 608 | fireEvent.change(secondInput, { target: { value: '0' } }); 609 | }); 610 | 611 | expect(onChange).toHaveBeenCalled(); 612 | expect(onChange).toHaveBeenCalledWith([nextValueFrom, null]); 613 | }); 614 | 615 | it('calls onChange properly given single initial value', () => { 616 | const onChange = vi.fn(); 617 | const value = '10:00:00'; 618 | 619 | const { container } = render( 620 | , 621 | ); 622 | 623 | const nextValueFrom = '16:00:00'; 624 | 625 | const customInputs = container.querySelectorAll('input[data-input]'); 626 | const hourInput = customInputs[0] as HTMLInputElement; 627 | const minuteInput = customInputs[1] as HTMLInputElement; 628 | const secondInput = customInputs[2] as HTMLInputElement; 629 | 630 | act(() => { 631 | fireEvent.change(hourInput, { target: { value: '16' } }); 632 | }); 633 | 634 | act(() => { 635 | fireEvent.change(minuteInput, { target: { value: '0' } }); 636 | }); 637 | 638 | act(() => { 639 | fireEvent.change(secondInput, { target: { value: '0' } }); 640 | }); 641 | 642 | expect(onChange).toHaveBeenCalled(); 643 | expect(onChange).toHaveBeenCalledWith([nextValueFrom, null]); 644 | }); 645 | 646 | it('calls onChange properly given initial value as an array', () => { 647 | const onChange = vi.fn(); 648 | const valueFrom = '10:00:00'; 649 | const valueTo = '16:00:00'; 650 | const value = [valueFrom, valueTo] as [string, string]; 651 | 652 | const { container } = render( 653 | , 654 | ); 655 | 656 | const nextValueFrom = '13:00:00'; 657 | 658 | const customInputs = container.querySelectorAll('input[data-input]'); 659 | const hourInput = customInputs[0] as HTMLInputElement; 660 | const minuteInput = customInputs[1] as HTMLInputElement; 661 | const secondInput = customInputs[2] as HTMLInputElement; 662 | 663 | act(() => { 664 | fireEvent.change(hourInput, { target: { value: '13' } }); 665 | }); 666 | 667 | act(() => { 668 | fireEvent.change(minuteInput, { target: { value: '0' } }); 669 | }); 670 | 671 | act(() => { 672 | fireEvent.change(secondInput, { target: { value: '0' } }); 673 | }); 674 | 675 | expect(onChange).toHaveBeenCalled(); 676 | expect(onChange).toHaveBeenCalledWith([nextValueFrom, valueTo]); 677 | }); 678 | }); 679 | 680 | describe('onChangeTo', () => { 681 | it('calls onChange properly given no initial value', () => { 682 | const onChange = vi.fn(); 683 | 684 | const { container } = render( 685 | , 686 | ); 687 | 688 | const nextValueTo = '16:00:00'; 689 | 690 | const customInputs = container.querySelectorAll('input[data-input]'); 691 | const hourInput = customInputs[3] as HTMLInputElement; 692 | const minuteInput = customInputs[4] as HTMLInputElement; 693 | const secondInput = customInputs[5] as HTMLInputElement; 694 | 695 | act(() => { 696 | fireEvent.change(hourInput, { target: { value: '16' } }); 697 | }); 698 | 699 | act(() => { 700 | fireEvent.change(minuteInput, { target: { value: '0' } }); 701 | }); 702 | 703 | act(() => { 704 | fireEvent.change(secondInput, { target: { value: '0' } }); 705 | }); 706 | 707 | expect(onChange).toHaveBeenCalled(); 708 | expect(onChange).toHaveBeenCalledWith([null, nextValueTo]); 709 | }); 710 | 711 | it('calls onChange properly given single initial value', () => { 712 | const onChange = vi.fn(); 713 | const value = '10:00:00'; 714 | 715 | const { container } = render( 716 | , 717 | ); 718 | 719 | const nextValueTo = '16:00:00'; 720 | 721 | const customInputs = container.querySelectorAll('input[data-input]'); 722 | const hourInput = customInputs[3] as HTMLInputElement; 723 | const minuteInput = customInputs[4] as HTMLInputElement; 724 | const secondInput = customInputs[5] as HTMLInputElement; 725 | 726 | act(() => { 727 | fireEvent.change(hourInput, { target: { value: '16' } }); 728 | }); 729 | 730 | act(() => { 731 | fireEvent.change(minuteInput, { target: { value: '0' } }); 732 | }); 733 | 734 | act(() => { 735 | fireEvent.change(secondInput, { target: { value: '0' } }); 736 | }); 737 | 738 | expect(onChange).toHaveBeenCalled(); 739 | expect(onChange).toHaveBeenCalledWith([value, nextValueTo]); 740 | }); 741 | 742 | it('calls onChange properly given initial value as an array', () => { 743 | const onChange = vi.fn(); 744 | const valueFrom = '10:00:00'; 745 | const valueTo = '16:00:00'; 746 | const value = [valueFrom, valueTo] as [string, string]; 747 | 748 | const { container } = render( 749 | , 750 | ); 751 | 752 | const nextValueTo = '13:00:00'; 753 | 754 | const customInputs = container.querySelectorAll('input[data-input]'); 755 | const hourInput = customInputs[3] as HTMLInputElement; 756 | const minuteInput = customInputs[4] as HTMLInputElement; 757 | const secondInput = customInputs[5] as HTMLInputElement; 758 | 759 | act(() => { 760 | fireEvent.change(hourInput, { target: { value: '13' } }); 761 | }); 762 | 763 | act(() => { 764 | fireEvent.change(minuteInput, { target: { value: '0' } }); 765 | }); 766 | 767 | act(() => { 768 | fireEvent.change(secondInput, { target: { value: '0' } }); 769 | }); 770 | 771 | expect(onChange).toHaveBeenCalled(); 772 | expect(onChange).toHaveBeenCalledWith([valueFrom, nextValueTo]); 773 | }); 774 | }); 775 | it('calls onClick callback when clicked a page (sample of mouse events family)', () => { 776 | const onClick = vi.fn(); 777 | 778 | const { container } = render(); 779 | 780 | const wrapper = container.firstElementChild as HTMLDivElement; 781 | fireEvent.click(wrapper); 782 | 783 | expect(onClick).toHaveBeenCalled(); 784 | }); 785 | 786 | it('calls onTouchStart callback when touched a page (sample of touch events family)', () => { 787 | const onTouchStart = vi.fn(); 788 | 789 | const { container } = render(); 790 | 791 | const wrapper = container.firstElementChild as HTMLDivElement; 792 | fireEvent.touchStart(wrapper); 793 | 794 | expect(onTouchStart).toHaveBeenCalled(); 795 | }); 796 | }); 797 | -------------------------------------------------------------------------------- /packages/react-timerange-picker/src/TimeRangePicker.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import { createElement, useCallback, useEffect, useMemo, useRef, useState } from 'react'; 4 | import { createPortal } from 'react-dom'; 5 | import makeEventProps from 'make-event-props'; 6 | import clsx from 'clsx'; 7 | import Clock from 'react-clock'; 8 | import Fit from 'react-fit'; 9 | 10 | import TimeInput from 'react-time-picker/dist/esm/TimeInput'; 11 | 12 | import type { 13 | ClassName, 14 | CloseReason, 15 | Detail, 16 | LooseValue, 17 | OpenReason, 18 | Value, 19 | } from './shared/types.js'; 20 | 21 | const baseClassName = 'react-timerange-picker'; 22 | const outsideActionEvents = ['mousedown', 'focusin', 'touchstart'] as const; 23 | 24 | const iconProps = { 25 | xmlns: 'http://www.w3.org/2000/svg', 26 | width: 19, 27 | height: 19, 28 | viewBox: '0 0 19 19', 29 | stroke: 'black', 30 | strokeWidth: 2, 31 | }; 32 | 33 | const ClockIcon = ( 34 | 43 | ); 44 | 45 | const ClearIcon = ( 46 | 54 | ); 55 | 56 | type ReactNodeLike = React.ReactNode | string | number | boolean | null | undefined; 57 | 58 | type Icon = ReactNodeLike | ReactNodeLike[]; 59 | 60 | type IconOrRenderFunction = Icon | React.ComponentType | React.ReactElement; 61 | 62 | type ClockProps = Omit, 'value'>; 63 | 64 | type EventProps = ReturnType; 65 | 66 | export type TimeRangePickerProps = { 67 | /** 68 | * `aria-label` for the AM/PM select input. 69 | * 70 | * @example 'Select AM/PM' 71 | */ 72 | amPmAriaLabel?: string; 73 | /** 74 | * Automatically focuses the input on mount. 75 | * 76 | * @example true 77 | */ 78 | autoFocus?: boolean; 79 | /** 80 | * Class name(s) that will be added along with `"react-timerange-picker"` to the main React-TimeRange-Picker `
` element. 81 | * 82 | * @example 'class1 class2' 83 | * @example ['class1', 'class2 class3'] 84 | */ 85 | className?: ClassName; 86 | /** 87 | * `aria-label` for the clear button. 88 | * 89 | * @example 'Clear value' 90 | */ 91 | clearAriaLabel?: string; 92 | /** 93 | * Content of the clear button. Setting the value explicitly to `null` will hide the icon. 94 | * 95 | * @example 'Clear' 96 | * @example 97 | * @example ClearIcon 98 | */ 99 | clearIcon?: IconOrRenderFunction | null; 100 | /** 101 | * `aria-label` for the clock button. 102 | * 103 | * @example 'Toggle clock' 104 | */ 105 | clockAriaLabel?: string; 106 | /** 107 | * Props to pass to React-Clock component. 108 | */ 109 | clockProps?: ClockProps; 110 | /** 111 | * Content of the clock button. Setting the value explicitly to `null` will hide the icon. 112 | * 113 | * @example 'Clock' 114 | * @example 115 | * @example ClockIcon 116 | */ 117 | clockIcon?: IconOrRenderFunction | null; 118 | /** 119 | * Whether to close the clock on value selection. 120 | * 121 | * **Note**: It's recommended to use `shouldCloseClock` function instead. 122 | * 123 | * @default true 124 | * @example false 125 | */ 126 | closeClock?: boolean; 127 | /** 128 | * `data-testid` attribute for the main React-TimeRange-Picker `
` element. 129 | * 130 | * @example 'timerange-picker' 131 | */ 132 | 'data-testid'?: string; 133 | /** 134 | * When set to `true`, will remove the clock and the button toggling its visibility. 135 | * 136 | * @default false 137 | * @example true 138 | */ 139 | disableClock?: boolean; 140 | /** 141 | * Whether the time range picker should be disabled. 142 | * 143 | * @default false 144 | * @example true 145 | */ 146 | disabled?: boolean; 147 | /** 148 | * Input format based on [Unicode Technical Standard #35](https://www.unicode.org/reports/tr35/tr35-dates.html#Date_Field_Symbol_Table). Supported values are: `H`, `HH`, `h`, `hh`, `m`, `mm`, `s`, `ss`, `a`. 149 | * 150 | * **Note**: When using SSR, setting this prop may help resolving hydration errors caused by locale mismatch between server and client. 151 | * 152 | * @example 'h:m:s a' 153 | */ 154 | format?: string; 155 | /** 156 | * `aria-label` for the hour input. 157 | * 158 | * @example 'Hour' 159 | */ 160 | hourAriaLabel?: string; 161 | /** 162 | * `placeholder` for the hour input. 163 | * 164 | * @default '--' 165 | * @example 'hh' 166 | */ 167 | hourPlaceholder?: string; 168 | /** 169 | * `id` attribute for the main React-TimeRange-Picker `
` element. 170 | * 171 | * @example 'timerange-picker' 172 | */ 173 | id?: string; 174 | /** 175 | * Whether the clock should be opened. 176 | * 177 | * @default false 178 | * @example true 179 | */ 180 | isOpen?: boolean; 181 | /** 182 | * Locale that should be used by the time picker and the calendar. Can be any [IETF language tag](https://en.wikipedia.org/wiki/IETF_language_tag). 183 | * 184 | * **Note**: When using SSR, setting this prop may help resolving hydration errors caused by locale mismatch between server and client. 185 | * 186 | * @example 'hu-HU' 187 | */ 188 | locale?: string; 189 | /** 190 | * How detailed time picking shall be. Can be `"hour"`, `"minute"` or `"second"`. 191 | * 192 | * @default 'minute' 193 | * @example 'second' 194 | */ 195 | maxDetail?: Detail; 196 | /** 197 | * Maximum date that the user can select. 198 | * 199 | * @example new Date() 200 | * @example '22:15:00' 201 | */ 202 | maxTime?: string; 203 | /** 204 | * Minimum date that the user can select. 205 | * 206 | * @example new Date() 207 | * @example '22:15:00' 208 | */ 209 | minTime?: string; 210 | /** 211 | * `aria-label` for the minute input. 212 | * 213 | * @example 'Minute' 214 | */ 215 | minuteAriaLabel?: string; 216 | /** 217 | * `placeholder` for the minute input. 218 | * 219 | * @default '--' 220 | * @example 'mm' 221 | */ 222 | minutePlaceholder?: string; 223 | /** 224 | * Input name. 225 | * 226 | * @default 'timerange' 227 | */ 228 | name?: string; 229 | /** 230 | * `aria-label` for the native time input. 231 | * 232 | * @example 'Time' 233 | */ 234 | nativeInputAriaLabel?: string; 235 | /** 236 | * Function called when the user picks a valid time. 237 | * 238 | * @example (value) => alert('New time is: ', value) 239 | */ 240 | onChange?: (value: Value) => void; 241 | /** 242 | * Function called when the clock closes. 243 | * 244 | * @example () => alert('Clock closed') 245 | */ 246 | onClockClose?: () => void; 247 | /** 248 | * Function called when the clock opens. 249 | * 250 | * @example () => alert('Clock opened') 251 | */ 252 | onClockOpen?: () => void; 253 | /** 254 | * Function called when the user focuses an input. 255 | * 256 | * @example (event) => alert('Focused input: ', event.target.name) 257 | */ 258 | onFocus?: (event: React.FocusEvent) => void; 259 | /** 260 | * Function called when the user picks an invalid time. 261 | * 262 | * @example () => alert('Invalid time') 263 | */ 264 | onInvalidChange?: () => void; 265 | /** 266 | * Whether to open the clock on input focus. 267 | * 268 | * **Note**: It's recommended to use `shouldOpenClock` function instead. 269 | * 270 | * @default true 271 | * @example false 272 | */ 273 | openClockOnFocus?: boolean; 274 | /** 275 | * Element to render the clock in using portal. 276 | * 277 | * @example document.getElementById('my-div') 278 | */ 279 | portalContainer?: HTMLElement | null; 280 | /** 281 | * Divider between time inputs. 282 | * 283 | * @default '–' 284 | * @example ' to ' 285 | */ 286 | rangeDivider?: React.ReactNode; 287 | /** 288 | * Whether time input should be required. 289 | * 290 | * @default false 291 | * @example true 292 | */ 293 | required?: boolean; 294 | /** 295 | * `aria-label` for the second input. 296 | * 297 | * @example 'Second' 298 | */ 299 | secondAriaLabel?: string; 300 | /** 301 | * `placeholder` for the second input. 302 | * 303 | * @default '--' 304 | * @example 'ss' 305 | */ 306 | secondPlaceholder?: string; 307 | /** 308 | * Function called before the clock closes. `reason` can be `"buttonClick"`, `"escape"`, `"outsideAction"`, or `"select"`. If it returns `false`, the clock will not close. 309 | * 310 | * @example ({ reason }) => reason !== 'outsideAction' 311 | */ 312 | shouldCloseClock?: ({ reason }: { reason: CloseReason }) => boolean; 313 | /** 314 | * Function called before the clock opens. `reason` can be `"buttonClick"` or `"focus"`. If it returns `false`, the clock will not open. 315 | * 316 | * @example ({ reason }) => reason !== 'focus' 317 | */ 318 | shouldOpenClock?: ({ reason }: { reason: OpenReason }) => boolean; 319 | /** 320 | * Input value. 321 | * 322 | * @example new Date(2017, 0, 1, 22, 15) 323 | * @example '22:15:00' 324 | * @example [new Date(2017, 0, 1, 22, 15), new Date(2017, 0, 1, 23, 45)] 325 | * @example ["22:15:00", "23:45:00"] 326 | */ 327 | value?: LooseValue; 328 | } & Omit; 329 | 330 | export default function TimeRangePicker(props: TimeRangePickerProps): React.ReactElement { 331 | const { 332 | amPmAriaLabel, 333 | autoFocus, 334 | className, 335 | clearAriaLabel, 336 | clearIcon = ClearIcon, 337 | clockAriaLabel, 338 | clockIcon = ClockIcon, 339 | closeClock: shouldCloseClockOnSelect = true, 340 | 'data-testid': dataTestid, 341 | disableClock, 342 | disabled, 343 | format, 344 | hourAriaLabel, 345 | hourPlaceholder, 346 | id, 347 | isOpen: isOpenProps = null, 348 | locale, 349 | maxDetail = 'minute', 350 | maxTime, 351 | minTime, 352 | minuteAriaLabel, 353 | minutePlaceholder, 354 | name = 'timerange', 355 | nativeInputAriaLabel, 356 | onChange: onChangeProps, 357 | onClockClose, 358 | onClockOpen, 359 | onFocus: onFocusProps, 360 | onInvalidChange, 361 | openClockOnFocus = true, 362 | rangeDivider = '–', 363 | required, 364 | secondAriaLabel, 365 | secondPlaceholder, 366 | shouldCloseClock, 367 | shouldOpenClock, 368 | value, 369 | ...otherProps 370 | } = props; 371 | 372 | const [isOpen, setIsOpen] = useState(isOpenProps); 373 | const wrapper = useRef(null); 374 | const clockWrapper = useRef(null); 375 | 376 | useEffect(() => { 377 | setIsOpen(isOpenProps); 378 | }, [isOpenProps]); 379 | 380 | function openClock({ reason }: { reason: OpenReason }) { 381 | if (shouldOpenClock) { 382 | if (!shouldOpenClock({ reason })) { 383 | return; 384 | } 385 | } 386 | 387 | setIsOpen(true); 388 | 389 | if (onClockOpen) { 390 | onClockOpen(); 391 | } 392 | } 393 | 394 | const closeClock = useCallback( 395 | ({ reason }: { reason: CloseReason }) => { 396 | if (shouldCloseClock) { 397 | if (!shouldCloseClock({ reason })) { 398 | return; 399 | } 400 | } 401 | 402 | setIsOpen(false); 403 | 404 | if (onClockClose) { 405 | onClockClose(); 406 | } 407 | }, 408 | [onClockClose, shouldCloseClock], 409 | ); 410 | 411 | function toggleClock() { 412 | if (isOpen) { 413 | closeClock({ reason: 'buttonClick' }); 414 | } else { 415 | openClock({ reason: 'buttonClick' }); 416 | } 417 | } 418 | 419 | function onChange(value: Value, shouldCloseClock: boolean = shouldCloseClockOnSelect) { 420 | if (shouldCloseClock) { 421 | closeClock({ reason: 'select' }); 422 | } 423 | 424 | if (onChangeProps) { 425 | onChangeProps(value); 426 | } 427 | } 428 | 429 | function onChangeFrom(valueFrom: string | null, closeClock: boolean) { 430 | const [, valueTo] = Array.isArray(value) ? value : [value]; 431 | 432 | onChange([valueFrom, valueTo || null], closeClock); 433 | } 434 | 435 | function onChangeTo(valueTo: string | null, closeClock: boolean) { 436 | const [valueFrom] = Array.isArray(value) ? value : [value]; 437 | 438 | onChange([valueFrom || null, valueTo], closeClock); 439 | } 440 | 441 | function onFocus(event: React.FocusEvent) { 442 | if (onFocusProps) { 443 | onFocusProps(event); 444 | } 445 | 446 | if ( 447 | // Internet Explorer still fires onFocus on disabled elements 448 | disabled || 449 | isOpen || 450 | !openClockOnFocus || 451 | event.target.dataset.select === 'true' 452 | ) { 453 | return; 454 | } 455 | 456 | openClock({ reason: 'focus' }); 457 | } 458 | 459 | const onKeyDown = useCallback( 460 | (event: KeyboardEvent) => { 461 | if (event.key === 'Escape') { 462 | closeClock({ reason: 'escape' }); 463 | } 464 | }, 465 | [closeClock], 466 | ); 467 | 468 | function clear() { 469 | onChange(null); 470 | } 471 | 472 | function stopPropagation(event: React.FocusEvent) { 473 | event.stopPropagation(); 474 | } 475 | 476 | const onOutsideAction = useCallback( 477 | (event: Event) => { 478 | const { current: wrapperEl } = wrapper; 479 | const { current: clockWrapperEl } = clockWrapper; 480 | 481 | // Try event.composedPath first to handle clicks inside a Shadow DOM. 482 | const target = ( 483 | 'composedPath' in event ? event.composedPath()[0] : (event as Event).target 484 | ) as HTMLElement; 485 | 486 | if ( 487 | target && 488 | wrapperEl && 489 | !wrapperEl.contains(target) && 490 | (!clockWrapperEl || !clockWrapperEl.contains(target)) 491 | ) { 492 | closeClock({ reason: 'outsideAction' }); 493 | } 494 | }, 495 | [closeClock], 496 | ); 497 | 498 | const handleOutsideActionListeners = useCallback( 499 | (shouldListen = isOpen) => { 500 | for (const event of outsideActionEvents) { 501 | if (shouldListen) { 502 | document.addEventListener(event, onOutsideAction); 503 | } else { 504 | document.removeEventListener(event, onOutsideAction); 505 | } 506 | } 507 | 508 | if (shouldListen) { 509 | document.addEventListener('keydown', onKeyDown); 510 | } else { 511 | document.removeEventListener('keydown', onKeyDown); 512 | } 513 | }, 514 | [isOpen, onOutsideAction, onKeyDown], 515 | ); 516 | 517 | // biome-ignore lint/correctness/useExhaustiveDependencies: useEffect intentionally triggered on isOpen change 518 | useEffect(() => { 519 | handleOutsideActionListeners(); 520 | 521 | return () => { 522 | handleOutsideActionListeners(false); 523 | }; 524 | }, [handleOutsideActionListeners, isOpen]); 525 | 526 | function renderInputs() { 527 | const [valueFrom, valueTo] = Array.isArray(value) ? value : [value]; 528 | 529 | const ariaLabelProps = { 530 | amPmAriaLabel, 531 | hourAriaLabel, 532 | minuteAriaLabel, 533 | nativeInputAriaLabel, 534 | secondAriaLabel, 535 | }; 536 | 537 | const placeholderProps = { 538 | hourPlaceholder, 539 | minutePlaceholder, 540 | secondPlaceholder, 541 | }; 542 | 543 | const commonProps = { 544 | ...ariaLabelProps, 545 | ...placeholderProps, 546 | className: `${baseClassName}__inputGroup`, 547 | disabled, 548 | format, 549 | isClockOpen: isOpen, 550 | locale, 551 | maxDetail, 552 | maxTime, 553 | minTime, 554 | onInvalidChange, 555 | required, 556 | }; 557 | 558 | return ( 559 |
560 | 567 | {rangeDivider} 568 | 569 | {clearIcon !== null && ( 570 | 580 | )} 581 | {clockIcon !== null && !disableClock && ( 582 | 593 | )} 594 |
595 | ); 596 | } 597 | 598 | function renderClock() { 599 | if (isOpen === null || disableClock) { 600 | return null; 601 | } 602 | 603 | const { clockProps, portalContainer, value } = props; 604 | 605 | const className = `${baseClassName}__clock`; 606 | const classNames = clsx(className, `${className}--${isOpen ? 'open' : 'closed'}`); 607 | 608 | const [valueFrom] = Array.isArray(value) ? value : [value]; 609 | 610 | const clock = ; 611 | 612 | return portalContainer ? ( 613 | createPortal( 614 |
615 | {clock} 616 |
, 617 | portalContainer, 618 | ) 619 | ) : ( 620 | 621 |
{ 623 | if (ref && !isOpen) { 624 | ref.removeAttribute('style'); 625 | } 626 | }} 627 | className={classNames} 628 | > 629 | {clock} 630 |
631 |
632 | ); 633 | } 634 | 635 | const eventProps = useMemo( 636 | () => makeEventProps(otherProps), 637 | // biome-ignore lint/correctness/useExhaustiveDependencies: FIXME 638 | [otherProps], 639 | ); 640 | 641 | return ( 642 |
655 | {renderInputs()} 656 | {renderClock()} 657 |
658 | ); 659 | } 660 | -------------------------------------------------------------------------------- /packages/react-timerange-picker/src/index.ts: -------------------------------------------------------------------------------- 1 | import TimeRangePicker from './TimeRangePicker.js'; 2 | 3 | export type { TimeRangePickerProps } from './TimeRangePicker.js'; 4 | 5 | export { TimeRangePicker }; 6 | 7 | export default TimeRangePicker; 8 | -------------------------------------------------------------------------------- /packages/react-timerange-picker/src/shared/types.ts: -------------------------------------------------------------------------------- 1 | export type Range = [T, T]; 2 | 3 | export type AmPmType = 'am' | 'pm'; 4 | 5 | export type ClassName = string | null | undefined | (string | null | undefined)[]; 6 | 7 | export type CloseReason = 'buttonClick' | 'escape' | 'outsideAction' | 'select'; 8 | 9 | export type Detail = 'hour' | 'minute' | 'second'; 10 | 11 | type LooseValuePiece = string | Date | null; 12 | 13 | export type LooseValue = LooseValuePiece | Range; 14 | 15 | export type OpenReason = 'buttonClick' | 'focus'; 16 | 17 | type ValuePiece = string | Date | null; 18 | 19 | export type Value = ValuePiece | Range; 20 | -------------------------------------------------------------------------------- /packages/react-timerange-picker/tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "noEmit": false, 5 | "outDir": "dist", 6 | "rootDir": "src" 7 | }, 8 | "include": ["src"], 9 | "exclude": ["src/**/*.spec.ts", "src/**/*.spec.tsx"] 10 | } 11 | -------------------------------------------------------------------------------- /packages/react-timerange-picker/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "declaration": true, 4 | "esModuleInterop": true, 5 | "isolatedDeclarations": true, 6 | "isolatedModules": true, 7 | "jsx": "react-jsx", 8 | "module": "nodenext", 9 | "moduleDetection": "force", 10 | "noEmit": true, 11 | "noUncheckedIndexedAccess": true, 12 | "outDir": "dist", 13 | "skipLibCheck": true, 14 | "strict": true, 15 | "target": "es5", 16 | "verbatimModuleSyntax": true 17 | }, 18 | "exclude": ["dist"] 19 | } 20 | -------------------------------------------------------------------------------- /packages/react-timerange-picker/vitest.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vitest/config'; 2 | 3 | export default defineConfig({ 4 | test: { 5 | environment: 'happy-dom', 6 | server: { 7 | deps: { 8 | inline: ['vitest-canvas-mock'], 9 | }, 10 | }, 11 | setupFiles: 'vitest.setup.ts', 12 | watch: false, 13 | }, 14 | }); 15 | -------------------------------------------------------------------------------- /packages/react-timerange-picker/vitest.setup.ts: -------------------------------------------------------------------------------- 1 | import { afterEach } from 'vitest'; 2 | import { cleanup } from '@testing-library/react'; 3 | import '@testing-library/jest-dom/vitest'; 4 | import 'vitest-canvas-mock'; 5 | 6 | afterEach(() => { 7 | cleanup(); 8 | }); 9 | -------------------------------------------------------------------------------- /sample/.gitignore: -------------------------------------------------------------------------------- 1 | dist 2 | node_modules 3 | -------------------------------------------------------------------------------- /sample/Sample.css: -------------------------------------------------------------------------------- 1 | html, 2 | body { 3 | height: 100%; 4 | } 5 | 6 | body { 7 | margin: 0; 8 | font-family: Segoe UI, Tahoma, sans-serif; 9 | } 10 | 11 | .Sample input, 12 | .Sample button { 13 | font: inherit; 14 | } 15 | 16 | .Sample header { 17 | background-color: #323639; 18 | box-shadow: 0 0 8px rgba(0, 0, 0, 0.5); 19 | padding: 20px; 20 | color: white; 21 | } 22 | 23 | .Sample header h1 { 24 | font-size: inherit; 25 | margin: 0; 26 | } 27 | 28 | .Sample__container { 29 | display: flex; 30 | flex-direction: row; 31 | flex-wrap: wrap; 32 | align-items: flex-start; 33 | margin: 10px 0; 34 | padding: 10px; 35 | } 36 | 37 | .Sample__container > * > * { 38 | margin: 10px; 39 | } 40 | 41 | .Sample__container__content { 42 | display: flex; 43 | max-width: 100%; 44 | flex-basis: 420px; 45 | flex-direction: column; 46 | flex-grow: 100; 47 | align-items: stretch; 48 | } 49 | -------------------------------------------------------------------------------- /sample/Sample.tsx: -------------------------------------------------------------------------------- 1 | import { useState } from 'react'; 2 | import TimeRangePicker from '@wojtekmaj/react-timerange-picker'; 3 | 4 | import './Sample.css'; 5 | 6 | type ValuePiece = Date | string | null; 7 | 8 | type Value = ValuePiece | [ValuePiece, ValuePiece]; 9 | 10 | const now = new Date(); 11 | const nextHour = new Date(); 12 | nextHour.setHours(nextHour.getHours() + 1); 13 | 14 | export default function Sample() { 15 | const [value, onChange] = useState([now, nextHour]); 16 | 17 | return ( 18 |
19 |
20 |

react-timerange-picker sample page

21 |
22 |
23 |
24 | 25 |
26 |
27 |
28 | ); 29 | } 30 | -------------------------------------------------------------------------------- /sample/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | react-timerange-picker sample page 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /sample/index.tsx: -------------------------------------------------------------------------------- 1 | import { createRoot } from 'react-dom/client'; 2 | 3 | import Sample from './Sample.js'; 4 | 5 | const root = document.getElementById('root'); 6 | 7 | if (!root) { 8 | throw new Error('Could not find root element'); 9 | } 10 | 11 | createRoot(root).render(); 12 | -------------------------------------------------------------------------------- /sample/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-timerange-picker-sample-page", 3 | "version": "3.0.0", 4 | "description": "A sample page for React-TimeRange-Picker.", 5 | "private": true, 6 | "type": "module", 7 | "scripts": { 8 | "build": "vite build", 9 | "dev": "vite", 10 | "preview": "vite preview" 11 | }, 12 | "author": { 13 | "name": "Wojciech Maj", 14 | "email": "kontakt@wojtekmaj.pl" 15 | }, 16 | "license": "MIT", 17 | "dependencies": { 18 | "@wojtekmaj/react-timerange-picker": "latest", 19 | "react": "^18.2.0", 20 | "react-dom": "^18.2.0" 21 | }, 22 | "devDependencies": { 23 | "@vitejs/plugin-react": "^4.3.4", 24 | "typescript": "^5.0.0", 25 | "vite": "^6.2.4" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /sample/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "isolatedModules": true, 4 | "jsx": "react-jsx", 5 | "module": "preserve", 6 | "moduleDetection": "force", 7 | "noEmit": true, 8 | "noUncheckedIndexedAccess": true, 9 | "skipLibCheck": true, 10 | "strict": true, 11 | "target": "esnext", 12 | "verbatimModuleSyntax": true 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /sample/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite'; 2 | import react from '@vitejs/plugin-react'; 3 | 4 | export default defineConfig({ 5 | base: './', 6 | plugins: [react()], 7 | }); 8 | -------------------------------------------------------------------------------- /sample/yarn.lock: -------------------------------------------------------------------------------- 1 | # This file is generated by running "yarn install" inside your project. 2 | # Manual changes might be lost - proceed with caution! 3 | 4 | __metadata: 5 | version: 8 6 | cacheKey: 10c0 7 | 8 | "@ampproject/remapping@npm:^2.2.0": 9 | version: 2.3.0 10 | resolution: "@ampproject/remapping@npm:2.3.0" 11 | dependencies: 12 | "@jridgewell/gen-mapping": "npm:^0.3.5" 13 | "@jridgewell/trace-mapping": "npm:^0.3.24" 14 | checksum: 10c0/81d63cca5443e0f0c72ae18b544cc28c7c0ec2cea46e7cb888bb0e0f411a1191d0d6b7af798d54e30777d8d1488b2ec0732aac2be342d3d7d3ffd271c6f489ed 15 | languageName: node 16 | linkType: hard 17 | 18 | "@babel/code-frame@npm:^7.25.9, @babel/code-frame@npm:^7.26.0, @babel/code-frame@npm:^7.26.2": 19 | version: 7.26.2 20 | resolution: "@babel/code-frame@npm:7.26.2" 21 | dependencies: 22 | "@babel/helper-validator-identifier": "npm:^7.25.9" 23 | js-tokens: "npm:^4.0.0" 24 | picocolors: "npm:^1.0.0" 25 | checksum: 10c0/7d79621a6849183c415486af99b1a20b84737e8c11cd55b6544f688c51ce1fd710e6d869c3dd21232023da272a79b91efb3e83b5bc2dc65c1187c5fcd1b72ea8 26 | languageName: node 27 | linkType: hard 28 | 29 | "@babel/compat-data@npm:^7.25.9": 30 | version: 7.26.3 31 | resolution: "@babel/compat-data@npm:7.26.3" 32 | checksum: 10c0/d63e71845c34dfad8d7ff8c15b562e620dbf60e68e3abfa35681d24d612594e8e5ec9790d831a287ecd79ce00f48e7ffddc85c5ce94af7242d45917b9c1a5f90 33 | languageName: node 34 | linkType: hard 35 | 36 | "@babel/core@npm:^7.26.0": 37 | version: 7.26.0 38 | resolution: "@babel/core@npm:7.26.0" 39 | dependencies: 40 | "@ampproject/remapping": "npm:^2.2.0" 41 | "@babel/code-frame": "npm:^7.26.0" 42 | "@babel/generator": "npm:^7.26.0" 43 | "@babel/helper-compilation-targets": "npm:^7.25.9" 44 | "@babel/helper-module-transforms": "npm:^7.26.0" 45 | "@babel/helpers": "npm:^7.26.0" 46 | "@babel/parser": "npm:^7.26.0" 47 | "@babel/template": "npm:^7.25.9" 48 | "@babel/traverse": "npm:^7.25.9" 49 | "@babel/types": "npm:^7.26.0" 50 | convert-source-map: "npm:^2.0.0" 51 | debug: "npm:^4.1.0" 52 | gensync: "npm:^1.0.0-beta.2" 53 | json5: "npm:^2.2.3" 54 | semver: "npm:^6.3.1" 55 | checksum: 10c0/91de73a7ff5c4049fbc747930aa039300e4d2670c2a91f5aa622f1b4868600fc89b01b6278385fbcd46f9574186fa3d9b376a9e7538e50f8d118ec13cfbcb63e 56 | languageName: node 57 | linkType: hard 58 | 59 | "@babel/generator@npm:^7.26.0, @babel/generator@npm:^7.26.3": 60 | version: 7.26.3 61 | resolution: "@babel/generator@npm:7.26.3" 62 | dependencies: 63 | "@babel/parser": "npm:^7.26.3" 64 | "@babel/types": "npm:^7.26.3" 65 | "@jridgewell/gen-mapping": "npm:^0.3.5" 66 | "@jridgewell/trace-mapping": "npm:^0.3.25" 67 | jsesc: "npm:^3.0.2" 68 | checksum: 10c0/54f260558e3e4ec8942da3cde607c35349bb983c3a7c5121243f96893fba3e8cd62e1f1773b2051f936f8c8a10987b758d5c7d76dbf2784e95bb63ab4843fa00 69 | languageName: node 70 | linkType: hard 71 | 72 | "@babel/helper-compilation-targets@npm:^7.25.9": 73 | version: 7.25.9 74 | resolution: "@babel/helper-compilation-targets@npm:7.25.9" 75 | dependencies: 76 | "@babel/compat-data": "npm:^7.25.9" 77 | "@babel/helper-validator-option": "npm:^7.25.9" 78 | browserslist: "npm:^4.24.0" 79 | lru-cache: "npm:^5.1.1" 80 | semver: "npm:^6.3.1" 81 | checksum: 10c0/a6b26a1e4222e69ef8e62ee19374308f060b007828bc11c65025ecc9e814aba21ff2175d6d3f8bf53c863edd728ee8f94ba7870f8f90a37d39552ad9933a8aaa 82 | languageName: node 83 | linkType: hard 84 | 85 | "@babel/helper-module-imports@npm:^7.25.9": 86 | version: 7.25.9 87 | resolution: "@babel/helper-module-imports@npm:7.25.9" 88 | dependencies: 89 | "@babel/traverse": "npm:^7.25.9" 90 | "@babel/types": "npm:^7.25.9" 91 | checksum: 10c0/078d3c2b45d1f97ffe6bb47f61961be4785d2342a4156d8b42c92ee4e1b7b9e365655dd6cb25329e8fe1a675c91eeac7e3d04f0c518b67e417e29d6e27b6aa70 92 | languageName: node 93 | linkType: hard 94 | 95 | "@babel/helper-module-transforms@npm:^7.26.0": 96 | version: 7.26.0 97 | resolution: "@babel/helper-module-transforms@npm:7.26.0" 98 | dependencies: 99 | "@babel/helper-module-imports": "npm:^7.25.9" 100 | "@babel/helper-validator-identifier": "npm:^7.25.9" 101 | "@babel/traverse": "npm:^7.25.9" 102 | peerDependencies: 103 | "@babel/core": ^7.0.0 104 | checksum: 10c0/ee111b68a5933481d76633dad9cdab30c41df4479f0e5e1cc4756dc9447c1afd2c9473b5ba006362e35b17f4ebddd5fca090233bef8dfc84dca9d9127e56ec3a 105 | languageName: node 106 | linkType: hard 107 | 108 | "@babel/helper-plugin-utils@npm:^7.25.9": 109 | version: 7.25.9 110 | resolution: "@babel/helper-plugin-utils@npm:7.25.9" 111 | checksum: 10c0/483066a1ba36ff16c0116cd24f93de05de746a603a777cd695ac7a1b034928a65a4ecb35f255761ca56626435d7abdb73219eba196f9aa83b6c3c3169325599d 112 | languageName: node 113 | linkType: hard 114 | 115 | "@babel/helper-string-parser@npm:^7.25.9": 116 | version: 7.25.9 117 | resolution: "@babel/helper-string-parser@npm:7.25.9" 118 | checksum: 10c0/7244b45d8e65f6b4338a6a68a8556f2cb161b782343e97281a5f2b9b93e420cad0d9f5773a59d79f61d0c448913d06f6a2358a87f2e203cf112e3c5b53522ee6 119 | languageName: node 120 | linkType: hard 121 | 122 | "@babel/helper-validator-identifier@npm:^7.25.9": 123 | version: 7.25.9 124 | resolution: "@babel/helper-validator-identifier@npm:7.25.9" 125 | checksum: 10c0/4fc6f830177b7b7e887ad3277ddb3b91d81e6c4a24151540d9d1023e8dc6b1c0505f0f0628ae653601eb4388a8db45c1c14b2c07a9173837aef7e4116456259d 126 | languageName: node 127 | linkType: hard 128 | 129 | "@babel/helper-validator-option@npm:^7.25.9": 130 | version: 7.25.9 131 | resolution: "@babel/helper-validator-option@npm:7.25.9" 132 | checksum: 10c0/27fb195d14c7dcb07f14e58fe77c44eea19a6a40a74472ec05c441478fa0bb49fa1c32b2d64be7a38870ee48ef6601bdebe98d512f0253aea0b39756c4014f3e 133 | languageName: node 134 | linkType: hard 135 | 136 | "@babel/helpers@npm:^7.26.0": 137 | version: 7.26.0 138 | resolution: "@babel/helpers@npm:7.26.0" 139 | dependencies: 140 | "@babel/template": "npm:^7.25.9" 141 | "@babel/types": "npm:^7.26.0" 142 | checksum: 10c0/343333cced6946fe46617690a1d0789346960910225ce359021a88a60a65bc0d791f0c5d240c0ed46cf8cc63b5fd7df52734ff14e43b9c32feae2b61b1647097 143 | languageName: node 144 | linkType: hard 145 | 146 | "@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.25.9, @babel/parser@npm:^7.26.0, @babel/parser@npm:^7.26.3": 147 | version: 7.26.3 148 | resolution: "@babel/parser@npm:7.26.3" 149 | dependencies: 150 | "@babel/types": "npm:^7.26.3" 151 | bin: 152 | parser: ./bin/babel-parser.js 153 | checksum: 10c0/48f736374e61cfd10ddbf7b80678514ae1f16d0e88bc793d2b505d73d9b987ea786fc8c2f7ee8f8b8c467df062030eb07fd0eb2168f0f541ca1f542775852cad 154 | languageName: node 155 | linkType: hard 156 | 157 | "@babel/plugin-transform-react-jsx-self@npm:^7.25.9": 158 | version: 7.25.9 159 | resolution: "@babel/plugin-transform-react-jsx-self@npm:7.25.9" 160 | dependencies: 161 | "@babel/helper-plugin-utils": "npm:^7.25.9" 162 | peerDependencies: 163 | "@babel/core": ^7.0.0-0 164 | checksum: 10c0/ce0e289f6af93d7c4dc6b385512199c5bb138ae61507b4d5117ba88b6a6b5092f704f1bdf80080b7d69b1b8c36649f2a0b250e8198667d4d30c08bbb1546bd99 165 | languageName: node 166 | linkType: hard 167 | 168 | "@babel/plugin-transform-react-jsx-source@npm:^7.25.9": 169 | version: 7.25.9 170 | resolution: "@babel/plugin-transform-react-jsx-source@npm:7.25.9" 171 | dependencies: 172 | "@babel/helper-plugin-utils": "npm:^7.25.9" 173 | peerDependencies: 174 | "@babel/core": ^7.0.0-0 175 | checksum: 10c0/fc9ee08efc9be7cbd2cc6788bbf92579adf3cab37912481f1b915221be3d22b0613b5b36a721df5f4c0ab65efe8582fcf8673caab83e6e1ce4cc04ceebf57dfa 176 | languageName: node 177 | linkType: hard 178 | 179 | "@babel/template@npm:^7.25.9": 180 | version: 7.25.9 181 | resolution: "@babel/template@npm:7.25.9" 182 | dependencies: 183 | "@babel/code-frame": "npm:^7.25.9" 184 | "@babel/parser": "npm:^7.25.9" 185 | "@babel/types": "npm:^7.25.9" 186 | checksum: 10c0/ebe677273f96a36c92cc15b7aa7b11cc8bc8a3bb7a01d55b2125baca8f19cae94ff3ce15f1b1880fb8437f3a690d9f89d4e91f16fc1dc4d3eb66226d128983ab 187 | languageName: node 188 | linkType: hard 189 | 190 | "@babel/traverse@npm:^7.25.9": 191 | version: 7.26.4 192 | resolution: "@babel/traverse@npm:7.26.4" 193 | dependencies: 194 | "@babel/code-frame": "npm:^7.26.2" 195 | "@babel/generator": "npm:^7.26.3" 196 | "@babel/parser": "npm:^7.26.3" 197 | "@babel/template": "npm:^7.25.9" 198 | "@babel/types": "npm:^7.26.3" 199 | debug: "npm:^4.3.1" 200 | globals: "npm:^11.1.0" 201 | checksum: 10c0/cf25d0eda9505daa0f0832ad786b9e28c9d967e823aaf7fbe425250ab198c656085495aa6bed678b27929e095c84eea9fd778b851a31803da94c9bc4bf4eaef7 202 | languageName: node 203 | linkType: hard 204 | 205 | "@babel/types@npm:^7.0.0, @babel/types@npm:^7.20.7, @babel/types@npm:^7.25.9, @babel/types@npm:^7.26.0, @babel/types@npm:^7.26.3, @babel/types@npm:^7.3.0": 206 | version: 7.26.3 207 | resolution: "@babel/types@npm:7.26.3" 208 | dependencies: 209 | "@babel/helper-string-parser": "npm:^7.25.9" 210 | "@babel/helper-validator-identifier": "npm:^7.25.9" 211 | checksum: 10c0/966c5242c5e55c8704bf7a7418e7be2703a0afa4d19a8480999d5a4ef13d095dd60686615fe5983cb7593b4b06ba3a7de8d6ca501c1d78bdd233a10d90be787b 212 | languageName: node 213 | linkType: hard 214 | 215 | "@esbuild/aix-ppc64@npm:0.25.0": 216 | version: 0.25.0 217 | resolution: "@esbuild/aix-ppc64@npm:0.25.0" 218 | conditions: os=aix & cpu=ppc64 219 | languageName: node 220 | linkType: hard 221 | 222 | "@esbuild/android-arm64@npm:0.25.0": 223 | version: 0.25.0 224 | resolution: "@esbuild/android-arm64@npm:0.25.0" 225 | conditions: os=android & cpu=arm64 226 | languageName: node 227 | linkType: hard 228 | 229 | "@esbuild/android-arm@npm:0.25.0": 230 | version: 0.25.0 231 | resolution: "@esbuild/android-arm@npm:0.25.0" 232 | conditions: os=android & cpu=arm 233 | languageName: node 234 | linkType: hard 235 | 236 | "@esbuild/android-x64@npm:0.25.0": 237 | version: 0.25.0 238 | resolution: "@esbuild/android-x64@npm:0.25.0" 239 | conditions: os=android & cpu=x64 240 | languageName: node 241 | linkType: hard 242 | 243 | "@esbuild/darwin-arm64@npm:0.25.0": 244 | version: 0.25.0 245 | resolution: "@esbuild/darwin-arm64@npm:0.25.0" 246 | conditions: os=darwin & cpu=arm64 247 | languageName: node 248 | linkType: hard 249 | 250 | "@esbuild/darwin-x64@npm:0.25.0": 251 | version: 0.25.0 252 | resolution: "@esbuild/darwin-x64@npm:0.25.0" 253 | conditions: os=darwin & cpu=x64 254 | languageName: node 255 | linkType: hard 256 | 257 | "@esbuild/freebsd-arm64@npm:0.25.0": 258 | version: 0.25.0 259 | resolution: "@esbuild/freebsd-arm64@npm:0.25.0" 260 | conditions: os=freebsd & cpu=arm64 261 | languageName: node 262 | linkType: hard 263 | 264 | "@esbuild/freebsd-x64@npm:0.25.0": 265 | version: 0.25.0 266 | resolution: "@esbuild/freebsd-x64@npm:0.25.0" 267 | conditions: os=freebsd & cpu=x64 268 | languageName: node 269 | linkType: hard 270 | 271 | "@esbuild/linux-arm64@npm:0.25.0": 272 | version: 0.25.0 273 | resolution: "@esbuild/linux-arm64@npm:0.25.0" 274 | conditions: os=linux & cpu=arm64 275 | languageName: node 276 | linkType: hard 277 | 278 | "@esbuild/linux-arm@npm:0.25.0": 279 | version: 0.25.0 280 | resolution: "@esbuild/linux-arm@npm:0.25.0" 281 | conditions: os=linux & cpu=arm 282 | languageName: node 283 | linkType: hard 284 | 285 | "@esbuild/linux-ia32@npm:0.25.0": 286 | version: 0.25.0 287 | resolution: "@esbuild/linux-ia32@npm:0.25.0" 288 | conditions: os=linux & cpu=ia32 289 | languageName: node 290 | linkType: hard 291 | 292 | "@esbuild/linux-loong64@npm:0.25.0": 293 | version: 0.25.0 294 | resolution: "@esbuild/linux-loong64@npm:0.25.0" 295 | conditions: os=linux & cpu=loong64 296 | languageName: node 297 | linkType: hard 298 | 299 | "@esbuild/linux-mips64el@npm:0.25.0": 300 | version: 0.25.0 301 | resolution: "@esbuild/linux-mips64el@npm:0.25.0" 302 | conditions: os=linux & cpu=mips64el 303 | languageName: node 304 | linkType: hard 305 | 306 | "@esbuild/linux-ppc64@npm:0.25.0": 307 | version: 0.25.0 308 | resolution: "@esbuild/linux-ppc64@npm:0.25.0" 309 | conditions: os=linux & cpu=ppc64 310 | languageName: node 311 | linkType: hard 312 | 313 | "@esbuild/linux-riscv64@npm:0.25.0": 314 | version: 0.25.0 315 | resolution: "@esbuild/linux-riscv64@npm:0.25.0" 316 | conditions: os=linux & cpu=riscv64 317 | languageName: node 318 | linkType: hard 319 | 320 | "@esbuild/linux-s390x@npm:0.25.0": 321 | version: 0.25.0 322 | resolution: "@esbuild/linux-s390x@npm:0.25.0" 323 | conditions: os=linux & cpu=s390x 324 | languageName: node 325 | linkType: hard 326 | 327 | "@esbuild/linux-x64@npm:0.25.0": 328 | version: 0.25.0 329 | resolution: "@esbuild/linux-x64@npm:0.25.0" 330 | conditions: os=linux & cpu=x64 331 | languageName: node 332 | linkType: hard 333 | 334 | "@esbuild/netbsd-arm64@npm:0.25.0": 335 | version: 0.25.0 336 | resolution: "@esbuild/netbsd-arm64@npm:0.25.0" 337 | conditions: os=netbsd & cpu=arm64 338 | languageName: node 339 | linkType: hard 340 | 341 | "@esbuild/netbsd-x64@npm:0.25.0": 342 | version: 0.25.0 343 | resolution: "@esbuild/netbsd-x64@npm:0.25.0" 344 | conditions: os=netbsd & cpu=x64 345 | languageName: node 346 | linkType: hard 347 | 348 | "@esbuild/openbsd-arm64@npm:0.25.0": 349 | version: 0.25.0 350 | resolution: "@esbuild/openbsd-arm64@npm:0.25.0" 351 | conditions: os=openbsd & cpu=arm64 352 | languageName: node 353 | linkType: hard 354 | 355 | "@esbuild/openbsd-x64@npm:0.25.0": 356 | version: 0.25.0 357 | resolution: "@esbuild/openbsd-x64@npm:0.25.0" 358 | conditions: os=openbsd & cpu=x64 359 | languageName: node 360 | linkType: hard 361 | 362 | "@esbuild/sunos-x64@npm:0.25.0": 363 | version: 0.25.0 364 | resolution: "@esbuild/sunos-x64@npm:0.25.0" 365 | conditions: os=sunos & cpu=x64 366 | languageName: node 367 | linkType: hard 368 | 369 | "@esbuild/win32-arm64@npm:0.25.0": 370 | version: 0.25.0 371 | resolution: "@esbuild/win32-arm64@npm:0.25.0" 372 | conditions: os=win32 & cpu=arm64 373 | languageName: node 374 | linkType: hard 375 | 376 | "@esbuild/win32-ia32@npm:0.25.0": 377 | version: 0.25.0 378 | resolution: "@esbuild/win32-ia32@npm:0.25.0" 379 | conditions: os=win32 & cpu=ia32 380 | languageName: node 381 | linkType: hard 382 | 383 | "@esbuild/win32-x64@npm:0.25.0": 384 | version: 0.25.0 385 | resolution: "@esbuild/win32-x64@npm:0.25.0" 386 | conditions: os=win32 & cpu=x64 387 | languageName: node 388 | linkType: hard 389 | 390 | "@isaacs/cliui@npm:^8.0.2": 391 | version: 8.0.2 392 | resolution: "@isaacs/cliui@npm:8.0.2" 393 | dependencies: 394 | string-width: "npm:^5.1.2" 395 | string-width-cjs: "npm:string-width@^4.2.0" 396 | strip-ansi: "npm:^7.0.1" 397 | strip-ansi-cjs: "npm:strip-ansi@^6.0.1" 398 | wrap-ansi: "npm:^8.1.0" 399 | wrap-ansi-cjs: "npm:wrap-ansi@^7.0.0" 400 | checksum: 10c0/b1bf42535d49f11dc137f18d5e4e63a28c5569de438a221c369483731e9dac9fb797af554e8bf02b6192d1e5eba6e6402cf93900c3d0ac86391d00d04876789e 401 | languageName: node 402 | linkType: hard 403 | 404 | "@isaacs/fs-minipass@npm:^4.0.0": 405 | version: 4.0.1 406 | resolution: "@isaacs/fs-minipass@npm:4.0.1" 407 | dependencies: 408 | minipass: "npm:^7.0.4" 409 | checksum: 10c0/c25b6dc1598790d5b55c0947a9b7d111cfa92594db5296c3b907e2f533c033666f692a3939eadac17b1c7c40d362d0b0635dc874cbfe3e70db7c2b07cc97a5d2 410 | languageName: node 411 | linkType: hard 412 | 413 | "@jridgewell/gen-mapping@npm:^0.3.5": 414 | version: 0.3.8 415 | resolution: "@jridgewell/gen-mapping@npm:0.3.8" 416 | dependencies: 417 | "@jridgewell/set-array": "npm:^1.2.1" 418 | "@jridgewell/sourcemap-codec": "npm:^1.4.10" 419 | "@jridgewell/trace-mapping": "npm:^0.3.24" 420 | checksum: 10c0/c668feaf86c501d7c804904a61c23c67447b2137b813b9ce03eca82cb9d65ac7006d766c218685d76e3d72828279b6ee26c347aa1119dab23fbaf36aed51585a 421 | languageName: node 422 | linkType: hard 423 | 424 | "@jridgewell/resolve-uri@npm:^3.1.0": 425 | version: 3.1.2 426 | resolution: "@jridgewell/resolve-uri@npm:3.1.2" 427 | checksum: 10c0/d502e6fb516b35032331406d4e962c21fe77cdf1cbdb49c6142bcbd9e30507094b18972778a6e27cbad756209cfe34b1a27729e6fa08a2eb92b33943f680cf1e 428 | languageName: node 429 | linkType: hard 430 | 431 | "@jridgewell/set-array@npm:^1.2.1": 432 | version: 1.2.1 433 | resolution: "@jridgewell/set-array@npm:1.2.1" 434 | checksum: 10c0/2a5aa7b4b5c3464c895c802d8ae3f3d2b92fcbe84ad12f8d0bfbb1f5ad006717e7577ee1fd2eac00c088abe486c7adb27976f45d2941ff6b0b92b2c3302c60f4 435 | languageName: node 436 | linkType: hard 437 | 438 | "@jridgewell/sourcemap-codec@npm:^1.4.10, @jridgewell/sourcemap-codec@npm:^1.4.14": 439 | version: 1.5.0 440 | resolution: "@jridgewell/sourcemap-codec@npm:1.5.0" 441 | checksum: 10c0/2eb864f276eb1096c3c11da3e9bb518f6d9fc0023c78344cdc037abadc725172c70314bdb360f2d4b7bffec7f5d657ce006816bc5d4ecb35e61b66132db00c18 442 | languageName: node 443 | linkType: hard 444 | 445 | "@jridgewell/trace-mapping@npm:^0.3.24, @jridgewell/trace-mapping@npm:^0.3.25": 446 | version: 0.3.25 447 | resolution: "@jridgewell/trace-mapping@npm:0.3.25" 448 | dependencies: 449 | "@jridgewell/resolve-uri": "npm:^3.1.0" 450 | "@jridgewell/sourcemap-codec": "npm:^1.4.14" 451 | checksum: 10c0/3d1ce6ebc69df9682a5a8896b414c6537e428a1d68b02fcc8363b04284a8ca0df04d0ee3013132252ab14f2527bc13bea6526a912ecb5658f0e39fd2860b4df4 452 | languageName: node 453 | linkType: hard 454 | 455 | "@npmcli/agent@npm:^3.0.0": 456 | version: 3.0.0 457 | resolution: "@npmcli/agent@npm:3.0.0" 458 | dependencies: 459 | agent-base: "npm:^7.1.0" 460 | http-proxy-agent: "npm:^7.0.0" 461 | https-proxy-agent: "npm:^7.0.1" 462 | lru-cache: "npm:^10.0.1" 463 | socks-proxy-agent: "npm:^8.0.3" 464 | checksum: 10c0/efe37b982f30740ee77696a80c196912c274ecd2cb243bc6ae7053a50c733ce0f6c09fda085145f33ecf453be19654acca74b69e81eaad4c90f00ccffe2f9271 465 | languageName: node 466 | linkType: hard 467 | 468 | "@npmcli/fs@npm:^4.0.0": 469 | version: 4.0.0 470 | resolution: "@npmcli/fs@npm:4.0.0" 471 | dependencies: 472 | semver: "npm:^7.3.5" 473 | checksum: 10c0/c90935d5ce670c87b6b14fab04a965a3b8137e585f8b2a6257263bd7f97756dd736cb165bb470e5156a9e718ecd99413dccc54b1138c1a46d6ec7cf325982fe5 474 | languageName: node 475 | linkType: hard 476 | 477 | "@pkgjs/parseargs@npm:^0.11.0": 478 | version: 0.11.0 479 | resolution: "@pkgjs/parseargs@npm:0.11.0" 480 | checksum: 10c0/5bd7576bb1b38a47a7fc7b51ac9f38748e772beebc56200450c4a817d712232b8f1d3ef70532c80840243c657d491cf6a6be1e3a214cff907645819fdc34aadd 481 | languageName: node 482 | linkType: hard 483 | 484 | "@rollup/rollup-android-arm-eabi@npm:4.34.9": 485 | version: 4.34.9 486 | resolution: "@rollup/rollup-android-arm-eabi@npm:4.34.9" 487 | conditions: os=android & cpu=arm 488 | languageName: node 489 | linkType: hard 490 | 491 | "@rollup/rollup-android-arm64@npm:4.34.9": 492 | version: 4.34.9 493 | resolution: "@rollup/rollup-android-arm64@npm:4.34.9" 494 | conditions: os=android & cpu=arm64 495 | languageName: node 496 | linkType: hard 497 | 498 | "@rollup/rollup-darwin-arm64@npm:4.34.9": 499 | version: 4.34.9 500 | resolution: "@rollup/rollup-darwin-arm64@npm:4.34.9" 501 | conditions: os=darwin & cpu=arm64 502 | languageName: node 503 | linkType: hard 504 | 505 | "@rollup/rollup-darwin-x64@npm:4.34.9": 506 | version: 4.34.9 507 | resolution: "@rollup/rollup-darwin-x64@npm:4.34.9" 508 | conditions: os=darwin & cpu=x64 509 | languageName: node 510 | linkType: hard 511 | 512 | "@rollup/rollup-freebsd-arm64@npm:4.34.9": 513 | version: 4.34.9 514 | resolution: "@rollup/rollup-freebsd-arm64@npm:4.34.9" 515 | conditions: os=freebsd & cpu=arm64 516 | languageName: node 517 | linkType: hard 518 | 519 | "@rollup/rollup-freebsd-x64@npm:4.34.9": 520 | version: 4.34.9 521 | resolution: "@rollup/rollup-freebsd-x64@npm:4.34.9" 522 | conditions: os=freebsd & cpu=x64 523 | languageName: node 524 | linkType: hard 525 | 526 | "@rollup/rollup-linux-arm-gnueabihf@npm:4.34.9": 527 | version: 4.34.9 528 | resolution: "@rollup/rollup-linux-arm-gnueabihf@npm:4.34.9" 529 | conditions: os=linux & cpu=arm & libc=glibc 530 | languageName: node 531 | linkType: hard 532 | 533 | "@rollup/rollup-linux-arm-musleabihf@npm:4.34.9": 534 | version: 4.34.9 535 | resolution: "@rollup/rollup-linux-arm-musleabihf@npm:4.34.9" 536 | conditions: os=linux & cpu=arm & libc=musl 537 | languageName: node 538 | linkType: hard 539 | 540 | "@rollup/rollup-linux-arm64-gnu@npm:4.34.9": 541 | version: 4.34.9 542 | resolution: "@rollup/rollup-linux-arm64-gnu@npm:4.34.9" 543 | conditions: os=linux & cpu=arm64 & libc=glibc 544 | languageName: node 545 | linkType: hard 546 | 547 | "@rollup/rollup-linux-arm64-musl@npm:4.34.9": 548 | version: 4.34.9 549 | resolution: "@rollup/rollup-linux-arm64-musl@npm:4.34.9" 550 | conditions: os=linux & cpu=arm64 & libc=musl 551 | languageName: node 552 | linkType: hard 553 | 554 | "@rollup/rollup-linux-loongarch64-gnu@npm:4.34.9": 555 | version: 4.34.9 556 | resolution: "@rollup/rollup-linux-loongarch64-gnu@npm:4.34.9" 557 | conditions: os=linux & cpu=loong64 & libc=glibc 558 | languageName: node 559 | linkType: hard 560 | 561 | "@rollup/rollup-linux-powerpc64le-gnu@npm:4.34.9": 562 | version: 4.34.9 563 | resolution: "@rollup/rollup-linux-powerpc64le-gnu@npm:4.34.9" 564 | conditions: os=linux & cpu=ppc64 & libc=glibc 565 | languageName: node 566 | linkType: hard 567 | 568 | "@rollup/rollup-linux-riscv64-gnu@npm:4.34.9": 569 | version: 4.34.9 570 | resolution: "@rollup/rollup-linux-riscv64-gnu@npm:4.34.9" 571 | conditions: os=linux & cpu=riscv64 & libc=glibc 572 | languageName: node 573 | linkType: hard 574 | 575 | "@rollup/rollup-linux-s390x-gnu@npm:4.34.9": 576 | version: 4.34.9 577 | resolution: "@rollup/rollup-linux-s390x-gnu@npm:4.34.9" 578 | conditions: os=linux & cpu=s390x & libc=glibc 579 | languageName: node 580 | linkType: hard 581 | 582 | "@rollup/rollup-linux-x64-gnu@npm:4.34.9": 583 | version: 4.34.9 584 | resolution: "@rollup/rollup-linux-x64-gnu@npm:4.34.9" 585 | conditions: os=linux & cpu=x64 & libc=glibc 586 | languageName: node 587 | linkType: hard 588 | 589 | "@rollup/rollup-linux-x64-musl@npm:4.34.9": 590 | version: 4.34.9 591 | resolution: "@rollup/rollup-linux-x64-musl@npm:4.34.9" 592 | conditions: os=linux & cpu=x64 & libc=musl 593 | languageName: node 594 | linkType: hard 595 | 596 | "@rollup/rollup-win32-arm64-msvc@npm:4.34.9": 597 | version: 4.34.9 598 | resolution: "@rollup/rollup-win32-arm64-msvc@npm:4.34.9" 599 | conditions: os=win32 & cpu=arm64 600 | languageName: node 601 | linkType: hard 602 | 603 | "@rollup/rollup-win32-ia32-msvc@npm:4.34.9": 604 | version: 4.34.9 605 | resolution: "@rollup/rollup-win32-ia32-msvc@npm:4.34.9" 606 | conditions: os=win32 & cpu=ia32 607 | languageName: node 608 | linkType: hard 609 | 610 | "@rollup/rollup-win32-x64-msvc@npm:4.34.9": 611 | version: 4.34.9 612 | resolution: "@rollup/rollup-win32-x64-msvc@npm:4.34.9" 613 | conditions: os=win32 & cpu=x64 614 | languageName: node 615 | linkType: hard 616 | 617 | "@types/babel__core@npm:^7.20.5": 618 | version: 7.20.5 619 | resolution: "@types/babel__core@npm:7.20.5" 620 | dependencies: 621 | "@babel/parser": "npm:^7.20.7" 622 | "@babel/types": "npm:^7.20.7" 623 | "@types/babel__generator": "npm:*" 624 | "@types/babel__template": "npm:*" 625 | "@types/babel__traverse": "npm:*" 626 | checksum: 10c0/bdee3bb69951e833a4b811b8ee9356b69a61ed5b7a23e1a081ec9249769117fa83aaaf023bb06562a038eb5845155ff663e2d5c75dd95c1d5ccc91db012868ff 627 | languageName: node 628 | linkType: hard 629 | 630 | "@types/babel__generator@npm:*": 631 | version: 7.6.4 632 | resolution: "@types/babel__generator@npm:7.6.4" 633 | dependencies: 634 | "@babel/types": "npm:^7.0.0" 635 | checksum: 10c0/e0051b450e4ba2df0a7e386f08df902a4e920f6f8d6f185d69ddbe9b0e2e2d3ae434bb51e437bc0fca2a9a0f5dc4ca44d3a1941ef75e74371e8be5bf64416fe4 636 | languageName: node 637 | linkType: hard 638 | 639 | "@types/babel__template@npm:*": 640 | version: 7.4.1 641 | resolution: "@types/babel__template@npm:7.4.1" 642 | dependencies: 643 | "@babel/parser": "npm:^7.1.0" 644 | "@babel/types": "npm:^7.0.0" 645 | checksum: 10c0/6f180e96c39765487f27e861d43eebed341ec7a2fc06cdf5a52c22872fae67f474ca165d149c708f4fd9d5482beb66c0a92f77411b234bb30262ed2303e50b1a 646 | languageName: node 647 | linkType: hard 648 | 649 | "@types/babel__traverse@npm:*": 650 | version: 7.18.3 651 | resolution: "@types/babel__traverse@npm:7.18.3" 652 | dependencies: 653 | "@babel/types": "npm:^7.3.0" 654 | checksum: 10c0/4214fd3e95925d9a7efa01142969a310263430d4f5de89be6c9c193110666677415161b474fa627d751dfd0f1eb7dc1c84c48f8b53098625c6bc78917683215a 655 | languageName: node 656 | linkType: hard 657 | 658 | "@types/estree@npm:1.0.6": 659 | version: 1.0.6 660 | resolution: "@types/estree@npm:1.0.6" 661 | checksum: 10c0/cdfd751f6f9065442cd40957c07fd80361c962869aa853c1c2fd03e101af8b9389d8ff4955a43a6fcfa223dd387a089937f95be0f3eec21ca527039fd2d9859a 662 | languageName: node 663 | linkType: hard 664 | 665 | "@types/lodash.memoize@npm:^4.1.7": 666 | version: 4.1.7 667 | resolution: "@types/lodash.memoize@npm:4.1.7" 668 | dependencies: 669 | "@types/lodash": "npm:*" 670 | checksum: 10c0/979a59dbbae968a03834fdb544dc5ddd34620a2912d5030c997a1aa919326425a900c93bc69554b2a873cf54f09b4dd2752b3a1c29ab4bffac5983113c58b1b5 671 | languageName: node 672 | linkType: hard 673 | 674 | "@types/lodash@npm:*": 675 | version: 4.14.192 676 | resolution: "@types/lodash@npm:4.14.192" 677 | checksum: 10c0/6807402e293cb943808a444d1ef514ce13de4f870b3b382fe729f8235ea280c4d037b9514443723afd3d04b2cf9e8f1b3fc0075d947edfeb1078347dc2b471b0 678 | languageName: node 679 | linkType: hard 680 | 681 | "@vitejs/plugin-react@npm:^4.3.4": 682 | version: 4.3.4 683 | resolution: "@vitejs/plugin-react@npm:4.3.4" 684 | dependencies: 685 | "@babel/core": "npm:^7.26.0" 686 | "@babel/plugin-transform-react-jsx-self": "npm:^7.25.9" 687 | "@babel/plugin-transform-react-jsx-source": "npm:^7.25.9" 688 | "@types/babel__core": "npm:^7.20.5" 689 | react-refresh: "npm:^0.14.2" 690 | peerDependencies: 691 | vite: ^4.2.0 || ^5.0.0 || ^6.0.0 692 | checksum: 10c0/38a47a1dbafae0b97142943d83ee3674cb3331153a60b1a3fd29d230c12c9dfe63b7c345b231a3450168ed8a9375a9a1a253c3d85e9efdc19478c0d56b98496c 693 | languageName: node 694 | linkType: hard 695 | 696 | "@wojtekmaj/date-utils@npm:^1.1.3, @wojtekmaj/date-utils@npm:^1.5.0": 697 | version: 1.5.1 698 | resolution: "@wojtekmaj/date-utils@npm:1.5.1" 699 | checksum: 10c0/7c213cca5ab6b84ef61b9aea2b9fb8a04bf4c9764b28a97ffc4ee46a3e81560532a74d106a6f8aeef4792e1aaa6ea3dfd3c4a639dddbea560eb3f33cd62b8d7d 700 | languageName: node 701 | linkType: hard 702 | 703 | "@wojtekmaj/react-timerange-picker@npm:latest": 704 | version: 6.0.0 705 | resolution: "@wojtekmaj/react-timerange-picker@npm:6.0.0" 706 | dependencies: 707 | clsx: "npm:^2.0.0" 708 | make-event-props: "npm:^1.6.0" 709 | react-clock: "npm:^5.0.0" 710 | react-fit: "npm:^2.0.0" 711 | react-time-picker: "npm:^7.0.0" 712 | peerDependencies: 713 | "@types/react": ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 714 | react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 715 | react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 716 | peerDependenciesMeta: 717 | "@types/react": 718 | optional: true 719 | checksum: 10c0/a0fa3ca5791dc3aad68cfa3c994833ebc504d01c9d27811e75cc16afa0e22a31c4eb87d5a9273789e5fa8784a3f067cd225ae011f6a0d1f839278282648054f2 720 | languageName: node 721 | linkType: hard 722 | 723 | "abbrev@npm:^3.0.0": 724 | version: 3.0.0 725 | resolution: "abbrev@npm:3.0.0" 726 | checksum: 10c0/049704186396f571650eb7b22ed3627b77a5aedf98bb83caf2eac81ca2a3e25e795394b0464cfb2d6076df3db6a5312139eac5b6a126ca296ac53c5008069c28 727 | languageName: node 728 | linkType: hard 729 | 730 | "agent-base@npm:^7.0.2, agent-base@npm:^7.1.0, agent-base@npm:^7.1.2": 731 | version: 7.1.3 732 | resolution: "agent-base@npm:7.1.3" 733 | checksum: 10c0/6192b580c5b1d8fb399b9c62bf8343d76654c2dd62afcb9a52b2cf44a8b6ace1e3b704d3fe3547d91555c857d3df02603341ff2cb961b9cfe2b12f9f3c38ee11 734 | languageName: node 735 | linkType: hard 736 | 737 | "ansi-regex@npm:^5.0.1": 738 | version: 5.0.1 739 | resolution: "ansi-regex@npm:5.0.1" 740 | checksum: 10c0/9a64bb8627b434ba9327b60c027742e5d17ac69277960d041898596271d992d4d52ba7267a63ca10232e29f6107fc8a835f6ce8d719b88c5f8493f8254813737 741 | languageName: node 742 | linkType: hard 743 | 744 | "ansi-regex@npm:^6.0.1": 745 | version: 6.0.1 746 | resolution: "ansi-regex@npm:6.0.1" 747 | checksum: 10c0/cbe16dbd2c6b2735d1df7976a7070dd277326434f0212f43abf6d87674095d247968209babdaad31bb00882fa68807256ba9be340eec2f1004de14ca75f52a08 748 | languageName: node 749 | linkType: hard 750 | 751 | "ansi-styles@npm:^4.0.0": 752 | version: 4.3.0 753 | resolution: "ansi-styles@npm:4.3.0" 754 | dependencies: 755 | color-convert: "npm:^2.0.1" 756 | checksum: 10c0/895a23929da416f2bd3de7e9cb4eabd340949328ab85ddd6e484a637d8f6820d485f53933446f5291c3b760cbc488beb8e88573dd0f9c7daf83dccc8fe81b041 757 | languageName: node 758 | linkType: hard 759 | 760 | "ansi-styles@npm:^6.1.0": 761 | version: 6.2.1 762 | resolution: "ansi-styles@npm:6.2.1" 763 | checksum: 10c0/5d1ec38c123984bcedd996eac680d548f31828bd679a66db2bdf11844634dde55fec3efa9c6bb1d89056a5e79c1ac540c4c784d592ea1d25028a92227d2f2d5c 764 | languageName: node 765 | linkType: hard 766 | 767 | "balanced-match@npm:^1.0.0": 768 | version: 1.0.2 769 | resolution: "balanced-match@npm:1.0.2" 770 | checksum: 10c0/9308baf0a7e4838a82bbfd11e01b1cb0f0cf2893bc1676c27c2a8c0e70cbae1c59120c3268517a8ae7fb6376b4639ef81ca22582611dbee4ed28df945134aaee 771 | languageName: node 772 | linkType: hard 773 | 774 | "brace-expansion@npm:^2.0.1": 775 | version: 2.0.1 776 | resolution: "brace-expansion@npm:2.0.1" 777 | dependencies: 778 | balanced-match: "npm:^1.0.0" 779 | checksum: 10c0/b358f2fe060e2d7a87aa015979ecea07f3c37d4018f8d6deb5bd4c229ad3a0384fe6029bb76cd8be63c81e516ee52d1a0673edbe2023d53a5191732ae3c3e49f 780 | languageName: node 781 | linkType: hard 782 | 783 | "browserslist@npm:^4.24.0": 784 | version: 4.24.3 785 | resolution: "browserslist@npm:4.24.3" 786 | dependencies: 787 | caniuse-lite: "npm:^1.0.30001688" 788 | electron-to-chromium: "npm:^1.5.73" 789 | node-releases: "npm:^2.0.19" 790 | update-browserslist-db: "npm:^1.1.1" 791 | bin: 792 | browserslist: cli.js 793 | checksum: 10c0/bab261ef7b6e1656a719a9fa31240ae7ce4d5ba68e479f6b11e348d819346ab4c0ff6f4821f43adcc9c193a734b186775a83b37979e70a69d182965909fe569a 794 | languageName: node 795 | linkType: hard 796 | 797 | "cacache@npm:^19.0.1": 798 | version: 19.0.1 799 | resolution: "cacache@npm:19.0.1" 800 | dependencies: 801 | "@npmcli/fs": "npm:^4.0.0" 802 | fs-minipass: "npm:^3.0.0" 803 | glob: "npm:^10.2.2" 804 | lru-cache: "npm:^10.0.1" 805 | minipass: "npm:^7.0.3" 806 | minipass-collect: "npm:^2.0.1" 807 | minipass-flush: "npm:^1.0.5" 808 | minipass-pipeline: "npm:^1.2.4" 809 | p-map: "npm:^7.0.2" 810 | ssri: "npm:^12.0.0" 811 | tar: "npm:^7.4.3" 812 | unique-filename: "npm:^4.0.0" 813 | checksum: 10c0/01f2134e1bd7d3ab68be851df96c8d63b492b1853b67f2eecb2c37bb682d37cb70bb858a16f2f0554d3c0071be6dfe21456a1ff6fa4b7eed996570d6a25ffe9c 814 | languageName: node 815 | linkType: hard 816 | 817 | "caniuse-lite@npm:^1.0.30001688": 818 | version: 1.0.30001690 819 | resolution: "caniuse-lite@npm:1.0.30001690" 820 | checksum: 10c0/646bd469032afa90400a84dec30a2b00a6eda62c03ead358117e3f884cda8aacec02ec058a6dbee5eaf9714f83e483b9b0eb4fb42febb8076569f5ca40f1d347 821 | languageName: node 822 | linkType: hard 823 | 824 | "chownr@npm:^3.0.0": 825 | version: 3.0.0 826 | resolution: "chownr@npm:3.0.0" 827 | checksum: 10c0/43925b87700f7e3893296c8e9c56cc58f926411cce3a6e5898136daaf08f08b9a8eb76d37d3267e707d0dcc17aed2e2ebdf5848c0c3ce95cf910a919935c1b10 828 | languageName: node 829 | linkType: hard 830 | 831 | "clsx@npm:^2.0.0": 832 | version: 2.1.1 833 | resolution: "clsx@npm:2.1.1" 834 | checksum: 10c0/c4c8eb865f8c82baab07e71bfa8897c73454881c4f99d6bc81585aecd7c441746c1399d08363dc096c550cceaf97bd4ce1e8854e1771e9998d9f94c4fe075839 835 | languageName: node 836 | linkType: hard 837 | 838 | "color-convert@npm:^2.0.1": 839 | version: 2.0.1 840 | resolution: "color-convert@npm:2.0.1" 841 | dependencies: 842 | color-name: "npm:~1.1.4" 843 | checksum: 10c0/37e1150172f2e311fe1b2df62c6293a342ee7380da7b9cfdba67ea539909afbd74da27033208d01d6d5cfc65ee7868a22e18d7e7648e004425441c0f8a15a7d7 844 | languageName: node 845 | linkType: hard 846 | 847 | "color-name@npm:~1.1.4": 848 | version: 1.1.4 849 | resolution: "color-name@npm:1.1.4" 850 | checksum: 10c0/a1a3f914156960902f46f7f56bc62effc6c94e84b2cae157a526b1c1f74b677a47ec602bf68a61abfa2b42d15b7c5651c6dbe72a43af720bc588dff885b10f95 851 | languageName: node 852 | linkType: hard 853 | 854 | "convert-source-map@npm:^2.0.0": 855 | version: 2.0.0 856 | resolution: "convert-source-map@npm:2.0.0" 857 | checksum: 10c0/8f2f7a27a1a011cc6cc88cc4da2d7d0cfa5ee0369508baae3d98c260bb3ac520691464e5bbe4ae7cdf09860c1d69ecc6f70c63c6e7c7f7e3f18ec08484dc7d9b 858 | languageName: node 859 | linkType: hard 860 | 861 | "cross-spawn@npm:^7.0.0": 862 | version: 7.0.6 863 | resolution: "cross-spawn@npm:7.0.6" 864 | dependencies: 865 | path-key: "npm:^3.1.0" 866 | shebang-command: "npm:^2.0.0" 867 | which: "npm:^2.0.1" 868 | checksum: 10c0/053ea8b2135caff68a9e81470e845613e374e7309a47731e81639de3eaeb90c3d01af0e0b44d2ab9d50b43467223b88567dfeb3262db942dc063b9976718ffc1 869 | languageName: node 870 | linkType: hard 871 | 872 | "debug@npm:4, debug@npm:^4.1.0, debug@npm:^4.3.1, debug@npm:^4.3.4": 873 | version: 4.4.0 874 | resolution: "debug@npm:4.4.0" 875 | dependencies: 876 | ms: "npm:^2.1.3" 877 | peerDependenciesMeta: 878 | supports-color: 879 | optional: true 880 | checksum: 10c0/db94f1a182bf886f57b4755f85b3a74c39b5114b9377b7ab375dc2cfa3454f09490cc6c30f829df3fc8042bc8b8995f6567ce5cd96f3bc3688bd24027197d9de 881 | languageName: node 882 | linkType: hard 883 | 884 | "detect-element-overflow@npm:^1.4.0": 885 | version: 1.4.2 886 | resolution: "detect-element-overflow@npm:1.4.2" 887 | checksum: 10c0/dcc5f6d89c31f6035202cce64b96093338e777752b62c401c672e84908097ef01f833af5864e1c86c6440e4f843658f006d1084fb9090983ea5c438c8ad4a180 888 | languageName: node 889 | linkType: hard 890 | 891 | "eastasianwidth@npm:^0.2.0": 892 | version: 0.2.0 893 | resolution: "eastasianwidth@npm:0.2.0" 894 | checksum: 10c0/26f364ebcdb6395f95124fda411f63137a4bfb5d3a06453f7f23dfe52502905bd84e0488172e0f9ec295fdc45f05c23d5d91baf16bd26f0fe9acd777a188dc39 895 | languageName: node 896 | linkType: hard 897 | 898 | "electron-to-chromium@npm:^1.5.73": 899 | version: 1.5.75 900 | resolution: "electron-to-chromium@npm:1.5.75" 901 | checksum: 10c0/df769b7a5e9895a8ba8eb7f31b9525a0e00b8aef6e3ecab3faebe90756fc9ac008dddb8d9a2a78d2079cbaebd27da6e1379f77e910163f405bb1a3d622ec4276 902 | languageName: node 903 | linkType: hard 904 | 905 | "emoji-regex@npm:^8.0.0": 906 | version: 8.0.0 907 | resolution: "emoji-regex@npm:8.0.0" 908 | checksum: 10c0/b6053ad39951c4cf338f9092d7bfba448cdfd46fe6a2a034700b149ac9ffbc137e361cbd3c442297f86bed2e5f7576c1b54cc0a6bf8ef5106cc62f496af35010 909 | languageName: node 910 | linkType: hard 911 | 912 | "emoji-regex@npm:^9.2.2": 913 | version: 9.2.2 914 | resolution: "emoji-regex@npm:9.2.2" 915 | checksum: 10c0/af014e759a72064cf66e6e694a7fc6b0ed3d8db680427b021a89727689671cefe9d04151b2cad51dbaf85d5ba790d061cd167f1cf32eb7b281f6368b3c181639 916 | languageName: node 917 | linkType: hard 918 | 919 | "encoding@npm:^0.1.13": 920 | version: 0.1.13 921 | resolution: "encoding@npm:0.1.13" 922 | dependencies: 923 | iconv-lite: "npm:^0.6.2" 924 | checksum: 10c0/36d938712ff00fe1f4bac88b43bcffb5930c1efa57bbcdca9d67e1d9d6c57cfb1200fb01efe0f3109b2ce99b231f90779532814a81370a1bd3274a0f58585039 925 | languageName: node 926 | linkType: hard 927 | 928 | "env-paths@npm:^2.2.0": 929 | version: 2.2.1 930 | resolution: "env-paths@npm:2.2.1" 931 | checksum: 10c0/285325677bf00e30845e330eec32894f5105529db97496ee3f598478e50f008c5352a41a30e5e72ec9de8a542b5a570b85699cd63bd2bc646dbcb9f311d83bc4 932 | languageName: node 933 | linkType: hard 934 | 935 | "err-code@npm:^2.0.2": 936 | version: 2.0.3 937 | resolution: "err-code@npm:2.0.3" 938 | checksum: 10c0/b642f7b4dd4a376e954947550a3065a9ece6733ab8e51ad80db727aaae0817c2e99b02a97a3d6cecc648a97848305e728289cf312d09af395403a90c9d4d8a66 939 | languageName: node 940 | linkType: hard 941 | 942 | "esbuild@npm:^0.25.0": 943 | version: 0.25.0 944 | resolution: "esbuild@npm:0.25.0" 945 | dependencies: 946 | "@esbuild/aix-ppc64": "npm:0.25.0" 947 | "@esbuild/android-arm": "npm:0.25.0" 948 | "@esbuild/android-arm64": "npm:0.25.0" 949 | "@esbuild/android-x64": "npm:0.25.0" 950 | "@esbuild/darwin-arm64": "npm:0.25.0" 951 | "@esbuild/darwin-x64": "npm:0.25.0" 952 | "@esbuild/freebsd-arm64": "npm:0.25.0" 953 | "@esbuild/freebsd-x64": "npm:0.25.0" 954 | "@esbuild/linux-arm": "npm:0.25.0" 955 | "@esbuild/linux-arm64": "npm:0.25.0" 956 | "@esbuild/linux-ia32": "npm:0.25.0" 957 | "@esbuild/linux-loong64": "npm:0.25.0" 958 | "@esbuild/linux-mips64el": "npm:0.25.0" 959 | "@esbuild/linux-ppc64": "npm:0.25.0" 960 | "@esbuild/linux-riscv64": "npm:0.25.0" 961 | "@esbuild/linux-s390x": "npm:0.25.0" 962 | "@esbuild/linux-x64": "npm:0.25.0" 963 | "@esbuild/netbsd-arm64": "npm:0.25.0" 964 | "@esbuild/netbsd-x64": "npm:0.25.0" 965 | "@esbuild/openbsd-arm64": "npm:0.25.0" 966 | "@esbuild/openbsd-x64": "npm:0.25.0" 967 | "@esbuild/sunos-x64": "npm:0.25.0" 968 | "@esbuild/win32-arm64": "npm:0.25.0" 969 | "@esbuild/win32-ia32": "npm:0.25.0" 970 | "@esbuild/win32-x64": "npm:0.25.0" 971 | dependenciesMeta: 972 | "@esbuild/aix-ppc64": 973 | optional: true 974 | "@esbuild/android-arm": 975 | optional: true 976 | "@esbuild/android-arm64": 977 | optional: true 978 | "@esbuild/android-x64": 979 | optional: true 980 | "@esbuild/darwin-arm64": 981 | optional: true 982 | "@esbuild/darwin-x64": 983 | optional: true 984 | "@esbuild/freebsd-arm64": 985 | optional: true 986 | "@esbuild/freebsd-x64": 987 | optional: true 988 | "@esbuild/linux-arm": 989 | optional: true 990 | "@esbuild/linux-arm64": 991 | optional: true 992 | "@esbuild/linux-ia32": 993 | optional: true 994 | "@esbuild/linux-loong64": 995 | optional: true 996 | "@esbuild/linux-mips64el": 997 | optional: true 998 | "@esbuild/linux-ppc64": 999 | optional: true 1000 | "@esbuild/linux-riscv64": 1001 | optional: true 1002 | "@esbuild/linux-s390x": 1003 | optional: true 1004 | "@esbuild/linux-x64": 1005 | optional: true 1006 | "@esbuild/netbsd-arm64": 1007 | optional: true 1008 | "@esbuild/netbsd-x64": 1009 | optional: true 1010 | "@esbuild/openbsd-arm64": 1011 | optional: true 1012 | "@esbuild/openbsd-x64": 1013 | optional: true 1014 | "@esbuild/sunos-x64": 1015 | optional: true 1016 | "@esbuild/win32-arm64": 1017 | optional: true 1018 | "@esbuild/win32-ia32": 1019 | optional: true 1020 | "@esbuild/win32-x64": 1021 | optional: true 1022 | bin: 1023 | esbuild: bin/esbuild 1024 | checksum: 10c0/5767b72da46da3cfec51661647ec850ddbf8a8d0662771139f10ef0692a8831396a0004b2be7966cecdb08264fb16bdc16290dcecd92396fac5f12d722fa013d 1025 | languageName: node 1026 | linkType: hard 1027 | 1028 | "escalade@npm:^3.2.0": 1029 | version: 3.2.0 1030 | resolution: "escalade@npm:3.2.0" 1031 | checksum: 10c0/ced4dd3a78e15897ed3be74e635110bbf3b08877b0a41be50dcb325ee0e0b5f65fc2d50e9845194d7c4633f327e2e1c6cce00a71b617c5673df0374201d67f65 1032 | languageName: node 1033 | linkType: hard 1034 | 1035 | "exponential-backoff@npm:^3.1.1": 1036 | version: 3.1.1 1037 | resolution: "exponential-backoff@npm:3.1.1" 1038 | checksum: 10c0/160456d2d647e6019640bd07111634d8c353038d9fa40176afb7cd49b0548bdae83b56d05e907c2cce2300b81cae35d800ef92fefb9d0208e190fa3b7d6bb579 1039 | languageName: node 1040 | linkType: hard 1041 | 1042 | "foreground-child@npm:^3.1.0": 1043 | version: 3.1.1 1044 | resolution: "foreground-child@npm:3.1.1" 1045 | dependencies: 1046 | cross-spawn: "npm:^7.0.0" 1047 | signal-exit: "npm:^4.0.1" 1048 | checksum: 10c0/9700a0285628abaeb37007c9a4d92bd49f67210f09067638774338e146c8e9c825c5c877f072b2f75f41dc6a2d0be8664f79ffc03f6576649f54a84fb9b47de0 1049 | languageName: node 1050 | linkType: hard 1051 | 1052 | "fs-minipass@npm:^3.0.0": 1053 | version: 3.0.3 1054 | resolution: "fs-minipass@npm:3.0.3" 1055 | dependencies: 1056 | minipass: "npm:^7.0.3" 1057 | checksum: 10c0/63e80da2ff9b621e2cb1596abcb9207f1cf82b968b116ccd7b959e3323144cce7fb141462200971c38bbf2ecca51695069db45265705bed09a7cd93ae5b89f94 1058 | languageName: node 1059 | linkType: hard 1060 | 1061 | "fsevents@npm:~2.3.2, fsevents@npm:~2.3.3": 1062 | version: 2.3.3 1063 | resolution: "fsevents@npm:2.3.3" 1064 | dependencies: 1065 | node-gyp: "npm:latest" 1066 | checksum: 10c0/a1f0c44595123ed717febbc478aa952e47adfc28e2092be66b8ab1635147254ca6cfe1df792a8997f22716d4cbafc73309899ff7bfac2ac3ad8cf2e4ecc3ec60 1067 | conditions: os=darwin 1068 | languageName: node 1069 | linkType: hard 1070 | 1071 | "fsevents@patch:fsevents@npm%3A~2.3.2#optional!builtin, fsevents@patch:fsevents@npm%3A~2.3.3#optional!builtin": 1072 | version: 2.3.3 1073 | resolution: "fsevents@patch:fsevents@npm%3A2.3.3#optional!builtin::version=2.3.3&hash=df0bf1" 1074 | dependencies: 1075 | node-gyp: "npm:latest" 1076 | conditions: os=darwin 1077 | languageName: node 1078 | linkType: hard 1079 | 1080 | "gensync@npm:^1.0.0-beta.2": 1081 | version: 1.0.0-beta.2 1082 | resolution: "gensync@npm:1.0.0-beta.2" 1083 | checksum: 10c0/782aba6cba65b1bb5af3b095d96249d20edbe8df32dbf4696fd49be2583faf676173bf4809386588828e4dd76a3354fcbeb577bab1c833ccd9fc4577f26103f8 1084 | languageName: node 1085 | linkType: hard 1086 | 1087 | "get-user-locale@npm:^2.2.1": 1088 | version: 2.2.1 1089 | resolution: "get-user-locale@npm:2.2.1" 1090 | dependencies: 1091 | "@types/lodash.memoize": "npm:^4.1.7" 1092 | lodash.memoize: "npm:^4.1.1" 1093 | checksum: 10c0/c820c890aed5fa661435f0364cde6ec90ed9f497a5451528123571f1a77db45a6e2b92462808648499573cb3f2924f90f629ce4f82a60dc1d55047932a3abe71 1094 | languageName: node 1095 | linkType: hard 1096 | 1097 | "glob@npm:^10.2.2, glob@npm:^10.3.10": 1098 | version: 10.3.10 1099 | resolution: "glob@npm:10.3.10" 1100 | dependencies: 1101 | foreground-child: "npm:^3.1.0" 1102 | jackspeak: "npm:^2.3.5" 1103 | minimatch: "npm:^9.0.1" 1104 | minipass: "npm:^5.0.0 || ^6.0.2 || ^7.0.0" 1105 | path-scurry: "npm:^1.10.1" 1106 | bin: 1107 | glob: dist/esm/bin.mjs 1108 | checksum: 10c0/13d8a1feb7eac7945f8c8480e11cd4a44b24d26503d99a8d8ac8d5aefbf3e9802a2b6087318a829fad04cb4e829f25c5f4f1110c68966c498720dd261c7e344d 1109 | languageName: node 1110 | linkType: hard 1111 | 1112 | "globals@npm:^11.1.0": 1113 | version: 11.12.0 1114 | resolution: "globals@npm:11.12.0" 1115 | checksum: 10c0/758f9f258e7b19226bd8d4af5d3b0dcf7038780fb23d82e6f98932c44e239f884847f1766e8fa9cc5635ccb3204f7fa7314d4408dd4002a5e8ea827b4018f0a1 1116 | languageName: node 1117 | linkType: hard 1118 | 1119 | "graceful-fs@npm:^4.2.6": 1120 | version: 4.2.11 1121 | resolution: "graceful-fs@npm:4.2.11" 1122 | checksum: 10c0/386d011a553e02bc594ac2ca0bd6d9e4c22d7fa8cfbfc448a6d148c59ea881b092db9dbe3547ae4b88e55f1b01f7c4a2ecc53b310c042793e63aa44cf6c257f2 1123 | languageName: node 1124 | linkType: hard 1125 | 1126 | "http-cache-semantics@npm:^4.1.1": 1127 | version: 4.1.1 1128 | resolution: "http-cache-semantics@npm:4.1.1" 1129 | checksum: 10c0/ce1319b8a382eb3cbb4a37c19f6bfe14e5bb5be3d09079e885e8c513ab2d3cd9214902f8a31c9dc4e37022633ceabfc2d697405deeaf1b8f3552bb4ed996fdfc 1130 | languageName: node 1131 | linkType: hard 1132 | 1133 | "http-proxy-agent@npm:^7.0.0": 1134 | version: 7.0.0 1135 | resolution: "http-proxy-agent@npm:7.0.0" 1136 | dependencies: 1137 | agent-base: "npm:^7.1.0" 1138 | debug: "npm:^4.3.4" 1139 | checksum: 10c0/a11574ff39436cee3c7bc67f259444097b09474605846ddd8edf0bf4ad8644be8533db1aa463426e376865047d05dc22755e638632819317c0c2f1b2196657c8 1140 | languageName: node 1141 | linkType: hard 1142 | 1143 | "https-proxy-agent@npm:^7.0.1": 1144 | version: 7.0.2 1145 | resolution: "https-proxy-agent@npm:7.0.2" 1146 | dependencies: 1147 | agent-base: "npm:^7.0.2" 1148 | debug: "npm:4" 1149 | checksum: 10c0/7735eb90073db087e7e79312e3d97c8c04baf7ea7ca7b013382b6a45abbaa61b281041a98f4e13c8c80d88f843785bcc84ba189165b4b4087b1e3496ba656d77 1150 | languageName: node 1151 | linkType: hard 1152 | 1153 | "iconv-lite@npm:^0.6.2": 1154 | version: 0.6.3 1155 | resolution: "iconv-lite@npm:0.6.3" 1156 | dependencies: 1157 | safer-buffer: "npm:>= 2.1.2 < 3.0.0" 1158 | checksum: 10c0/98102bc66b33fcf5ac044099d1257ba0b7ad5e3ccd3221f34dd508ab4070edff183276221684e1e0555b145fce0850c9f7d2b60a9fcac50fbb4ea0d6e845a3b1 1159 | languageName: node 1160 | linkType: hard 1161 | 1162 | "imurmurhash@npm:^0.1.4": 1163 | version: 0.1.4 1164 | resolution: "imurmurhash@npm:0.1.4" 1165 | checksum: 10c0/8b51313850dd33605c6c9d3fd9638b714f4c4c40250cff658209f30d40da60f78992fb2df5dabee4acf589a6a82bbc79ad5486550754bd9ec4e3fc0d4a57d6a6 1166 | languageName: node 1167 | linkType: hard 1168 | 1169 | "ip-address@npm:^9.0.5": 1170 | version: 9.0.5 1171 | resolution: "ip-address@npm:9.0.5" 1172 | dependencies: 1173 | jsbn: "npm:1.1.0" 1174 | sprintf-js: "npm:^1.1.3" 1175 | checksum: 10c0/331cd07fafcb3b24100613e4b53e1a2b4feab11e671e655d46dc09ee233da5011284d09ca40c4ecbdfe1d0004f462958675c224a804259f2f78d2465a87824bc 1176 | languageName: node 1177 | linkType: hard 1178 | 1179 | "is-fullwidth-code-point@npm:^3.0.0": 1180 | version: 3.0.0 1181 | resolution: "is-fullwidth-code-point@npm:3.0.0" 1182 | checksum: 10c0/bb11d825e049f38e04c06373a8d72782eee0205bda9d908cc550ccb3c59b99d750ff9537982e01733c1c94a58e35400661f57042158ff5e8f3e90cf936daf0fc 1183 | languageName: node 1184 | linkType: hard 1185 | 1186 | "isexe@npm:^2.0.0": 1187 | version: 2.0.0 1188 | resolution: "isexe@npm:2.0.0" 1189 | checksum: 10c0/228cfa503fadc2c31596ab06ed6aa82c9976eec2bfd83397e7eaf06d0ccf42cd1dfd6743bf9aeb01aebd4156d009994c5f76ea898d2832c1fe342da923ca457d 1190 | languageName: node 1191 | linkType: hard 1192 | 1193 | "isexe@npm:^3.1.1": 1194 | version: 3.1.1 1195 | resolution: "isexe@npm:3.1.1" 1196 | checksum: 10c0/9ec257654093443eb0a528a9c8cbba9c0ca7616ccb40abd6dde7202734d96bb86e4ac0d764f0f8cd965856aacbff2f4ce23e730dc19dfb41e3b0d865ca6fdcc7 1197 | languageName: node 1198 | linkType: hard 1199 | 1200 | "jackspeak@npm:^2.3.5": 1201 | version: 2.3.6 1202 | resolution: "jackspeak@npm:2.3.6" 1203 | dependencies: 1204 | "@isaacs/cliui": "npm:^8.0.2" 1205 | "@pkgjs/parseargs": "npm:^0.11.0" 1206 | dependenciesMeta: 1207 | "@pkgjs/parseargs": 1208 | optional: true 1209 | checksum: 10c0/f01d8f972d894cd7638bc338e9ef5ddb86f7b208ce177a36d718eac96ec86638a6efa17d0221b10073e64b45edc2ce15340db9380b1f5d5c5d000cbc517dc111 1210 | languageName: node 1211 | linkType: hard 1212 | 1213 | "js-tokens@npm:^3.0.0 || ^4.0.0, js-tokens@npm:^4.0.0": 1214 | version: 4.0.0 1215 | resolution: "js-tokens@npm:4.0.0" 1216 | checksum: 10c0/e248708d377aa058eacf2037b07ded847790e6de892bbad3dac0abba2e759cb9f121b00099a65195616badcb6eca8d14d975cb3e89eb1cfda644756402c8aeed 1217 | languageName: node 1218 | linkType: hard 1219 | 1220 | "jsbn@npm:1.1.0": 1221 | version: 1.1.0 1222 | resolution: "jsbn@npm:1.1.0" 1223 | checksum: 10c0/4f907fb78d7b712e11dea8c165fe0921f81a657d3443dde75359ed52eb2b5d33ce6773d97985a089f09a65edd80b11cb75c767b57ba47391fee4c969f7215c96 1224 | languageName: node 1225 | linkType: hard 1226 | 1227 | "jsesc@npm:^3.0.2": 1228 | version: 3.1.0 1229 | resolution: "jsesc@npm:3.1.0" 1230 | bin: 1231 | jsesc: bin/jsesc 1232 | checksum: 10c0/531779df5ec94f47e462da26b4cbf05eb88a83d9f08aac2ba04206508fc598527a153d08bd462bae82fc78b3eaa1a908e1a4a79f886e9238641c4cdefaf118b1 1233 | languageName: node 1234 | linkType: hard 1235 | 1236 | "json5@npm:^2.2.3": 1237 | version: 2.2.3 1238 | resolution: "json5@npm:2.2.3" 1239 | bin: 1240 | json5: lib/cli.js 1241 | checksum: 10c0/5a04eed94810fa55c5ea138b2f7a5c12b97c3750bc63d11e511dcecbfef758003861522a070c2272764ee0f4e3e323862f386945aeb5b85b87ee43f084ba586c 1242 | languageName: node 1243 | linkType: hard 1244 | 1245 | "lodash.memoize@npm:^4.1.1": 1246 | version: 4.1.2 1247 | resolution: "lodash.memoize@npm:4.1.2" 1248 | checksum: 10c0/c8713e51eccc650422716a14cece1809cfe34bc5ab5e242b7f8b4e2241c2483697b971a604252807689b9dd69bfe3a98852e19a5b89d506b000b4187a1285df8 1249 | languageName: node 1250 | linkType: hard 1251 | 1252 | "loose-envify@npm:^1.0.0, loose-envify@npm:^1.1.0": 1253 | version: 1.4.0 1254 | resolution: "loose-envify@npm:1.4.0" 1255 | dependencies: 1256 | js-tokens: "npm:^3.0.0 || ^4.0.0" 1257 | bin: 1258 | loose-envify: cli.js 1259 | checksum: 10c0/655d110220983c1a4b9c0c679a2e8016d4b67f6e9c7b5435ff5979ecdb20d0813f4dec0a08674fcbdd4846a3f07edbb50a36811fd37930b94aaa0d9daceb017e 1260 | languageName: node 1261 | linkType: hard 1262 | 1263 | "lru-cache@npm:^10.0.1, lru-cache@npm:^9.1.1 || ^10.0.0": 1264 | version: 10.2.0 1265 | resolution: "lru-cache@npm:10.2.0" 1266 | checksum: 10c0/c9847612aa2daaef102d30542a8d6d9b2c2bb36581c1bf0dc3ebf5e5f3352c772a749e604afae2e46873b930a9e9523743faac4e5b937c576ab29196774712ee 1267 | languageName: node 1268 | linkType: hard 1269 | 1270 | "lru-cache@npm:^5.1.1": 1271 | version: 5.1.1 1272 | resolution: "lru-cache@npm:5.1.1" 1273 | dependencies: 1274 | yallist: "npm:^3.0.2" 1275 | checksum: 10c0/89b2ef2ef45f543011e38737b8a8622a2f8998cddf0e5437174ef8f1f70a8b9d14a918ab3e232cb3ba343b7abddffa667f0b59075b2b80e6b4d63c3de6127482 1276 | languageName: node 1277 | linkType: hard 1278 | 1279 | "make-event-props@npm:^1.6.0": 1280 | version: 1.6.2 1281 | resolution: "make-event-props@npm:1.6.2" 1282 | checksum: 10c0/ecf0b742e43a392c07e2267baca2397e750d38cc14ef3cb72ef8bfe4a8c8b0fd99a03a2eeab84a26c2b204f7c231da6af31fa26321fbfd413ded43ba1825e867 1283 | languageName: node 1284 | linkType: hard 1285 | 1286 | "make-fetch-happen@npm:^14.0.3": 1287 | version: 14.0.3 1288 | resolution: "make-fetch-happen@npm:14.0.3" 1289 | dependencies: 1290 | "@npmcli/agent": "npm:^3.0.0" 1291 | cacache: "npm:^19.0.1" 1292 | http-cache-semantics: "npm:^4.1.1" 1293 | minipass: "npm:^7.0.2" 1294 | minipass-fetch: "npm:^4.0.0" 1295 | minipass-flush: "npm:^1.0.5" 1296 | minipass-pipeline: "npm:^1.2.4" 1297 | negotiator: "npm:^1.0.0" 1298 | proc-log: "npm:^5.0.0" 1299 | promise-retry: "npm:^2.0.1" 1300 | ssri: "npm:^12.0.0" 1301 | checksum: 10c0/c40efb5e5296e7feb8e37155bde8eb70bc57d731b1f7d90e35a092fde403d7697c56fb49334d92d330d6f1ca29a98142036d6480a12681133a0a1453164cb2f0 1302 | languageName: node 1303 | linkType: hard 1304 | 1305 | "minimatch@npm:^9.0.1": 1306 | version: 9.0.3 1307 | resolution: "minimatch@npm:9.0.3" 1308 | dependencies: 1309 | brace-expansion: "npm:^2.0.1" 1310 | checksum: 10c0/85f407dcd38ac3e180f425e86553911d101455ca3ad5544d6a7cec16286657e4f8a9aa6695803025c55e31e35a91a2252b5dc8e7d527211278b8b65b4dbd5eac 1311 | languageName: node 1312 | linkType: hard 1313 | 1314 | "minipass-collect@npm:^2.0.1": 1315 | version: 2.0.1 1316 | resolution: "minipass-collect@npm:2.0.1" 1317 | dependencies: 1318 | minipass: "npm:^7.0.3" 1319 | checksum: 10c0/5167e73f62bb74cc5019594709c77e6a742051a647fe9499abf03c71dca75515b7959d67a764bdc4f8b361cf897fbf25e2d9869ee039203ed45240f48b9aa06e 1320 | languageName: node 1321 | linkType: hard 1322 | 1323 | "minipass-fetch@npm:^4.0.0": 1324 | version: 4.0.0 1325 | resolution: "minipass-fetch@npm:4.0.0" 1326 | dependencies: 1327 | encoding: "npm:^0.1.13" 1328 | minipass: "npm:^7.0.3" 1329 | minipass-sized: "npm:^1.0.3" 1330 | minizlib: "npm:^3.0.1" 1331 | dependenciesMeta: 1332 | encoding: 1333 | optional: true 1334 | checksum: 10c0/7fa30ce7c373fb6f94c086b374fff1589fd7e78451855d2d06c2e2d9df936d131e73e952163063016592ed3081444bd8d1ea608533313b0149156ce23311da4b 1335 | languageName: node 1336 | linkType: hard 1337 | 1338 | "minipass-flush@npm:^1.0.5": 1339 | version: 1.0.5 1340 | resolution: "minipass-flush@npm:1.0.5" 1341 | dependencies: 1342 | minipass: "npm:^3.0.0" 1343 | checksum: 10c0/2a51b63feb799d2bb34669205eee7c0eaf9dce01883261a5b77410c9408aa447e478efd191b4de6fc1101e796ff5892f8443ef20d9544385819093dbb32d36bd 1344 | languageName: node 1345 | linkType: hard 1346 | 1347 | "minipass-pipeline@npm:^1.2.4": 1348 | version: 1.2.4 1349 | resolution: "minipass-pipeline@npm:1.2.4" 1350 | dependencies: 1351 | minipass: "npm:^3.0.0" 1352 | checksum: 10c0/cbda57cea20b140b797505dc2cac71581a70b3247b84480c1fed5ca5ba46c25ecc25f68bfc9e6dcb1a6e9017dab5c7ada5eab73ad4f0a49d84e35093e0c643f2 1353 | languageName: node 1354 | linkType: hard 1355 | 1356 | "minipass-sized@npm:^1.0.3": 1357 | version: 1.0.3 1358 | resolution: "minipass-sized@npm:1.0.3" 1359 | dependencies: 1360 | minipass: "npm:^3.0.0" 1361 | checksum: 10c0/298f124753efdc745cfe0f2bdfdd81ba25b9f4e753ca4a2066eb17c821f25d48acea607dfc997633ee5bf7b6dfffb4eee4f2051eb168663f0b99fad2fa4829cb 1362 | languageName: node 1363 | linkType: hard 1364 | 1365 | "minipass@npm:^3.0.0": 1366 | version: 3.3.6 1367 | resolution: "minipass@npm:3.3.6" 1368 | dependencies: 1369 | yallist: "npm:^4.0.0" 1370 | checksum: 10c0/a114746943afa1dbbca8249e706d1d38b85ed1298b530f5808ce51f8e9e941962e2a5ad2e00eae7dd21d8a4aae6586a66d4216d1a259385e9d0358f0c1eba16c 1371 | languageName: node 1372 | linkType: hard 1373 | 1374 | "minipass@npm:^5.0.0 || ^6.0.2 || ^7.0.0, minipass@npm:^7.0.2, minipass@npm:^7.0.3, minipass@npm:^7.0.4, minipass@npm:^7.1.2": 1375 | version: 7.1.2 1376 | resolution: "minipass@npm:7.1.2" 1377 | checksum: 10c0/b0fd20bb9fb56e5fa9a8bfac539e8915ae07430a619e4b86ff71f5fc757ef3924b23b2c4230393af1eda647ed3d75739e4e0acb250a6b1eb277cf7f8fe449557 1378 | languageName: node 1379 | linkType: hard 1380 | 1381 | "minizlib@npm:^3.0.1": 1382 | version: 3.0.2 1383 | resolution: "minizlib@npm:3.0.2" 1384 | dependencies: 1385 | minipass: "npm:^7.1.2" 1386 | checksum: 10c0/9f3bd35e41d40d02469cb30470c55ccc21cae0db40e08d1d0b1dff01cc8cc89a6f78e9c5d2b7c844e485ec0a8abc2238111213fdc5b2038e6d1012eacf316f78 1387 | languageName: node 1388 | linkType: hard 1389 | 1390 | "mkdirp@npm:^3.0.1": 1391 | version: 3.0.1 1392 | resolution: "mkdirp@npm:3.0.1" 1393 | bin: 1394 | mkdirp: dist/cjs/src/bin.js 1395 | checksum: 10c0/9f2b975e9246351f5e3a40dcfac99fcd0baa31fbfab615fe059fb11e51f10e4803c63de1f384c54d656e4db31d000e4767e9ef076a22e12a641357602e31d57d 1396 | languageName: node 1397 | linkType: hard 1398 | 1399 | "ms@npm:^2.1.3": 1400 | version: 2.1.3 1401 | resolution: "ms@npm:2.1.3" 1402 | checksum: 10c0/d924b57e7312b3b63ad21fc5b3dc0af5e78d61a1fc7cfb5457edaf26326bf62be5307cc87ffb6862ef1c2b33b0233cdb5d4f01c4c958cc0d660948b65a287a48 1403 | languageName: node 1404 | linkType: hard 1405 | 1406 | "nanoid@npm:^3.3.8": 1407 | version: 3.3.8 1408 | resolution: "nanoid@npm:3.3.8" 1409 | bin: 1410 | nanoid: bin/nanoid.cjs 1411 | checksum: 10c0/4b1bb29f6cfebf3be3bc4ad1f1296fb0a10a3043a79f34fbffe75d1621b4318319211cd420549459018ea3592f0d2f159247a6f874911d6d26eaaadda2478120 1412 | languageName: node 1413 | linkType: hard 1414 | 1415 | "negotiator@npm:^1.0.0": 1416 | version: 1.0.0 1417 | resolution: "negotiator@npm:1.0.0" 1418 | checksum: 10c0/4c559dd52669ea48e1914f9d634227c561221dd54734070791f999c52ed0ff36e437b2e07d5c1f6e32909fc625fe46491c16e4a8f0572567d4dd15c3a4fda04b 1419 | languageName: node 1420 | linkType: hard 1421 | 1422 | "node-gyp@npm:latest": 1423 | version: 11.0.0 1424 | resolution: "node-gyp@npm:11.0.0" 1425 | dependencies: 1426 | env-paths: "npm:^2.2.0" 1427 | exponential-backoff: "npm:^3.1.1" 1428 | glob: "npm:^10.3.10" 1429 | graceful-fs: "npm:^4.2.6" 1430 | make-fetch-happen: "npm:^14.0.3" 1431 | nopt: "npm:^8.0.0" 1432 | proc-log: "npm:^5.0.0" 1433 | semver: "npm:^7.3.5" 1434 | tar: "npm:^7.4.3" 1435 | which: "npm:^5.0.0" 1436 | bin: 1437 | node-gyp: bin/node-gyp.js 1438 | checksum: 10c0/a3b885bbee2d271f1def32ba2e30ffcf4562a3db33af06b8b365e053153e2dd2051b9945783c3c8e852d26a0f20f65b251c7e83361623383a99635c0280ee573 1439 | languageName: node 1440 | linkType: hard 1441 | 1442 | "node-releases@npm:^2.0.19": 1443 | version: 2.0.19 1444 | resolution: "node-releases@npm:2.0.19" 1445 | checksum: 10c0/52a0dbd25ccf545892670d1551690fe0facb6a471e15f2cfa1b20142a5b255b3aa254af5f59d6ecb69c2bec7390bc643c43aa63b13bf5e64b6075952e716b1aa 1446 | languageName: node 1447 | linkType: hard 1448 | 1449 | "nopt@npm:^8.0.0": 1450 | version: 8.1.0 1451 | resolution: "nopt@npm:8.1.0" 1452 | dependencies: 1453 | abbrev: "npm:^3.0.0" 1454 | bin: 1455 | nopt: bin/nopt.js 1456 | checksum: 10c0/62e9ea70c7a3eb91d162d2c706b6606c041e4e7b547cbbb48f8b3695af457dd6479904d7ace600856bf923dd8d1ed0696f06195c8c20f02ac87c1da0e1d315ef 1457 | languageName: node 1458 | linkType: hard 1459 | 1460 | "p-map@npm:^7.0.2": 1461 | version: 7.0.3 1462 | resolution: "p-map@npm:7.0.3" 1463 | checksum: 10c0/46091610da2b38ce47bcd1d8b4835a6fa4e832848a6682cf1652bc93915770f4617afc844c10a77d1b3e56d2472bb2d5622353fa3ead01a7f42b04fc8e744a5c 1464 | languageName: node 1465 | linkType: hard 1466 | 1467 | "path-key@npm:^3.1.0": 1468 | version: 3.1.1 1469 | resolution: "path-key@npm:3.1.1" 1470 | checksum: 10c0/748c43efd5a569c039d7a00a03b58eecd1d75f3999f5a28303d75f521288df4823bc057d8784eb72358b2895a05f29a070bc9f1f17d28226cc4e62494cc58c4c 1471 | languageName: node 1472 | linkType: hard 1473 | 1474 | "path-scurry@npm:^1.10.1": 1475 | version: 1.10.1 1476 | resolution: "path-scurry@npm:1.10.1" 1477 | dependencies: 1478 | lru-cache: "npm:^9.1.1 || ^10.0.0" 1479 | minipass: "npm:^5.0.0 || ^6.0.2 || ^7.0.0" 1480 | checksum: 10c0/e5dc78a7348d25eec61ab166317e9e9c7b46818aa2c2b9006c507a6ff48c672d011292d9662527213e558f5652ce0afcc788663a061d8b59ab495681840c0c1e 1481 | languageName: node 1482 | linkType: hard 1483 | 1484 | "picocolors@npm:^1.0.0, picocolors@npm:^1.1.0, picocolors@npm:^1.1.1": 1485 | version: 1.1.1 1486 | resolution: "picocolors@npm:1.1.1" 1487 | checksum: 10c0/e2e3e8170ab9d7c7421969adaa7e1b31434f789afb9b3f115f6b96d91945041ac3ceb02e9ec6fe6510ff036bcc0bf91e69a1772edc0b707e12b19c0f2d6bcf58 1488 | languageName: node 1489 | linkType: hard 1490 | 1491 | "postcss@npm:^8.5.3": 1492 | version: 8.5.3 1493 | resolution: "postcss@npm:8.5.3" 1494 | dependencies: 1495 | nanoid: "npm:^3.3.8" 1496 | picocolors: "npm:^1.1.1" 1497 | source-map-js: "npm:^1.2.1" 1498 | checksum: 10c0/b75510d7b28c3ab728c8733dd01538314a18c52af426f199a3c9177e63eb08602a3938bfb66b62dc01350b9aed62087eabbf229af97a1659eb8d3513cec823b3 1499 | languageName: node 1500 | linkType: hard 1501 | 1502 | "proc-log@npm:^5.0.0": 1503 | version: 5.0.0 1504 | resolution: "proc-log@npm:5.0.0" 1505 | checksum: 10c0/bbe5edb944b0ad63387a1d5b1911ae93e05ce8d0f60de1035b218cdcceedfe39dbd2c697853355b70f1a090f8f58fe90da487c85216bf9671f9499d1a897e9e3 1506 | languageName: node 1507 | linkType: hard 1508 | 1509 | "promise-retry@npm:^2.0.1": 1510 | version: 2.0.1 1511 | resolution: "promise-retry@npm:2.0.1" 1512 | dependencies: 1513 | err-code: "npm:^2.0.2" 1514 | retry: "npm:^0.12.0" 1515 | checksum: 10c0/9c7045a1a2928094b5b9b15336dcd2a7b1c052f674550df63cc3f36cd44028e5080448175b6f6ca32b642de81150f5e7b1a98b728f15cb069f2dd60ac2616b96 1516 | languageName: node 1517 | linkType: hard 1518 | 1519 | "react-clock@npm:^5.0.0": 1520 | version: 5.0.0 1521 | resolution: "react-clock@npm:5.0.0" 1522 | dependencies: 1523 | "@wojtekmaj/date-utils": "npm:^1.5.0" 1524 | clsx: "npm:^2.0.0" 1525 | get-user-locale: "npm:^2.2.1" 1526 | peerDependencies: 1527 | "@types/react": ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 1528 | react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 1529 | react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 1530 | peerDependenciesMeta: 1531 | "@types/react": 1532 | optional: true 1533 | checksum: 10c0/f96492d12c936a7e15a83efa077afe45e1c18e3f447d7605313fe5a31886390906a69a8a426bd502fb0dfe38a2913cb221a2efc8fc786396be9709a46c13caed 1534 | languageName: node 1535 | linkType: hard 1536 | 1537 | "react-dom@npm:^18.2.0": 1538 | version: 18.2.0 1539 | resolution: "react-dom@npm:18.2.0" 1540 | dependencies: 1541 | loose-envify: "npm:^1.1.0" 1542 | scheduler: "npm:^0.23.0" 1543 | peerDependencies: 1544 | react: ^18.2.0 1545 | checksum: 10c0/66dfc5f93e13d0674e78ef41f92ed21dfb80f9c4ac4ac25a4b51046d41d4d2186abc915b897f69d3d0ebbffe6184e7c5876f2af26bfa956f179225d921be713a 1546 | languageName: node 1547 | linkType: hard 1548 | 1549 | "react-fit@npm:^2.0.0": 1550 | version: 2.0.1 1551 | resolution: "react-fit@npm:2.0.1" 1552 | dependencies: 1553 | detect-element-overflow: "npm:^1.4.0" 1554 | warning: "npm:^4.0.0" 1555 | peerDependencies: 1556 | "@types/react": ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 1557 | react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 1558 | react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 1559 | peerDependenciesMeta: 1560 | "@types/react": 1561 | optional: true 1562 | "@types/react-dom": 1563 | optional: true 1564 | checksum: 10c0/0202f4e3241bd2e967ec3728c97ab57842353ae48f218ca56d28be14737a7a759e40c3cd05700d9e328ab88e377eccb296f1e33530e6775d3acc05df97084018 1565 | languageName: node 1566 | linkType: hard 1567 | 1568 | "react-refresh@npm:^0.14.2": 1569 | version: 0.14.2 1570 | resolution: "react-refresh@npm:0.14.2" 1571 | checksum: 10c0/875b72ef56b147a131e33f2abd6ec059d1989854b3ff438898e4f9310bfcc73acff709445b7ba843318a953cb9424bcc2c05af2b3d80011cee28f25aef3e2ebb 1572 | languageName: node 1573 | linkType: hard 1574 | 1575 | "react-time-picker@npm:^7.0.0": 1576 | version: 7.0.0 1577 | resolution: "react-time-picker@npm:7.0.0" 1578 | dependencies: 1579 | "@wojtekmaj/date-utils": "npm:^1.1.3" 1580 | clsx: "npm:^2.0.0" 1581 | get-user-locale: "npm:^2.2.1" 1582 | make-event-props: "npm:^1.6.0" 1583 | react-clock: "npm:^5.0.0" 1584 | react-fit: "npm:^2.0.0" 1585 | update-input-width: "npm:^1.4.0" 1586 | peerDependencies: 1587 | "@types/react": ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 1588 | react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 1589 | react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 1590 | peerDependenciesMeta: 1591 | "@types/react": 1592 | optional: true 1593 | checksum: 10c0/538a1964de1ef9021b195f856efedc207019b6da1b9bbdcb6899c876ec6b4eeb02f4f16b77677dc0edb704099ed7f204dde0821573b7a1f1f24909e02ea2aee6 1594 | languageName: node 1595 | linkType: hard 1596 | 1597 | "react-timerange-picker-sample-page@workspace:.": 1598 | version: 0.0.0-use.local 1599 | resolution: "react-timerange-picker-sample-page@workspace:." 1600 | dependencies: 1601 | "@vitejs/plugin-react": "npm:^4.3.4" 1602 | "@wojtekmaj/react-timerange-picker": "npm:latest" 1603 | react: "npm:^18.2.0" 1604 | react-dom: "npm:^18.2.0" 1605 | typescript: "npm:^5.0.0" 1606 | vite: "npm:^6.2.4" 1607 | languageName: unknown 1608 | linkType: soft 1609 | 1610 | "react@npm:^18.2.0": 1611 | version: 18.2.0 1612 | resolution: "react@npm:18.2.0" 1613 | dependencies: 1614 | loose-envify: "npm:^1.1.0" 1615 | checksum: 10c0/b562d9b569b0cb315e44b48099f7712283d93df36b19a39a67c254c6686479d3980b7f013dc931f4a5a3ae7645eae6386b4aa5eea933baa54ecd0f9acb0902b8 1616 | languageName: node 1617 | linkType: hard 1618 | 1619 | "retry@npm:^0.12.0": 1620 | version: 0.12.0 1621 | resolution: "retry@npm:0.12.0" 1622 | checksum: 10c0/59933e8501727ba13ad73ef4a04d5280b3717fd650408460c987392efe9d7be2040778ed8ebe933c5cbd63da3dcc37919c141ef8af0a54a6e4fca5a2af177bfe 1623 | languageName: node 1624 | linkType: hard 1625 | 1626 | "rollup@npm:^4.30.1": 1627 | version: 4.34.9 1628 | resolution: "rollup@npm:4.34.9" 1629 | dependencies: 1630 | "@rollup/rollup-android-arm-eabi": "npm:4.34.9" 1631 | "@rollup/rollup-android-arm64": "npm:4.34.9" 1632 | "@rollup/rollup-darwin-arm64": "npm:4.34.9" 1633 | "@rollup/rollup-darwin-x64": "npm:4.34.9" 1634 | "@rollup/rollup-freebsd-arm64": "npm:4.34.9" 1635 | "@rollup/rollup-freebsd-x64": "npm:4.34.9" 1636 | "@rollup/rollup-linux-arm-gnueabihf": "npm:4.34.9" 1637 | "@rollup/rollup-linux-arm-musleabihf": "npm:4.34.9" 1638 | "@rollup/rollup-linux-arm64-gnu": "npm:4.34.9" 1639 | "@rollup/rollup-linux-arm64-musl": "npm:4.34.9" 1640 | "@rollup/rollup-linux-loongarch64-gnu": "npm:4.34.9" 1641 | "@rollup/rollup-linux-powerpc64le-gnu": "npm:4.34.9" 1642 | "@rollup/rollup-linux-riscv64-gnu": "npm:4.34.9" 1643 | "@rollup/rollup-linux-s390x-gnu": "npm:4.34.9" 1644 | "@rollup/rollup-linux-x64-gnu": "npm:4.34.9" 1645 | "@rollup/rollup-linux-x64-musl": "npm:4.34.9" 1646 | "@rollup/rollup-win32-arm64-msvc": "npm:4.34.9" 1647 | "@rollup/rollup-win32-ia32-msvc": "npm:4.34.9" 1648 | "@rollup/rollup-win32-x64-msvc": "npm:4.34.9" 1649 | "@types/estree": "npm:1.0.6" 1650 | fsevents: "npm:~2.3.2" 1651 | dependenciesMeta: 1652 | "@rollup/rollup-android-arm-eabi": 1653 | optional: true 1654 | "@rollup/rollup-android-arm64": 1655 | optional: true 1656 | "@rollup/rollup-darwin-arm64": 1657 | optional: true 1658 | "@rollup/rollup-darwin-x64": 1659 | optional: true 1660 | "@rollup/rollup-freebsd-arm64": 1661 | optional: true 1662 | "@rollup/rollup-freebsd-x64": 1663 | optional: true 1664 | "@rollup/rollup-linux-arm-gnueabihf": 1665 | optional: true 1666 | "@rollup/rollup-linux-arm-musleabihf": 1667 | optional: true 1668 | "@rollup/rollup-linux-arm64-gnu": 1669 | optional: true 1670 | "@rollup/rollup-linux-arm64-musl": 1671 | optional: true 1672 | "@rollup/rollup-linux-loongarch64-gnu": 1673 | optional: true 1674 | "@rollup/rollup-linux-powerpc64le-gnu": 1675 | optional: true 1676 | "@rollup/rollup-linux-riscv64-gnu": 1677 | optional: true 1678 | "@rollup/rollup-linux-s390x-gnu": 1679 | optional: true 1680 | "@rollup/rollup-linux-x64-gnu": 1681 | optional: true 1682 | "@rollup/rollup-linux-x64-musl": 1683 | optional: true 1684 | "@rollup/rollup-win32-arm64-msvc": 1685 | optional: true 1686 | "@rollup/rollup-win32-ia32-msvc": 1687 | optional: true 1688 | "@rollup/rollup-win32-x64-msvc": 1689 | optional: true 1690 | fsevents: 1691 | optional: true 1692 | bin: 1693 | rollup: dist/bin/rollup 1694 | checksum: 10c0/dd0be1f7c4f8a93040026be13ecc39259fb55313db0dac7eafd97a3ac01ab4584e6b1a8afd86b0259dcf391699d5560a678abe6c0729af0aa4f2d5df70f05c8c 1695 | languageName: node 1696 | linkType: hard 1697 | 1698 | "safer-buffer@npm:>= 2.1.2 < 3.0.0": 1699 | version: 2.1.2 1700 | resolution: "safer-buffer@npm:2.1.2" 1701 | checksum: 10c0/7e3c8b2e88a1841c9671094bbaeebd94448111dd90a81a1f606f3f67708a6ec57763b3b47f06da09fc6054193e0e6709e77325415dc8422b04497a8070fa02d4 1702 | languageName: node 1703 | linkType: hard 1704 | 1705 | "scheduler@npm:^0.23.0": 1706 | version: 0.23.0 1707 | resolution: "scheduler@npm:0.23.0" 1708 | dependencies: 1709 | loose-envify: "npm:^1.1.0" 1710 | checksum: 10c0/b777f7ca0115e6d93e126ac490dbd82642d14983b3079f58f35519d992fa46260be7d6e6cede433a92db70306310c6f5f06e144f0e40c484199e09c1f7be53dd 1711 | languageName: node 1712 | linkType: hard 1713 | 1714 | "semver@npm:^6.3.1": 1715 | version: 6.3.1 1716 | resolution: "semver@npm:6.3.1" 1717 | bin: 1718 | semver: bin/semver.js 1719 | checksum: 10c0/e3d79b609071caa78bcb6ce2ad81c7966a46a7431d9d58b8800cfa9cb6a63699b3899a0e4bcce36167a284578212d9ae6942b6929ba4aa5015c079a67751d42d 1720 | languageName: node 1721 | linkType: hard 1722 | 1723 | "semver@npm:^7.3.5": 1724 | version: 7.6.3 1725 | resolution: "semver@npm:7.6.3" 1726 | bin: 1727 | semver: bin/semver.js 1728 | checksum: 10c0/88f33e148b210c153873cb08cfe1e281d518aaa9a666d4d148add6560db5cd3c582f3a08ccb91f38d5f379ead256da9931234ed122057f40bb5766e65e58adaf 1729 | languageName: node 1730 | linkType: hard 1731 | 1732 | "shebang-command@npm:^2.0.0": 1733 | version: 2.0.0 1734 | resolution: "shebang-command@npm:2.0.0" 1735 | dependencies: 1736 | shebang-regex: "npm:^3.0.0" 1737 | checksum: 10c0/a41692e7d89a553ef21d324a5cceb5f686d1f3c040759c50aab69688634688c5c327f26f3ecf7001ebfd78c01f3c7c0a11a7c8bfd0a8bc9f6240d4f40b224e4e 1738 | languageName: node 1739 | linkType: hard 1740 | 1741 | "shebang-regex@npm:^3.0.0": 1742 | version: 3.0.0 1743 | resolution: "shebang-regex@npm:3.0.0" 1744 | checksum: 10c0/1dbed0726dd0e1152a92696c76c7f06084eb32a90f0528d11acd764043aacf76994b2fb30aa1291a21bd019d6699164d048286309a278855ee7bec06cf6fb690 1745 | languageName: node 1746 | linkType: hard 1747 | 1748 | "signal-exit@npm:^4.0.1": 1749 | version: 4.1.0 1750 | resolution: "signal-exit@npm:4.1.0" 1751 | checksum: 10c0/41602dce540e46d599edba9d9860193398d135f7ff72cab629db5171516cfae628d21e7bfccde1bbfdf11c48726bc2a6d1a8fb8701125852fbfda7cf19c6aa83 1752 | languageName: node 1753 | linkType: hard 1754 | 1755 | "smart-buffer@npm:^4.2.0": 1756 | version: 4.2.0 1757 | resolution: "smart-buffer@npm:4.2.0" 1758 | checksum: 10c0/a16775323e1404dd43fabafe7460be13a471e021637bc7889468eb45ce6a6b207261f454e4e530a19500cc962c4cc5348583520843b363f4193cee5c00e1e539 1759 | languageName: node 1760 | linkType: hard 1761 | 1762 | "socks-proxy-agent@npm:^8.0.3": 1763 | version: 8.0.5 1764 | resolution: "socks-proxy-agent@npm:8.0.5" 1765 | dependencies: 1766 | agent-base: "npm:^7.1.2" 1767 | debug: "npm:^4.3.4" 1768 | socks: "npm:^2.8.3" 1769 | checksum: 10c0/5d2c6cecba6821389aabf18728325730504bf9bb1d9e342e7987a5d13badd7a98838cc9a55b8ed3cb866ad37cc23e1086f09c4d72d93105ce9dfe76330e9d2a6 1770 | languageName: node 1771 | linkType: hard 1772 | 1773 | "socks@npm:^2.8.3": 1774 | version: 2.8.3 1775 | resolution: "socks@npm:2.8.3" 1776 | dependencies: 1777 | ip-address: "npm:^9.0.5" 1778 | smart-buffer: "npm:^4.2.0" 1779 | checksum: 10c0/d54a52bf9325165770b674a67241143a3d8b4e4c8884560c4e0e078aace2a728dffc7f70150660f51b85797c4e1a3b82f9b7aa25e0a0ceae1a243365da5c51a7 1780 | languageName: node 1781 | linkType: hard 1782 | 1783 | "source-map-js@npm:^1.2.1": 1784 | version: 1.2.1 1785 | resolution: "source-map-js@npm:1.2.1" 1786 | checksum: 10c0/7bda1fc4c197e3c6ff17de1b8b2c20e60af81b63a52cb32ec5a5d67a20a7d42651e2cb34ebe93833c5a2a084377e17455854fee3e21e7925c64a51b6a52b0faf 1787 | languageName: node 1788 | linkType: hard 1789 | 1790 | "sprintf-js@npm:^1.1.3": 1791 | version: 1.1.3 1792 | resolution: "sprintf-js@npm:1.1.3" 1793 | checksum: 10c0/09270dc4f30d479e666aee820eacd9e464215cdff53848b443964202bf4051490538e5dd1b42e1a65cf7296916ca17640aebf63dae9812749c7542ee5f288dec 1794 | languageName: node 1795 | linkType: hard 1796 | 1797 | "ssri@npm:^12.0.0": 1798 | version: 12.0.0 1799 | resolution: "ssri@npm:12.0.0" 1800 | dependencies: 1801 | minipass: "npm:^7.0.3" 1802 | checksum: 10c0/caddd5f544b2006e88fa6b0124d8d7b28208b83c72d7672d5ade44d794525d23b540f3396108c4eb9280dcb7c01f0bef50682f5b4b2c34291f7c5e211fd1417d 1803 | languageName: node 1804 | linkType: hard 1805 | 1806 | "string-width-cjs@npm:string-width@^4.2.0, string-width@npm:^4.1.0": 1807 | version: 4.2.3 1808 | resolution: "string-width@npm:4.2.3" 1809 | dependencies: 1810 | emoji-regex: "npm:^8.0.0" 1811 | is-fullwidth-code-point: "npm:^3.0.0" 1812 | strip-ansi: "npm:^6.0.1" 1813 | checksum: 10c0/1e525e92e5eae0afd7454086eed9c818ee84374bb80328fc41217ae72ff5f065ef1c9d7f72da41de40c75fa8bb3dee63d92373fd492c84260a552c636392a47b 1814 | languageName: node 1815 | linkType: hard 1816 | 1817 | "string-width@npm:^5.0.1, string-width@npm:^5.1.2": 1818 | version: 5.1.2 1819 | resolution: "string-width@npm:5.1.2" 1820 | dependencies: 1821 | eastasianwidth: "npm:^0.2.0" 1822 | emoji-regex: "npm:^9.2.2" 1823 | strip-ansi: "npm:^7.0.1" 1824 | checksum: 10c0/ab9c4264443d35b8b923cbdd513a089a60de339216d3b0ed3be3ba57d6880e1a192b70ae17225f764d7adbf5994e9bb8df253a944736c15a0240eff553c678ca 1825 | languageName: node 1826 | linkType: hard 1827 | 1828 | "strip-ansi-cjs@npm:strip-ansi@^6.0.1, strip-ansi@npm:^6.0.0, strip-ansi@npm:^6.0.1": 1829 | version: 6.0.1 1830 | resolution: "strip-ansi@npm:6.0.1" 1831 | dependencies: 1832 | ansi-regex: "npm:^5.0.1" 1833 | checksum: 10c0/1ae5f212a126fe5b167707f716942490e3933085a5ff6c008ab97ab2f272c8025d3aa218b7bd6ab25729ca20cc81cddb252102f8751e13482a5199e873680952 1834 | languageName: node 1835 | linkType: hard 1836 | 1837 | "strip-ansi@npm:^7.0.1": 1838 | version: 7.1.0 1839 | resolution: "strip-ansi@npm:7.1.0" 1840 | dependencies: 1841 | ansi-regex: "npm:^6.0.1" 1842 | checksum: 10c0/a198c3762e8832505328cbf9e8c8381de14a4fa50a4f9b2160138158ea88c0f5549fb50cb13c651c3088f47e63a108b34622ec18c0499b6c8c3a5ddf6b305ac4 1843 | languageName: node 1844 | linkType: hard 1845 | 1846 | "tar@npm:^7.4.3": 1847 | version: 7.4.3 1848 | resolution: "tar@npm:7.4.3" 1849 | dependencies: 1850 | "@isaacs/fs-minipass": "npm:^4.0.0" 1851 | chownr: "npm:^3.0.0" 1852 | minipass: "npm:^7.1.2" 1853 | minizlib: "npm:^3.0.1" 1854 | mkdirp: "npm:^3.0.1" 1855 | yallist: "npm:^5.0.0" 1856 | checksum: 10c0/d4679609bb2a9b48eeaf84632b6d844128d2412b95b6de07d53d8ee8baf4ca0857c9331dfa510390a0727b550fd543d4d1a10995ad86cdf078423fbb8d99831d 1857 | languageName: node 1858 | linkType: hard 1859 | 1860 | "typescript@npm:^5.0.0": 1861 | version: 5.0.4 1862 | resolution: "typescript@npm:5.0.4" 1863 | bin: 1864 | tsc: bin/tsc 1865 | tsserver: bin/tsserver 1866 | checksum: 10c0/2f5bd1cead194905957cb34e220b1d6ff1662399adef8ec1864f74620922d860ee35b6e50eafb3b636ea6fd437195e454e1146cb630a4236b5095ed7617395c2 1867 | languageName: node 1868 | linkType: hard 1869 | 1870 | "typescript@patch:typescript@npm%3A^5.0.0#optional!builtin": 1871 | version: 5.0.4 1872 | resolution: "typescript@patch:typescript@npm%3A5.0.4#optional!builtin::version=5.0.4&hash=b5f058" 1873 | bin: 1874 | tsc: bin/tsc 1875 | tsserver: bin/tsserver 1876 | checksum: 10c0/c3f7b80577bddf6fab202a7925131ac733bfc414aec298c2404afcddc7a6f242cfa8395cf2d48192265052e11a7577c27f6e5fac8d8fe6a6602023c83d6b3292 1877 | languageName: node 1878 | linkType: hard 1879 | 1880 | "unique-filename@npm:^4.0.0": 1881 | version: 4.0.0 1882 | resolution: "unique-filename@npm:4.0.0" 1883 | dependencies: 1884 | unique-slug: "npm:^5.0.0" 1885 | checksum: 10c0/38ae681cceb1408ea0587b6b01e29b00eee3c84baee1e41fd5c16b9ed443b80fba90c40e0ba69627e30855570a34ba8b06702d4a35035d4b5e198bf5a64c9ddc 1886 | languageName: node 1887 | linkType: hard 1888 | 1889 | "unique-slug@npm:^5.0.0": 1890 | version: 5.0.0 1891 | resolution: "unique-slug@npm:5.0.0" 1892 | dependencies: 1893 | imurmurhash: "npm:^0.1.4" 1894 | checksum: 10c0/d324c5a44887bd7e105ce800fcf7533d43f29c48757ac410afd42975de82cc38ea2035c0483f4de82d186691bf3208ef35c644f73aa2b1b20b8e651be5afd293 1895 | languageName: node 1896 | linkType: hard 1897 | 1898 | "update-browserslist-db@npm:^1.1.1": 1899 | version: 1.1.1 1900 | resolution: "update-browserslist-db@npm:1.1.1" 1901 | dependencies: 1902 | escalade: "npm:^3.2.0" 1903 | picocolors: "npm:^1.1.0" 1904 | peerDependencies: 1905 | browserslist: ">= 4.21.0" 1906 | bin: 1907 | update-browserslist-db: cli.js 1908 | checksum: 10c0/536a2979adda2b4be81b07e311bd2f3ad5e978690987956bc5f514130ad50cac87cd22c710b686d79731e00fbee8ef43efe5fcd72baa241045209195d43dcc80 1909 | languageName: node 1910 | linkType: hard 1911 | 1912 | "update-input-width@npm:^1.4.0": 1913 | version: 1.4.2 1914 | resolution: "update-input-width@npm:1.4.2" 1915 | checksum: 10c0/d3344f91c1c08a26f81d172dd774ca8834ddfaec1eb78e05280d303800a3236c4e122df14ea34fe7f0e1bdada733dec5d3676d38ce0777bafe603de0a6199473 1916 | languageName: node 1917 | linkType: hard 1918 | 1919 | "vite@npm:^6.2.4": 1920 | version: 6.2.4 1921 | resolution: "vite@npm:6.2.4" 1922 | dependencies: 1923 | esbuild: "npm:^0.25.0" 1924 | fsevents: "npm:~2.3.3" 1925 | postcss: "npm:^8.5.3" 1926 | rollup: "npm:^4.30.1" 1927 | peerDependencies: 1928 | "@types/node": ^18.0.0 || ^20.0.0 || >=22.0.0 1929 | jiti: ">=1.21.0" 1930 | less: "*" 1931 | lightningcss: ^1.21.0 1932 | sass: "*" 1933 | sass-embedded: "*" 1934 | stylus: "*" 1935 | sugarss: "*" 1936 | terser: ^5.16.0 1937 | tsx: ^4.8.1 1938 | yaml: ^2.4.2 1939 | dependenciesMeta: 1940 | fsevents: 1941 | optional: true 1942 | peerDependenciesMeta: 1943 | "@types/node": 1944 | optional: true 1945 | jiti: 1946 | optional: true 1947 | less: 1948 | optional: true 1949 | lightningcss: 1950 | optional: true 1951 | sass: 1952 | optional: true 1953 | sass-embedded: 1954 | optional: true 1955 | stylus: 1956 | optional: true 1957 | sugarss: 1958 | optional: true 1959 | terser: 1960 | optional: true 1961 | tsx: 1962 | optional: true 1963 | yaml: 1964 | optional: true 1965 | bin: 1966 | vite: bin/vite.js 1967 | checksum: 10c0/5a011ee5cce91de023a22564a314f04bf64d0d02b420d92c3d539d10257448d60e98e52b491404656426fba4a50dc25f107282540d7388fc5303dc441280155e 1968 | languageName: node 1969 | linkType: hard 1970 | 1971 | "warning@npm:^4.0.0": 1972 | version: 4.0.3 1973 | resolution: "warning@npm:4.0.3" 1974 | dependencies: 1975 | loose-envify: "npm:^1.0.0" 1976 | checksum: 10c0/aebab445129f3e104c271f1637fa38e55eb25f968593e3825bd2f7a12bd58dc3738bb70dc8ec85826621d80b4acfed5a29ebc9da17397c6125864d72301b937e 1977 | languageName: node 1978 | linkType: hard 1979 | 1980 | "which@npm:^2.0.1": 1981 | version: 2.0.2 1982 | resolution: "which@npm:2.0.2" 1983 | dependencies: 1984 | isexe: "npm:^2.0.0" 1985 | bin: 1986 | node-which: ./bin/node-which 1987 | checksum: 10c0/66522872a768b60c2a65a57e8ad184e5372f5b6a9ca6d5f033d4b0dc98aff63995655a7503b9c0a2598936f532120e81dd8cc155e2e92ed662a2b9377cc4374f 1988 | languageName: node 1989 | linkType: hard 1990 | 1991 | "which@npm:^5.0.0": 1992 | version: 5.0.0 1993 | resolution: "which@npm:5.0.0" 1994 | dependencies: 1995 | isexe: "npm:^3.1.1" 1996 | bin: 1997 | node-which: bin/which.js 1998 | checksum: 10c0/e556e4cd8b7dbf5df52408c9a9dd5ac6518c8c5267c8953f5b0564073c66ed5bf9503b14d876d0e9c7844d4db9725fb0dcf45d6e911e17e26ab363dc3965ae7b 1999 | languageName: node 2000 | linkType: hard 2001 | 2002 | "wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": 2003 | version: 7.0.0 2004 | resolution: "wrap-ansi@npm:7.0.0" 2005 | dependencies: 2006 | ansi-styles: "npm:^4.0.0" 2007 | string-width: "npm:^4.1.0" 2008 | strip-ansi: "npm:^6.0.0" 2009 | checksum: 10c0/d15fc12c11e4cbc4044a552129ebc75ee3f57aa9c1958373a4db0292d72282f54373b536103987a4a7594db1ef6a4f10acf92978f79b98c49306a4b58c77d4da 2010 | languageName: node 2011 | linkType: hard 2012 | 2013 | "wrap-ansi@npm:^8.1.0": 2014 | version: 8.1.0 2015 | resolution: "wrap-ansi@npm:8.1.0" 2016 | dependencies: 2017 | ansi-styles: "npm:^6.1.0" 2018 | string-width: "npm:^5.0.1" 2019 | strip-ansi: "npm:^7.0.1" 2020 | checksum: 10c0/138ff58a41d2f877eae87e3282c0630fc2789012fc1af4d6bd626eeb9a2f9a65ca92005e6e69a75c7b85a68479fe7443c7dbe1eb8fbaa681a4491364b7c55c60 2021 | languageName: node 2022 | linkType: hard 2023 | 2024 | "yallist@npm:^3.0.2": 2025 | version: 3.1.1 2026 | resolution: "yallist@npm:3.1.1" 2027 | checksum: 10c0/c66a5c46bc89af1625476f7f0f2ec3653c1a1791d2f9407cfb4c2ba812a1e1c9941416d71ba9719876530e3340a99925f697142989371b72d93b9ee628afd8c1 2028 | languageName: node 2029 | linkType: hard 2030 | 2031 | "yallist@npm:^4.0.0": 2032 | version: 4.0.0 2033 | resolution: "yallist@npm:4.0.0" 2034 | checksum: 10c0/2286b5e8dbfe22204ab66e2ef5cc9bbb1e55dfc873bbe0d568aa943eb255d131890dfd5bf243637273d31119b870f49c18fcde2c6ffbb7a7a092b870dc90625a 2035 | languageName: node 2036 | linkType: hard 2037 | 2038 | "yallist@npm:^5.0.0": 2039 | version: 5.0.0 2040 | resolution: "yallist@npm:5.0.0" 2041 | checksum: 10c0/a499c81ce6d4a1d260d4ea0f6d49ab4da09681e32c3f0472dee16667ed69d01dae63a3b81745a24bd78476ec4fcf856114cb4896ace738e01da34b2c42235416 2042 | languageName: node 2043 | linkType: hard 2044 | -------------------------------------------------------------------------------- /test/.gitignore: -------------------------------------------------------------------------------- 1 | dist 2 | node_modules 3 | -------------------------------------------------------------------------------- /test/LocaleOptions.tsx: -------------------------------------------------------------------------------- 1 | import { useRef } from 'react'; 2 | 3 | type LocaleOptionsProps = { 4 | locale: string | undefined; 5 | setLocale: (locale: string | undefined) => void; 6 | }; 7 | 8 | export default function LocaleOptions({ locale, setLocale }: LocaleOptionsProps) { 9 | const customLocale = useRef(null); 10 | 11 | function onChange(event: React.ChangeEvent) { 12 | const { value: nextLocale } = event.target; 13 | 14 | if (nextLocale === 'undefined') { 15 | setLocale(undefined); 16 | } else { 17 | setLocale(nextLocale); 18 | } 19 | } 20 | 21 | function onCustomChange(event: React.FormEvent) { 22 | event.preventDefault(); 23 | 24 | const input = customLocale.current; 25 | const { value: nextLocale } = input as HTMLInputElement; 26 | 27 | setLocale(nextLocale); 28 | } 29 | 30 | function resetLocale() { 31 | setLocale(undefined); 32 | } 33 | 34 | return ( 35 |
36 | Locale 37 | 38 |
39 | 47 | 48 |
49 |
50 | 58 | 59 |
60 |
61 | 69 | 70 |
71 |
72 | 80 | 81 |
82 |
83 | 84 |   85 | 94 |   95 | 98 | 101 |
102 |
103 | ); 104 | } 105 | -------------------------------------------------------------------------------- /test/MaxDetailOptions.tsx: -------------------------------------------------------------------------------- 1 | import type { Detail } from './shared/types.js'; 2 | 3 | const allViews = ['hour', 'minute', 'second'] as const; 4 | 5 | function upperCaseFirstLetter(str: string) { 6 | return str.slice(0, 1).toUpperCase() + str.slice(1); 7 | } 8 | 9 | type MaxDetailOptionsProps = { 10 | maxDetail: Detail; 11 | setMaxDetail: (maxDetail: Detail) => void; 12 | }; 13 | 14 | export default function MaxDetailOptions({ maxDetail, setMaxDetail }: MaxDetailOptionsProps) { 15 | function onChange(event: React.ChangeEvent) { 16 | const { value } = event.target; 17 | 18 | setMaxDetail(value as Detail); 19 | } 20 | 21 | return ( 22 |
23 | Maximum detail 24 | 25 | {allViews.map((view) => ( 26 |
27 | 35 | {/* biome-ignore lint/a11y/noLabelWithoutControl: Pinky promise this label won't ever be empty */} 36 | 37 |
38 | ))} 39 |
40 | ); 41 | } 42 | -------------------------------------------------------------------------------- /test/Test.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: Segoe UI, Tahoma, sans-serif; 4 | } 5 | 6 | .Test header { 7 | background-color: #323639; 8 | box-shadow: 0 0 8px rgba(0, 0, 0, 0.5); 9 | padding: 20px; 10 | color: white; 11 | } 12 | 13 | .Test header h1 { 14 | font-size: inherit; 15 | margin: 0; 16 | } 17 | 18 | .Test__container { 19 | display: flex; 20 | flex-direction: row; 21 | flex-wrap: wrap; 22 | align-items: flex-start; 23 | margin: 10px 0; 24 | padding: 10px; 25 | } 26 | 27 | .Test__container > * > * { 28 | margin: 10px; 29 | } 30 | 31 | .Test__container__options { 32 | display: flex; 33 | flex-basis: 400px; 34 | flex-grow: 1; 35 | flex-wrap: wrap; 36 | margin: 0; 37 | } 38 | 39 | .Test__container__options input, 40 | .Test__container__options button { 41 | font: inherit; 42 | } 43 | 44 | .Test__container__options fieldset { 45 | border: 1px solid black; 46 | flex-grow: 1; 47 | position: relative; 48 | top: -10px; 49 | } 50 | 51 | .Test__container__options fieldset legend { 52 | font-weight: 600; 53 | } 54 | 55 | .Test__container__options fieldset legend + * { 56 | margin-top: 0 !important; 57 | } 58 | 59 | .Test__container__options fieldset label { 60 | font-weight: 600; 61 | display: block; 62 | } 63 | 64 | .Test__container__options fieldset label:not(:first-of-type) { 65 | margin-top: 1em; 66 | } 67 | 68 | .Test__container__options fieldset input[type='checkbox'] + label, 69 | .Test__container__options fieldset input[type='radio'] + label { 70 | font-weight: normal; 71 | display: inline-block; 72 | margin: 0; 73 | } 74 | 75 | .Test__container__options fieldset form:not(:first-child), 76 | .Test__container__options fieldset div:not(:first-child) { 77 | margin-top: 1em; 78 | } 79 | 80 | .Test__container__options fieldset form:not(:last-child), 81 | .Test__container__options fieldset div:not(:last-child) { 82 | margin-bottom: 1em; 83 | } 84 | 85 | .Test__container__content { 86 | display: flex; 87 | max-width: 100%; 88 | flex-basis: 420px; 89 | flex-direction: column; 90 | flex-grow: 100; 91 | align-items: stretch; 92 | } 93 | -------------------------------------------------------------------------------- /test/Test.tsx: -------------------------------------------------------------------------------- 1 | import { useRef, useState } from 'react'; 2 | import TimeRangePicker from '@wojtekmaj/react-timerange-picker'; 3 | import '@wojtekmaj/react-timerange-picker/dist/TimeRangePicker.css'; 4 | import 'react-clock/dist/Clock.css'; 5 | import { getHoursMinutesSeconds } from '@wojtekmaj/date-utils'; 6 | 7 | import ValidityOptions from './ValidityOptions.js'; 8 | import MaxDetailOptions from './MaxDetailOptions.js'; 9 | import LocaleOptions from './LocaleOptions.js'; 10 | import ValueOptions from './ValueOptions.js'; 11 | import ViewOptions from './ViewOptions.js'; 12 | 13 | import './Test.css'; 14 | 15 | import type { Detail, LooseValue } from './shared/types.js'; 16 | 17 | const now = new Date(); 18 | 19 | const ariaLabelProps = { 20 | amPmAriaLabel: 'Select AM/PM', 21 | clearAriaLabel: 'Clear value', 22 | clockAriaLabel: 'Toggle clock', 23 | hourAriaLabel: 'Hour', 24 | minuteAriaLabel: 'Minute', 25 | nativeInputAriaLabel: 'Time', 26 | secondAriaLabel: 'Second', 27 | }; 28 | 29 | const placeholderProps = { 30 | hourPlaceholder: 'hh', 31 | minutePlaceholder: 'mm', 32 | secondPlaceholder: 'ss', 33 | }; 34 | 35 | export default function Test() { 36 | const portalContainer = useRef(null); 37 | const [disabled, setDisabled] = useState(false); 38 | const [locale, setLocale] = useState(); 39 | const [maxTime, setMaxTime] = useState(); 40 | const [maxDetail, setMaxDetail] = useState('minute'); 41 | const [minTime, setMinTime] = useState(); 42 | const [renderInPortal, setRenderInPortal] = useState(false); 43 | const [required, setRequired] = useState(true); 44 | const [value, setValue] = useState(getHoursMinutesSeconds(now)); 45 | 46 | return ( 47 |
48 |
49 |

react-timerange-picker test page

50 |
51 |
52 | 71 |
72 |
{ 74 | event.preventDefault(); 75 | 76 | console.warn('TimeRangePicker triggered submitting the form.'); 77 | console.log(event); 78 | }} 79 | > 80 | console.log('Clock closed')} 94 | onClockOpen={() => console.log('Clock opened')} 95 | portalContainer={renderInPortal ? portalContainer.current : undefined} 96 | required={required} 97 | value={value} 98 | /> 99 |
100 |
101 |
102 | 105 | 106 |
107 |
108 |
109 | ); 110 | } 111 | -------------------------------------------------------------------------------- /test/ValidityOptions.tsx: -------------------------------------------------------------------------------- 1 | type ValidityOptionsProps = { 2 | maxTime?: string; 3 | minTime?: string; 4 | required?: boolean; 5 | setMaxTime: (maxTime: string | undefined) => void; 6 | setMinTime: (minTime: string | undefined) => void; 7 | setRequired: (required: boolean) => void; 8 | }; 9 | 10 | export default function ValidityOptions({ 11 | maxTime, 12 | minTime, 13 | required, 14 | setMaxTime, 15 | setMinTime, 16 | setRequired, 17 | }: ValidityOptionsProps) { 18 | function onMinChange(event: React.ChangeEvent) { 19 | const { value } = event.target; 20 | 21 | setMinTime(value); 22 | } 23 | 24 | function onMaxChange(event: React.ChangeEvent) { 25 | const { value } = event.target; 26 | 27 | setMaxTime(value); 28 | } 29 | 30 | return ( 31 |
32 | Minimum and maximum time 33 | 34 |
35 | 36 | 37 |   38 | 41 |
42 | 43 |
44 | 45 | 46 |   47 | 50 |
51 | 52 |
53 | setRequired(event.target.checked)} 57 | type="checkbox" 58 | /> 59 | 60 |
61 |
62 | ); 63 | } 64 | -------------------------------------------------------------------------------- /test/ValueOptions.tsx: -------------------------------------------------------------------------------- 1 | import { getHoursMinutesSeconds } from '@wojtekmaj/date-utils'; 2 | 3 | import type { LooseValue } from './shared/types.js'; 4 | 5 | type ValueOptionsProps = { 6 | setValue: (value: LooseValue) => void; 7 | value?: LooseValue; 8 | }; 9 | 10 | export default function ValueOptions({ setValue, value }: ValueOptionsProps) { 11 | const [startTime, endTime] = Array.isArray(value) ? value : [value, null]; 12 | 13 | function setStartValue(nextStartTime: string | null) { 14 | if (!nextStartTime) { 15 | setValue(endTime); 16 | return; 17 | } 18 | 19 | if (Array.isArray(value)) { 20 | setValue([nextStartTime, endTime]); 21 | } else { 22 | setValue(nextStartTime); 23 | } 24 | } 25 | 26 | function setEndValue(nextEndTime: string | null) { 27 | if (!nextEndTime) { 28 | setValue(startTime || null); 29 | return; 30 | } 31 | 32 | setValue([startTime || null, nextEndTime]); 33 | } 34 | 35 | function onStartChange(event: React.ChangeEvent) { 36 | const { value: nextValue } = event.target; 37 | 38 | setStartValue(nextValue); 39 | } 40 | 41 | function onEndChange(event: React.ChangeEvent) { 42 | const { value: nextValue } = event.target; 43 | 44 | setEndValue(nextValue); 45 | } 46 | 47 | return ( 48 |
49 | Set time externally 50 | 51 |
52 | 53 | 63 |   64 | 67 | 70 |
71 | 72 |
73 | 74 | 84 |   85 | 88 | 91 |
92 |
93 | ); 94 | } 95 | -------------------------------------------------------------------------------- /test/ViewOptions.tsx: -------------------------------------------------------------------------------- 1 | type ViewOptionsProps = { 2 | disabled: boolean; 3 | renderInPortal: boolean; 4 | setDisabled: (disabled: boolean) => void; 5 | setRenderInPortal: (renderInPortal: boolean) => void; 6 | }; 7 | 8 | export default function ViewOptions({ 9 | disabled, 10 | renderInPortal, 11 | setDisabled, 12 | setRenderInPortal, 13 | }: ViewOptionsProps) { 14 | function onDisabledChange(event: React.ChangeEvent) { 15 | const { checked } = event.target; 16 | 17 | setDisabled(checked); 18 | } 19 | 20 | function onRenderInPortalChange(event: React.ChangeEvent) { 21 | const { checked } = event.target; 22 | 23 | setRenderInPortal(checked); 24 | } 25 | 26 | return ( 27 |
28 | View options 29 | 30 |
31 | 32 | 33 |
34 | 35 |
36 | 42 | 43 |
44 |
45 | ); 46 | } 47 | -------------------------------------------------------------------------------- /test/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | react-timerange-picker test page 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /test/index.tsx: -------------------------------------------------------------------------------- 1 | import { StrictMode } from 'react'; 2 | import { createRoot } from 'react-dom/client'; 3 | 4 | import Test from './Test.js'; 5 | 6 | const root = document.getElementById('root'); 7 | 8 | if (!root) { 9 | throw new Error('Could not find root element'); 10 | } 11 | 12 | createRoot(root).render( 13 | 14 | 15 | , 16 | ); 17 | -------------------------------------------------------------------------------- /test/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "test", 3 | "version": "2.0.0", 4 | "description": "A test page for React-TimeRange-Picker.", 5 | "private": true, 6 | "type": "module", 7 | "scripts": { 8 | "build": "vite build", 9 | "dev": "vite", 10 | "format": "biome format", 11 | "lint": "biome lint", 12 | "preview": "vite preview", 13 | "test": "yarn lint && yarn tsc && yarn format", 14 | "tsc": "tsc" 15 | }, 16 | "author": { 17 | "name": "Wojciech Maj", 18 | "email": "kontakt@wojtekmaj.pl" 19 | }, 20 | "license": "MIT", 21 | "dependencies": { 22 | "@wojtekmaj/date-utils": "^1.0.0", 23 | "@wojtekmaj/react-timerange-picker": "workspace:packages/react-timerange-picker", 24 | "react": "^18.2.0", 25 | "react-dom": "^18.2.0" 26 | }, 27 | "devDependencies": { 28 | "@biomejs/biome": "1.9.0", 29 | "@types/react": "*", 30 | "@vitejs/plugin-react": "^4.3.4", 31 | "typescript": "^5.5.2", 32 | "vite": "^6.2.4" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /test/shared/types.ts: -------------------------------------------------------------------------------- 1 | type Range = [T, T]; 2 | 3 | export type Detail = 'hour' | 'minute' | 'second'; 4 | 5 | type LooseValuePiece = string | Date | null; 6 | 7 | export type LooseValue = LooseValuePiece | Range; 8 | -------------------------------------------------------------------------------- /test/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "isolatedModules": true, 4 | "jsx": "react-jsx", 5 | "module": "preserve", 6 | "moduleDetection": "force", 7 | "noEmit": true, 8 | "noUncheckedIndexedAccess": true, 9 | "skipLibCheck": true, 10 | "strict": true, 11 | "target": "esnext", 12 | "verbatimModuleSyntax": true 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /test/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite'; 2 | import react from '@vitejs/plugin-react'; 3 | 4 | export default defineConfig({ 5 | base: './', 6 | plugins: [react()], 7 | }); 8 | --------------------------------------------------------------------------------